FloatActionButton+viewgroup+ValueAnimator制作可浮动的菜单

想要可浮动以及拖拽移动的菜单效果:没有做成更好的插件类型,只记录下关键过程。

1、FloatActionButton属于可浮动的按钮类型

2、自定义viewgroup存放FloatActionButton按钮以及实现拖拽移动效果

3、ValueAnimator 实现点击菜单动画效果

一、XML布局

<android.support.constraint.ConstraintLayout>
 <ssq.com.myapp.Unit.FloatActionButtonMenuView
        android:id="@+id/floatActionButtonMenuView"
        android:layout_width="40dp"
        android:layout_height="240dp"
        android:layout_marginBottom="250dp"
        android:layout_marginEnd="8dp"
        android:clickable="true"

        android:src="@drawable/float_button1"
        android:visibility="visible"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent">

        <android.support.design.widget.FloatingActionButton
            android:id="@+id/floatActionButton0"
            app:elevation="0dp"
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:layout_marginTop="20dp"
            android:src="@drawable/float_upload" />

        <android.support.design.widget.FloatingActionButton
            android:id="@+id/floatActionButton1"
            app:elevation="0dp"
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:layout_marginTop="20dp"
            android:src="@drawable/float_button1" />

        <android.support.design.widget.FloatingActionButton
            android:id="@+id/floatActionButton2"
            app:elevation="0dp"
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:layout_marginTop="20dp"
            android:src="@drawable/float_sub" />

        <android.support.design.widget.FloatingActionButton
            android:id="@+id/floatActionButton3"
            app:elevation="0dp"
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:layout_marginTop="20dp"
            android:src="@drawable/float_menu" />
    </ssq.com.myapp.Unit.FloatActionButtonMenuView>
</android.support.constraint.ConstraintLayout>

二、可拖拽效果关键函数

public boolean onTouchEvent(MotionEvent event) {
        int rawX = (int) event.getRawX();
        int rawY = (int) event.getRawY();
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                isDrag = false;
                getParent().requestDisallowInterceptTouchEvent(true);
                lastX = rawX;
                lastY = rawY;
                //  Log.e("down---->", "getX=" + getX() + ";screenWidthHalf=" + screenWidthHalf);
                break;
            case MotionEvent.ACTION_MOVE:
                isDrag = true;
                //计算手指移动了多少
                int dx = rawX - lastX;
                int dy = rawY - lastY;
                //这里修复一些手机无法触发点击事件的问题
                int distance= (int) Math.sqrt(dx*dx+dy*dy);
                // Log.e("distance---->",distance+"");
                if(distance<3){//给个容错范围,不然有部分手机还是无法点击
                    isDrag=false;
                    break;
                }
                float x = getX() + dx;
                float y = getY() + dy;
                //检测是否到达边缘 左上右下
                x = x < 0 ? 0 : x > screenWidth - getWidth() ? screenWidth - getWidth() : x;
                // y = y < statusHeight ? statusHeight : (y + getHeight() >= screenHeight ? screenHeight - getHeight() : y);
                if (y<0){
                    y=0;
                }
                if (y>screenHeight-statusHeight-getHeight()){
                    y=screenHeight-statusHeight-getHeight();
                }
                setX(x);
                setY(y);
                lastX = rawX;
                lastY = rawY;
                //  Log.e("move---->", "getX=" + getX() + ";screenWidthHalf=" + screenWidthHalf + " " + isDrag+" statusHeight="+statusHeight+ " virtualHeight"+virtualHeight+ " screenHeight"+ screenHeight+" getHeight="+getHeight()+" y"+y);
                break;
            case MotionEvent.ACTION_UP:
                if (isDrag) {
                    //恢复按压效果
                    setPressed(false);
                    // Log.e("ACTION_UP---->", "getX=" + getX() + ";screenWidthHalf=" + screenWidthHalf);
                    if (rawX >= screenWidthHalf) {
                        animate().setInterpolator(new DecelerateInterpolator())
                                .setDuration(500)
                                .xBy(screenWidth - getWidth() - getX())
                                .start();
                    } else {
                        ObjectAnimator oa = ObjectAnimator.ofFloat(this, "x", getX(), 0);
                        oa.setInterpolator(new DecelerateInterpolator());
                        oa.setDuration(500);
                        oa.start();
                    }
                }
                // Log.e("up---->",isDrag+"");
                break;
        }
        //如果是拖拽则消耗事件,否则正常传递即可。
        return isDrag || super.onTouchEvent(event);
}
public boolean onInterceptTouchEvent(MotionEvent ev) {  //拖拽跟点击事件拦截
    switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            break;
        case MotionEvent.ACTION_MOVE:  //必须要在MOVE中return才有效果,在这里return后UP事件也会被拦截
            return true;
        }
    return super.onInterceptTouchEvent(ev);
}

三、ValueAnimator部分:(只实现在Y轴上菜单效果)list用于动态存放FloatActionButton按钮

private void ShowMenu(){
    menuOpen = true;
    if(list.size()==0)
        return;
    int y = (int) list.get(3).getY(); //标准参考位置
    final FloatingActionButton f1=list.get(0);
    final FloatingActionButton f2=list.get(1);
    final  FloatingActionButton f3=list.get(2);
    ValueAnimator v1 = ValueAnimator.ofInt(y, y - DISTACE*3);//Y 轴方向移动distrace
    v1.setDuration(500);
    v1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            int l = (int) f1.getX();
            int t = (int) animation.getAnimatedValue();
            int r = f1.getWidth()+l;
            int b = f1.getHeight()+t;
            f1.layout(l, t, r, b);
        }
    });

    ValueAnimator v2y = ValueAnimator.ofInt(y, y - DISTACE*2);
    v2y.setDuration(500).addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            int t = (int) animation.getAnimatedValue();
            int l = (int) f2.getX();
            int r = f2.getWidth() + l;
            int b = f2.getHeight() + t;
            f2.layout(l, t, r, b);
        }
    });
    ValueAnimator v3 = ValueAnimator.ofInt(y, y - DISTACE*1); //起始位置主菜单y坐标,终位置向上移200
    v3.setDuration(500).addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            int t = (int) animation.getAnimatedValue();
            int l = (int) f3.getX();
            int r = f3.getWidth() + l;
            int b = f3.getHeight() + t;
           f3.layout(l, t, r, b);
        }
    });
    v1.start();
    v2y.start();
    v3.start();
}
private void hideMenu(){
    menuOpen = false;
    if(list.size()==0)
        return;
    FloatingActionButton menu=list.get(3);
    final FloatingActionButton f1=list.get(0);
    final FloatingActionButton f2=list.get(1);
    final  FloatingActionButton f3=list.get(2);
    int y=(int)f1.getY();
    ValueAnimator v1 = ValueAnimator.ofInt(y, (int) menu.getY());
    v1.setDuration(500);
    v1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            int t = (int) animation.getAnimatedValue();
            int l = (int) f1.getX();
            int r = f1.getWidth() + l;
            int b = f1.getHeight() + t;
            f1.layout(l, t, r, b);
        }
    });
    y=(int)f2.getY();
    ValueAnimator v2y = ValueAnimator.ofInt(y, (int) menu.getY());
    v2y.setDuration(500).addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            int t = (int) animation.getAnimatedValue();
            int l = (int) f2.getX();
            int r = f2.getWidth() + l;
            int b = f2.getHeight() + t;
            f2.layout(l, t, r, b);
        }
    });
    y=(int)f3.getY();
    ValueAnimator v3 = ValueAnimator.ofInt(y, (int) menu.getY());
    v3.setDuration(500).addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            int t = (int) animation.getAnimatedValue();
            int l = (int) f3.getX();
            int r = f3.getWidth() + l;
            int b = f3.getHeight() + t;
            f3.layout(l, t, r, b);
        }
    });
    v1.start();
    v2y.start();
    v3.start();
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值