刚忙完一段时间,今天刚清闲会,就把以前写的东西整理整理。于是冥冥中发现有些东西完全可以共享出来,毕竟那么常见,而且简单实用。
其实侧滑关闭 activity 在网上也有大量的文章去介绍他,我也有去看,要么是代码实在太多看不下去,要么就是跑了项目没有反应的。唯一的方法还是自己随手鲁一个~,侧滑这个东西在 android 中是比较少见的,ios 是最常见不过了,因为毕竟他们没有物理返回键。还有 UIScrollView 那些。然而我们用的最多的 QQ 也只是有个功能,并没有真正的滑动效果。至于微信的,我记得 N 久以前滑出了一个 bug。也没什么印象了。估计也是极小的概率事件。于是,当初我就强行的鲁了一个。下面我们一步步分析实现的思路以及代码。
首先来看下我们一些简单的定义:
- private Activity activity;
- private Scroller scroller;
- //上次ACTION_MOVE时的X坐标
- private int last_X;
- //屏幕宽度
- private int width;
- //可滑动的最小X坐标,小于该坐标的滑动不处理
- private int min_X;
- // 页面边缘的阴影图
- private Drawable left_shodow;
- //页面边缘阴影的宽度默认值
- private static final int SHADOW_WIDTH = 16;
- // 页面边缘阴影的宽度
- private int shadow_width;
- // Activity finish标识符
- private boolean isFinish;
这边我已经注释过了,就不做过多就写了。接下来,我们看下我们的一些初始化已经外部调用方法:
- private void initView(Activity activity) {
- this.activity = activity;
- scroller = new Scroller(activity);
- left_shodow = getResources().getDrawable(R.drawable.left_shadow);
- int density = (int) activity.getResources().getDisplayMetrics().density;
- shadow_width = SHADOW_WIDTH * density;
- // 这里你一定要设置成透明背景,不然会影响你看到底层布局
- setBackgroundColor(Color.argb(0, 0, 0, 0));
- }
- public void bindActivity(Activity activity) {
- ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
- View child = decorView.getChildAt(0);
- decorView.removeView(child);
- addView(child);
- decorView.addView(this);
我们主要看下 bindactivity 这个方法。这个是我们用来绑定一个 activity 的。这个 activity 你们可以基于 baseactivity 实现一个 backactivity。为什么要这么做,因为你每个 activity 都要写这么一句话,我感觉就是浪费时间,一个基类直接解决。这个 activity 我们可以这么写:
- public abstract class SWBackActivity extends Activity {
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- SWBackLayout layout = new SWBackLayout(this);
- layout.bindActivity(this);
- }
- protected abstract void afterInject();
- protected abstract void afterInitView();
- }
那么接下来我们看下,如果对手势的处理让他侧滑关闭呢?
- public boolean onTouchEvent(MotionEvent event) {
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- last_X = (int) event.getX();
- width = getWidth();
- min_X = width / 10;
- break;
- case MotionEvent.ACTION_MOVE:
- int rightMovedX = last_X - (int) event.getX();
- if (getScrollX() + rightMovedX >= 0) { // 左侧即将滑出屏幕
- scrollTo(0, 0);
- } else if ((int) event.getX() > min_X) { // 手指处于屏幕边缘时不处理滑动
- scrollBy(rightMovedX, 0);
- }
- last_X = (int) event.getX();
- break;
- case MotionEvent.ACTION_UP:
- if ( - getScrollX() < width / 3) {
- scrollBack();
- isFinish = false;
- } else {
- scrollClose();
- isFinish = true;
- }
- break;
- }
- return true;
- }
- private void scrollBack() {
- int startX = getScrollX();
- int dx = -getScrollX();
- scroller.startScroll(startX, 0, dx, 0, 300);
- invalidate();
- }
- private void scrollClose() {
- int startX = getScrollX();
- int dx = -getScrollX() - width;
- scroller.startScroll(startX, 0, dx, 0, 300);
- invalidate();
- }
- public void computeScroll() {
- if (scroller.computeScrollOffset()) {
- scrollTo(scroller.getCurrX(), 0);
- postInvalidate();
- } else if (isFinish) {
- activity.finish();
- }
- super.computeScroll();
- }
- protected void dispatchDraw(Canvas canvas) {
- super.dispatchDraw(canvas);
- drawShadow(canvas);
- }
- private void drawShadow(Canvas canvas) {
- // 保存画布当前的状态
- canvas.save();
- // 设置drawable的大小范围
- left_shodow.setBounds(0, 0, shadow_width, getHeight());
- // 让画布平移一定距离
- canvas.translate( - shadow_width, 0);
- // 绘制Drawable
- left_shodow.draw(canvas);
- // 恢复画布的状态
- canvas.restore();
- }
首先我们在 ACTION_DOWN 记录按下点的 X 坐标
然后在 ACTION_MOVE 中判断,如果我们 getScrollX() + rightMovedX 是否是大于 0 的,如果大于 0,表示 Activity 处于滑动状态,并且是向左滑动,同时我们进行了判断,手指处于屏幕边缘时不可以滑动。
最后在 ACTION_UP 中判断如果手指滑动的距离大于布局宽度的 1/3,表示将 Activity 滑出界面,否则滑动到起始位置,我们利用 Scroller 类的 startScroll() 方法设置好开始位置,滑动距离和时间,然后调用 postInvalidate() 刷新界面,之后就到 computeScroll() 方法中,我们利用 scrollTo() 方法对该布局的父布局进行滚动,滚动结束之后,我们判断界面是否滑出界面,如果是那就划出页面让 activity finish 掉。否则,布局就归位。
其实使用方法很简单,直接继承 SWBackActivity 就可以了。那么我们最后来看下效果图:
来源: http://blog.csdn.net/sw950729/article/details/76212258