您好,登錄后才能下訂單哦!
前幾天用了個app發(fā)現(xiàn)左滑可以返回首頁,發(fā)現(xiàn)這個功能很炫酷,就想著自己能不能做出來,于是研究了一下
原理
原理很簡單,但實現(xiàn)起來可能有些坑。這里記錄一下。源碼參考
處理onInterceptTouchEvent
事件攔截要處理一件事情:確定這次觸摸事件是不是應該交給SlideFinishLayout的onTouchEvent處理。
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean { val action = ev.action when (action){ MotionEvent.ACTION_DOWN -> { mLastX = ev.x.toInt() mIsDrag = false } MotionEvent.ACTION_MOVE -> { mScroller.computeScrollOffset() mIsDrag = !mScroller.isFinished val deltaY:Int = ev.x.toInt() - mLastX if (deltaY >= mTouchSlop){ mIsDrag = true } } } return mIsDrag }
onTouchEvent
這個是核心的實現(xiàn)方法.
這里會用到OverScroller的startScroll()方法來處理手指離開后的動畫。OverScroller使用起來非常的簡單,如果想讓View滾動就調(diào)用startScroll()傳入相應參數(shù),會把計算的結(jié)果回調(diào)給View的computeScroll()方法,下面是主要的實現(xiàn)思路:
override fun onTouchEvent(event: MotionEvent): Boolean { val action = event.action //1.初始化軌跡 initVelocityTrackerIfNotExists(event) when(action){ MotionEvent.ACTION_DOWN -> { //2.down 事件 mScroller放棄動畫 記錄觸摸的位置 if (!mScroller.isFinished){ mScroller.abortAnimation() } mLastX = event.rawX.toInt() mIsDrag = true dispatchScroll(0 , 0 , slideState) } MotionEvent.ACTION_MOVE -> { //3.move事件調(diào)用performDrag()方法 會調(diào)用offsetLeftAndRight() 從而移動View val currentX = event.rawX.toInt() val deltaX = currentX - mLastX log("x = ${event.rawX} y = ${event.rawX}") performDrag(deltaX) log("deltaX = $deltaX") mLastX = currentX } MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL ->{ //4.up事件 主要處理手指離開后的View的滾動,以及是否要達到銷毀的條件 //endDrag()方法會處理手指離開后的動畫以及是否達到銷毀條件 if (mIsDrag){ mLastX = 0 mIsDrag = false velocityTracker?.computeCurrentVelocity(1000 , mMaximumVelocity) val velocity = velocityTracker?.xVelocity?.toInt()!! isReachFinish = endDrag(velocity) postInvalidateOnAnimation() recycleVelocityTracker() } } } return true } //開始拖動 private fun performDrag(x:Int){ var canOffset = false isDragLeft = x > 0 slideState = SlideState.DRAGGING //計算 滾動的 距離 if (slideModel == DirectionModel.ONLY_LEFT ){ if (x > 0){ offsetLeftAndRight(x) canOffset = true } }else if (slideModel == DirectionModel.ONLY_RIGHT){ if (x<0){ offsetLeftAndRight(x) canOffset = true } }else{ offsetLeftAndRight(x) canOffset = true } if (canOffset){ dispatchScroll(x , left , slideState) } } //手指離開后的動作 fun endDrag(xVelocity:Int):Boolean{ slideState = SlideState.SETTLING val left = this.left log( "left = $left screenWidth * FACTOR= ${screenWidth * FACTOR}") log( "xVelocity = $xVelocity mMinimumVelocity= $mMinimumVelocity") if (Math.abs(left) > screenWidth * FACTOR || xVelocity > mMinimumVelocity){ if (left>0){ //左滑動 mScroller.startScroll(left , 0 , screenWidth - left , 0) }else{ //右滑動 mScroller.startScroll(left , 0 , left - screenWidth , 0) } return true }else{ mScroller.startScroll(left , 0 , -left , 0) return false } }
怎么使用
activity背景要透明的
<style name="AppTheme.Transparent" parent="Theme.AppCompat.Light.NoActionBar"> <item name="android:windowBackground">@color/transparent</item> <item name="android:windowIsTranslucent">true</item> </style>
設置activity進場和出場動畫
R.anim.enter
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:fromXDelta="100%p" android:toXDelta="0" android:duration="200" android:interpolator="@android:anim/accelerate_decelerate_interpolator"/> </set>
R.anim.exit
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="true" > <translate android:fromXDelta="0" android:toXDelta="100%p" android:duration="200" android:interpolator="@android:anim/accelerate_decelerate_interpolator"/> </set>
activity代碼如下
class TwoActivity : BaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_two) val index = intent?.getStringExtra("index") nextBtn.setOnClickListener { startActivity(Intent(this@TwoActivity , TwoActivity::class.java)) overridePendingTransition(R.anim.enter, 0) } //滑動達到finish的監(jiān)聽事件,slideFinishLayout沒有做任何處理 如果這里不掉用finish也不會退出activity slideFinishLayout.finishListener = { finish() overridePendingTransition(0, 0) } } override fun finish() { super.finish() overridePendingTransition(0, R.anim.exit) } }
存在的問題
堆棧之前的activity被意外銷毀了,此時的當前的activity雖然為透明的,但是背景是黑色的,可能是因為被意外銷毀還沒有來的及調(diào)用onCreate,但是打開不保留活動來測試是沒有問題的。
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。