Android自定义弹出菜单+动画实现

看到网上一个Demo里面弹出菜单的动画效果很好看,自己就利用工作空余时间也写了一下。具体实现如下:

1 自定义一个显示Icon的ImageView,主要用来判断该ImageView是否需要放在父布局底部水平中心位置

   import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.ImageView;


/**
 * Created by crab on 14-9-26.
 */
public class BottomCenterImageView extends ImageView {
    private boolean mLayoutParentBottomCenter=false;
    public BottomCenterImageView(Context context) {
        super(context);
    }


    public BottomCenterImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray a = context.getTheme().obtainStyledAttributes( attrs, R.styleable.HoriAnimationLayout,0, 0);
        mLayoutParentBottomCenter=a.getBoolean(R.styleable.HoriAnimationLayout_bottomCenter,false);
        a.recycle();
    }


    public BottomCenterImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.HoriAnimationLayout,defStyle,0);
        mLayoutParentBottomCenter=a.getBoolean(R.styleable.HoriAnimationLayout_bottomCenter,false);
        a.recycle();
    }
    public boolean isLayoutParentBottomCenter(){
        return mLayoutParentBottomCenter;
    }
}

2 建立一个容纳要显示ImageView的容器类

   import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.LinearLayout;


/**
 * Created by crab on 14-9-26.
 */
public class HoriAnimationLayout extends LinearLayout{
    private int mTwoLineHeight=0;
    private int mOnewLineHeight=0;
    //是否有一个view放在该布局的底部水平中间位置
    private boolean mHasChildLayoutBottom=false;
    public static final int STATE_OPEN=0;
    public static final int STATE_CLOSE=1;
    private static final long ANIMATION_DURATION=500L;
    private int mState=STATE_CLOSE;
    public HoriAnimationLayout(Context context) {
        super(context);
        init(context);
    }


    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        BottomCenterImageView child=null;
        int count=getChildCount();
        for(int i=0;i<count;i++){
            child= (BottomCenterImageView) getChildAt(i);
            if(!child.isLayoutParentBottomCenter()){
                child.setVisibility(View.INVISIBLE);
            }else{
                child.setOnClickListener(new OnClickListener(){


                    @Override
                    public void onClick(View v) {
                        if(mState==STATE_CLOSE){
                            open();
                        }else{
                            close();
                        }
                    }
                });
            }
        }
    }


    public HoriAnimationLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }


    public HoriAnimationLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }
    private void init(Context context){
        mOnewLineHeight=(int) getResources().getDimension(R.dimen.circle_icon_size);
        mTwoLineHeight=(int) getResources().getDimension(R.dimen.circle_anim_parent_height);
    }
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int childCount=getChildCount();
        if(childCount==0){
            throw new RuntimeException("请添加一个或者更多CircleAnimationImageView");
        }
        int gapCount=childCount-1;
        int gap=0;
        int leftOffset=0;
        BottomCenterImageView child=null;
        if(mHasChildLayoutBottom){
            gapCount=gapCount-1;
        }
        if(gapCount<=0){
            if(gapCount==-1){
                //只有一个并且需要直接布局到底部
                child= (BottomCenterImageView) getChildAt(0);
                child.layout((r-l)/2-child.getMeasuredWidth()/2,getMeasuredHeight()-child.getMeasuredHeight(),(r-l)/2+child.getMeasuredWidth()/2,getMeasuredHeight());
                return;
            }else if(gapCount==0){
                gap=(r-l)/2-mOnewLineHeight/2;
            }
        }else{
            gap=(r-l-(gapCount+1)*mOnewLineHeight)/gapCount;
        }
        for(int i=0;i<childCount;i++){
            child= (BottomCenterImageView) getChildAt(i);
            boolean isLayoutBottomCenter=child.isLayoutParentBottomCenter();
            if(isLayoutBottomCenter){
                child.layout((r-l)/2-child.getMeasuredWidth()/2,getMeasuredHeight()-child.getMeasuredHeight(),(r-l)/2+child.getMeasuredWidth()/2,getMeasuredHeight());
            }else{
                child.layout(leftOffset,0,leftOffset+child.getMeasuredWidth(),child.getMeasuredHeight());
                leftOffset=leftOffset+child.getMeasuredWidth()+gap;
            }
        }


    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width=MeasureSpec.getSize(widthMeasureSpec);
        int childCount=getChildCount();
        for(int i=0;i<childCount;i++){
            BottomCenterImageView child= (BottomCenterImageView) getChildAt(i);
            if(child.isLayoutParentBottomCenter()){
                mHasChildLayoutBottom=true;
            }
            int childMeasureSize=MeasureSpec.makeMeasureSpec(MeasureSpec.EXACTLY,mOnewLineHeight);
            child.measure(childMeasureSize,childMeasureSize);
        }
        int height=0;
        if(mHasChildLayoutBottom){
            height=mTwoLineHeight;
        }else{
            height=mOnewLineHeight;
        }
        setMeasuredDimension(width, height);
    }
    private void open(){
        if(mState==STATE_OPEN){
            return;
        }
        mState=STATE_OPEN;
        float dstX=getMeasuredWidth()/2-mOnewLineHeight/2;
        float dstY=getMeasuredHeight()-mOnewLineHeight;
        int childCount=getChildCount();
        Animation[] animations=new Animation[childCount];
        for(int i=0;i<childCount;i++) {
            final BottomCenterImageView child = (BottomCenterImageView) getChildAt(i);
            if(!child.isLayoutParentBottomCenter()) {
                float fromX = dstX - child.getLeft();
                float fromY = dstY - child.getTop();
                float toX = 0;
                float toY = 0;
                TranslateAnimation translateAnimation = new TranslateAnimation(Animation.ABSOLUTE, fromX, Animation.ABSOLUTE, toX,
                        Animation.ABSOLUTE, fromY, Animation.ABSOLUTE, toY);
                translateAnimation.setDuration(ANIMATION_DURATION);
                translateAnimation.setAnimationListener(new VisbleStateAniamtionListener(child, true));
                animations[i] = translateAnimation;
            }else{
                RotateAnimation rotateAnimation=new RotateAnimation(180,360,child.getWidth()/2,child.getHeight()/2);
                rotateAnimation.setDuration(ANIMATION_DURATION);
                rotateAnimation.setFillAfter(true);
                animations[i]=rotateAnimation;
            }
        }
        for(int i=0;i<childCount;i++){
            final BottomCenterImageView child = (BottomCenterImageView) getChildAt(i);
            child.startAnimation(animations[i]);
        }
    }
    private void close(){
        if(mState==STATE_CLOSE){
            return;
        }
        mState=STATE_CLOSE;
        float dstX=getMeasuredWidth()/2-mOnewLineHeight/2;
        float dstY=getMeasuredHeight()-mOnewLineHeight;
        int childCount=getChildCount();
        Animation[] animations=new Animation[childCount];
        for(int i=0;i<childCount;i++) {
            final BottomCenterImageView child = (BottomCenterImageView) getChildAt(i);
            if(!child.isLayoutParentBottomCenter()) {
                float fromX = 0;
                float fromY = 0;
                float toX = dstX - child.getLeft();
                float toY = dstY - child.getTop();
                TranslateAnimation translateAnimation = new TranslateAnimation(Animation.ABSOLUTE, fromX, Animation.ABSOLUTE, toX,
                        Animation.ABSOLUTE, fromY, Animation.ABSOLUTE, toY);
                translateAnimation.setDuration(ANIMATION_DURATION);
                translateAnimation.setAnimationListener(new VisbleStateAniamtionListener(child, false));
                animations[i] = translateAnimation;
            }else{
                RotateAnimation rotateAnimation=new RotateAnimation(0,180,child.getWidth()/2,child.getHeight()/2);
                rotateAnimation.setDuration(ANIMATION_DURATION);
                rotateAnimation.setFillAfter(true);
                animations[i]=rotateAnimation;
            }
        }
        for(int i=0;i<childCount;i++){
            final BottomCenterImageView child = (BottomCenterImageView) getChildAt(i);
            child.startAnimation(animations[i]);
        }
    }
    private class VisbleStateAniamtionListener implements Animation.AnimationListener{
        private View mView;
        private boolean mVisible;
        public VisbleStateAniamtionListener(View view,boolean visible){
            mView=view;
            mVisible=visible;
        }
        @Override
        public void onAnimationStart(Animation animation) {
            if(mView.getVisibility()!=View.VISIBLE){
                mView.setVisibility(View.VISIBLE);
            }
        }


        @Override
        public void onAnimationEnd(Animation animation) {
            if(mVisible){
                mView.setVisibility(View.VISIBLE);
            }else{
                mView.setVisibility(View.INVISIBLE);
            }
        }


        @Override
        public void onAnimationRepeat(Animation animation) {


        }
    }


}

3定义布局文件,用到的图片资源可以自己去网上下载,最好用园行图片

   <RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:customApp="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:background="#FFCCCCCC"
    android:layout_height="match_parent">


    <com.example.crab.mycameratest.HoriAnimationLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:orientation="horizontal"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        >
        <com.example.crab.mycameratest.BottomCenterImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/pg_thrid_facebook_click"
            />
        <com.example.crab.mycameratest.BottomCenterImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/pg_thrid_kupan_click"
            />
        <com.example.crab.mycameratest.BottomCenterImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/pg_thrid_sina_click"
            />
        <com.example.crab.mycameratest.BottomCenterImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/pg_thrid_twitter_click"
            />
        <com.example.crab.mycameratest.BottomCenterImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/pg_thrid_qq_click"
            />
        <com.example.crab.mycameratest.BottomCenterImageView
            android:id="@+id/animationTrigger"
            customApp:bottomCenter="true"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/pg_thrid_qq_click"
            />
       </com.example.crab.mycameratest.HoriAnimationLayout>


</RelativeLayout>

4定义自己需要用到的一些自定义资源与样式

   dimens.xml

   <resources>
    <dimen name="circle_icon_size">40dp</dimen>
    <dimen name="circle_anim_parent_height">128dp</dimen>
</resources>

   attrs.xml

    <declare-styleable name="HoriAnimationLayout">
        <attr name="bottomCenter" format="boolean"/>
    </declare-styleable>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值