Android可拖动悬浮按钮

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/LosingCarryJie/article/details/82228285

最近项目需要使用可拖拽的悬浮按钮,所以实现了一个小demo

这里写图片描述

因为是模拟器的缘故,拖动的时候看起来有点卡顿,如果在真机上运行时非常完美的

技术要突破的难点有下面几个:

1 如何悬浮? 使用相对布局或者帧布局,按钮放在最外层即可
2 如何拖动? 对按钮进行移动监听,动态修改按钮显示的位置
3 如何对拖动位置限制? 判断边界
4 如何将点击事件和滚动事件分别处理 见代码

AbastractDragFloatActionButton

这个类是一个抽象类,目的是为了将可移动和具体的业务分离。这个类提供了可移动的属性,具体的实现就隔离出去交给实现类去完成吧
不能直接继承ViewGroup!!!

package iot.com.iot;

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;

/**
 * 可拖动悬浮按钮抽象类,注意这里一定要继承ViewGroup的实现类而不是直接继承ViewGroup
 *
 * By  Jie  2018/8/30
 */
public abstract class AbastractDragFloatActionButton extends RelativeLayout {
    private int parentHeight;//悬浮的父布局高度
    private int parentWidth;

    public AbastractDragFloatActionButton(Context context) {
        this(context, null, 0);
    }

    public AbastractDragFloatActionButton(Context context, AttributeSet attrs) {
        this(context, attrs, 0);

    }

    public abstract int getLayoutId();

    public abstract void renderView(View view);

    public AbastractDragFloatActionButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        View view= LayoutInflater.from(context).inflate(getLayoutId(), this);
        renderView(view);
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        measureChildren(widthMeasureSpec, heightMeasureSpec);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }



    @Override
    protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
        View view = getChildAt(0);
        view.layout(0,0,view.getMeasuredWidth(),view.getMeasuredHeight());
    }

    private int lastX;
    private int lastY;

    private boolean isDrag;

    @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:
                isDrag = (parentHeight > 0 && parentWidth > 0);//只有父布局存在你才可以拖动
                if(!isDrag) break;

                int dx=rawX-lastX;
                int dy=rawY-lastY;
                //这里修复一些华为手机无法触发点击事件
                int distance= (int) Math.sqrt(dx*dx+dy*dy);
                isDrag = distance>0;//只有位移大于0说明拖动了
                if(!isDrag) break;

                float x=getX()+dx;
                float y=getY()+dy;
                //检测是否到达边缘 左上右下
                x=x<0?0:x>parentWidth-getWidth()?parentWidth-getWidth():x;
                y=y<0?0:y>parentHeight-getHeight()?parentHeight-getHeight():y;
                setX(x);
                setY(y);
                lastX=rawX;
                lastY=rawY;
                break;
            case MotionEvent.ACTION_UP:
                //如果是拖动状态下即非点击按压事件
                setPressed(!isDrag);
                break;
        }

        //如果不是拖拽,那么就不消费这个事件,以免影响点击事件的处理
        //拖拽事件要自己消费
        return isDrag || super.onTouchEvent(event);
    }

}

MyButton

具体的业务类,在这里可以拿到你的button的布局

public class MyButton extends AbastractDragFloatActionButton {
    public MyButton(Context context) {
        super(context);
    }

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

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

    @Override
    public int getLayoutId() {
        return R.layout.custom_button;//拿到你自己定义的悬浮布局
    }

    @Override
    public void renderView(View view) {
          //初始化那些布局
    }
}

MainActivity使用

public class MainActivity extends AppCompatActivity {

    private MyButton button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this,"直播开始啦!",Toast.LENGTH_SHORT).show();
            }
        });
    }

    private void initView() {
        button = findViewById(R.id.button);
    }
}

最后感谢简书的这篇文章对我的启发安卓可拖拽悬浮按钮二,文章里面有吸附的效果,如果项目中需要可以参考下~

猜你喜欢

转载自blog.csdn.net/LosingCarryJie/article/details/82228285
今日推荐