【转】Android 向右滑动销毁(finish)Activity, 随着手势的滑动而滑动的效果
今天给大家带来一个向右滑动销毁Activity的效果,Activtiy随着手指的移动而移动,该效果在Android应用中还是比较少见的,在IOS 中就比较常见了,例如“网易新闻” ,"美食杰" , "淘宝"等应用采用此效果,而Android应用中“知乎”采用的也是这种滑动切换Activity的效果, 不过我发现“淘宝”并没有随着手势的移动而移动,只是捕捉到滑动手势,然后产生平滑切换界面的动画效果,这个在Android中还是很好实现的, 网上很多滑动切换Activity的Demo貌似都是这种效果的吧,如果要实现类似“网易新闻”的随手势的滑动而滑动,似乎就要复杂一些了,我之前在 IOS中看到"网易新闻"的这种效果就很感兴趣,然后群里也有朋友问我怎么实现类似“知乎”这个应用的滑动切换的效果,我也特意去下了一个“知乎”,在之 前的实现中我遇到了一些瓶颈,没有实现出来就搁置了在那里,今天无意中看到给Activity设置透明的背景,于是乎我恍然大悟,真是灵感来源于瞬间,不 能强求啊,然后自己就将此效果实现了出来,给大家分享一下,希望给有此需求的你一点点帮助。
不知道大家对Scroller这个类以及View的scrollBy() 和scrollTo()的使用熟悉不?我之前介绍了Scroller类的滑动实现原理Android 带你从源码的角度解析Scroller的滚动实现原理, 在那里面也介绍了scrollBy() 和scrollTo()方法,不明白的同学可以去看看,这对实现此效果有很大的帮助,了解scrollBy() 和scrollTo()的朋友应该知道,如果想对某个View(例如Button)就行滚动,我们直接调用该View(Button)的 scrollBy()方法,并不是该View(Button)进行滚动,而是该View里面的内容(Button上面的文字)进行滚动,所以我们假如要让 View整体滚动就需要对其View的父布局调用scrollBy()方法,回到这篇文章来,假如我们想要对一个Activity进行滚动,我们就需求对 这个Activity布局文件的顶层布局的父布局进行滚动
例如下面的XML布局文件
- <LinearLayout=
- =
- =
- =
- =
- = > </LinearLayout>
了解了实现的原理之后,我们就来编写代码吧,首先新建一个android工程,取名SildingFinish
由于我们的需求可能不是在一个界面提供这个滑动切换的效果,所以我们应该将这部分滑动的逻辑抽取出来,我这里就他写成了一个扩展RelativeLayout的自定义布局SildingFinishLayout,首先我们看其代码
- package import import import import import import import import import import import /**
- * 自定义可以滑动的RelativeLayout, 类似于IOS的滑动删除页面效果,当我们要使用
- * 此功能的时候,需要将该Activity的顶层布局设置为SildingFinishLayout,
- * 然后需要调用setTouchView()方法来设置需要滑动的View
- *
- * @author xiaanming
- *
- * @blog http://blog.csdn.net/xiaanming
- *
- */ publicclassextendsimplements * SildingFinishLayout布局的父布局
- */ private * 处理滑动逻辑的View
- */ private * 滑动的最小距离
- */ privateint * 按下点的X坐标
- */ privateint * 按下点的Y坐标
- */ privateint * 临时存储X坐标
- */ privateint * 滑动类
- */ private * SildingFinishLayout的宽度
- */ privateint * 记录是否正在滑动
- */ privateboolean private privateboolean public this);
- publicint super new
- protectedvoidbooleanintintintint super if
- this this * 设置OnSildingFinishListener, 在onSildingFinish()方法中finish Activity
- *
- * @param onSildingFinishListener
- */ publicvoid this * 设置Touch的View
- *
- * @param touchView
- */ publicvoid this this public return * 滚动出界面
- */ privatevoid finalint
- , -delta + , ,
- * 滚动到起始位置
- */ privatevoid int , -delta, ,
- * touch的View是否是AbsListView, 例如ListView, GridView等其子类
- *
- * @return
- */ privateboolean returninstanceoftruefalse * touch的view是否是ScrollView或者其子类
- *
- * @return
- */ privateboolean returninstanceoftruefalse
- publicboolean switch case int int break case intint int if int true
- if if && isSilding) {
- );
- if returntrue break case false if) {
- true else false break
- if return
- returntrue
- publicvoid
- if if ifnull publicinterface publicvoid }
我们在onLayout()方法中利用getParent()方法获取该布局的父布局和获取其控件的宽度,主要是为之后的实现做准备工作。
我们的滑动逻辑主要是利用View的scrollBy() 方法, scrollTo()方法和Scroller类来实现的,当手指拖动视图的时候,我们监听手指在屏幕上滑动的距离利用View的scrollBy() 方法使得View随着手指的滑动而滑动,而当手指离开屏幕,我们在根据逻辑使用Scroller类startScroll()方法设置滑动的参数,然后再 根据View的scrollTo进行滚动。
对于View的滑动,存在一些Touch事件消费的处理等问题,因此我们需要对View的整个Touch事件很熟悉 ,最主要的就是Activity里面有一些ListView、 GridView、ScrollView等控件了, 假如我们Activity里面存在ListView、GridView等控件的话,我们对Activity的最外层布局进行滚动根本就无效果,因为 Touch事件被ListView、GridView等控件消费了,所以Activity的最外层布局根本得不到Touch事件,也就实现不了Touch 逻辑了,所以为了解决此Touch事件问题我提供了setTouchView(View touchView) 方法,这个方法是将Touch事件动态的设置到到View上面,所以针对上面的问题,我们将OnTouchListener直接设 置到ListView、GridView上面,这样子就避免了Activity的最外层接受不到Touch事件的问题了
接下来看onTouch()方法
首先我们在ACTION_DOWN记录按下点的X,Y坐标
然后在ACTION_MOVE中判断,如果我们在水平方向滑动的距离大于mTouchSlop并且在竖直方向滑动的距离小于mTouchSlop,表示 Activity处于滑动状态,我们判断如果touchView是ListView、GridView或者其子类的时候,因为我们手指在 ListView、GridView上面,伴随着item的点击事件的发生,所以我们对touchView设置ACTION_CANCEL来取消item 的点击事件,然后对该布局的父布局调用scrollBy()进行滚动,并且如果TouchView是AbsListView或者ScrollView直接 返回true,来取消AbsListView或者ScrollView本身的ACTION_MOVE事件,最直观的感受就是我们在滑动Activity的 时候,禁止AbsListView或者ScrollView的上下滑动
最后在ACTION_UP中判断如果手指滑动的距离大于控件长度的二分之一,表示将Activity滑出界面,否则滑动到起始位置,我们利用 Scroller类的startScroll()方法设置好开始位置,滑动距离和时间,然后调用postInvalidate()刷新界面,之后就到 computeScroll()方法中,我们利用scrollTo()方法对该布局的父布局进行滚动,滚动结束之后,我们判断界面是否滑出界面,如果是就 调用OnSildingFinishListener接口的onSildingFinish()方法,所以只要在onSildingFinish()方法 中finish界面就行了
整个滑动布局的代码就是这个样子,接下来我们就来使用了,主界面Activity只有三个按钮,分别跳转到普通布局的Activity,有ListView的Activity和有ScrollView的Activity中
- <LinearLayout=
- =
- =
- =
- =
- = > <Button =
- =
- =
- = /> <Button =
- =
- =
- = /> <Button =
- =
- =
- = /> </LinearLayout>
然后就是MainActivity的代码,根据ID实例化Button,然后为Button设置OnClickListener事件,不同的按钮跳转到不 同的Activity,然后设置从右向左滑动的动画,重写onBackPressed()方法,当我们按下手机物理键盘的返回键,添加从左向右滑出的动画
- package import import import import import import import import publicclassextendsimplements
- protectedvoid super this this this
- publicvoid null switch case newthisclass break case newthisclass break case newthisclass break
- publicvoid super , R.anim.base_slide_right_out);
- }
- <?xml version= encoding=?>
- >
- >
- </com.example.view.SildingFinishLayout>
- package import import import import import import import import import import import import import import publicclassextends privatenew
- protectedvoid super forint; i <= ; i++) {
- + i);
- new this new
- publicvoid this
- new
- publicvoid intlong newthisclass
- publicvoid super , R.anim.base_slide_right_out);
- }
在运行项目之前还有一个很重要的操作,也是之前我被卡到的问题,就是我们需要对Activity设置为透明,即设置主题android:theme="@android:style/Theme.Translucent"
- <activity =
- = > </activity> <activity =
- = > </activity> <activity =
- = > </activity>
tail/xiaanming/7026873
正是我们想要的效果,如果想要加入滑动切换界面的效果只需要三步就行了,首先将Activity布局的最外层修改为
SildingFinishLayout,然后在Activity里面调用setTouchView()方法设置touchView,设置
OnSildingFinishListener监听在onSildingFinish()方法中finish界面,最后设置Activity的背景为透
明(不是设置Activity布局文件的最顶层布局背景颜色透明,这点要区分一下)是不是很方便呢?好了,今天的讲解到这里就结束了,有疑问的朋友请在下
面留言,有兴趣的朋友可以下载源码看看!