Android左滑返回功能的實(shí)現(xiàn)示例代碼
前幾天用了個(gè)app發(fā)現(xiàn)左滑可以返回首頁,發(fā)現(xiàn)這個(gè)功能很炫酷,就想著自己能不能做出來,于是研究了一下
原理
- 將activity的背景設(shè)置為透明同時(shí)設(shè)置切換動(dòng)畫
- 手指滑動(dòng)的時(shí)候,根View跟著滑動(dòng),滑倒一定的距離就finish掉。
原理很簡單,但實(shí)現(xiàn)起來可能有些坑。這里記錄一下。源碼參考
處理onInterceptTouchEvent
事件攔截要處理一件事情:確定這次觸摸事件是不是應(yīng)該交給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
這個(gè)是核心的實(shí)現(xiàn)方法.
這里會(huì)用到OverScroller的startScroll()方法來處理手指離開后的動(dòng)畫。OverScroller使用起來非常的簡單,如果想讓View滾動(dòng)就調(diào)用startScroll()傳入相應(yīng)參數(shù),會(huì)把計(jì)算的結(jié)果回調(diào)給View的computeScroll()方法,下面是主要的實(shí)現(xiàn)思路:
override fun onTouchEvent(event: MotionEvent): Boolean { val action = event.action //1.初始化軌跡 initVelocityTrackerIfNotExists(event) when(action){ MotionEvent.ACTION_DOWN -> { //2.down 事件 mScroller放棄動(dòng)畫 記錄觸摸的位置 if (!mScroller.isFinished){ mScroller.abortAnimation() } mLastX = event.rawX.toInt() mIsDrag = true dispatchScroll(0 , 0 , slideState) } MotionEvent.ACTION_MOVE -> { //3.move事件調(diào)用performDrag()方法 會(huì)調(diào)用offsetLeftAndRight() 從而移動(dòng)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的滾動(dòng),以及是否要達(dá)到銷毀的條件 //endDrag()方法會(huì)處理手指離開后的動(dòng)畫以及是否達(dá)到銷毀條件 if (mIsDrag){ mLastX = 0 mIsDrag = false velocityTracker?.computeCurrentVelocity(1000 , mMaximumVelocity) val velocity = velocityTracker?.xVelocity?.toInt()!! isReachFinish = endDrag(velocity) postInvalidateOnAnimation() recycleVelocityTracker() } } } return true } //開始拖動(dòng) private fun performDrag(x:Int){ var canOffset = false isDragLeft = x > 0 slideState = SlideState.DRAGGING //計(jì)算 滾動(dòng)的 距離 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) } } //手指離開后的動(dòng)作 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){ //左滑動(dòng) mScroller.startScroll(left , 0 , screenWidth - left , 0) }else{ //右滑動(dòng) 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>
設(shè)置activity進(jìn)場和出場動(dòng)畫
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) } //滑動(dòng)達(dá)到finish的監(jiān)聽事件,slideFinishLayout沒有做任何處理 如果這里不掉用finish也不會(huì)退出activity slideFinishLayout.finishListener = { finish() overridePendingTransition(0, 0) } } override fun finish() { super.finish() overridePendingTransition(0, R.anim.exit) } }
存在的問題
堆棧之前的activity被意外銷毀了,此時(shí)的當(dāng)前的activity雖然為透明的,但是背景是黑色的,可能是因?yàn)楸灰馔怃N毀還沒有來的及調(diào)用onCreate,但是打開不保留活動(dòng)來測試是沒有問題的。
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android實(shí)現(xiàn)垂直進(jìn)度條VerticalSeekBar
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)垂直進(jìn)度條VerticalSeekBar的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-07-07Android性能優(yōu)化之plt?hook與native線程監(jiān)控詳解
這篇文章主要為大家介紹了Android性能優(yōu)化之plt?hook與native線程監(jiān)控詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09Android編程實(shí)現(xiàn)屏幕自適應(yīng)方向尺寸與分辨率的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)屏幕自適應(yīng)方向尺寸與分辨率的方法,涉及Android屏幕分辨率、布局、橫豎屏切換等相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-12-12Android Studio 導(dǎo)入新工程項(xiàng)目圖解
這篇文章主要介紹了Android Studio 導(dǎo)入新工程項(xiàng)目圖解,需要的朋友可以參考下2017-12-12android實(shí)現(xiàn)widget時(shí)鐘示例分享
這篇文章主要介紹了android實(shí)現(xiàn)widget時(shí)鐘示例,需要的朋友可以參考下2014-03-03鴻蒙手機(jī)版JNI實(shí)戰(zhàn)案例解析(JNI開發(fā)、SO庫生成、SO庫使用)
這篇文章主要介紹了鴻蒙手機(jī)版JNI實(shí)戰(zhàn)(JNI開發(fā)、SO庫生成、SO庫使用)的相關(guān)資料,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04圖文講解Android的ImageView類中的ScaleType屬性設(shè)置
這篇文章主要介紹了Android的ImageView類中的ScaleType屬性設(shè)置,同時(shí)文中還講了實(shí)現(xiàn)圖片寬度100%ImageView寬度且高度按比例自動(dòng)伸縮的方法,需要的朋友可以參考下2016-03-03