Activity 添加滑动关闭功能-[Android_YangKe]

微信是腾讯家族的一款旗舰产品,前些日子实在无聊就可劲刷朋友圈,刹那间发现微信具有二级页面滑动关闭功能,(屏随指动,纵享丝滑)用户好感倍增,顿时两眼泛水花开始膜拜大厂产品,工程师。

努力成为自己想要成为的人,心中默念:“当你停下来休息的时候,不要忘记别人还在奔跑”。于是开始学习相关技术丰富自己。百度,Google,Github,功夫不负有心人,通过自己几个小时的努力实现了自己想要的效果。我们看图:

《Activity 添加滑动关闭功能-[Android_YangKe]》 Android_YangKe.gif
《Activity 添加滑动关闭功能-[Android_YangKe]》 Android_YangKe.gif

由于动态图压缩比较严重,这里进行简单讲解。图一效果主要是:当我们手指没有将页面拖动到屏幕中间及后半部分时,应用会自动回弹到原始状态,当我们将页面拖动到屏幕后半部分时页面会 finish 掉。功能实现了,具体思路是什么呢?如果你对Activity,Window,View 整体轮廓不是很熟悉,请做知识储备 点我

下面我们看下项目结构:

《Activity 添加滑动关闭功能-[Android_YangKe]》 Android_YangKe.png

不要重复造轮子,没错这是一个三方库。但我们争取做到知其然,知其所以然。下面开始我们的分析,注意其中这样几个 API:

  • SwipeBackActivity
  • SwipeBackActivityHelper
  • SwipeBackActivityBase
  • SwipeBackLayout
  • ViewDragHelper
SwipeBackActivityBase

SwipeBackActivityBase从命名上我们可以看出此类为基类,它是滑动关闭 Activity 的抽象。为什么选择基类入手?一般阅读源码代码量都比较大,从基类入手便于我们了解整体框架轮廓,至于实现细节,我们根据需要再来分析。

代码之旅,即将开始:3,2,1…

public interface SwipeBackActivityBase {
    /**
     * 从当前 Activity 返回关联的 SwipeBackLayout 对象
     */
    public abstract SwipeBackLayout getSwipeBackLayout();
    /**
      * 设置开启或者关闭滑动关闭 Activity 功能
      */
    public abstract void setSwipeBackEnable(boolean enable);

    /**
     * 滑动 Activity 关闭 Activity 函数的抽象
     */
    public abstract void scrollToFinishActivity();
}

从以上代码我们可以 get 到三个技能点:
1> 获取当前 Activity 关联的 SwipeBackLayout 对象
2> 开启或者关闭滑动 Activity 关闭 Activity 的功能
3> 滑动关闭 Activity

SwipeBackActivity

SwipeBackActivitySwipeBackActivityBase的具体实现。也就是说我们的 Activity 继承此类后相应的页面就具有了滑动关闭功能。我们继续,前方有大量源码即将来袭,请注意查收!

public class SwipeBackActivity extends AppCompatActivity implements SwipeBackActivityBase {
    private SwipeBackActivityHelper mHelper;

    @Override protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mHelper = new SwipeBackActivityHelper(this);
        mHelper.onActivityCreate();
    }

    @Override protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        mHelper.onPostCreate();
    }

    @Override public SwipeBackLayout getSwipeBackLayout() {
        return mHelper.getSwipeBackLayout();
    }

    @Override public void setSwipeBackEnable(boolean enable) {
        getSwipeBackLayout().setEnableGesture(enable);
    }

    @Override public void scrollToFinishActivity() {
        Utils.convertActivityToTranslucent(this);
        getSwipeBackLayout().scrollToFinishActivity();
    }
}

代码是不是看起来很简洁,但简洁并不代表简单。我们可以看到SwipeBackActivity实现了SwipeBackActivityBase并重写了相应函数。同时,用户的滑动方向,手势判断,滑动阴影一并完成。良好的设计模式在这里体现的淋漓尽致,内功很重要,扯远了哈。通过以上代码我们可以获取到以下信息:
1> 首次出现的 SwipeBackActivityHelper
2> 我通过 SwipeBackActivityHelper 对象获取 SwipeBackLayout 对象
3> scrollToFinishActivity 函数的实现

不知道大家有没有发现一个共同点就是,所有的操作都必须依托于SwipeBackLayout对象,而SwipeBackLayout对象又依托于SwipeBackActivityHelper,好吧,我们来看下SwipeBackActivityHelper

当我翻开源码的时候其实内心是拒绝的,作者竟然没有给出一行注释。不过好在代码量不大,硬着头皮读吧。

public class SwipeBackActivityHelper {
    private Activity mActivity;
    private SwipeBackLayout mSwipeBackLayout;

    public SwipeBackActivityHelper(Activity activity) { this.mActivity = activity; }

    /**
     * 1> 处理 Activity 关联的 Window 背景
     * 2> 处理 Window 关联的 DecorView 对象
     * 3> 初始化 SwipeBackLayout 对象
     */
    public void onActivityCreate() {
        mActivity.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        mActivity.getWindow().getDecorView().setBackgroundDrawable(null);
        mSwipeBackLayout = (SwipeBackLayout) LayoutInflater.from(mActivity).inflate(
                me.imid.swipebacklayout.lib.R.layout.swipeback_layout, null);
    }

    public void onPostCreate() {
        mSwipeBackLayout.attachToActivity(mActivity);
    }

    public SwipeBackLayout getSwipeBackLayout() {
        return mSwipeBackLayout;
    }
}

onActivityCreate文中已经给出了注释,这里不再进行说明。代码掐头去尾就剩下onPostCreate函数,现在让我们找到SwipeBackLayout.java,然后定位到attachToActivity函数。

//SwipeBackLayout.java
public void attachToActivity(Activity activity) {
        ...代码省略...
        mActivity = activity;
        ViewGroup decor = (ViewGroup) activity.getWindow().getDecorView();
        ViewGroup decorChild = (ViewGroup) decor.getChildAt(0);
        decorChild.setBackgroundResource(background);
        decor.removeView(decorChild);
        addView(decorChild);
        setContentView(decorChild);
        addSwipeListener(new SwipeBackListenerActivityAdapter(activity));
        decor.addView(this);
    }

通过对上文的分析我们可以获取到以下几点信息:
1> 从当前 Activity 中获取 DecorView。DecorView 与 Activity 的恩怨情仇
2> 将手势监听与当前 Activity 绑定
3> 将 SwipeBackLayout 添加到 DecorView,也可以理解为将视图依托在 Activity 上进行展示。

SwipeBackLayout
public class SwipeBackLayout extends FrameLayout {
    ...代码省略百行...
}

对于自定义 View、ViewGroup 来说,一般代码量都比较大,动则成百上千,那么我们该使用什么样的姿势来打开它呢。其实从自定义 View 的几个关键函数开始就行,当然还有就是构造函数。

public SwipeBackLayout(Context context, AttributeSet attrs, int defStyle) {
    ...代码省略...
    mDragHelper = ViewDragHelper.create(this, new ViewDragCallback());//构建ViewDragHelper
    int mode = EDGE_FLAGS[a.getInt(R.styleable.SwipeBackLayout_edge_flag, 0)];
    setEdgeTrackingEnabled(mode);//设置滑动关闭 Activity 的模式。例:左侧关闭,右侧关闭等。

    int shadowLeft = a.getResourceId(R.styleable.SwipeBackLayout_shadow_left, R.drawable.shadow_left);
    int shadowRight = a.getResourceId(R.styleable.SwipeBackLayout_shadow_right, R.drawable.shadow_right);
    int shadowBottom = a.getResourceId(R.styleable.SwipeBackLayout_shadow_bottom, R.drawable.shadow_bottom);
    setShadow(shadowLeft, EDGE_LEFT);//设置左侧滑动时的阴影
    setShadow(shadowRight, EDGE_RIGHT);//设置右侧滑动时的阴影
    setShadow(shadowBottom, EDGE_BOTTOM);//设置底部滑动时的阴影
}

经过分析构造函数中大概做了如下几件事情:
1> 初始化属性信息
2> 构建 ViewDragHelper 对象
3> 初始化页面滚动时左、右、下侧阴影部分

然后就是 set 函数:
1> setEdgeTrackingEnabled //设置滑动方向。例:左侧滑动,右侧滑动
2> setShadow //设置阴影方向。例:左侧,右侧
3> setSwipeBackEnable // 设置是否开启滑动关闭功能,默认为 true
… 等等

总结:

如何给自己的应用添加滑动关闭 Activity 功能?

  • 将自己 Activity 继承自 SwipeBackActivity

如何开启或关闭“滑动关闭功能”?

  • 调用 setSwipeBackEnable(false); 可以禁止滑动关闭功能

如何修改滑动关闭 Activity 的方向?

  • setEdgeTrackingEnabled(SwipeBackLayout.EDGE_XXX);

对于 SwipeBackLayout 的理解:
1> 将依附在 Activity 上的 Window、DecorView 背景设置为空,透明
2> 将 DecorView 替换为 SwipeBackLayout
3> 对 SwipeBackLayout 进行手势监听,处理滑动事件动态更新页面

APK 下载
完!

喜欢有帮助的话: 双击、评论、转发,动一动你的小手让更多的人知道!关注 Android_YangKe

    原文作者:Android_YangKe
    原文地址: https://www.jianshu.com/p/d62cda41017c
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞