【转】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布局文件

 

[html] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. <LinearLayout=  
  2. =  
  3. =  
  4. =  
  5. =  
  6. = > </LinearLayout>  
如 果我们对LinearLayout进行滚动,并不能实现我们想要的效果,而只能对LinearLayout里面的内容或者说是子View进行滚动,所以我 们需要获取利用LinearLayout的getParent()方法获取父布局,其实Android系统会对我们的布局文件的最外层套一个 FrameLayout,所以我们其实就是对FrameLayout进行滚动就行了

 

了解了实现的原理之后,我们就来编写代码吧,首先新建一个android工程,取名SildingFinish

由于我们的需求可能不是在一个界面提供这个滑动切换的效果,所以我们应该将这部分滑动的逻辑抽取出来,我这里就他写成了一个扩展RelativeLayout的自定义布局SildingFinishLayout,首先我们看其代码

 

[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. package import import import import import import import import import import import /** 
  2.  * 自定义可以滑动的RelativeLayout, 类似于IOS的滑动删除页面效果,当我们要使用 
  3.  * 此功能的时候,需要将该Activity的顶层布局设置为SildingFinishLayout, 
  4.  * 然后需要调用setTouchView()方法来设置需要滑动的View 
  5.  *  
  6.  * @author xiaanming 
  7.  *  
  8.  * @blog http://blog.csdn.net/xiaanming 
  9.  *  
  10.  */ publicclassextendsimplements      * SildingFinishLayout布局的父布局 
  11.      */ private      * 处理滑动逻辑的View 
  12.      */ private      * 滑动的最小距离 
  13.      */ privateint      * 按下点的X坐标 
  14.      */ privateint      * 按下点的Y坐标 
  15.      */ privateint      * 临时存储X坐标 
  16.      */ privateint      * 滑动类 
  17.      */ private      * SildingFinishLayout的宽度 
  18.      */ privateint      * 记录是否正在滑动 
  19.      */ privateboolean private privateboolean public this);  
  20. publicint super new   
  21. protectedvoidbooleanintintintint super if   
  22. this this      * 设置OnSildingFinishListener, 在onSildingFinish()方法中finish Activity 
  23.      *  
  24.      * @param onSildingFinishListener 
  25.      */ publicvoid this      * 设置Touch的View 
  26.      *  
  27.      * @param touchView 
  28.      */ publicvoid this this public return      * 滚动出界面 
  29.      */ privatevoid finalint   
  30. , -delta + ,  
  31.      * 滚动到起始位置 
  32.      */ privatevoid int , -delta, ,  
  33.      * touch的View是否是AbsListView, 例如ListView, GridView等其子类 
  34.      *  
  35.      * @return 
  36.      */ privateboolean returninstanceoftruefalse      * touch的view是否是ScrollView或者其子类 
  37.      *  
  38.      * @return 
  39.      */ privateboolean returninstanceoftruefalse   
  40. publicboolean switch case int int break case intint int if int true   
  41.   
  42. if if && isSilding) {  
  43. );  
  44.   
  45. if returntrue break case false if) {  
  46. true else false break   
  47.   
  48. if return   
  49. returntrue   
  50. publicvoid   
  51. 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中

 

[html] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. <LinearLayout=  
  2. =  
  3. =  
  4. =  
  5. =  
  6. = > <Button =  
  7. =  
  8. =  
  9. = /> <Button =  
  10. =  
  11. =  
  12. = /> <Button =  
  13. =  
  14. =  
  15. = /> </LinearLayout>  

 

然后就是MainActivity的代码,根据ID实例化Button,然后为Button设置OnClickListener事件,不同的按钮跳转到不 同的Activity,然后设置从右向左滑动的动画,重写onBackPressed()方法,当我们按下手机物理键盘的返回键,添加从左向右滑出的动画

 

[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. package import import import import import import import import publicclassextendsimplements   
  2. protectedvoid super this this this   
  3. publicvoid null switch case newthisclass break case newthisclass break case newthisclass break   
  4.   
  5. publicvoid super , R.anim.base_slide_right_out);  
  6. }  
在这里我之贴出含有ListView的Activity的代码,先看布局,我们自定义滑动布局SildingFinishLayout应该放在XML的最顶层

 

 

[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. <?xml version= encoding=?>  
  2.   
  3.   
  4.   
  5.   
  6.   
  7.  >  
  8.   
  9.   
  10.   
  11.  >  
  12. </com.example.view.SildingFinishLayout>  

 


[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. package import import import import import import import import import import import import import import publicclassextends privatenew   
  2. protectedvoid super forint; i <= ; i++) {  
  3.  + i);  
  4. new this new   
  5. publicvoid this   
  6. new   
  7. publicvoid intlong newthisclass   
  8.   
  9. publicvoid super , R.anim.base_slide_right_out);  
  10. }  
利 用ID找到SildingFinishLayout实例,利用setTouchView()方法设置touchView到ListView上面,然后调用 setOnSildingFinishListener()设置OnSildingFinishListener,在onSildingFinish() 中finish界面就可以啦。

在运行项目之前还有一个很重要的操作,也是之前我被卡到的问题,就是我们需要对Activity设置为透明,即设置主题android:theme="@android:style/Theme.Translucent" 

[html] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. <activity =  
  2. = > </activity> <activity =  
  3. = > </activity> <activity =  
  4. = > </activity>  
好了,现在我们可以运行项目看看效果啦

 

tail/xiaanming/7026873 



正是我们想要的效果,如果想要加入滑动切换界面的效果只需要三步就行了,首先将Activity布局的最外层修改为 SildingFinishLayout,然后在Activity里面调用setTouchView()方法设置touchView,设置 OnSildingFinishListener监听在onSildingFinish()方法中finish界面,最后设置Activity的背景为透 明(不是设置Activity布局文件的最顶层布局背景颜色透明,这点要区分一下)是不是很方便呢?好了,今天的讲解到这里就结束了,有疑问的朋友请在下 面留言,有兴趣的朋友可以下载源码看看!

项目源码,点击下载

 

原文地址

posted @ 2015-09-24 17:13  NoodleUtopia  阅读(426)  评论(0编辑  收藏  举报