Android 类似于ArcMenu(github上开源项目)的自定义多个按钮视图

最近的项目中有个比较好的开源的多个分享按钮的自定义视图,感觉比较好,所以就研究了下,写了下来。其实这个demo类似于github上开源项目ArcMenu开源项目,项目下载地址为:https://github.com/daCapricorn/ArcMenu

实现效果图:

技术分享

1、点击该按钮,五个按钮飞入屏幕;

2、点击五个按钮其中的一个后,改按钮放到直至消失,其余的按钮变小直至消失。

体验感还是挺好的。

技术分享

再次点击五个按钮飞出屏幕。


好了,下面上源码吧。比较多,但都是些自定义的空间,看两遍就能看懂啦。。

技术分享

只有一个布局文件:share_layout:

里面定义了布局和按钮,这些都是自定义的布局或按钮。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <com.customview.InOutRelativeLayout
        android:id="@+id/buttons_wrapper"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:clipChildren="false"
        android:clipToPadding="false" >

        <!-- 微信 -->

        <com.customview.InOutImageButton
            android:id="@+id/button_weixinfriends"
            android:layout_width="46dip"
            android:layout_height="46dip"
            android:layout_alignParentBottom="true"
            android:layout_marginBottom="210dip"
            android:layout_marginLeft="30dip"
            android:background="@drawable/weixin"
            android:visibility="invisible" />

        <!-- 微信朋友圈 -->

        <com.customview.InOutImageButton
            android:id="@+id/button_friendsQuan"
            android:layout_width="46dip"
            android:layout_height="46dip"
            android:layout_alignParentBottom="true"
            android:layout_marginBottom="190dip"
            android:layout_marginLeft="103dip"
            android:background="@drawable/friend_quan"
            android:visibility="invisible" />
        <!-- 清除 -->

        <com.customview.InOutImageButton
            android:id="@+id/button_clear"
            android:layout_width="46dip"
            android:layout_height="46dip"
            android:layout_alignParentBottom="true"
            android:layout_marginBottom="127dip"
            android:layout_marginLeft="113dip"
            android:background="@drawable/clear"
            android:visibility="invisible" />
        <!-- 重置 -->

        <com.customview.InOutImageButton
            android:id="@+id/button_reset"
            android:layout_width="46dip"
            android:layout_height="46dip"
            android:layout_alignParentBottom="true"
            android:layout_marginBottom="50dip"
            android:layout_marginLeft="97dip"
            android:background="@drawable/reset"
            android:visibility="invisible" />
        <!-- 截屏 -->

        <com.customview.InOutImageButton
            android:id="@+id/button_screenshot"
            android:layout_width="46dip"
            android:layout_height="46dip"
            android:layout_alignParentBottom="true"
            android:layout_marginLeft="30dip"
            android:background="@drawable/screenshot"
            android:visibility="invisible" />
    </com.customview.InOutRelativeLayout>

    <com.customview.InOutRelativeLayout
        android:id="@+id/button_control_show_hide"
        android:layout_width="60dip"
        android:layout_height="60dip"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_marginBottom="100dip"
        android:layout_marginLeft="20dip"
        android:background="@drawable/btn_selector" >

        <ImageView
            android:id="@+id/button_control_show_hide_icon"
            android:layout_width="60dip"
            android:layout_height="60dip"
            android:layout_alignParentBottom="true"
            android:layout_alignParentLeft="true"
            android:layout_marginBottom="100dip"
            android:layout_marginLeft="20dip"
            android:visibility="visible" />
    </com.customview.InOutRelativeLayout>

</RelativeLayout>

下面是主view界面MainActivity类:

布局和触发事件都是在该类中进行的

package com.view;

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.widget.Toast;

import com.anim.AbstractInOutAnimationSet.Direction;
import com.anim.AnimationControlUtils;
import com.anim.ClickAnimationSet;
import com.anim.NotClickAnimationSet;
import com.customview.InOutImageButton;
import com.customview.InOutRelativeLayout;

/**
 * 自定义弹入弹出按钮MainActivity
 * 
 * @author zhongyao
 */
public class MainActivity extends ActionBarActivity {
	private View mControlButton;
	private boolean mAreButtonsShowins;
	private InOutRelativeLayout mButtonsWrapper;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.share_layout);

		/**
		 * 初始化控件
		 */
		initshareView();
	}

	/**
	 * 初始化控件
	 */
	private void initshareView() {
		mControlButton = findViewById(R.id.button_control_show_hide);
		mControlButton.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				/**
				 * 弹出收回开关
				 */
				toggleButton();
			}
		});

		// 所有弹出收回按钮视图集合
		mButtonsWrapper = (InOutRelativeLayout) findViewById(R.id.buttons_wrapper);

		// 设置每个弹出收回按钮的点击事件,点击后放大并隐藏
		for (int i = 0, count = mButtonsWrapper.getChildCount(); i < count; i++) {
			if (mButtonsWrapper.getChildAt(i) instanceof InOutImageButton) {
				View view = mButtonsWrapper.getChildAt(i);
				view.setOnClickListener(new OnClickListener() {
					@Override
					public void onClick(View subject) {
						startButtonClickAnimations(subject);
					}
				});
			}
		}
	}

	/**
	 * 弹出收回开关
	 */
	private void toggleButton() {
		if (mAreButtonsShowins) {

			// 按钮弹出
			AnimationControlUtils.startAnimations(mButtonsWrapper,
					Direction.OUT, 4);
		} else {

			// 按钮弹入
			AnimationControlUtils.startAnimations(mButtonsWrapper,
					Direction.IN, 4);
		}

		mAreButtonsShowins = !mAreButtonsShowins;
	}

	/**
	 * 弹出收回按钮点击后动画(点击弹出按钮添加的动画)
	 * 
	 * @param view
	 */
	private void startButtonClickAnimations(View subject) {
		mAreButtonsShowins = false;

		// 为每一个按钮都设置动画
		for (int i = 0, count = mButtonsWrapper.getChildCount(); i < count; i++) {
			if (mButtonsWrapper.getChildAt(i) instanceof InOutImageButton) {
				View view = mButtonsWrapper.getChildAt(i);
				if (view.getId() == subject.getId()) {
					// 点击按钮放大并消失
					ClickAnimationSet clickset = new ClickAnimationSet(600);
					clickset.setAnimationListener(new CustomAnimationListener(
							view));
					view.startAnimation(clickset);
				} else {
					// 未点击按钮缩小并消失
					view.startAnimation(new NotClickAnimationSet(600));
				}
			}
		}
	}

	/**
	 * 按钮点击监听器
	 */
	private class CustomAnimationListener implements AnimationListener {
		private View view;

		public CustomAnimationListener(View view) {
			this.view = view;
		}

		@Override
		public void onAnimationStart(Animation animation) {
		}

		@Override
		public void onAnimationEnd(Animation animation) {
			int id = view.getId();
			switch (id) {
			case R.id.button_weixinfriends:// 分享到微信
				Toast.makeText(getApplicationContext(), "分享到朋友圈",
						Toast.LENGTH_SHORT).show();
				break;
			case R.id.button_friendsQuan:// 分享到朋友圈
				Toast.makeText(getApplicationContext(), "分享到微信好友",
						Toast.LENGTH_SHORT).show();
				break;
			case R.id.button_clear:
				Toast.makeText(getApplicationContext(), "清除轨迹",
						Toast.LENGTH_SHORT).show();
				break;
			case R.id.button_reset:
				Toast.makeText(getApplicationContext(), "重置轨迹",
						Toast.LENGTH_SHORT).show();
				break;
			case R.id.button_screenshot:
				Toast.makeText(getApplicationContext(), "截屏",
						Toast.LENGTH_SHORT).show();
				break;
			default:
				break;
			}
		}

		@Override
		public void onAnimationRepeat(Animation animation) {

		}

	}

}

按钮弹入弹出工具类AnimationControlUtils:

package com.anim;

import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
import android.view.animation.AnticipateInterpolator;
import android.view.animation.OvershootInterpolator;

import com.anim.AbstractInOutAnimationSet.Direction;
import com.customview.InOutImageButton;
/**
 * 按钮弹入弹出工具类
 * @author zhongyao
 */
public class AnimationControlUtils {

	// 动画总用时单位毫秒
	private static final int DIRECTION = 500;

	
	public static void startAnimations(ViewGroup buttons, Direction directioin,
			int flagButton) {
		switch (directioin) {
		case IN:
			startAnimationsIn(buttons, flagButton);
			break;

		case OUT:
			startAnimationsOut(buttons, flagButton);
			break;
		}
	}

	/**
	 * @param buttons
	 *            所有弹出收回按钮集合
	 */
	private static void startAnimationsIn(ViewGroup buttons, int flagButton) {
		final int count = buttons.getChildCount();
		for (int i = 0; i < count; i++) {

			if (buttons.getChildAt(i) instanceof InOutImageButton) {
				// 为每个按钮
				InOutImageButton button = (InOutImageButton) buttons
						.getChildAt(i);

				if (flagButton == 4) {

					// 按钮移动动画
					PopupButtonAnimationSet animation = new PopupButtonAnimationSet(
							Direction.IN, DIRECTION, button);
					long offset = i * 100 / (count - 1);
					// 设置启动动画时间,目的是不同时移动
					animation.setStartOffset(offset);
					// 设置图片的回弹(overshoot)效果
					animation.setInterpolator(new OvershootInterpolator(2.0f));
					button.startAnimation(animation);
				} else{
					AlphaAnimation myAnimation_Alpha = new AlphaAnimation(0.0f,
							1.0f);
					myAnimation_Alpha
							.setInterpolator(new AnticipateInterpolator(2.0F));
					myAnimation_Alpha.setFillAfter(true);
					button.startAnimation(myAnimation_Alpha);
				}

			}

		}
	}

	/**
	 * @param composerButtons
	 */
	private static void startAnimationsOut(ViewGroup buttons, int flagButton) {
		final int count = buttons.getChildCount();
		for (int i = 0; i < count; i++) {

			if ((buttons.getChildAt(i) instanceof InOutImageButton)) {
				InOutImageButton button = (InOutImageButton) buttons
						.getChildAt(i);

				if (flagButton == 4) {
					PopupButtonAnimationSet animation = new PopupButtonAnimationSet(
							Direction.OUT, DIRECTION, button);
					long offset = (count - 1 - i) * 100 / (count - 1);
					animation.setStartOffset(offset);
					animation.setInterpolator(new AnticipateInterpolator(2.0F));
					button.startAnimation(animation);
				} else {
					AlphaAnimation myAnimation_Alpha = new AlphaAnimation(1.0f,
							0.0f);
					myAnimation_Alpha
							.setInterpolator(new AnticipateInterpolator(2.0F));
					myAnimation_Alpha.setFillAfter(false);
					button.startAnimation(myAnimation_Alpha);
				}
			}
		}
	}
}

按钮动画抽象类AbstractInOutAnimationSet,anim包中剩余的其他三个类都集成该抽象类:

package com.anim;

import android.view.View;
import android.view.animation.AnimationSet;
/**
 * 按钮动画抽象类
 * @author zhongyao
 */
public abstract class AbstractInOutAnimationSet extends AnimationSet {

	/**
	 * 记录当前动画方向
	 */
	private final Direction mDirectioin;

	public enum Direction {
		IN, OUT
	}

	public AbstractInOutAnimationSet(Direction directioin, long duration,
			View[] views) {
		super(true);

		mDirectioin = directioin;

		switch (directioin) {
		case IN:
			addInAnimation(views);
			break;

		case OUT:
			addOutAnimation(views);
			break;
		}

		// 添加完动画之后再设置执行总时间
		setDuration(duration);
	}

	public Direction getDirection() {
		return mDirectioin;
	}

	/**
	 * @param views
	 */
	protected abstract void addInAnimation(View[] views);

	/**
	 * @param views
	 */
	protected abstract void addOutAnimation(View[] views);

}

弹出收回按钮移动轨迹动画集合PopupButtonAnimationSet:
package com.anim;

import android.view.View;
import android.view.ViewGroup;
import android.view.animation.TranslateAnimation;

/**
 *	弹出收回按钮移动轨迹动画集合
 */
public class PopupButtonAnimationSet extends AbstractInOutAnimationSet {

	private static final int mXOffset = 16;
	private static final int mYOffset = 243;
	
	public PopupButtonAnimationSet(Direction directioin, long duration,
			View subject) {
		super(directioin, duration, new View[]{ subject});
	}

	/**  480 * 800手机上值变化规律
	弹出
	x = 0.0 , y = 456.0
	x = -62.0 , y = 446.0
	x = -118.0 , y = 418.0
	x = -162.0 , y = 374.0
	x = -190.0 , y = 318.0
	x = -200.0 , y = 256.0
	*/
	@Override
	protected void addInAnimation(View[] views) {
		ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) views[0].getLayoutParams();
		// 计算每个弹出收回按钮的移动轨迹
		float x = -layoutParams.leftMargin + mXOffset;
		float y = layoutParams.bottomMargin + mYOffset;
		
		// 移动位置动画
		TranslateAnimation translateAnimation = new TranslateAnimation(x, 0.0f, y, 0.0f);
		addAnimation(translateAnimation);
	}
	
	/**
	收回
	x = 0.0 , y = 456.0
	x = -62.0 , y = 446.0
	x = -118.0 , y = 418.0
	x = -162.0 , y = 374.0
	x = -190.0 , y = 318.0
	x = -200.0 , y = 256.0
	 */	

	@Override
	protected void addOutAnimation(View[] views) {
		ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) views[0].getLayoutParams();
		float x = -layoutParams.leftMargin + mXOffset;
		float y = layoutParams.bottomMargin + mYOffset;
		TranslateAnimation animation = new TranslateAnimation(0.0F, x, 0.0F, y);
		addAnimation(animation);
	}

}

点击按钮放大并消失动画集合ClickAnimationSet:

package com.anim;

import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.ScaleAnimation;

/**
 *	点击按钮放大并消失动画集合
 */
public class ClickAnimationSet extends AbstractInOutAnimationSet {

	public ClickAnimationSet(long duration) {
		super(Direction.OUT, duration, null);
	}

	@Override
	protected void addInAnimation(View[] views) {
		
	}

	@Override
	protected void addOutAnimation(View[] views) {
		addAnimation(new ScaleAnimation(1.0F, 5.0F, 1.0F, 5.0F, 1, 0.5F,
				Animation.RELATIVE_TO_SELF, 0.5F));
    	addAnimation(new AlphaAnimation(1.0F, 0.0F));
	}
	
}

弹出收回按钮点击后动画NotClickAnimationSet:

package com.anim;

import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.ScaleAnimation;

/**
 *	弹出收回按钮点击后动画
 */
public class NotClickAnimationSet extends AbstractInOutAnimationSet {

	public NotClickAnimationSet(long duration) {
		// 只是控制直接调用addOutAnimation
		super(Direction.OUT, duration, null);
	}

	@Override
	protected void addInAnimation(View[] views) {
	}

	@Override
	protected void addOutAnimation(View[] views) {
		addAnimation(new ScaleAnimation(1.0F, 0.0F, 1.0F, 0.0F, 
				Animation.RELATIVE_TO_SELF, 0.5F, 1, 0.5F));
		addAnimation(new AlphaAnimation(1.0F, 0.0F));
	}

}

下面就是在布局中引用过的自定义布局、自定义按钮:

自定义布局InOutRelativeLayout:

package com.customview;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.widget.RelativeLayout;

import com.anim.AbstractInOutAnimationSet;
import com.anim.AbstractInOutAnimationSet.Direction;

public class InOutRelativeLayout extends RelativeLayout {

	private Animation mAnimation;

	public InOutRelativeLayout(Context context) {
		super(context);
	}


	public InOutRelativeLayout(Context context, AttributeSet attrs) {
		super(context, attrs);
	}
	
	public InOutRelativeLayout(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}
	
	@Override
	protected void onAnimationStart() {
		super.onAnimationStart();
		if (mAnimation instanceof AnimationSet) {
			setVisibility(View.VISIBLE);
		}
	}

	@Override
	protected void onAnimationEnd() {
		super.onAnimationEnd();
		
		if (mAnimation instanceof AbstractInOutAnimationSet) {
			AbstractInOutAnimationSet animationSet = (AbstractInOutAnimationSet) mAnimation;
			if (animationSet.getDirection() == Direction.OUT) {
				setVisibility(View.GONE);
			} else {
				setVisibility(View.VISIBLE);
			}
		}
	}

	@Override
	public void startAnimation(Animation animation) {
		super.startAnimation(animation);
		mAnimation = animation;
		getRootView().postInvalidate();
	}
}

弹出,收回按钮InOutImageButton:

package com.customview;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Animation;
import android.widget.ImageButton;

import com.anim.AbstractInOutAnimationSet;

/**
 *	弹出,收回按钮
 */
public class InOutImageButton extends ImageButton {

	private Animation mAnimation;

	public InOutImageButton(Context context) {
		super(context);
	}


	public InOutImageButton(Context context, AttributeSet attrs) {
		super(context, attrs);
	}
	
	public InOutImageButton(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	@Override
	protected void onAnimationStart() {
		super.onAnimationStart();
		if (mAnimation instanceof AbstractInOutAnimationSet) {
			setVisibility(View.VISIBLE);
		}
	}

	@Override
	protected void onAnimationEnd() {
		super.onAnimationEnd();
		if (mAnimation instanceof AbstractInOutAnimationSet) {
			AbstractInOutAnimationSet animation = (AbstractInOutAnimationSet) mAnimation;

			if (animation.getDirection() == com.anim.AbstractInOutAnimationSet.Direction.OUT) {
				setVisibility(View.GONE);
			} else {
				setVisibility(View.VISIBLE);
			}
		}
	}

	@Override
	public void startAnimation(Animation animation) {
		super.startAnimation(animation);
		mAnimation = animation;
		getRootView().postInvalidate();
	}
}

基本就是这些,下面我提供下源码,大家可以结合下源码看:

点击下载源码



郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。