自定义ViewGroup实现点击按钮弹出多个按钮

原文是实现4个顶角弹出,我需要左边正中弹出,做了修改

原文地址:点击打开链接


原文效果图



修改后效果图,没录GIF,就看弹出来是的图片吧




修改后代码:

package com.jisai.bodyfriend.view.ArcMenu;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationSet;
import android.view.animation.OvershootInterpolator;
import android.view.animation.RotateAnimation;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;

import com.jisai.bodyfriend.R;


public class ArcMenu extends ViewGroup implements OnClickListener
{

	private static final String TAG = "ArcMenu";


	/**
	 * 菜单显示的半径,默认200dp
	 */
	private int mRadius = 200;
	/**
	 * 用户点击的按钮
	 */
	private View mButton;
	/**
	 * 当前ArcMenu的状态
	 */
	private Status mCurrentStatus = Status.CLOSE;
	/**
	 * 回调接口
	 */
	private OnMenuItemClickListener onMenuItemClickListener;

	/**
	 * 状态的枚举类
	 * 
	 * @author zhy
	 * 
	 */
	public enum Status
	{
		OPEN, CLOSE
	}



	public interface OnMenuItemClickListener
	{
		void onClick(View view, int pos);
	}

	public ArcMenu(Context context)
	{
		this(context, null);
	}

	public ArcMenu(Context context, AttributeSet attrs)
	{
		this(context, attrs, 0);

	}

	/**
	 * 初始化属性
	 * 
	 * @param context
	 * @param attrs
	 * @param defStyle
	 */
	public ArcMenu(Context context, AttributeSet attrs, int defStyle)
	{

		super(context, attrs, defStyle);
		// dp convert to px
		mRadius = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
				mRadius, getResources().getDisplayMetrics());
		TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
				R.styleable.ArcMenu, defStyle, 0);

		int n = a.getIndexCount();
		for (int i = 0; i < n; i++)
		{
			int attr = a.getIndex(i);
			switch (attr)
			{
			case R.styleable.ArcMenu_position:
				int val = a.getInt(attr, 0);

				break;
			case R.styleable.ArcMenu_radius:
				// dp convert to px
				mRadius = a.getDimensionPixelSize(attr, (int) TypedValue
						.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 100f,
								getResources().getDisplayMetrics()));
				break;

			}
		}
		a.recycle();
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
	{
		int count = getChildCount();
		for (int i = 0; i < count; i++)
		{
			// mesure child
			getChildAt(i).measure(MeasureSpec.UNSPECIFIED,
					MeasureSpec.UNSPECIFIED);
		}
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b)
	{
		if (changed)
		{

			layoutButton();
			int count = getChildCount();
			/**
			 * 设置所有孩子的位置 例如(第一个为按钮): 左上时,从左到右 ] 第2个:mRadius(sin0 , cos0)
			 * 第3个:mRadius(sina ,cosa) 注:[a = Math.PI / 2 * (cCount - 1)]
			 * 第4个:mRadius(sin2a ,cos2a) 第5个:mRadius(sin3a , cos3a) ...
			 */
			for (int i = 0; i < count - 1; i++)
			{
				View child = getChildAt(i + 1);
				child.setVisibility(View.GONE);
				// childview width
				int cWidth = child.getMeasuredWidth();
				// childview height
				int cHeight = child.getMeasuredHeight();
				int cl,ct ;
				int d =30+(120/(count-2)*i);
				Log.e(TAG,"i===="+i+"d======"+d+"c===="+count);
				if(d>90){
					d=180-d;
					cl = (int) (mRadius * Math.sin(d * Math.PI / 180));
					ct =(int) (getMeasuredHeight()/2.0)-(int) (mRadius * Math.cos(d * Math.PI / 180))-cHeight/2;
				}else{
					cl = (int) (mRadius * Math.sin(d * Math.PI / 180));
					ct = (int) (mRadius * Math.cos(d * Math.PI / 180))+(int) (getMeasuredHeight()/2.0)-cHeight/2;
				}

//				int cl = (int) (mRadius * Math.sin(Math.PI *(3/4.0) / (count - 2)
//						* i));
//				int ct = (int) (mRadius * Math.cos(Math.PI *(3/4.0) / (count - 2)
//						* i));
//				// childview width
//				int cWidth = child.getMeasuredWidth();
//				// childview height
//				int cHeight = child.getMeasuredHeight();

					//ct = getMeasuredHeight() - cHeight - ct;

//				// 右上,右下
//				if (mPosition == Position.RIGHT_TOP
//						|| mPosition == Position.RIGHT_BOTTOM)
//				{
//					cl = getMeasuredWidth() - cWidth - cl;
//				}

				Log.e(TAG, cl + " , " + ct);
				child.layout(cl, ct, cl + cWidth, ct + cHeight);

			}
		}
	}

	/**
	 * 第一个子元素为按钮,为按钮布局且初始化点击事件
	 */
	private void layoutButton()
	{
		View cButton = getChildAt(0);

		cButton.setOnClickListener(this);

		int l ;
		int t ;
		int width = cButton.getMeasuredWidth();
		int height = cButton.getMeasuredHeight();
		l = 0;
		t = (getMeasuredHeight() - height)/2;
		Log.e(TAG, l + " , " + t + " , " + (l + width) + " , " + (t + height));
		cButton.layout(l, t, l + width, t + height);

	}

	/**
	 * 为按钮添加点击事件
	 */
	@Override
	public void onClick(View v)
	{
		mButton = findViewById(R.id.id_button);
		if (mButton == null)
		{
			mButton = getChildAt(0);
		}
		rotateView(mButton, 0f, 270f, 300);
		toggleMenu(300);
	}

	/**
	 * 按钮的旋转动画
	 * 
	 * @param view
	 * @param fromDegrees
	 * @param toDegrees
	 * @param durationMillis
	 */
	public static void rotateView(View view, float fromDegrees,
			float toDegrees, int durationMillis)
	{
		RotateAnimation rotate = new RotateAnimation(fromDegrees, toDegrees,
				Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
				0.5f);
		rotate.setDuration(durationMillis);
		rotate.setFillAfter(true);
		view.startAnimation(rotate);
	}

	public void toggleMenu(int durationMillis)
	{
		int count = getChildCount();
		for (int i = 0; i < count - 1; i++)
		{
			final View childView = getChildAt(i + 1);
			childView.setVisibility(View.VISIBLE);

			int xflag = -1;
			int yflag = 1;


			// childview width
			int cWidth = childView.getMeasuredWidth();
			// childview height
			int cHeight = childView.getMeasuredHeight();
			int cl,ct ;
			int d =30+(120/(count-2)*i);
			Log.e(TAG,"i===="+i+"d======"+d+"c===="+count);
			if(d>90){
				d=180-d;
				cl = (int) (mRadius * Math.sin(d * Math.PI / 180));
				ct =(int) (getMeasuredHeight()/2.0)-(int) (mRadius * Math.cos(d * Math.PI / 180))-cHeight/2;
			}else{
				cl = (int) (mRadius * Math.sin(d * Math.PI / 180));
				ct = (int) (mRadius * Math.cos(d * Math.PI / 180))+(int) (getMeasuredHeight()/2.0)-cHeight/2;
			}
			if(ct>(getMeasuredHeight()/2.0)){
				ct=0-(ct-(int)( getMeasuredHeight()/2.0))-cHeight/2;
			}else{
				ct=(int)( getMeasuredHeight()/2.0)-ct-cHeight/2;
			}
			AnimationSet animset = new AnimationSet(true);
			Animation animation = null;
			if (mCurrentStatus == Status.CLOSE)
			{// to open
				animset.setInterpolator(new OvershootInterpolator(2F));

				animation = new TranslateAnimation(xflag * cl,0, yflag * ct, 0);
				childView.setClickable(true);
				childView.setFocusable(true);
			} else
			{// to close
				animation = new TranslateAnimation(0, xflag * cl, 0, yflag* ct);
				childView.setClickable(false);
				childView.setFocusable(false);
			}
			animation.setAnimationListener(new AnimationListener()
			{
				public void onAnimationStart(Animation animation)
				{
				}

				public void onAnimationRepeat(Animation animation)
				{
				}

				public void onAnimationEnd(Animation animation)
				{
					if (mCurrentStatus == Status.CLOSE)
						childView.setVisibility(View.GONE);

				}
			});

			animation.setFillAfter(true);
			animation.setDuration(durationMillis);
			// 为动画设置一个开始延迟时间,纯属好看,可以不设
			animation.setStartOffset((i * 100) / (count - 1));
			RotateAnimation rotate = new RotateAnimation(0, 720,
					Animation.RELATIVE_TO_SELF, 0.5f,
					Animation.RELATIVE_TO_SELF, 0.5f);
			rotate.setDuration(durationMillis);
			rotate.setFillAfter(true);
			animset.addAnimation(rotate);
			animset.addAnimation(animation);
			childView.startAnimation(animset);
			final int index = i + 1;
			childView.setOnClickListener(new OnClickListener()
			{
				@Override
				public void onClick(View v)
				{
					if (onMenuItemClickListener != null)
						onMenuItemClickListener.onClick(childView, index - 1);
					menuItemAnin(index - 1);
					changeStatus();
					
				}
			});

		}
		changeStatus();
		Log.e(TAG, mCurrentStatus.name() +"");
	}

	private void changeStatus()
	{
		mCurrentStatus = (mCurrentStatus == Status.CLOSE ? Status.OPEN
				: Status.CLOSE);
	}
	/**
	 * 开始菜单动画,点击的MenuItem放大消失,其他的缩小消失
	 * @param item
	 */
	private void menuItemAnin(int item)
	{
		for (int i = 0; i < getChildCount() - 1; i++)
		{
			View childView = getChildAt(i + 1);
			if (i == item)
			{
				childView.startAnimation(scaleBigAnim(300));
			} else
			{
				childView.startAnimation(scaleSmallAnim(300));
			}
			childView.setClickable(false);
			childView.setFocusable(false);

		}

	}
	
	/**
	 * 缩小消失
	 * @param durationMillis
	 * @return
	 */
	private Animation scaleSmallAnim(int durationMillis)
	{
		Animation anim = new ScaleAnimation(1.0f, 0f, 1.0f, 0f,
				Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
				0.5f);
		anim.setDuration(durationMillis);
		anim.setFillAfter(true);
		return anim;
	}
	/**
	 * 放大,透明度降低
	 * @param durationMillis
	 * @return
	 */
	private Animation scaleBigAnim(int durationMillis)
	{
		AnimationSet animationset = new AnimationSet(true);

		Animation anim = new ScaleAnimation(1.0f, 4.0f, 1.0f, 4.0f,
				Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
				0.5f);
		Animation alphaAnimation = new AlphaAnimation(1, 0);
		animationset.addAnimation(anim);
		animationset.addAnimation(alphaAnimation);
		animationset.setDuration(durationMillis);
		animationset.setFillAfter(true);
		return animationset;
	}


	public int getmRadius()
	{
		return mRadius;
	}

	public void setmRadius(int mRadius)
	{
		this.mRadius = mRadius;
	}

	public Status getmCurrentStatus()
	{
		return mCurrentStatus;
	}

	public void setmCurrentStatus(Status mCurrentStatus)
	{
		this.mCurrentStatus = mCurrentStatus;
	}

	public OnMenuItemClickListener getOnMenuItemClickListener()
	{
		return onMenuItemClickListener;
	}

	public void setOnMenuItemClickListener(
			OnMenuItemClickListener onMenuItemClickListener)
	{
		this.onMenuItemClickListener = onMenuItemClickListener;
	}

}


猜你喜欢

转载自blog.csdn.net/ink_s/article/details/78929514