ViewDragHelper是Android系統(tǒng)原生封裝用于ViewGroup滑動(dòng)的類庫.(ViewDragHelper只能用在ViewGroup中.)
使用ViewDragHelper,可以非常方便的在ViewGroup中移動(dòng),滑動(dòng)任意一個(gè)子View,并且控制相當(dāng)方便.
1:基礎(chǔ)代碼模版
public class ViewDragTestLayout extends RelativeLayout {
ViewDragHelper mViewDragHelper;
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
//中間參數(shù)表示靈敏度,比如滑動(dòng)了多少像素才視為觸發(fā)了滑動(dòng).值越大越靈敏.
mViewDragHelper = ViewDragHelper.create(this, 1f, new DragCallback());
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
//固定寫法
int action = MotionEventCompat.getActionMasked(ev);
if (action == MotionEvent.ACTION_CANCEL
|| action == MotionEvent.ACTION_UP) {
mViewDragHelper.cancel();
return false;
}
return mViewDragHelper.shouldInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
//固定寫法
mViewDragHelper.processTouchEvent(event);
return true;
}
@Override
public void computeScroll() {
//固定寫法
//此方法用于自動(dòng)滾動(dòng),比如自動(dòng)回滾到默認(rèn)位置.
if (mViewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(this);
}
}
}
以上代碼,可以粘貼復(fù)制. 都是模版代碼;
2:ViewDragHelper.Callback
//這個(gè)類的回調(diào)方法,才是ViewDragHelper的重點(diǎn)
private class ViewDragCallback extends ViewDragHelper.Callback{
@Override
public boolean tryCaptureView(View child, int pointerId) {
//child 表示想要滑動(dòng)的view
//pointerId 表示觸摸點(diǎn)的id, 比如多點(diǎn)按壓的那個(gè)id
//返回值表示,是否可以capture,也就是是否可以滑動(dòng).可以根據(jù)不同的child決定是否可以滑動(dòng)
return true;
}
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//child 表示當(dāng)前正在移動(dòng)的view
//left 表示當(dāng)前的view正要移動(dòng)到左邊距為left的地方
//dx 表示和上一次滑動(dòng)的距離間隔
//返回值就是child要移動(dòng)的目標(biāo)位置.可以通過控制返回值,從而控制child只能在ViewGroup的范圍中移動(dòng).
return left;
}
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
//child 表示當(dāng)前正在移動(dòng)的view
//top 表示當(dāng)前的view正要移動(dòng)到上邊距為top的地方
//dx 表示和上一次滑動(dòng)的距離間隔
return top;
}
}
重寫以上3個(gè)方法, 你的ViewGroup就可以正常工作了.子View就可以被任意拖動(dòng)了.
3:控制child的移動(dòng)范圍在父view中
//控制child只能在ViewGroup的橫向中移動(dòng)
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
final int leftBound = getPaddingLeft();
final int rightBound = getWidth() - mDragView.getWidth();
final int newLeft = Math.min(Math.max(left, leftBound), rightBound);
return newLeft;
}
//控制child只能在ViewGroup的縱向中移動(dòng)
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
final int topBound = getPaddingTop();
final int bottomBound = getHeight() - mDragView.getHeight();
final int newTop = Math.min(Math.max(top, topBound), bottomBound);
return newTop;
}
回調(diào)順序
//一次滑動(dòng)周期的回調(diào)順序.(開始拖動(dòng)到放手)
getOrderedChildIndex - 0
getOrderedChildIndex - 0
tryCaptureView - tryCaptureView -1 0
onViewCaptured - null
onViewDragStateChanged - null
clampViewPositionHorizontal - left:11 dx:11
clampViewPositionVertical - top:5 dy:5
onViewPositionChanged - null
...
clampViewPositionHorizontal - left:100 dx:23
clampViewPositionVertical - top:44 dy:11
onViewPositionChanged - null
onViewReleased - null
onViewDragStateChanged - null
4:開啟邊界滑動(dòng)
//開啟4個(gè)邊
mViewDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_ALL);
//各個(gè)邊
public static final int EDGE_LEFT = 1 << 0;
public static final int EDGE_RIGHT = 1 << 1;
public static final int EDGE_TOP = 1 << 2;
public static final int EDGE_BOTTOM = 1 << 3;
//當(dāng)開啟邊界滑動(dòng)之后, 此方法就會(huì)回調(diào)
@Override
public void onEdgeTouched(int edgeFlags, int pointerId) {
//通常開啟邊界之后, 都需要手動(dòng)capture view.之后就可以滑動(dòng)view了.
mViewDragHelper.captureChildView(getChildAt(1), pointerId);
}
@Override
public boolean tryCaptureView(View child, int pointerId) {
//開啟邊界之后, 這個(gè)方法的返回值可能需要進(jìn)一步處理.要不然開邊界就沒啥意思了.
return false;
}
回調(diào)順序:
getOrderedChildIndex - 2
onEdgeTouched - edgeFlags:4 pointerId:0
getOrderedChildIndex - 2
tryCaptureView - tryCaptureView -1 0
...
5:釋放后的回彈效果
有些時(shí)候, 當(dāng)釋放的時(shí)候, 需要將View回到原來的位置.
//釋放的時(shí)候, 會(huì)回調(diào)下面的方法
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
//調(diào)用這個(gè)方法,就可以設(shè)置releasedChild回彈得位置.
mViewDragHelper.settleCapturedViewAt(0, 100);//參數(shù)就是x,y的坐標(biāo)
postInvalidate();//注意一定要調(diào)用這個(gè)方法,否則沒效果.
}
//以下2個(gè)方法最終調(diào)用的都是forceSettleCapturedViewAt().
mViewDragHelper.settleCapturedViewAt(0, 100);
mViewDragHelper.smoothSlideViewTo(getChildAt(1), 0, 100);
//所以...發(fā)揮你的想象力,看看有什么妙用!!!
//如果你還沒有忘記的話...前文應(yīng)該有說過,涉及到scroll,需要重寫view的此方法.
//此方法一定要重寫,否則沒效果
@Override
public void computeScroll() {
//固定寫法
if (mViewDragHelper.continueSettling(true)) {
postInvalidate();//注意此處.
}
}
通過上面2個(gè)方法的設(shè)置, 當(dāng)手指釋放的時(shí)候, View就會(huì)自動(dòng)滑動(dòng)到指定的位置...(不是一下子就到指定的位置哦,有一個(gè)滑動(dòng)的過程.)
注意:如果需要滑動(dòng)的View,會(huì)消耗touch事件,比如:Button,那么需要重寫以下方法.
@Override
public int getViewHorizontalDragRange(View child) {
return child.getMeasuredWidth();//只要返回大于0的值就行
}
@Override
public int getViewVerticalDragRange(View child) {
return child.getMeasuredHeight();//只要返回大于0的值就行
}
到這里, 就結(jié)束啦...
相關(guān)閱讀:
http://blog.csdn.net/lmj623565791/article/details/46858663
http://blog.csdn.net/pi9nc/article/details/39583377
至此: 文章就結(jié)束了,如有疑問: QQ群:274306954 歡迎您的加入.