【Android进阶】自定义控件实现底部扇形展开菜单效果
这个项目是优化的其他人的,主要优化了界面菜单的显示,下面开始。
先看效果图
项目的总结构
下面开始贴代码,由于必要的地方都添加了注释,所以不过多讲解
anim_button.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" > <Button android:id="@+id/btn_sleep" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:layout_marginBottom="10dp" android:layout_marginLeft="10dp" android:visibility="invisible" android:background="@drawable/composer_sleep" /> <Button android:id="@+id/btn_thought" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:layout_marginBottom="10dp" android:layout_marginLeft="10dp" android:visibility="invisible" android:background="@drawable/composer_thought" /> <Button android:id="@+id/btn_music" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:layout_marginBottom="10dp" android:layout_marginLeft="10dp" android:visibility="invisible" android:background="@drawable/composer_music" /> <Button android:id="@+id/btn_place" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:layout_marginBottom="10dp" android:layout_marginLeft="10dp" android:visibility="invisible" android:background="@drawable/composer_place" /> <Button android:id="@+id/btn_with" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:layout_marginBottom="10dp" android:layout_marginLeft="10dp" android:visibility="invisible" android:background="@drawable/composer_with" /> <Button android:id="@+id/btn_camera" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:layout_marginBottom="10dp" android:layout_marginLeft="10dp" android:visibility="invisible" android:background="@drawable/composer_camera" /> <Button android:id="@+id/btn_menu" android:layout_width="60dp" android:layout_height="60dp" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:background="@drawable/friends_delete" /> </RelativeLayout>
主界面的布局main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <com.example.anim.AnimButtons android:id="@+id/animButtons" android:layout_width="fill_parent" android:layout_height="fill_parent" /> </LinearLayout>
最重要的,自定义控件的实现
AnimButtons.java
package com.example.anim; import android.R.anim; import android.content.Context; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.view.animation.Animation; import android.view.animation.Animation.AnimationListener; import android.view.animation.ScaleAnimation; import android.view.animation.TranslateAnimation; import android.widget.Button; import android.widget.RelativeLayout; /** * 底部展开菜单实现 * * @author ZhaoKaiQiang * * Time:2014年3月11日 */ public class AnimButtons extends RelativeLayout { private Context context; private int leftMargin = 0, bottomMargin = 0; private final int buttonWidth = 58;// 图片宽高 private final int r = 180;// 半径 private final int maxTimeSpent = 200;// 最长动画耗时 private final int minTimeSpent = 80;// 最短动画耗时 private int intervalTimeSpent;// 每相邻2个的时间间隔 private Button[] btns; private Button btn_menu; private RelativeLayout.LayoutParams params; private boolean isOpen = false;// 是否菜单打开状态 private float angle;// 每个按钮之间的夹角 public int bottomMargins = this.getMeasuredHeight() - buttonWidth - bottomMargin; public AnimButtons(Context context) { super(context); this.context = context; } public AnimButtons(Context context, AttributeSet attrs) { super(context, attrs); this.context = context; } @Override protected void onFinishInflate() { super.onFinishInflate(); View view = LayoutInflater.from(context).inflate(R.layout.anim_buttons, this); initButtons(view); } private void initButtons(View view) { // 可以根据按钮的个数自己增减 btns = new Button[4]; btns[0] = (Button) view.findViewById(R.id.btn_camera); btns[1] = (Button) view.findViewById(R.id.btn_with); btns[2] = (Button) view.findViewById(R.id.btn_place); btns[3] = (Button) view.findViewById(R.id.btn_music); // btns[4] = (Button) view.findViewById(R.id.btn_thought); // btns[5] = (Button) view.findViewById(R.id.btn_sleep); btn_menu = (Button) view.findViewById(R.id.btn_menu); leftMargin = ((RelativeLayout.LayoutParams) (btn_menu.getLayoutParams())).leftMargin; bottomMargin = ((RelativeLayout.LayoutParams) (btn_menu .getLayoutParams())).bottomMargin; for (int i = 0; i < btns.length; i++) { // 初始化的时候按钮重合 btns[i].setLayoutParams(btn_menu.getLayoutParams()); btns[i].setTag(String.valueOf(i)); btns[i].setOnClickListener(clickListener); } intervalTimeSpent = (maxTimeSpent - minTimeSpent) / btns.length; angle = (float) Math.PI / (2 * (btns.length - 1)); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); bottomMargins = this.getMeasuredHeight() - buttonWidth - bottomMargin; btn_menu.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (!isOpen) { openMenu(); } else { closeMenu(); } } }); } public void closeMenu() { if (isOpen == true) { isOpen = false; for (int i = 0; i < btns.length; i++) { float xLenth = (float) (r * Math.sin(i * angle)); float yLenth = (float) (r * Math.cos(i * angle)); btns[i].startAnimation(animTranslate(-xLenth, yLenth, leftMargin, bottomMargins, btns[i], maxTimeSpent - i * intervalTimeSpent)); btns[i].setVisibility(View.INVISIBLE); } } } public void openMenu() { isOpen = true; for (int i = 0; i < btns.length; i++) { float xLenth = (float) (r * Math.sin(i * angle)); float yLenth = (float) (r * Math.cos(i * angle)); btns[i].startAnimation(animTranslate(xLenth, -yLenth, leftMargin + (int) xLenth, bottomMargins - (int) yLenth, btns[i], minTimeSpent + i * intervalTimeSpent)); btns[i].setVisibility(View.VISIBLE); } } private Animation animScale(float toX, float toY) { Animation animation = new ScaleAnimation(1.0f, toX, 1.0f, toY, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); animation.setInterpolator(context, anim.accelerate_decelerate_interpolator); animation.setDuration(400); animation.setFillAfter(false); return animation; } private Animation animTranslate(float toX, float toY, final int lastX, final int lastY, final Button button, long durationMillis) { Animation animation = new TranslateAnimation(0, toX, 0, toY); animation.setAnimationListener(new AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationRepeat(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { params = new RelativeLayout.LayoutParams(0, 0); params.height = buttonWidth; params.width = buttonWidth; params.setMargins(lastX, lastY, 0, 0); button.setLayoutParams(params); button.clearAnimation(); } }); animation.setDuration(durationMillis); return animation; } View.OnClickListener clickListener = new View.OnClickListener() { @Override public void onClick(View v) { int selectedItem = Integer.parseInt((String) v.getTag()); for (int i = 0; i < btns.length; i++) { if (i == selectedItem) { btns[i].startAnimation(animScale(2.0f, 2.0f)); } else { btns[i].startAnimation(animScale(0.0f, 0.0f)); } } if (onButtonClickListener != null) { onButtonClickListener.onButtonClick(v, selectedItem); } } }; public boolean isOpen() { return isOpen; } private OnButtonClickListener onButtonClickListener; public interface OnButtonClickListener { void onButtonClick(View v, int id); } public void setOnButtonClickListener( OnButtonClickListener onButtonClickListener) { this.onButtonClickListener = onButtonClickListener; } }
AnimButtonsActivity.java
package com.example.anim; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.Toast; /** * 主界面 * @author ZhaoKaiQiang * * Time:2014年3月11日 */ public class AnimButtonsActivity extends Activity { private AnimButtons animButtons; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); animButtons = (AnimButtons) findViewById(R.id.animButtons); animButtons .setOnButtonClickListener(new AnimButtons.OnButtonClickListener() { @Override public void onButtonClick(View v, int id) { Toast.makeText(AnimButtonsActivity.this, "id-->" + id, 0).show(); animButtons.closeMenu(); } }); } }
点击下载源码
如有问题,请留言