自定义 浮动button 自动靠边 附加收缩功能

悬浮按钮可全屏滑动,左吸附、右吸附,外加右吸附后2秒后收缩功能,收缩完点击弹出 ,先看下效果,右吸附和收缩:

左吸附部分注释掉了,可根据实际情况修改使用 

package com.example.test1.customView;

import android.animation.ObjectAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;
import android.widget.Button;

import androidx.annotation.NonNull;

import com.example.test1.utils.LoggUtils;

/**
 * Created by WJY.
 * Date: 2021/3/10
 * Time: 15:10
 * Description: 自定义 浮动button 自动靠边
 */
@SuppressLint("AppCompatCustomView")
public class DragFloatActionButton extends Button {

    private int parentHeight;
    private int parentWidth;
    private int lastX;
    private int lastY;
    private boolean isDrag;

    Handler mHndler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case 0:
                    animate().setInterpolator(new DecelerateInterpolator())
                            .setDuration(200)
                            .xBy((float) (parentWidth - getWidth() - getX() + (0.7*getWidth())))
                            .start();
                    break;
            }
        }
    };

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

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

    public DragFloatActionButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    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:
                setPressed(true);
                isDrag = false;
                getParent().requestDisallowInterceptTouchEvent(true);
                lastX = rawX;
                lastY = rawY;
                ViewGroup parent;
                if (getParent() != null) {
                    parent = (ViewGroup) getParent();
                    parentHeight = parent.getHeight();
                    parentWidth = parent.getWidth();
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (parentHeight <= 0 || parentWidth == 0) {
                    isDrag = false;
                    break;
                } else {
                    isDrag = true;
                }
                int dx = rawX - lastX;
                int dy = rawY - lastY;
                //这里修复一些华为手机无法触发点击事件
                int distance = (int) Math.sqrt(dx * dx + dy * dy);
                if (distance == 0) {
                    isDrag = false;
                    break;
                }
                float x = getX() + dx;
                float y = getY() + dy;
                //检测是否到达边缘 左上右下
                x = x < 0 ? 0 : x > parentWidth - getWidth() ? parentWidth - getWidth() : x;
                y = getY() < 0 ? 0 : getY() + getHeight() > parentHeight ? parentHeight - getHeight() : y;
                setX(x);
                setY(y);
                lastX = rawX;
                lastY = rawY;
                Log.e("Log", "isDrag=" + isDrag + "getX=" + getX() + ";getY=" + getY() + ";parentWidth=" + parentWidth);
                break;
            case MotionEvent.ACTION_UP:
                if (!isNotDrag()) {
                    //恢复按压效果
                    setPressed(false);
                    //靠右吸附
                    animate().setInterpolator(new DecelerateInterpolator())
                            .setDuration(200)
                            .xBy(parentWidth - getWidth() - getX())
                            .start();
                    LoggUtils.e("靠右吸附","getX()="+getX()+"---getWidth()="+getWidth());
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                Thread.sleep(2000);
                                mHndler.sendEmptyMessage(0);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }).start();
                    //下面注释掉的是靠左和靠右吸附两种情况,可根据实际使用修改
//                    if (rawX >= parentWidth / 2) {
//                        //靠右吸附
//                        animate().setInterpolator(new DecelerateInterpolator())
//                                .setDuration(200)
//                                .xBy(parentWidth - getWidth() - getX())
//                                .start();
//                        LoggUtils.e("靠右吸附","getX()="+getX()+"---getWidth()="+getWidth());
//                        new Thread(new Runnable() {
//                            @Override
//                            public void run() {
//                                try {
//                                    Thread.sleep(2000);
//                                    mHndler.sendEmptyMessage(0);
//                                } catch (InterruptedException e) {
//                                    e.printStackTrace();
//                                }
//                            }
//                        }).start();
//                    } else {
//                        //靠左吸附
//                        ObjectAnimator oa = ObjectAnimator.ofFloat(this, "x", getX(), 0);
//                        oa.setInterpolator(new DecelerateInterpolator());
//                        oa.setDuration(200);
//                        oa.start();
//                        LoggUtils.e("靠左吸附","getX()="+getX()+"---getWidth()="+getWidth());
//                    }
                }
                break;
        }
        //如果是拖拽则消耗事件,否则正常传递即可。
        return !isNotDrag() || super.onTouchEvent(event);
    }

    private boolean isNotDrag() {
        return !isDrag && (getX() == 0 || (getX() == parentWidth - getWidth()));
    }
}

在布局中使用,就相当与一个控件

<com.example.test1.customView.DragFloatActionButton
        android:id="@+id/floatBtn"
        android:layout_width="@dimen/dimen_81dp"
        android:layout_height="@dimen/dimen_40dp"
        android:background="@drawable/bg_blue_leftcorner"
        android:drawableLeft="@mipmap/icon_left"
        android:paddingLeft="@dimen/dimen_14dp"
        android:paddingRight="@dimen/dimen_14dp"
        android:text="吸附"
        android:textColor="@color/white"
        android:textSize="14sp"
        android:layout_gravity="bottom|right"
        android:visibility="visible"/>

其中用到的一个button背景是自定义的一个文件bg_blue_leftcorner.xml,也可根据实际需求来写

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">

    <solid android:color="@color/blue_10" />
    <corners android:bottomLeftRadius="@dimen/dimen_20dp"
        android:topLeftRadius="@dimen/dimen_20dp"/>

</shape>

到此,一个可吸附的悬浮按钮就完成了,不足之处欢迎指正。

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

时代新人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值