1. 程式人生 > >Android可拖動懸浮按鈕

Android可拖動懸浮按鈕

最近專案需要使用可拖拽的懸浮按鈕,所以實現了一個小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);
    }
}

最後感謝簡書的這篇文章對我的啟發安卓可拖拽懸浮按鈕二,文章裡面有吸附的效果,如果專案中需要可以參考下~