最近的项目中有个比较好的开源的多个分享按钮的自定义视图,感觉比较好,所以就研究了下,写了下来。其实这个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();
}
}