【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();
					}
				});
	}
}

点击下载源码


如有问题,请留言



转载于:https://www.cnblogs.com/oversea201405/p/3749551.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值