看到网上一个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>

Android自定义弹出菜单+动画实现相关推荐

  1. android 上下收缩动画,Android 带有弹出收缩动画的扇形菜单实例

    最近试着做了个Android 带有弹出收缩动画的扇形菜单,留个笔记记录一下. 效果如下 public class MainActivity extends AppCompatActivity impl ...

  2. Kotlin 仿微信长按列表弹出菜单(动画)

    一.测试 实现: 二.项目: 仿微信长按列表弹出菜单代码,MainActivity.kt class MainActivity : AppCompatActivity(), AdapterView.O ...

  3. android popupmenu 动态添加,Android PopupMenu弹出菜单的实现

    Android PopupMenu弹出菜单的实现 (1)布局文件:用于弹出菜单的处罚button: xmlns:tools="http://schemas.android.com/tools ...

  4. android 自定义 popupwindow,Android自定义弹出窗口PopupWindow使用技巧

    PopupWindow是Android上自定义弹出窗口,使用起来很方便. PopupWindow的构造函数为 public PopupWindow(View contentView, int widt ...

  5. android自定义弹出对话框,使用FlyDialog实现自定义Android弹窗对话框

    前言 学习的时候要用到弹窗,但是又觉得i同自带的弹窗样式有点不太美观,搜索资料后发现了FlycoDialog这个开源库,效果很好,而且实现起来也比较方便. 先列举一些比较好看的效果: NormalLi ...

  6. Android Dialog弹出方式动画

    //自定义Dialogclass myDialog extends Dialog{private Window window = null;public myDialog(Context contex ...

  7. android自定义弹出框样式实现

    前言: 做项目时,感觉Android自带的弹出框样式比较丑,很多应用都是自己做的弹出框,这里也试着自己做了一个. 废话不说先上图片: 实现机制 1.先自定义一个弹出框的样式 2.自己实现CustomD ...

  8. android 加号弹出菜单,Android仿微信、qq点击右上角加号弹出操作框

    Android仿微信.qq点击右上角加号弹出操作框,先上图,类似于下图这种,点击加号,会弹出一个对话框,如下图: 微信: 自己实现: 接下来,我们来实现此功能: 其实,实现原理就是,点击"+ ...

  9. Android 关机弹出菜单

    特别推荐: 移动资讯--<<我是开发者>>个人专访 关于android远程登录源码解析 Android源码之热血足球+PPT讲解 在Android系统中,长按Power键默认会 ...

最新文章

  1. centOS6.5 安装 python2.7 pip
  2. 首次使用Cesium加载3D数据成功
  3. spring源码分析之定时任务Scheduled注解
  4. Swoole 自定义项目初始化事件处理的实现
  5. linux消息队列操作
  6. Laravel大型项目系列教程(一)
  7. opencv对图像是软解码_C ++ OpenCV解码缓慢
  8. codeforces 297 E. Anya and Cubes
  9. linux 使用 vim 玩python
  10. 22. Django进阶:文件上传
  11. MongoDB 通过 Java 代码 CRUD 文档
  12. 【配送路径规划】基于matlab模拟退火算法求解单配送中心多客户多车辆最短路径规划问题【含Matlab源码 1604期】
  13. 工业基础类IFC—总体架构和空间结构
  14. Origin下载安装教程(亲测有用)
  15. Span 介绍及使用(一)
  16. 听别人的故事探索属于自己的方法
  17. Linux CentOS7 备份及还原系统
  18. 拓展名为html包括,在Windows中,帮助文件的扩展名为()。选项: a、“.html” b、“.sys” c、“.h...
  19. python面向对象_05(面向对象封装案例 II)
  20. 计算机应用基础本科试题及答案,计算机应用基础课程(本科)网考模拟试题

热门文章

  1. 小T成长记-操作系统篇1-一条小小的除法指令引起的翻车事故
  2. 登录设备出现linux,批准此iphone 前往已登录iCloud的其他设备来批准这台iPhone
  3. 前端实现文件下载功能的三种方式
  4. 最大比例【更相减损术】
  5. 极路由 java_极路由4pro安装java(Jamvm 2.0.0 + gnu classpath 0.9.8)
  6. java取模_Java 中的取模和取余
  7. java处理表情符号,从Java字符串中删除✅,,✈,♛和其他此类表情符号/图像/符号...
  8. android版手机qq退出方法,安卓qq2013怎么退出 手机qq4.1怎么退出方法
  9. thinkphp6 request参数读取
  10. VirtualBox虚拟机启动爆出:fatal:No bootable medium found! System halted的错误