Android左滑返回功能的实现示例代码
程序员文章站
2022-08-08 09:52:33
前几天用了个app发现左滑可以返回首页,发现这个功能很炫酷,就想着自己能不能做出来,于是研究了一下
原理
将activity的背景设置为透明同时设置切换动画...
前几天用了个app发现左滑可以返回首页,发现这个功能很炫酷,就想着自己能不能做出来,于是研究了一下
原理
- 将activity的背景设置为透明同时设置切换动画
- 手指滑动的时候,根view跟着滑动,滑倒一定的距离就finish掉。
原理很简单,但实现起来可能有些坑。这里记录一下。源码参考
处理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
这个是核心的实现方法.
这里会用到overscroller的startscroll()方法来处理手指离开后的动画。overscroller使用起来非常的简单,如果想让view滚动就调用startscroll()传入相应参数,会把计算的结果回调给view的computescroll()方法,下面是主要的实现思路:
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事件调用performdrag()方法 会调用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的监听事件,slidefinishlayout没有做任何处理 如果这里不掉用finish也不会退出activity slidefinishlayout.finishlistener = { finish() overridependingtransition(0, 0) } } override fun finish() { super.finish() overridependingtransition(0, r.anim.exit) } }
存在的问题
堆栈之前的activity被意外销毁了,此时的当前的activity虽然为透明的,但是背景是黑色的,可能是因为被意外销毁还没有来的及调用oncreate,但是打开不保留活动来测试是没有问题的。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。