100行代码实现Activity右滑退出
2016-04-13 20:18
246 查看
很多Android App上已经增加了Activity右滑退出的效果,这个功能通常可以叫做SwipeBackActivity。这个效果最早来源于iOS,这样的操作优化确实提升了用户体验。在github上大概看了一下,实现很多也比较复杂。本文将介绍一种简单的方法来实现这个功能,只需在页面中调用两行代码就可以轻松搞定,对页面基本没有侵入性。
先来看一下最终的效果图
正式介绍代码之前,先来说明讲基本原理。我们知道在Android的PhoneWindow中包含一个DecorView,它是整个Activity的根View,实际上就是一个FrameLayout。DecorView中又会一个子View(一个资源id名字为content的FrameLayout),我们称之为contentView,它是我们页面布局的parent布局,即我们通过setContentView()方法设置的布局就是直接添加到这个id为content的FrameLayout上。如果将我们自己定义的View称作userView,那么DecorView、contentView和userView这三个View之间就是依次包含的关系。
有了上面的这些概念,就可以很容易的实现我们的功能。我们只需要将DecorView、contentView背景设置成透明,然后将userView根据用户的手势向右进行移动,当userView全部移动出屏幕之后将Activity销毁,就形成了Activity右滑退出的假象。
下面来看一下具体的代码实现。
首先获得了屏幕宽度,获得TouchSlop增加滑动判断的准确性,否则任何微小的滑动都会被误认为是用户的滑动行为。ArgbEvaluator用来对变化的颜色求值。然后分别获得DecorView、contentView和userView,并将DecorView的背景色设置为透明。
重点来看一下DecorView、contentView和userView的获取方法。
DecorView:通过getWindow()的getDecorView()方法获得。
contentView:之前提到contentView在系统中的资源id为content,可以直接通过findViewById(android.R.id.content)来获得这个View。
userView:userView是直接添加到contentView上的,通过contentView.getChildAt(0)得到的就是userView。
然后定义用于userView的属性动画,在属性动画的监听方法中,设置contentView的背景色不断变化,并且设置userView的偏移量。当属性动画的值大于屏幕宽度时,将Activity销毁。
最后在需要实现右滑退出的Activity页面,创建一个SwipBackController的对象,然后在OnTouchEvent中将MotionEvent传给它的processEvent()方法就可以了。我们并没有给Activity设置什么属性,也不需要继承什么类,就可以轻松实现这个功能。
完整代码下载
先来看一下最终的效果图
正式介绍代码之前,先来说明讲基本原理。我们知道在Android的PhoneWindow中包含一个DecorView,它是整个Activity的根View,实际上就是一个FrameLayout。DecorView中又会一个子View(一个资源id名字为content的FrameLayout),我们称之为contentView,它是我们页面布局的parent布局,即我们通过setContentView()方法设置的布局就是直接添加到这个id为content的FrameLayout上。如果将我们自己定义的View称作userView,那么DecorView、contentView和userView这三个View之间就是依次包含的关系。
有了上面的这些概念,就可以很容易的实现我们的功能。我们只需要将DecorView、contentView背景设置成透明,然后将userView根据用户的手势向右进行移动,当userView全部移动出屏幕之后将Activity销毁,就形成了Activity右滑退出的假象。
下面来看一下具体的代码实现。
private int mScreenWidth; private int mTouchSlop; private boolean isMoving = false; private float mInitX; private float mInitY; private ViewGroup decorView;//窗口根布局 private ViewGroup contentView;//content布局 private ViewGroup userView;//用户添加的布局 private ArgbEvaluator evaluator; private ValueAnimator mAnimator; private VelocityTracker mVelTracker; public SwipeBackController(final Activity activity) { mScreenWidth = activity.getResources().getDisplayMetrics().widthPixels; mTouchSlop = ViewConfiguration.get(activity).getScaledTouchSlop(); evaluator = new ArgbEvaluator(); decorView = (ViewGroup) activity.getWindow().getDecorView(); decorView.setBackgroundDrawable(new ColorDrawable(Color.parseColor("#00ffffff"))); contentView = (ViewGroup) activity.findViewById(android.R.id.content); userView = (ViewGroup) contentView.getChildAt(0); mAnimator = new ValueAnimator(); mAnimator.setDuration(ANIMATION_DURATION); mAnimator.setInterpolator(new DecelerateInterpolator()); mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { int x = (Integer) valueAnimator.getAnimatedValue(); if (x >= mScreenWidth) { activity.finish(); } handleView(x); handleBackgroundColor(x); } }); } public void handleView(int x) { userView.setTranslationX(x); } /** * 控制背景颜色和透明度 * @param x */ private void handleBackgroundColor(float x) { int colorValue = (int) evaluator.evaluate(x / mScreenWidth, Color.parseColor("#dd000000"), Color.parseColor("#00000000")); contentView.setBackgroundColor(colorValue); Log.d(TAG, "x is " + x); }
首先获得了屏幕宽度,获得TouchSlop增加滑动判断的准确性,否则任何微小的滑动都会被误认为是用户的滑动行为。ArgbEvaluator用来对变化的颜色求值。然后分别获得DecorView、contentView和userView,并将DecorView的背景色设置为透明。
重点来看一下DecorView、contentView和userView的获取方法。
DecorView:通过getWindow()的getDecorView()方法获得。
contentView:之前提到contentView在系统中的资源id为content,可以直接通过findViewById(android.R.id.content)来获得这个View。
userView:userView是直接添加到contentView上的,通过contentView.getChildAt(0)得到的就是userView。
然后定义用于userView的属性动画,在属性动画的监听方法中,设置contentView的背景色不断变化,并且设置userView的偏移量。当属性动画的值大于屏幕宽度时,将Activity销毁。
public boolean processEvent(MotionEvent event) { getVelocityTracker(event); if (mAnimator.isRunning()) { return true; } int pointId = -1; switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mInitX = event.getRawX(); mInitY = event.getRawY(); pointId = event.getPointerId(0); break; case MotionEvent.ACTION_MOVE: if (!isMoving) { float dx = Math.abs(event.getRawX() - mInitX); float dy = Math.abs(event.getRawY() - mInitY); if (dx > mTouchSlop && dx > dy && mInitX < DEFAULT_TOUCH_THRESHOLD) { isMoving = true; } } if (isMoving) { handleView((int) event.getRawX()); handleBackgroundColor(event.getRawX()); } break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: int distance = (int) (event.getRawX() - mInitX); mVelTracker.computeCurrentVelocity(1000); //获取x方向上的速度 float velocityX = mVelTracker.getXVelocity(pointId); Log.d(TAG, "mVelocityX is " + velocityX); if (isMoving && Math.abs(userView.getTranslationX()) >= 0) { if (distance >= mScreenWidth / 4 || velocityX > 1000f) { mAnimator.setIntValues((int) event.getRawX(), mScreenWidth); } else { mAnimator.setIntValues((int) event.getRawX(), 0); } mAnimator.start(); isMoving = false; } mInitX = 0; mInitY = 0; recycleVelocityTracker(); break; } return true; }在onTouchEvent中根据当前移动的距离,调用handleView和handleBackgroundColor方法分别来设置userView的位置和contentView的背景色。当ACTION_UP的时候,会根据当时用户手势滑动的速度和当前已经划过的距离去判断,是否继续滑动销毁Activity还是恢复页面的初始状态。然后根据判断结果去执行动画。
public class SecondActivity extends Activity { private SwipeBackController swipeBackController; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_second); swipeBackController = new SwipeBackController(this); } @Override public boolean onTouchEvent(MotionEvent ev) { if (swipeBackController.processEvent(ev)) { return true; } else { return super.onTouchEvent(ev); } } }
最后在需要实现右滑退出的Activity页面,创建一个SwipBackController的对象,然后在OnTouchEvent中将MotionEvent传给它的processEvent()方法就可以了。我们并没有给Activity设置什么属性,也不需要继承什么类,就可以轻松实现这个功能。
完整代码下载
相关文章推荐
- lingo
- C语言输出控制符
- Java中怎么切换窗口
- C# 结构体直接赋值的问题
- git学习笔记
- java 获取 jar 包内文件列表
- Qt中关于中文字符编码问题
- c++ STL学习笔记
- C#中struct的字节对齐、转换操作和复制为二进制数据(byte[])
- MSYS2 环境搭建(在Qt Creator可以设置环境变量来进行引用这些库)
- C++ stl set用法例子
- Python smtplib发送邮件 包含文本、附件、图片
- 使用模板技术处理ASP.NET中GridView额外序号列的问题
- c#中关于结构体和字节数组转化
- 关于C# byte[]与struct的转换
- MATLAB中的分类器
- Java中的内部类
- c++数组的操作
- Matlab中的一些小技巧
- python2.7升python3.2