Android-->ViewDragHelper的詳細(xì)使用方法

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 歡迎您的加入.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子咬荷,更是在濱河造成了極大的恐慌奠涌,老刑警劉巖以蕴,帶你破解...
    沈念sama閱讀 219,366評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)颠黎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來滞项,“玉大人狭归,你說我怎么就攤上這事∥呐校” “怎么了过椎?”我有些...
    開封第一講書人閱讀 165,689評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)戏仓。 經(jīng)常有香客問我疚宇,道長(zhǎng),這世上最難降的妖魔是什么赏殃? 我笑而不...
    開封第一講書人閱讀 58,925評(píng)論 1 295
  • 正文 為了忘掉前任敷待,我火速辦了婚禮,結(jié)果婚禮上嗓奢,老公的妹妹穿的比我還像新娘。我一直安慰自己浑厚,他們只是感情好股耽,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著钳幅,像睡著了一般物蝙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上敢艰,一...
    開封第一講書人閱讀 51,727評(píng)論 1 305
  • 那天诬乞,我揣著相機(jī)與錄音,去河邊找鬼。 笑死震嫉,一個(gè)胖子當(dāng)著我的面吹牛森瘪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播票堵,決...
    沈念sama閱讀 40,447評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼扼睬,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了悴势?” 一聲冷哼從身側(cè)響起窗宇,我...
    開封第一講書人閱讀 39,349評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎特纤,沒想到半個(gè)月后军俊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,820評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡捧存,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評(píng)論 3 337
  • 正文 我和宋清朗相戀三年粪躬,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片矗蕊。...
    茶點(diǎn)故事閱讀 40,127評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡短蜕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出傻咖,到底是詐尸還是另有隱情朋魔,我是刑警寧澤,帶...
    沈念sama閱讀 35,812評(píng)論 5 346
  • 正文 年R本政府宣布卿操,位于F島的核電站警检,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏害淤。R本人自食惡果不足惜扇雕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望窥摄。 院中可真熱鬧镶奉,春花似錦、人聲如沸崭放。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽币砂。三九已至建峭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間决摧,已是汗流浹背亿蒸。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評(píng)論 1 272
  • 我被黑心中介騙來泰國打工凑兰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人边锁。 一個(gè)月前我還...
    沈念sama閱讀 48,388評(píng)論 3 373
  • 正文 我出身青樓姑食,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親砚蓬。 傳聞我的和親對(duì)象是個(gè)殘疾皇子矢门,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,182評(píng)論 25 707
  • 大白天在我身邊飛來飛去。
    媚生閱讀 509評(píng)論 0 50
  • 余秀華的“穿過半個(gè)中國去睡你”橫空出世之后灰蛙,中國的詩壇很是喧囂了一陣子祟剔。有人據(jù)此斷言,現(xiàn)代詩在神州大地上將全面迎來...
    依依原上草閱讀 624評(píng)論 9 7