自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Android高手進(jìn)階之ViewDragHelper使用詳解以及拖動(dòng)上下滑卡片實(shí)現(xiàn)

開(kāi)發(fā) 前端
今天我們就來(lái)講解下ViewDragHelper;ViewDragHelper是針對(duì) ViewGroup 中的拖拽和重新定位 views 操作時(shí)提供了一系列非常有用的方法和狀態(tài)追蹤。

[[426553]]

前言

正好項(xiàng)目中有個(gè)頁(yè)面底部拖動(dòng)上下滑的UI;

今天我們就來(lái)講解下ViewDragHelper;

這幾天項(xiàng)目比較忙,文章更新會(huì)慢,各位老鐵可以看歷史記錄;

一、viewDragHleper詳解

ViewDragHelper是針對(duì) ViewGroup 中的拖拽和重新定位 views 操作時(shí)提供了一系列非常有用的方法和狀態(tài)追蹤;

1、ViewDragHelper初始化

  1. public class ViewDragTest extends LinearLayout  { 
  2.     ViewDragHelper mViewDragHelper; 
  3.     @Override 
  4.     protected void onAttachedToWindow() { 
  5.         super.onAttachedToWindow(); 
  6.         //中間參數(shù)表示靈敏度,比如滑動(dòng)了多少像素才視為觸發(fā)了滑動(dòng).值越大越靈敏. 
  7.         mViewDragHelper = ViewDragHelper.create(this, 1f, new DragCallback()); 
  8.     } 
  9.     @Override 
  10.     public boolean onInterceptTouchEvent(MotionEvent ev) { 
  11.         //固定寫(xiě)法 
  12.         int action = MotionEventCompat.getActionMasked(ev); 
  13.         if (action == MotionEvent.ACTION_CANCEL  
  14.         || action == MotionEvent.ACTION_UP) { 
  15.             mViewDragHelper.cancel(); 
  16.             return false
  17.         } 
  18.         return mViewDragHelper.shouldInterceptTouchEvent(ev); 
  19.     } 
  20.     @Override 
  21.     public boolean onTouchEvent(MotionEvent event) { 
  22.         //固定寫(xiě)法 
  23.         mViewDragHelper.processTouchEvent(event); 
  24.         return true
  25.     } 
  26.     @Override 
  27.     public void computeScroll() { 
  28.         //固定寫(xiě)法 
  29.         //此方法用于自動(dòng)滾動(dòng),比如自動(dòng)回滾到默認(rèn)位置. 
  30.         if (mViewDragHelper.continueSettling(true)) { 
  31.             ViewCompat.postInvalidateOnAnimation(this); 
  32.         } 
  33.     } 

2、ViewDragHelper.Callback

  1. //這個(gè)類的回調(diào)方法,才是ViewDragHelper的重點(diǎn) 
  2. private class ViewDragCallback extends ViewDragHelper.Callback{ 
  3.    @Override 
  4.    public boolean tryCaptureView(View child, int pointerId) { 
  5.        //child 表示想要滑動(dòng)的view 
  6.        //pointerId 表示觸摸點(diǎn)的id, 比如多點(diǎn)按壓的那個(gè)id 
  7.        //返回值表示,是否可以capture,也就是是否可以滑動(dòng).可以根據(jù)不同的child決定是否可以滑動(dòng) 
  8.        return true
  9.    } 
  10.    @Override 
  11.    public int clampViewPositionHorizontal(View child, int leftint dx) { 
  12.        //child 表示當(dāng)前正在移動(dòng)的view 
  13.        //left 表示當(dāng)前的view正要移動(dòng)到左邊距為left的地方 
  14.        //dx 表示和上一次滑動(dòng)的距離間隔 
  15.        //返回值就是child要移動(dòng)的目標(biāo)位置.可以通過(guò)控制返回值,從而控制child只能在ViewGroup的范圍中移動(dòng). 
  16.        return left
  17.    } 
  18.    @Override 
  19.    public int clampViewPositionVertical(View child, int topint dy) { 
  20.        //child 表示當(dāng)前正在移動(dòng)的view 
  21.        //top 表示當(dāng)前的view正要移動(dòng)到上邊距為top的地方 
  22.        //dx 表示和上一次滑動(dòng)的距離間隔 
  23.        return top
  24.    } 

重寫(xiě)以上3個(gè)方法,可以正常工作了.子View就可以被任意拖動(dòng)了;

3、控制child的移動(dòng)范圍在父view中

  1. //控制child只能在ViewGroup的橫向中移動(dòng) 
  2. @Override   
  3. public int clampViewPositionHorizontal(View child, int leftint dx) { 
  4.   final int leftBound = getPaddingLeft();   
  5.   final int rightBound = getWidth() - mDragView.getWidth();   
  6.   final int newLeft = Math.min(Math.max(left, leftBound), rightBound);   
  7.   return newLeft;   
  8. }  
  9. //控制child只能在ViewGroup的縱向中移動(dòng) 
  10. @Override   
  11. public int clampViewPositionVertical(View child, int topint dy) {   
  12.   final int topBound = getPaddingTop();   
  13.   final int bottomBound = getHeight() - mDragView.getHeight();   
  14.   final int newTop = Math.min(Math.max(top, topBound), bottomBound);   
  15.   return newTop;   
  16. }  

4、開(kāi)啟邊界滑動(dòng)

  1. //開(kāi)啟4個(gè)邊 
  2. mViewDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_ALL); 
  3. //各個(gè)邊 
  4. public static final int EDGE_LEFT = 1 << 0; 
  5. public static final int EDGE_RIGHT = 1 << 1; 
  6. public static final int EDGE_TOP = 1 << 2; 
  7. public static final int EDGE_BOTTOM = 1 << 3; 
  8. //當(dāng)開(kāi)啟邊界滑動(dòng)之后, 此方法就會(huì)回調(diào) 
  9. @Override 
  10. public void onEdgeTouched(int edgeFlags, int pointerId) { 
  11.     //通常開(kāi)啟邊界之后, 都需要手動(dòng)capture view.之后就可以滑動(dòng)view了. 
  12.     mViewDragHelper.captureChildView(getChildAt(1), pointerId); 
  13. @Override 
  14. public boolean tryCaptureView(View child, int pointerId) { 
  15.     //開(kāi)啟邊界之后, 這個(gè)方法的返回值可能需要進(jìn)一步處理.要不然開(kāi)邊界就沒(méi)啥意思了. 
  16.     return false

5、釋放后的回彈效果

有些時(shí)候, 當(dāng)釋放的時(shí)候, 需要將View回到原來(lái)的位置;

  1. //釋放的時(shí)候, 會(huì)回調(diào)下面的方法 
  2. @Override 
  3. public void onViewReleased(View releasedChild, float xvel, float yvel) { 
  4.     //調(diào)用這個(gè)方法,就可以設(shè)置releasedChild回彈得位置. 
  5.     mViewDragHelper.settleCapturedViewAt(0, 100);//參數(shù)就是x,y的坐標(biāo) 
  6.     postInvalidate();//注意一定要調(diào)用這個(gè)方法,否則沒(méi)效果. 
  7. //以下2個(gè)方法最終調(diào)用的都是forceSettleCapturedViewAt(). 
  8. mViewDragHelper.settleCapturedViewAt(0, 100); 
  9. mViewDragHelper.smoothSlideViewTo(getChildAt(1), 0, 100); 
  10. //所以...發(fā)揮你的想象力,看看有什么妙用!!! 
  11. //如果你還沒(méi)有忘記的話...前文應(yīng)該有說(shuō)過(guò),涉及到scroll,需要重寫(xiě)view的此方法. 
  12. //此方法一定要重寫(xiě),否則沒(méi)效果 
  13. @Override 
  14. public void computeScroll() { 
  15.   //固定寫(xiě)法 
  16.   if (mViewDragHelper.continueSettling(true)) { 
  17.       postInvalidate();//注意此處. 
  18.   } 
  19. 通過(guò)上面2個(gè)方法的設(shè)置, 當(dāng)手指釋放的時(shí)候, View就會(huì)自動(dòng)滑動(dòng)到指定的位置...(不是一下子就到指定的位置哦,有一個(gè)滑動(dòng)的過(guò)程.) 
  20. 注意:如果需要滑動(dòng)的View,會(huì)消耗touch事件,比如:Button,那么需要重寫(xiě)以下方法. 
  21. @Override 
  22. public int getViewHorizontalDragRange(View child) { 
  23.     return child.getMeasuredWidth();//只要返回大于0的值就行 
  24. @Override 
  25. public int getViewVerticalDragRange(View child) { 
  26.     return child.getMeasuredHeight();//只要返回大于0的值就行 

6、簡(jiǎn)單api介紹

ViewDragHelper的API

  1. ViewDragHelper create(ViewGroup forParent, Callback cb); 
  • 一個(gè)靜態(tài)的創(chuàng)建方法,
  • 參數(shù)1:出入的是相應(yīng)的ViewGroup
  • 參數(shù)2:是一個(gè)回掉
  1. shouldInterceptTouchEvent(MotionEvent ev)  
  • 處理事件分發(fā)的(主要是將ViewGroup的事件分發(fā),委托給ViewDragHelper進(jìn)行處理)
  • 參數(shù)1:MotionEvent ev 主要是ViewGroup的事件
  • processTouchEvent(MotionEvent event) 處理相應(yīng)TouchEvent的方法,這里要注意一個(gè)問(wèn)題,處理相應(yīng)的TouchEvent的時(shí)候要將結(jié)果返回為true,消費(fèi)本次事件!否則將無(wú)法使用ViewDragHelper處理相應(yīng)的拖拽事件!

ViewDragHelper.Callback的API

  1. tryCaptureView(View child, int pointerId)  
  • 這是一個(gè)抽象類,必須去實(shí)現(xiàn),也只有在這個(gè)方法返回true的時(shí)候下面的方法才會(huì)生效;
  • 參數(shù)1:捕獲的View(也就是你拖動(dòng)的這個(gè)View)
  1. onViewDragStateChanged(int state)  
  • 當(dāng)狀態(tài)改變的時(shí)候回調(diào),返回相應(yīng)的狀態(tài)(這里有三種狀態(tài))
  • STATE_IDLE 閑置狀態(tài)
  • STATE_DRAGGING 正在拖動(dòng)
  • STATE_SETTLING 放置到某個(gè)位置
  1. onViewPositionChanged(View changedView, int leftint topint dx, int dy)  
  • 當(dāng)你拖動(dòng)的View位置發(fā)生改變的時(shí)候回調(diào)
  • 參數(shù)1:你當(dāng)前拖動(dòng)的這個(gè)View
  • 參數(shù)2:距離左邊的距離
  • 參數(shù)3:距離右邊的距離
  • 參數(shù)4:x軸的變化量
  • 參數(shù)5:y軸的變化量
  1. onViewCaptured(View capturedChild, int activePointerId) 
  • 捕獲View的時(shí)候調(diào)用的方法
  • 參數(shù)1:捕獲的View(也就是你拖動(dòng)的這個(gè)View)
  1. onViewReleased(View releasedChild, float xvel, float yvel)  
  • 當(dāng)View停止拖拽的時(shí)候調(diào)用的方法,一般在這個(gè)方法中重置一些參數(shù),比如回彈什么的
  • 參數(shù)1:你拖拽的這個(gè)View
  • 參數(shù)2:x軸的速率
  • 參數(shù)3:y軸的速率
  1. clampViewPositionVertical(View child, int topint dy)  
  • 豎直拖拽的時(shí)候回調(diào)的方法
  • 參數(shù)1:拖拽的View
  • 參數(shù)2:距離頂部的距離
  • 參數(shù)3:變化量
  1. clampViewPositionHorizontal(View child, int leftint dx)  
  • 水平拖拽的時(shí)候回調(diào)的方法
  • 參數(shù)1:拖拽的View
  • 參數(shù)2:距離左邊的距離
  • 參數(shù)3:變化量

二、簡(jiǎn)單的實(shí)現(xiàn)demo

下面是簡(jiǎn)單實(shí)現(xiàn)的demo,可以直接復(fù)制使用的

1、BottomView的ViewDragHelper實(shí)現(xiàn)

  1. public class BottomView extends LinearLayout { 
  2.     private ViewDragHelper mDragHelper; 
  3.     private View view
  4.     private int mDragBorder, verticalRange, mDragState, peekHeight, mDragHeight; 
  5.     private final double AUTO_OPEN_SPEED_LIMIT = 800.0; 
  6.     private boolean inflate = false, isExpanded = false, isDragHeightSet = false
  7.     private MotionEvent globalEvent; 
  8.     View try_view; 
  9.     public BottomView(Context context) { 
  10.         super(context); 
  11.     } 
  12.     public BottomView(Context context, @Nullable AttributeSet attrs) { 
  13.         super(context, attrs); 
  14.         initView(context, attrs); 
  15.     } 
  16.     public BottomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 
  17.         super(context, attrs, defStyleAttr); 
  18.         initView(context, attrs); 
  19.     } 
  20.     void initView(Context context, AttributeSet attrs) { 
  21.         peekHeight = 300; 
  22.     } 
  23.     @Override 
  24.     protected void onAttachedToWindow() { 
  25.         super.onAttachedToWindow(); 
  26.     } 
  27.     @Override 
  28.     protected void onFinishInflate() { 
  29.         super.onFinishInflate(); 
  30.         mDragHelper = ViewDragHelper.create(this, 1.0f, new DragHelperCallback()); 
  31.         view = getChildAt(0); 
  32.         try_view = findViewById(R.id.ll_try_view); 
  33.     } 
  34.     @Override 
  35.     protected void onLayout(boolean b, int leftint topint rightint bottom) { 
  36.         verticalRange = getMeasuredHeight() - peekHeight; 
  37.         if (!inflate) { 
  38.             mDragBorder = verticalRange; 
  39.             inflate = true
  40.         } 
  41.         view.layout(left, mDragBorder, right, bottom + mDragBorder); 
  42.     } 
  43.     @Override 
  44.     public boolean onInterceptTouchEvent(MotionEvent ev) { 
  45.         int action = MotionEventCompat.getActionMasked(ev); 
  46.         if ((action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) && !isDraggingAllowed(ev)) { 
  47.             mDragHelper.cancel(); 
  48.             return false
  49.         } 
  50.         return mDragHelper.shouldInterceptTouchEvent(ev); 
  51.     } 
  52.     @Override 
  53.     public boolean onTouchEvent(MotionEvent event) { 
  54.         if (isDraggingAllowed(event) || isMoving()) { 
  55.             mDragHelper.processTouchEvent(event); 
  56.             return true
  57.         } 
  58.         return super.onTouchEvent(event); 
  59.     } 
  60.     @Override 
  61.     public boolean dispatchTouchEvent(MotionEvent ev) { 
  62.         globalEvent = ev; 
  63.         return super.dispatchTouchEvent(ev); 
  64.     } 
  65.     boolean isDraggingAllowed(MotionEvent event) { 
  66.         int[] viewLocations = new int[2]; 
  67.         view.getLocationOnScreen(viewLocations); 
  68.         int upperLimit = viewLocations[1] + (isDragHeightSet ? mDragHeight : peekHeight); 
  69.         int lowerLimit = viewLocations[1]; 
  70.         int y = (int) event.getRawY(); 
  71.         return (y > lowerLimit && y < upperLimit); 
  72.     } 
  73.     boolean isMoving() { 
  74.         return (mDragState == ViewDragHelper.STATE_DRAGGING || 
  75.                 mDragState == ViewDragHelper.STATE_SETTLING); 
  76.     } 
  77.     class DragHelperCallback extends ViewDragHelper.Callback { 
  78.         @Override 
  79.         public boolean tryCaptureView(View child, int pointerId) { 
  80.             return true
  81.         } 
  82.         @Override 
  83.         public int clampViewPositionVertical(View child, int topint dy) { 
  84.             return top
  85.         } 
  86.         @Override 
  87.         public void onViewDragStateChanged(int state) { 
  88.             super.onViewDragStateChanged(state); 
  89.             mDragState = state; 
  90.         } 
  91.         @Override 
  92.         public int getViewVerticalDragRange(View child) { 
  93.             return verticalRange; 
  94.         } 
  95.         @Override 
  96.         public void onViewReleased(View releasedChild, float xvel, float yvel) { 
  97.             super.onViewReleased(releasedChild, xvel, yvel); 
  98.             boolean settleToOpen = false
  99.             if (yvel > AUTO_OPEN_SPEED_LIMIT && xvel < yvel) { 
  100.                 settleToOpen = true
  101.             } else if (yvel < -AUTO_OPEN_SPEED_LIMIT && xvel > yvel) { 
  102.                 settleToOpen = false
  103.             } else if (mDragBorder > (2 * verticalRange / 3)) { 
  104.                 settleToOpen = true
  105.             } else if (mDragBorder < (verticalRange / 3)) { 
  106.                 settleToOpen = false
  107.             } 
  108.             final int settleDestY = settleToOpen ? verticalRange : 0; 
  109.             isExpanded = settleToOpen ? false : true
  110.             if (mDragHelper.settleCapturedViewAt(releasedChild.getLeft(), settleDestY)) { 
  111.                 ViewCompat.postInvalidateOnAnimation(BottomView.this); 
  112.             } 
  113.         } 
  114.         @Override 
  115.         public void onViewPositionChanged(View changedView, int leftint topint dx, int dy) { 
  116.             super.onViewPositionChanged(changedView, lefttop, dx, dy); 
  117.             mDragBorder = top < 0 ? 0 : top > verticalRange ? verticalRange : top
  118.             float offset = 1 - ((float) mDragBorder / verticalRange); 
  119.            // if (listener != null) listener.onDrag(offset); 
  120.             requestLayout(); 
  121.         } 
  122.     } 
  123.     @Override 
  124.     public void computeScroll() { 
  125.         super.computeScroll(); 
  126.         if (mDragHelper.continueSettling(true)) { 
  127.             ViewCompat.postInvalidateOnAnimation(this); 
  128.         } 
  129.     } 
  130.     public boolean expandOnTouchView() { 
  131.         if (isDraggingAllowed(globalEvent) && mDragHelper.smoothSlideViewTo(view, 0, 0)) { 
  132.             isExpanded = true
  133.             ViewCompat.postInvalidateOnAnimation(BottomView.this); 
  134.             return true
  135.         } 
  136.         return false
  137.     } 
  138.     public boolean expandView() { 
  139.         if (mDragHelper.smoothSlideViewTo(view, 0, 0)) { 
  140.             isExpanded = true
  141.             ViewCompat.postInvalidateOnAnimation(BottomView.this); 
  142.             return true
  143.         } 
  144.         return false
  145.     } 
  146.     public boolean collapseOnTouchView() { 
  147.         if (isDraggingAllowed(globalEvent) && mDragHelper.smoothSlideViewTo(view, 0, verticalRange)) { 
  148.             isExpanded = false
  149.             ViewCompat.postInvalidateOnAnimation(BottomView.this); 
  150.             return true
  151.         } 
  152.         return false
  153.     } 
  154.     public boolean collapseView() { 
  155.         if (mDragHelper.smoothSlideViewTo(view, 0, verticalRange)) { 
  156.             isExpanded = false
  157.             ViewCompat.postInvalidateOnAnimation(BottomView.this); 
  158.             return true
  159.         } 
  160.         return false
  161.     } 
  162.     public boolean isViewExpanded() { 
  163.         return isExpanded; 
  164.     } 
  165.     public void setPeekHeight(int peekHeight) { 
  166.         this.peekHeight = peekHeight; 
  167.         requestLayout(); 
  168.     } 
  169.     public void dragHeight(int mDragHeight) { 
  170.         isDragHeightSet = true
  171.         this.mDragHeight = mDragHeight; 
  172.     } 

2、布局文件

總結(jié)

面對(duì)不懂的知識(shí)點(diǎn),不要害怕,勇敢面對(duì);一起加油

本文轉(zhuǎn)載自微信公眾號(hào)「Android開(kāi)發(fā)編程」

 

責(zé)任編輯:姜華 來(lái)源: Android開(kāi)發(fā)編程
相關(guān)推薦

2021-09-09 06:55:43

AndroidViewDragHel原理

2021-08-23 06:27:46

AndroidctivitysetContentV

2021-07-14 14:27:01

AndroidAOPhugo

2021-08-25 07:43:17

AndroidSurfaceViewTextureView

2021-09-14 07:06:12

Android磁盤緩存

2021-09-12 07:30:10

配置

2021-09-07 06:40:25

AndroidLiveData原理

2021-08-09 20:29:27

Android沉浸式狀態(tài)欄

2015-07-28 17:11:00

編程技術(shù)提升

2021-08-10 20:41:33

AndroidApp流程

2021-09-01 06:48:16

AndroidGlide緩存

2021-10-03 15:08:32

Android

2021-08-17 13:41:11

AndroidView事件

2021-09-02 07:00:01

Glide流程Android

2022-04-24 15:26:38

服務(wù)卡鴻蒙

2014-07-15 17:17:31

AdapterAndroid

2009-07-16 13:51:43

2021-08-11 17:15:17

AndroidActivity場(chǎng)景

2021-08-26 07:38:41

AndroidMediaPlayerTextureView

2022-05-09 11:52:38

Java卡片服務(wù)卡片
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)