Android可拖動懸浮按鈕
阿新 • • 發佈:2018-11-10
最近專案需要使用可拖拽的懸浮按鈕,所以實現了一個小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);
}
}
最後感謝簡書的這篇文章對我的啟發安卓可拖拽懸浮按鈕二,文章裡面有吸附的效果,如果專案中需要可以參考下~