DragFrameLayout實現(xiàn)拖動子控件的效果
效果圖
介紹
DragFrameLayout
繼承自FrameLayout
,可以對其內(nèi)部的子View進行拖曳诞仓,子View的數(shù)量不限,一次只可以拖動一個view速兔。
當然也可以繼承RealtiveLayout
使用步驟
- 將這個類
DragFrameLayout
放入xml中狂芋,里面放入需要拖動的View, - 獲取
DragFrameLayout
和子View - 將子View作為可拖動的
view
將入DragFrameLayout
中(實際是放入內(nèi)部集合中)
//注意:不是addView(tv)
,是addDragView(tv)
DragFrameLayout dragFrameLayout = (DragFrameLayout) findViewById(R.id.dragFrameLayout);
TextView tv = (TextView) findViewById(R.id.tv);
dragFrameLayout.addDragView(tv);
DragFrameLayout源碼介紹
- 首先我們繼承
FrameLayout
,需要重寫4個構造方法憨栽,其中4個參數(shù)的構造方法是用于API>=21
帜矾,所以翼虫,我們只需要重寫其余3個構造方法即可。 - 創(chuàng)建接口用于拖動控件的處理
- 事件分發(fā)與攔截
- 在其構造方法里面創(chuàng)建
ViewDragHelper
對象并重寫回調中的方法
第一步:創(chuàng)建拖動回調
下面有完整版代碼屡萤,類和方法的名字可能不同珍剑,但是步驟邏輯處理是一樣的。
public interface OnDragDropListener {
void onDragDrop(boolean captured);
}
private OnDragDropListener onDragDropListener;
public void setOnDragDropListener(OnDragDropListener onDragDropListener) {
this.onDragDropListener = onDragDropListener;
}
第二步:重寫構造方法
注意:有一個參數(shù)和兩個參數(shù)的構造方法中用的是this
,不是super
死陆,這樣會調用3個參數(shù)的構造方法招拙。
在3個參數(shù)的構造方法中創(chuàng)建viewList
,用于存放我們要拖動的childView
;并對外公開添加的方法
創(chuàng)建ViewDragHelper
對象,再起回調中重寫5個方法
回調中重寫的方法 | 說明 |
---|---|
boolean tryCaptureView(View child, int pointerId) | 是否捕獲childView: 如果viewList包含child措译,那么捕獲childView别凤;如果不包含child,就不捕獲childView |
int clampViewPositionHorizontal(View child, int left, int dx) | 到左邊界的距離 |
int clampViewPositionVertical | 到上邊界的距離 |
onViewCaptured(View capturedChild, int activePointerId) | 當捕獲到child后的處理:獲取child的監(jiān)聽 |
void onViewReleased(View releasedChild, float xvel, float yvel) | 當釋放child后的處理:取消監(jiān)聽领虹,不再處理 |
void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) | 不需要重寫 |
public class DragFrameLayout extends FrameLayout {
public DragFrameLayout(@NonNull Context context) {
this(context,null);
}
public DragFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public DragFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {
super(context, attrs, defStyleAttr);
//第二步:創(chuàng)建存放View的集合
viewList = new ArrayList<>();
dragHelper = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() {
/**
* 是否捕獲childView:
* 如果viewList包含child规哪,那么捕獲childView
* 如果不包含child,就不捕獲childView
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return viewList.contains(child);
}
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
}
/**
* 當捕獲到child后的處理:
* 獲取child的監(jiān)聽
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
if (onDragDropListener != null) {
onDragDropListener.onDragDrop(true);
}
}
/**
* 當釋放child后的處理:
* 取消監(jiān)聽塌衰,不再處理
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
if (onDragDropListener != null) {
onDragDropListener.onDragDrop(false);
}
}
/**
* 到左邊界的距離
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
return left;
}
/**
* 到上邊界的距離
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
return top;
}
});
}
}
由于viewList
是用private
修飾的诉稍,所以需要對外公開的添加chiildView
的方法
public void addDragChildView(View child) {
viewList.add(child);
}
第三步:處理事件
需要重寫2個方法:是否攔截事件和自身如何處理事件,分別是:onInterceptTouchEvent(MotionEvent ev)
最疆、onTouchEvent(MotionEvent event)
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
//當手指抬起或事件取消的時候 就不攔截事件
int actionMasked = ev.getActionMasked();
if (actionMasked == MotionEvent.ACTION_CANCEL || actionMasked == MotionEvent.ACTION_UP) {
return false;
}
return dragHelper.shouldInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
dragHelper.processTouchEvent(event);
return true;
}
其它
demo:https://git.oschina.net/customView/CustomDragFrameLayout
demo是從google Android Sample中抽取出來的:https://developer.android.google.cn/samples/ElevationDrag/index.html