Android拖拽和嵌套滑動

View.onDragListener(View)

  • Api 11引入的工具類谈截,用于實現(xiàn)View的拖拽操作,列表拖動

  • 適用于用戶的托起,放下操作,重在內(nèi)容的移動挣磨,拖拽時可以附加拖拽數(shù)據(jù),數(shù)據(jù)分為本地數(shù)據(jù)LocalState(App內(nèi)進行拖拽)荤懂,跨進程數(shù)據(jù)ClipData(兩個App之間進行拖拽)茁裙;比如添加物品進購物車

  • 不需要進行自定義View,使用view.startDrag()/startDragAndDrop()來啟動拖拽操作
    通過view.setDragListener()或者重寫View的onDragEvent()來監(jiān)聽View的拖拽狀態(tài)

  • 拖拽原理:創(chuàng)建一個圖層(DragShadowBuilder)在屏幕的最上層,這個圖層會隨著用戶手指的移動而移動

使用

開啟拖拽

val clipData = ClipData.newPlainText("name", "drag data")
ViewCompat.startDragAndDrop(view, clipData, View.DragShadowBuilder(it), "LocalState", 0)

//或者view.startDragAndDrop()
val clipData = ClipData.newPlainText("name", "drag data")
view.startDragAndDrop(clipData, View.DragShadowBuilder(it), "LocalState", 0)

拖拽監(jiān)聽

view.setOnDragListener(HDragListener)

//重寫OnDragListener實現(xiàn)拖拽監(jiān)聽
inner class HDragListener : OnDragListener {
     override fun onDrag(v: View, event: DragEvent): Boolean {
           when (event.action) {
               DragEvent.ACTION_DRAG_STARTED ->{
                   //開始拖拽時回調(diào)
               }
               DragEvent.ACTION_DRAG_ENTERED ->{
                   //拖拽到View的邊界內(nèi)回調(diào)(可進行排序操作)
               }
               DragEvent.ACTION_DRAG_ENDED ->{
                   //結(jié)束拖拽時回調(diào)
               }
          }

          return true
    }
}

//或者重寫View的onDragEvent()實現(xiàn)拖拽監(jiān)聽
override fun onDragEvent(event: DragEvent): Boolean {
  //當前界面中所有View都會回調(diào)這個方法
}

ViewDragHelper(ViewGroup)

  • 2015年 SupportV4 包新增的工具類节仿,主要用于ViewGroup中子View的拖拽操作

  • 需要開發(fā)者在自定義ViewGroup中使用晤锥,重寫ViewGroup的onInterceptTouchEvent()和onTouchEvent()來接管觸摸事件

  • 拖拽原理:實時修改被拖拽的子View的mLeft,mTop,mRight,mBottom值

使用:

自定義Callback實現(xiàn)ViewDragHelper.callback接口,監(jiān)聽拖拽回調(diào)

inner class HDragCallback : ViewDragHelper.Callback() {
 //記錄下被托起的View的初始位置
 private var capturedLeft = 0
 private var capturedTop = 0

 /*** 返回true時View可以被拖起來*/
 override fun tryCaptureView(child: View, pointerId: Int): Boolean {
      return true
 }

 override fun clampViewPositionHorizontal(child: View, left: Int, dx: Int): Int {
      return left  //水平偏移
 }

 override fun clampViewPositionVertical(child: View, top: Int, dy: Int): Int {
      return top  //垂直偏移
 }

 /*** View被拖起時回調(diào)*/
 override fun onViewCaptured(capturedChild: View, activePointerId: Int) {
      capturedChild.elevation = elevation + 1
      capturedLeft = capturedChild.left
      capturedTop = capturedChild.top
 }

 /*** 拖拽狀態(tài)改變時回調(diào)*/
 override fun onViewDragStateChanged(state: Int) {
      if (state == ViewDragHelper.STATE_IDLE) {
          val capturedView = mDragHelper.capturedView!!
          capturedView.elevation = capturedView.elevation - 1
      }
 }

 override fun onViewPositionChanged(changedView: View, left: Int, top: Int,dx: Int, dy: Int) {
      //位置改變時回調(diào)
 }

 /*** View被松開時回調(diào)*/
 override fun onViewReleased(releasedChild: View, xvel: Float, yvel: Float) {
      mDragHelper.settleCapturedViewAt(capturedLeft, capturedTop)
          //更新下一幀的繪制 和computeScroll結(jié)合
          postInvalidateOnAnimation()
  }
}

重寫ViewGroup的onInterceptTouchEvent()和onTouchEvent()來接管觸摸事件

private val mDragHelper by lazy {
  ViewDragHelper.create(this, HDragCallback())
}

override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
  return mDragHelper.shouldInterceptTouchEvent(ev)
}

override fun onTouchEvent(event: MotionEvent): Boolean {
  mDragHelper.processTouchEvent(event)
  return true
}

//和DragCallback的onViewReleased()相結(jié)合,循環(huán)繪制每一幀
override fun computeScroll() {
  if (mDragHelper.continueSettling(true)) {
          ViewCompat.postInvalidateOnAnimation(this)
  }
}

嵌套滑動

不同向嵌套

  • onInterceptTouchEvent 父 View 攔截子View

  • requestDisallowInterceptTouchEvent() 子 View 阻止父 View 攔截

同向嵌套

  • 父 View 會徹底卡住子 View(滑動沖突)
    原因:搶奪條件一致粟耻,但父View的onInterceptTouchEvent() 早于子View的dispatchTouchEvent()

  • 本質(zhì)上是策略問題:嵌套狀態(tài)下用戶手指滑動查近,他是想滑誰?

    1. 場景一:NestedScrollView 子View能滑動的時候滑動子View挤忙;滑不動的時候滑動父View

    2. 場景二:Google 的樣例

      父View展開的時候:

      ? 上滑:優(yōu)先滑動父View

      ? 下滑:滑不動

      父View半展開的時候:

      ? 上滑:優(yōu)先滑動父View霜威,滑到父View完全折疊后開始滑動子View

      ? 下滑:優(yōu)先滑動父View,滑到父View完全展開后開始滑動子View

      父View折疊的時候:

      ? 上滑:滑動子View

      ? 下滑:優(yōu)先滑動子View册烈,滑到子View頂部后開始滑動父View

  • 滑動嵌套解決方案: 自定義滑動策略(父View戈泼,子View誰來消費滑動事件)

  • 實現(xiàn):

    1. 大多數(shù)場景下SDk就能解決:ScrollView嵌套問題,換成NestedScrollView

    2. 自己實現(xiàn):實現(xiàn) NestedScrollingChild2 接口來實現(xiàn)自定義的嵌套滑動邏輯

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市赏僧,隨后出現(xiàn)的幾起案子大猛,更是在濱河造成了極大的恐慌,老刑警劉巖淀零,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件挽绩,死亡現(xiàn)場離奇詭異,居然都是意外死亡驾中,警方通過查閱死者的電腦和手機唉堪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來肩民,“玉大人唠亚,你說我怎么就攤上這事〕痔担” “怎么了灶搜?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我割卖,道長前酿,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任究珊,我火速辦了婚禮薪者,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘剿涮。我一直安慰自己言津,他們只是感情好,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布取试。 她就那樣靜靜地躺著悬槽,像睡著了一般。 火紅的嫁衣襯著肌膚如雪瞬浓。 梳的紋絲不亂的頭發(fā)上初婆,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天,我揣著相機與錄音猿棉,去河邊找鬼磅叛。 笑死,一個胖子當著我的面吹牛萨赁,可吹牛的內(nèi)容都是我干的弊琴。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼杖爽,長吁一口氣:“原來是場噩夢啊……” “哼敲董!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起慰安,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤腋寨,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后化焕,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體萄窜,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年撒桨,在試婚紗的時候發(fā)現(xiàn)自己被綠了脂倦。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡元莫,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蝶押,到底是詐尸還是另有隱情踱蠢,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站茎截,受9級特大地震影響苇侵,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜企锌,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一榆浓、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧撕攒,春花似錦陡鹃、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至擦俐,卻和暖如春脊阴,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蚯瞧。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工嘿期, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人埋合。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓备徐,卻偏偏與公主長得像,于是被迫代替她去往敵國和親饥悴。 傳聞我的和親對象是個殘疾皇子坦喘,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

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