真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

用代碼解析Android如何實(shí)現(xiàn)仿抖音右滑清屏左滑列表功能

這篇文章主要用代碼解析Android如何實(shí)現(xiàn)仿抖音右滑清屏左滑列表功能,內(nèi)容簡(jiǎn)而易懂,希望大家可以學(xué)習(xí)一下,學(xué)習(xí)完之后肯定會(huì)有收獲的,下面讓小編帶大家一起來看看吧。

企業(yè)建站必須是能夠以充分展現(xiàn)企業(yè)形象為主要目的,是企業(yè)文化與產(chǎn)品對(duì)外擴(kuò)展宣傳的重要窗口,一個(gè)合格的網(wǎng)站不僅僅能為公司帶來巨大的互聯(lián)網(wǎng)上的收集和信息發(fā)布平臺(tái),創(chuàng)新互聯(lián)公司面向各種領(lǐng)域:成都砂巖浮雕網(wǎng)站設(shè)計(jì)、成都全網(wǎng)營銷推廣解決方案、網(wǎng)站設(shè)計(jì)等建站排名服務(wù)。


概述

項(xiàng)目中要實(shí)現(xiàn)仿抖音直播間滑動(dòng)清屏,側(cè)滑列表的功能,在此記錄下實(shí)現(xiàn)過程和踩坑記錄希望避免大家走些彎路,也當(dāng)作自己的一個(gè)總結(jié)

首先看下Demo中的效果

用代碼解析Android如何實(shí)現(xiàn)仿抖音右滑清屏左滑列表功能

閱讀文章需要提前熟悉些事件分發(fā)的內(nèi)容,相信大家都已經(jīng)了解過了

關(guān)于這方面的知識(shí),在Android中是再重要不過的了,是遲早都要掌握的知識(shí),所以還是希望大家都能提早掌握,最好可以跟著源碼一起分析,理解掌握的更深刻一點(diǎn)

實(shí)踐

所以網(wǎng)上基于這部分內(nèi)容講解已經(jīng)很詳細(xì)了,這里就不再搬磚了,主要分享一下自己項(xiàng)目中結(jié)合這部分知識(shí)運(yùn)用過程中產(chǎn)生的一些想法和經(jīng)驗(yàn),解決的一些bug

用代碼解析Android如何實(shí)現(xiàn)仿抖音右滑清屏左滑列表功能

以上就是功能在實(shí)現(xiàn)過程中要解決的問題,下面詳細(xì)展開

1. 布局結(jié)構(gòu)

布局結(jié)構(gòu)始終是界面設(shè)計(jì)時(shí)首先要考慮的一個(gè)問題,從接到一個(gè)需求開始,首先要根據(jù)項(xiàng)目中現(xiàn)有的布局結(jié)構(gòu),考慮如何更優(yōu)雅的嵌入布局層次。如果一不小心,走上了錯(cuò)誤的實(shí)現(xiàn)道路,那么不好意思,即使功能最后實(shí)現(xiàn)了,到了后期,也有千萬種理由迫使你不得不走上重構(gòu)的道路。

 比如實(shí)現(xiàn)不合理,導(dǎo)致的布局結(jié)構(gòu)復(fù)雜,嵌套冗余層次,比如代碼業(yè)務(wù)邏輯處理復(fù)雜蹩腳,比如資源浪費(fèi),內(nèi)存消耗過多等等。雖然功能好使,使用起來也沒有差別,但是,作為一個(gè)有追求的程序員,我們還是要避免這種情況的發(fā)生不是嗎

不巧的是,本文就屬于上述踩坑記錄,下面詳細(xì)分析

 1.1 初步實(shí)現(xiàn)

上來以后,思路很直接明了的去想要實(shí)現(xiàn)清屏和滑屏的功能是每個(gè)房間都有的功能,每個(gè)房間又都是一個(gè)RecyclerView 的一個(gè)Item。所以,很明顯在Item的布局上包一層,實(shí)現(xiàn)清屏和側(cè)滑列表的功能就可以了,這樣每個(gè)房間都可以上下滑,切換房間。切換以后,滑屏的功能是在每個(gè)房間里的,互不影響,所以很好理解

我們項(xiàng)目中實(shí)現(xiàn)直播間上下滑切換的功能是RecyclerView + 自定義LinearLayoutManager實(shí)現(xiàn)的,這部分內(nèi)容網(wǎng)上demo很多,就不展開了

 具體實(shí)施,是自定義布局繼承RelativeLayout,解析自定義的布局文件,里面包含,直播間的房間布局,和自己右側(cè)滑塊兒布局,然后用自己實(shí)現(xiàn)的布局替換之前的房間Item布局位置

用代碼解析Android如何實(shí)現(xiàn)仿抖音右滑清屏左滑列表功能

  • 由于我們自定義的Container布局是繼承子RelativeLayout實(shí)現(xiàn)的,內(nèi)部三個(gè)子View 又全部是占滿父布局的,所以就是三層覆蓋的效果,類似抖音直播間效果
  •  這里我們盡量將覆蓋層/清屏控件,封裝成一個(gè)ViewGroup 內(nèi)部包含了上邊細(xì)分的各個(gè)子View,例如頭部個(gè)人信息,頭像列表等等;中間彈幕,SVGA禮物展示區(qū)域;底部聊天評(píng)論區(qū)域方便管理
  • 還有右側(cè)滑塊我們也做成繼承自RelativeLayout形式,解析自定義布局,方便擴(kuò)展

 這樣我們調(diào)用封裝的Container將清屏控件,和右側(cè)滑塊兒布局View分別添加到內(nèi)部即可

API提供如下

// 添加需要清屏的view
 fun addClearViews(vararg views: View?)
 // 添加需要滑入的view
 fun addSlideView(view: RightSlideLayout)

這樣我們?cè)谝曨l播放頁面滑動(dòng),就可以在Container內(nèi)判斷手勢(shì),處理清屏控件或者滑出右側(cè)滑塊兒了

右側(cè)滑塊再動(dòng)態(tài)加載Fragment,展示列表布局,基本完成功能效果了

1.2 重構(gòu)

本來以為開開心心的可以上線了,誰知到下邊繼續(xù)體驗(yàn)和對(duì)比抖音到過程中還是發(fā)現(xiàn)不足:

第一個(gè)是,右側(cè)滑塊兒(后邊稱RightSlider)包含在房間,這樣上下切換房間(后邊稱Container),RightSlider布局也會(huì)隨著Container新建而新建,雖然有RecyclerView的布局緩存,但是至少也會(huì)新建Holder幾次,造成資源的浪費(fèi)。第二個(gè)是,RightSlider的新建就會(huì)導(dǎo)致里邊的Fragment的新建,所以又會(huì)重新請(qǐng)求加載列表數(shù)據(jù),再次造成資源浪費(fèi),而且,新建后右側(cè)列表又會(huì)重新頂?shù)筋^,之前滑動(dòng)過的距離就會(huì)丟失。這樣就造成,用戶從右側(cè)列表點(diǎn)擊切換房間后,再次滑出RightSlider切換房間,發(fā)現(xiàn)又要從頭開始往下滑,這樣肯定不符合用戶體驗(yàn)。觀察抖音列表后發(fā)現(xiàn),每次滑動(dòng)到固定位置點(diǎn)擊Item切換房間后,再次滑出滑塊兒,發(fā)現(xiàn)列表還是之前的位置,好像跟之前滑出的是一個(gè)滑塊兒的效果,于是恍然大悟,滑塊兒是跟Activity綁定的,也就是要把RightSlider放在跟Activity布局那一層

其實(shí)提出RightSlider到外層的過程中,還是走了不少彎路,因?yàn)橹爱吘挂呀?jīng)實(shí)現(xiàn)好的邏輯,如果改動(dòng)布局結(jié)構(gòu),肯定要重寫滑動(dòng)沖突、事件分發(fā)這部分代碼,工作量又不可預(yù)計(jì)。所以想著能不能不動(dòng)布局結(jié)構(gòu)的情況下實(shí)現(xiàn)仿抖音效果

動(dòng)態(tài)替換Fragment

首先想到的是滑出RightSlider里的列表每次都好像是同一個(gè),那么保證里邊的Fragment是同一個(gè)不就好了,滑出的滑塊兒雖然不同,但是里邊裝載的Fragment列表是同一個(gè),這樣就營造出同一個(gè)滑塊兒的效果。

但是實(shí)現(xiàn)過程中還是出現(xiàn)了問題,由于RecyclerView的預(yù)加載功能,導(dǎo)致我們項(xiàng)目中,從第一個(gè)房間上滑到下一個(gè)房間,過程中會(huì)新建兩個(gè)Holder,這樣Fragment替換就出了問題,切換房間后Fragment添加不上去,折騰一下午后最終放棄這個(gè)方案

固定List高度

然后想的,既然Fragment替換不了了,那么RecyclerView肯定不是同一個(gè)了,如果點(diǎn)擊后記錄當(dāng)前RecyclerView滑動(dòng)的位置,下次滑出時(shí),代碼固定到當(dāng)前位置不是也可以偽造出同一個(gè)滑塊兒的效果嘛,這部分也去找了一些資料,實(shí)現(xiàn)了個(gè)小demo。其中用到的主要方法是

/**
    * 獲取滑動(dòng)距離
    */
    fun getScollYDistance(): Int {
    // 獲取recyclerview 的layoutManager
        val layoutManager = recyclerView.layoutManager as LinearLayoutManager
        // 獲取當(dāng)前第一個(gè)可見View的位置
        val position = layoutManager.findFirstVisibleItemPosition()
        // 根據(jù)position 獲取當(dāng)前View
        val firstVisiableChildView = layoutManager.findViewByPosition(position)
        // 獲取當(dāng)前View 高度
        val itemHeight = firstVisiableChildView.height
        // 滑動(dòng)距離
        return position * itemHeight - firstVisiableChildView.top
    }

 滑動(dòng)距離計(jì)算的思想是:根據(jù)當(dāng)前可見View 的position * 每個(gè)ItemView 的高度 + 當(dāng)前View已經(jīng)滑出去的部分

用代碼解析Android如何實(shí)現(xiàn)仿抖音右滑清屏左滑列表功能

計(jì)算出高度后,每次加載時(shí),調(diào)用RecyclerView的API

recyclerView.scrollBy(0,scroll) //scroll 剛才計(jì)算的高度

還有其他幾個(gè)滑動(dòng)的方法:

// 帶動(dòng)畫移動(dòng)距離
public void smoothScrollBy(int dx, int dy)
// 帶動(dòng)畫移動(dòng)到position
public void smoothScrollToPosition(int position)
// 移動(dòng)到adapter position ,由LayoutManager實(shí)現(xiàn)
public void scrollToPosition(int position)
// 空實(shí)現(xiàn),無效
public void scrollTo(int x, int y)

原理上可以實(shí)現(xiàn),但是最后綜合比較還是放棄了這種方式,因?yàn)榭偢杏X這種方法屬于投機(jī)取巧不是正道,還是老老實(shí)實(shí)將RightSlider 提到外面得了

 2. 動(dòng)畫

動(dòng)畫也是這個(gè)功能中很重要的一個(gè)方面,因?yàn)閯?dòng)畫效果的流暢直接影響了用戶體驗(yàn),所以這方面也是細(xì)扣了很久。首先這個(gè)功能主要分成三個(gè)動(dòng)畫效果:

 2.1 進(jìn)場(chǎng)出場(chǎng)

包含清屏控件入場(chǎng)、出場(chǎng):

mClearAnimator = ValueAnimator.ofFloat(0f, 1.0f).setDuration(300)
        mClearAnimator.addUpdateListener(ValueAnimator.AnimatorUpdateListener { valueAnimator ->
            val value = valueAnimator.animatedValue as Float
            translateClearChild((startX + value * (endX - startX)).toInt())
        })
        mClearAnimator.addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationEnd(animation: Animator) {
                isCleared = !isCleared
            }
        })

這里使用了屬性動(dòng)畫ValueAnimator,其中 translateClearChild 負(fù)責(zé)移動(dòng)View 代碼如下:

/**
    * 移動(dòng)清屏控件
    */
    private fun translateClearChild(translate: Int) {
        for (i in mClearViews.indices) {
            mClearViews[i].translationX = translate.toFloat()
        }
    }

滑塊兒的入場(chǎng)、出場(chǎng):

mSlideInAnimator = ValueAnimator.ofFloat(0f, 1.0f).setDuration(500)
// 設(shè)置減速攔截器
mSlideInAnimator.interpolator = DecelerateInterpolator(3f)
mSlideInAnimator.addUpdateListener(ValueAnimator.AnimatorUpdateListener { valueAnimator ->
            val value = valueAnimator.animatedValue as Float
            translateSlideView((startX + value * (endX - startX)).toInt())
        })
mSlideInAnimator.addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationStart(animation: Animator) {
                mSlideView!!.visibility = View.VISIBLE
                mBgColorView.isClickable = true
            }
            override fun onAnimationEnd(animation: Animator) {
                if (!isSlideShow && translateX == 0) {
                    isSlideShow = !isSlideShow
                } else if (isSlideShow && abs(translateX) == width - mSlideView!!.paddingLeft) {
                    isSlideShow = !isSlideShow
                }
                if (!isSlideShow) {
                    parent.requestDisallowInterceptTouchEvent(false)
                    mSlideView!!.visibility = View.GONE
                    removeView(mBgColorView)
                    addView(mBgColorView, childCount - 4)
                }
                isSliderGoning = false
            }
        })

這里startX,endX 分別代表入場(chǎng)和出場(chǎng)時(shí)候,動(dòng)畫起止位置。由于清屏控件沒有中間位置狀態(tài),直接是從0 到屏幕寬度兩個(gè)值之間替換;而滑塊兒中間由于要跟隨手勢(shì)移動(dòng),所以要記錄中間translateX,標(biāo)記為startX

 2.2 跟隨手勢(shì)

跟隨手勢(shì)實(shí)現(xiàn)主要是攔截移動(dòng)手勢(shì),根據(jù)按下手勢(shì)位置坐標(biāo)和Move移動(dòng)位置坐標(biāo)的差值,調(diào)用移動(dòng)SliderView的方法

val x = event.rawX.toInt()
// 標(biāo)記移動(dòng)距離
val offsetX = x - mDownX
when (event.action) {
            MotionEvent.ACTION_MOVE -> {
                if ((isSlideShow) && offsetX > 0 && mSlideInAnimator.isRunning && !isSliderGoning) {
                    // 滑入情況下,向右滑一段松開,再向右滑,清除回彈動(dòng)畫,跟隨手勢(shì)
                    mSlideInAnimator.cancel()
                    translateSlideView(offsetX)
                }
                if ((isSlideShow) && offsetX > 0 && !mSlideInAnimator.isRunning) {
                    // 滑入情況下,向右滑,跟隨手勢(shì)
                    translateSlideView(offsetX)
                }
                return true
            }
      }

 2.3 顏色漸變

跟隨手勢(shì)滑動(dòng)過程中還伴隨的左側(cè)空白區(qū)域顏色漸變,這部分可以在RightSlider移動(dòng)過程中的距離值關(guān)聯(lián)起來,設(shè)置起始顏色透明和截止顏色灰色蒙層。再根據(jù)距離動(dòng)態(tài)算出當(dāng)前顏色在區(qū)間范圍內(nèi)取值,主要代碼邏輯如下

/**
    * 移動(dòng)滑塊兒
    */
    private fun translateSlideView(translate: Int) {
        val percent = (mSlideView!!.width.toFloat() - translate) / mSlideView!!.width
        // 根據(jù)百分比算出色值
val color = (MASK_DARK_COLOR * percent).toInt() shl 24
        // 動(dòng)態(tài)設(shè)置背景色漸變
        mBgColorView.setBackgroundColor(color)
        translateX = translate
        mSlideView!!.translationX = translate.toFloat()
    }

 3 事件分發(fā)

這部分可以說是本功能實(shí)現(xiàn)的核心,也是耗費(fèi)了相當(dāng)時(shí)間的精力,從最開始的Container包含RightSlider布局處理經(jīng)典的事件分發(fā)順序,到最后重構(gòu)布局,將RightSlider提到外層變成不是包含關(guān)系,而是并列或者說是覆蓋關(guān)系,中間對(duì)事件傳遞的順序理解又深入了一層

3.1 傳遞順序

重構(gòu)之前的布局結(jié)構(gòu)是每個(gè)Container包含了一個(gè)RightSlider,兩個(gè)是一個(gè)整體使用的,滑動(dòng)的邏輯都可以在Container層內(nèi)的onInterceptTouchEvent方法內(nèi)處理。判斷是否攔截事件即可,然后RightSlider內(nèi)想要禁止父層Container攔截事件,可以使用parent.requestDisallowInterceptTouchEvent(true)禁止父層攔截;是屬于經(jīng)典模式的事件分發(fā)模型,事件分發(fā)的順序在一個(gè)U型結(jié)構(gòu)里,比較好處理

然后重構(gòu)以后布局結(jié)構(gòu)變成了如下圖所示

用代碼解析Android如何實(shí)現(xiàn)仿抖音右滑清屏左滑列表功能

每個(gè)Container 共用一個(gè)RightSlider,這樣屬于事件的分發(fā)處理不在一個(gè)ViewGroup的U型模型里了,這樣的分發(fā)順序也是屬于自己的一個(gè)大膽嘗試,想著實(shí)在不行,還是要把Activity內(nèi)布局包一層,將Container和RightSlider 放在一個(gè)U型結(jié)構(gòu)里去處理。

還好最后不斷踩坑,終于實(shí)現(xiàn)了事件從Activity分發(fā),到RightSlider,再分發(fā)到Container的過程

這里貼下Demo里的布局實(shí)現(xiàn):


    
        
            
            
        
    
    
        
            
            
        
    

 其中做了部分簡(jiǎn)化,主要幫助大家理解布局層次

然后貼下RightSlider核心分發(fā)代碼:

override fun dispatchTouchEvent(event: MotionEvent): Boolean {
// 獲取坐標(biāo),這里用rawX 相對(duì)屏幕絕對(duì)位置,不然隨手勢(shì)移動(dòng)過程中父布局的移動(dòng),導(dǎo)致獲取的坐標(biāo)左右抖動(dòng),會(huì)出現(xiàn)移動(dòng)過程中左右一直抖動(dòng)現(xiàn)象
        val x = event.rawX.toInt()
        val y = event.rawY.toInt()
// X方向位移
        val offsetX = x - mDownX
        if (!mSlideContainerLayout.isSlideShow){
        // Container滑塊兒沒滑出來不分發(fā)事件
            return false
        }
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
            // 記錄按下點(diǎn)坐標(biāo)
                mDownX = x
                mDownY = y
                mSlideContainerLayout.setDownXY(mDownX,mDownY)
            }
            MotionEvent.ACTION_MOVE -> if (abs(x - mDownX) < abs(y - mDownY) && paddingLeft < x) { // 上下滑動(dòng)情況處理
                if (isSlideHorizontal) {
                    return mSlideContainerLayout.dispatchTouchEvent(event)
                }
            } else if ( offsetX < 0 && mSlideContainerLayout.isAlignLeftSide()) {
            // 向左滑動(dòng),滑塊兒已經(jīng)靠最左邊了,不分發(fā)
                return super.dispatchTouchEvent(event)
            } else if (abs(x - mDownX) > abs(y - mDownY)){
            // 水平方向移動(dòng),分發(fā)事件
                isSlideHorizontal = true
                    return mSlideContainerLayout.dispatchTouchEvent(event)// 事件傳遞給Container處理
            }
            MotionEvent.ACTION_UP,
            MotionEvent.ACTION_CANCEL ->{
            // 抬起時(shí)處理
                if (offsetX < 0 && mSlideContainerLayout.isAlignLeftSide()){
                    return super.dispatchTouchEvent(event)
                }
                if (abs(x - mDownX) > abs(y - mDownY) || isSlideHorizontal){
                    isSlideHorizontal = false
                    return mSlideContainerLayout.dispatchTouchEvent(event)
                }
                isSlideHorizontal = false
            }
        }
        return super.dispatchTouchEvent(event)
    }

 3.2 滑動(dòng)沖突

 因?yàn)榉块g是可以上下滑動(dòng)的,所以可以判斷如果滑塊兒沒滑粗來時(shí),直接返回分發(fā),不讓RightSlider和Container處理事件

if (!mSlideContainerLayout.isSlideShow){
 return false
 }

然后滑塊兒滑出來以后,因?yàn)槔镞呌辛斜?,所以要消費(fèi)上下滑動(dòng)事件,可以處理如下:

MotionEvent.ACTION_MOVE -> if (abs(x - mDownX) < abs(y - mDownY) && paddingLeft < x) {
                if (isSlideHorizontal) {
                    return mSlideContainerLayout.dispatchTouchEvent(event)
                }
            }

 其中paddingLeft < x 是因?yàn)榛瑝K左邊有一部分空白區(qū)域 paddingLeft ,所以當(dāng)x坐標(biāo)在此區(qū)域右側(cè)時(shí)才處理事件

Container動(dòng)畫執(zhí)行過程中,說明正在消費(fèi)事件,此時(shí)禁止父層攔截事件  

if (mClearAnimator.isRunning || mSlideInAnimator.isRunning || isSlideShow) {
              // 滑入情況下,禁止上下滑切換直播間
              parent.requestDisallowInterceptTouchEvent(true)
    }

 Container處理事件時(shí)候和直播間上的進(jìn)入房間頭像列表沖突,解決方法是判斷mDownY 大于進(jìn)入頭像列表高度時(shí)才處理事件,因?yàn)檎H嘶牖瑝K都是在屏幕中下部操作的,所以太靠上的部分不處理事件也可以接受

MotionEvent.ACTION_MOVE -> {
                if (!mClearAnimator.isRunning && mDownY > 200 && abs(x - mDownX) > abs(y - mDownY)) {
                    // 清屏不在執(zhí)行時(shí) && 高度大于200dp(解決進(jìn)入房間頭像滑動(dòng)沖突)&& 橫向滑動(dòng)時(shí)攔截事件
                    if (abs(x - mDownX) > 10) {
                        return true
                    }
                }
            }

 3.3 滑動(dòng)優(yōu)化

這部分有很多細(xì)節(jié)處理的地方,包括動(dòng)畫執(zhí)行到一半情況下,再次左右滑動(dòng),先向左后向右,左右滑一半再上下滑等等各種情況具體可以看代碼中SlideContainerLayout中onTouchEvent方法內(nèi)處理邏輯,都添加了注釋

override fun onTouchEvent(event: MotionEvent): Boolean {
        mVelocityTracker!!.addMovement(event)
        val x = event.rawX.toInt()
        val offsetX = x - mDownX
        if (mLastOffsetList.size > 2){
            mLastOffsetList.removeFirst()
        }
        mLastOffsetList.add(offsetX)
        var slideRight = (offsetX - mLastOffsetList.first) > 0
        when (event.action) {
            MotionEvent.ACTION_MOVE -> {
                if ((isSlideShow) && offsetX > 0 && mSlideInAnimator.isRunning && !isSliderGoning) {
                    // 滑入情況下,向右滑一段松開,再向右滑,清除回彈動(dòng)畫,跟隨手勢(shì)
                    mSlideInAnimator.cancel()
                    translateSlideView(offsetX)
                }
                if ((isSlideShow) && offsetX > 0 && !mSlideInAnimator.isRunning) {
                    // 滑入情況下,向右滑,跟隨手勢(shì)
                    translateSlideView(offsetX)
                }
                return true
            }
            MotionEvent.ACTION_UP -> {
                mVelocityTracker!!.computeCurrentVelocity(10)
                if (isSlideShow && offsetX > 0 && abs(offsetX) > width / 3 && !isSliderGoning && mVelocityTracker!!.xVelocity >= 0) {
                    // 滑入情況下,向右滑距離超過寬度1/3,滑出滑塊
                    startX = offsetX
                    endX = width - mSlideView!!.paddingLeft
                    isSliderGoning = true
                    mSlideInAnimator.start()
                    return true
                }
                if (abs(mVelocityTracker!!.xVelocity) > 1) {
                    if (isCleared && offsetX < 0) {
                        // 清屏情況下,左滑速度超過10個(gè)像素時(shí) ===》滑入清屏控件
                        layerShowWithAnim()
                    } else if (!isCleared && offsetX > 0 && !isSlideShow && !mSlideInAnimator.isRunning) {
                        // 未清屏 && 向右速度 > 10 && 沒滑入滑塊 && 滑塊動(dòng)畫沒執(zhí)行的時(shí)候 ===》清屏
                        layerGoneWithAnim()
                    } else if (isSlideShow && offsetX > 0 && slideRight) {
                        // 滑入情況下 && 向右速度 > 10 ===》滑出滑塊
                        mSlideInAnimator.cancel()
                        isSliderGoning = true
                        startX = translateX
                        endX = width - mSlideView!!.paddingLeft
                        mSlideInAnimator.start()
                    } else if (isSlideShow && offsetX < 0 && translateX != 0) {
                        // 滑入情況下 && 向左速度 > 10 && 已經(jīng)向右滑動(dòng)了一段距離 ===》 滑塊回彈
                        startX = translateX
                        endX = 0
                        mSlideInAnimator.start()
                    } else if (!isSlideShow && offsetX < 0 && !mSlideInAnimator.isRunning) {
                        // 沒滑入情況下 && 向左滑速度 > 10 && 沒右正在滑入情況下 ===》 滑入滑塊
                        sliderShowWithAnim()
                    } else {
                        if (isSlideShow && translateX != 0) {
                            // 滑入情況下 && 已經(jīng)向右滑動(dòng)過,速度沒達(dá)到松開 ===》回彈
                            startX = translateX
                            mSlideInAnimator.start()
                        }
                    }
                }else {
                    if (isSlideShow && translateX != 0) {
                        // 滑入情況下 && 已經(jīng)向右滑動(dòng)過,速度沒達(dá)到松開 ===》回彈
                        startX = translateX
                        mSlideInAnimator.start()
                    }
                }
                return super.onTouchEvent(event)
            }
            MotionEvent.ACTION_CANCEL -> {
                if (isSlideShow) {
                    //取消事件時(shí),滑入情況下回彈
                    startX = translateX
                    mSlideInAnimator.start()
                }
            }
        }
        return super.onTouchEvent(event)
    }

以上就是關(guān)于用代碼解析Android如何實(shí)現(xiàn)仿抖音右滑清屏左滑列表功能的內(nèi)容,如果你們有學(xué)習(xí)到知識(shí)或者技能,可以把它分享出去讓更多的人看到。


網(wǎng)頁標(biāo)題:用代碼解析Android如何實(shí)現(xiàn)仿抖音右滑清屏左滑列表功能
本文地址:http://weahome.cn/article/gpiide.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部