【android开发】手势滑动关闭Activity(随手指消失)的辅助类的实现
来源:互联网 发布:定车票的软件 编辑:程序博客网 时间:2024/06/06 03:13
【CSDN抽风,把我写一个多小时的东西覆盖了。真的是哔了狗了,自己又没有备份。。。重写吧。。。】
这个类主要是实现向右滑动关闭Activity,效果如下:
老套路,先写思路:
1)将Activity的背景设置为透明模式。(从而可以看到下一层Activity)
2)创建一个FrameLayout,将contentView从DecorView中移除,并将contentView添加到我们的FrameLayout中,最后再将我们的FrameLayout添加回原来contentView的地方。
【熟悉android ViewTree的人应该能轻松理解contentView和DecorView。针对不熟悉的朋友,我做简单介绍:我们将Activity界面看做由ActionBar部分 + ContentView部分(onCreate中的setContentView方法设置的部分) 组成,如果我们设置为NoActionBar类型的主题时,ActionBar部分将不存在,整个Activity都由ContentView部分组成。而Activity会有个rootView来容纳他们,这个rootView就是DecorView。】示意图如下:
3)实现FrameLayout的拦截逻辑,当手势向右滑动时,拦截事件,将contentView进行水平方向移动。
分析完开动代码。
1、创建自定义ViewGroup类并申明必须要的参数,代码如下:
class MySwipeView extends FrameLayout { private Activity activity;// 绑定的Activity private ViewGroup decorView; private View contentView;// activity的ContentView private float intercept_X = 0;// onInterceptTouchEvent刚触摸时的X坐标 private float intercept_Y = 0;// onInterceptTouchEvent手指刚触摸时的y坐标 private int touchSlop = 0;// 产生滑动的最小值 public MySwipeView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); touchSlop = ViewConfiguration.get(getContext()) .getScaledTouchSlop(); setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); } public MySwipeView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public MySwipeView(Context context) { this(context, null); }}
2、实现Activity的绑定,并将contentView从decorView中移除,然后添加到我们的FrameLayout中,最后将我们的FrameLayout添加回DecorView。代码如下:
/** * 绑定Activity * @param activity */public void setActivity(Activity activity) { this.activity = activity; initCoverView();}/** * 将contentView从DecorView中移除,并添加到CoverView中,最后再将CoverView添加到DecorView中 */private void initCoverView() { decorView = (ViewGroup) activity.getWindow().getDecorView(); // decorView.setBackgroundColor(Color.parseColor("#33000000")); contentView = (ViewGroup) decorView .findViewById(android.R.id.content); ViewGroup contentParent = (ViewGroup) contentView.getParent(); contentParent.removeView(contentView); addView(contentView); contentView.setBackgroundColor(Color.WHITE); contentParent.addView(this);}
3、实现事件拦截代码。说到事件拦截,熟悉android事件分发机制的朋友,应该知道。ViewGroup有个public boolean onInterceptTouchEvent(MotionEvent ev)方法,当此方法返回true时,ViewGroup将不会传递事件给他的childView,同时会调用该ViewGroup的onTouchEvent来处理该事件;反之,返回false时,事件将会传递给他的childView处理。我们通过实现onInterceptTouchEvent的逻辑来过滤我们需要的事件。代码如下,看一两遍理解没问题的:
@Overridepublic boolean onInterceptTouchEvent(android.view.MotionEvent ev) { return shouldInterceptEvent(ev);};/** * 判断是否应该拦截事件。 * 如果水平方向的偏移量(不取绝对值) > 垂直方向的偏移量(取绝对值),并且水平方向的偏移量大于最小滑动距离,我们将拦截事件。 * 【实际过程中,我们发现touchSlope还是偏小,所以取了其3倍的数值作为最小滑动距离】 * @param event * 事件对象 * @return true表示拦截,false反之 */private boolean shouldInterceptEvent(MotionEvent event) { boolean shouldInterceptEvent = false; switch (event.getAction()) { case MotionEvent.ACTION_DOWN: intercept_X = event.getX(); intercept_Y = event.getY(); break; case MotionEvent.ACTION_MOVE: float offsetY = Math.abs(event.getY() - intercept_Y); float offsetX = Math.abs(event.getX() - intercept_X); if (offsetY >= touchSlop * 3 || offsetY > offsetX) { shouldInterceptEvent = false; } else if (event.getX() - intercept_X >= touchSlop * 3) { shouldInterceptEvent = true; } else { shouldInterceptEvent = false; } break; case MotionEvent.ACTION_UP: shouldInterceptEvent = false; break; default: break; } return shouldInterceptEvent;}
4、实现onTouchEvent代码:
@Overridepublic boolean onTouchEvent(android.view.MotionEvent event) { processTouchEvent(event); return true;};/** * 对onTouchEvent事件进行处理 * @param event * 事件对象 */private void processTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: break; case MotionEvent.ACTION_MOVE: //如果是向右滑动,我们动态改变contentView的便宜值 float offsetX = event.getX() - intercept_X; if (offsetX > 0) { contentView.setTranslationX(offsetX); } break; case MotionEvent.ACTION_UP: //如果手释放时是在屏幕的1/3之内,我们视为用户不想关闭Activity,则弹回。反之,关闭 if (contentView.getTranslationX() >= contentView .getMeasuredWidth() / 3) { collapse(); } else { open(); } break; default: break; }}/** * 展开Activity */private void open() { contentView.clearAnimation(); ObjectAnimator anim = ObjectAnimator.ofFloat(contentView, View.TRANSLATION_X, 0); anim.start();}/** * 折叠Activity(finish掉) */private void collapse() { contentView.clearAnimation(); ObjectAnimator anim = ObjectAnimator.ofFloat(contentView, View.TRANSLATION_X, contentView.getMeasuredWidth()); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { activity.finish(); } }); anim.start();}
5、到此,我们基本完成了FrameLayout的开发。我们最后可以将此FrameLayout放到一个类中包裹起来,做成一个工具类。(可选)。代码如下:
public class SwipeToFinishView { private MySwipeView mySwipeView; public SwipeToFinishView(Activity activity) { mySwipeView = new MySwipeView(activity); mySwipeView.setActivity(activity); }//核心Viewprivate class MySwipeView extends FrameLayout { ..... }}
6、将Activity设置为背景透明模式。
1)新建透明Activity的style。代码形如:
<style name="SwipTheme" parent="BaseTheme"> <item name="android:windowBackground">@android:color/transparent</item> <item name="android:windowIsTranslucent">true</item> <item name="android:windowAnimationStyle"> @android:style/Animation.Translucent </item></style>
2)应用此Style到Activity,在AndroidManifest文件中指定的Activity代码添加代码如下:
android:theme="@style/SwipTheme"
7、如何使用:
在Activity的setContentView之后,new此类即可,代码如下。
SwipeToFinishView swipeToFinishView= new SwipeToFinishView(this);
【 使 用 前 提 】
1、该Activity的主题应该是NoActionBar(没有ActionBar)
2、该Activity使用的主题应该包含下面三个item(用于将Activity的背景透明)
<item name="android:windowBackground">@android:color/transparent </item> <item name="android:windowIsTranslucent">true </item> <item name="android:windowAnimationStyle">@android:style/Animation.Translucent </item>
3、并在style.xml中新增加一个Style应用到该Activity的主题上。新增的style代码如下:
<style name="SwipTheme" parent="BaseTheme"> <item name="android:windowBackground">@android:color/transparent</item> <item name="android:windowIsTranslucent">true</item> <item name="android:windowAnimationStyle" >@android:style/Animation.Translucent</item> </style>
最后在Activity的申明中添加下面的代码:
android:theme="@style/SwipTheme"
【 总 结 】
这个类写的很简单,基本就是一个ViewGroup的拦截代码和处理代码,但是中间也需要了一些小问题。
刚开始,我是使用的ViewDragHelper来做的,但是,后来当Activity有可获取焦点类型的View时(例如使用了ListView),ViewDragHelper无法正常工作。无奈之下自己手动实现拦截代码。
老样子,源代码如下。
/** * 跟随手势向右滑动消失的View帮助类。<br/> * 使用方法:在Activity的setContentView之后,new此类即可,代码如下。<br/> * SwipeToFinishView swipeToFinishView= new SwipeToFinishView(this); * <hr/> * 使用前提:<br/> * <ol> * <li>该Activity的主题应该是NoActionBar(没有ActionBar)</li> * <li>该Activity使用的主题应该包含下面三个item(用于将Activity的背景透明) * <ul> * <li> * * <item name="android:windowBackground">@android:color/transparent * </item> * * </li> * <li> * * <item name="android:windowIsTranslucent">true </item> * * </li> * <li> * * <item * name="android:windowAnimationStyle">@android:style/Animation.Translucent * </item> * * </li> * * </ul> * </li> * </ol> * 例如:我想给SecondActivity添加滑动消失功能,我就会在onCreate中添加代码:<br/> * SwipeToFinishView swipeToFinishView= new SwipeToFinishView(this);<br/> * 并在style.xml中新增加一个Style应用到该Activity的主题上。新增的style代码如下:<br/> * <!-- SecondActivity theme. --> <br/> * <style name="SwipTheme" parent="BaseTheme"><br/> * <item * name="android:windowBackground">@android:color/transparent</item> <br/> * <item * name="android:windowIsTranslucent">true</item> <br/> * <item name="android:windowAnimationStyle" * >@android:style/Animation.Translucent</item> </style> <br/> * 最后在Activity的申明中添加下面的代码:<br/> * android:theme="@style/SwipTheme" * * @author 蓝亭书序 2016.11.29 * */public class SwipeToFinishView { private MySwipeView mySwipeView; public SwipeToFinishView(Activity activity) { mySwipeView = new MySwipeView(activity); mySwipeView.setActivity(activity); } /** * 核心View * * @author 蓝亭书序 * */ private class MySwipeView extends FrameLayout { private Activity activity;// 绑定的Activity private ViewGroup decorView; private View contentView;// activity的ContentView private float intercept_X = 0;// onInterceptTouchEvent刚触摸时的X坐标 private float intercept_Y = 0;// onInterceptTouchEvent手指刚触摸时的y坐标 private int touchSlop = 0;// 产生滑动的最小值 public MySwipeView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); touchSlop = ViewConfiguration.get(getContext()) .getScaledTouchSlop(); setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); } public MySwipeView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public MySwipeView(Context context) { this(context, null); } @Override public boolean onInterceptTouchEvent(android.view.MotionEvent ev) { return shouldInterceptEvent(ev); }; @SuppressLint("ClickableViewAccessibility") public boolean onTouchEvent(android.view.MotionEvent event) { processTouchEvent(event); return true; }; /** * 绑定Activity * * @param activity */ public void setActivity(Activity activity) { this.activity = activity; initCoverView(); } /** * 将contentView从DecorView中移除,并添加到CoverView中,最后再将CoverView添加到DecorView中 */ private void initCoverView() { decorView = (ViewGroup) activity.getWindow().getDecorView(); // decorView.setBackgroundColor(Color.parseColor("#33000000")); contentView = (ViewGroup) decorView .findViewById(android.R.id.content); ViewGroup contentParent = (ViewGroup) contentView.getParent(); contentParent.removeView(contentView); addView(contentView); contentView.setBackgroundColor(Color.WHITE); contentParent.addView(this); } /** * 判断是否应该拦截事件 * * @param event * 事件对象 * @return true表示拦截,false反之 */ private boolean shouldInterceptEvent(MotionEvent event) { boolean shouldInterceptEvent = false; switch (event.getAction()) { case MotionEvent.ACTION_DOWN: intercept_X = event.getX(); intercept_Y = event.getY(); break; case MotionEvent.ACTION_MOVE: float offsetY = Math.abs(event.getY() - intercept_Y); float offsetX = Math.abs(event.getX() - intercept_X); if (offsetY >= touchSlop * 3 || offsetY > offsetX) { shouldInterceptEvent = false; } else if (event.getX() - intercept_X >= touchSlop * 3) { shouldInterceptEvent = true; } else { shouldInterceptEvent = false; } break; case MotionEvent.ACTION_UP: shouldInterceptEvent = false; break; default: break; } return shouldInterceptEvent; } /** * 对onTouchEvent事件进行处理 * * @param event * 事件对象 */ private void processTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: break; case MotionEvent.ACTION_MOVE: float offsetX = event.getX() - intercept_X; if (offsetX > 0) { contentView.setTranslationX(offsetX); } break; case MotionEvent.ACTION_UP: if (contentView.getTranslationX() >= contentView .getMeasuredWidth() / 3) { collapse(); } else { open(); } break; default: break; } } /** * 展开Activity */ private void open() { contentView.clearAnimation(); ObjectAnimator anim = ObjectAnimator.ofFloat(contentView, View.TRANSLATION_X, 0); anim.start(); } /** * 折叠Activity(finish掉) */ private void collapse() { contentView.clearAnimation(); ObjectAnimator anim = ObjectAnimator.ofFloat(contentView, View.TRANSLATION_X, contentView.getMeasuredWidth()); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { activity.finish(); } }); anim.start(); } }}
- 【android开发】手势滑动关闭Activity(随手指消失)的辅助类的实现
- android窗体动画:activity启动从底部向上滑动出现,关闭的时候从顶部向下滑动消失的动画实现
- android窗体动画:activity启动从底部向上滑动出现,关闭的时候从顶部向下滑动消失的动画实现 .
- Activity启动从底部向上滑动出现,关闭的时候从顶部向下滑动消失的动画实现---Android提高篇 ——诺诺"涂鸦"记忆
- android窗体动画:activity启动从底部向上滑动出现,关闭的时候从顶部向下滑动消失的动画实现
- android窗体动画:activity启动从底部向上滑动出现,关闭的时候从顶部向下滑动消失的动画实现【转】
- android手势滑动关闭当前activity
- 关闭DrawerLayout的手势滑动
- android窗体动画:activity启动从底部向上滑动出现,关闭的时候从顶部向下滑动消失,并解决activity跳转的时候出现短暂的黑屏
- android窗体动画:activity启动从底部向上滑动出现,关闭的时候从顶部向下滑动消失,并解决activity跳转的时候出现短暂的黑屏
- android手势操作&&实现滑动切换activity
- 手势滑动结束 Activity(一)基本功能的实现
- 手势滑动结束 Activity(一)基本功能的实现
- Android中Activity中左右滑动手势的监听
- Android之自定义View实现随手势滑动的控件
- Android 向右滑动销毁(finish)Activity, 随着手势的滑动而滑动的效果
- Android 向右滑动销毁(finish)Activity, 随着手势的滑动而滑动的效果
- Android 向右滑动销毁(finish)Activity, 随着手势的滑动而滑动的效果
- Thinking in BigData(六)大数据技术核心之ETL
- 第十四周4
- Android菜鸟练习第十三课 导出Module为Jar
- JS简单验证身份证号
- 在改版的Spring官网下载所需的jar包
- 【android开发】手势滑动关闭Activity(随手指消失)的辅助类的实现
- 关于ajax的理解
- Android应用性能优化之使用SparseArray替代HashMap
- PHP 获取页面URL
- 欢迎使用CSDN-markdown编辑器
- 用python计算md5,sha1,crc32
- 基于结构光的深度测距structure light coding
- NetworkWordCount 例子工作流程详解
- WordPress简单移除程序和插件更新提示