玩转编程

将滑动关闭进行到底

2018-01-11  本文已影响26701人  欧阳锋

坦率地讲,我并不是一个果粉。我也不觉得iOS系统比Android优秀,曾经有过一段时间将iPhone用作主流机。最后还是换成了安卓机,原因是iPhone的性价比的确不高,加上系统的一些限制,可玩性非常有限。而如果你问我,iOS系统里面有什么你特别喜欢的功能,滑动关闭无疑是其中一个。当人们在专注屏幕内容的时候,还要转移注意力聚焦屏幕下方的按钮,其实是有一些成本的,最直观的感觉就是不太自然。用过iPhone后再用安卓,人们总是习惯性地右滑...

Demo下载体验

扫描二维码下载

为了实现类似iOS的滑动关闭效果,在大约一年多前,我开发了一个小工具Snake。使用这个小工具仅需要一行代码就可以轻松集成滑动关闭功能,当前这个工具的最新版本是0.1.0,老版本截止于0.0.6。

对于老版本的设计,有两个明显的缺陷:

  <item name="android:windowBackground">@android:color/transparent</item>
  <item name="android:windowIsTranslucent">true</item>

为了克服这些问题,我完全重写了这个小工具,新版本将来到0.1.0。新版本不仅解决了上面两个问题,而且对代码进行了简化,去掉了冗余设计。同时,在灵活性上面有了大幅度的提高,可以让你完全不要改动原有代码架构就能使用滑动关闭功能,真正的零侵入性设计。废话不多说,一起来看一下,怎么使用吧!

如何使用

1)添加依赖

dependencies {
    // Gradle高版本这里可以使用implementation代替compile
    // x.x.x代表最新版本号,请到文章底部点击Github链接查看
    // 截止文章截稿日期,最新版本号都是0.1.0
    compile 'com.youngfeng.android:snake:x.x.x'
    annotationProcessor 'com.youngfeng.android:snake-compiler:x.x.x'
}

2) 在Application的onCreate方法中,对Snake进行初始化

public class SnakeApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        Snake.init(this);
    }
}

3)在Activity中使用

@EnableDragToClose()
public class FirstActivity extends BaseActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Snake.host(this);
 }

以上两个步骤已经使Activity拥有了滑动关闭功能,不相信吗?试试看!

4)在Fragment中使用

注意:Fragment类中不需要使用host接口对其进行托管,Snake将自动完成托管。

通过以上四个步骤,你已经成功完成了对滑动关闭的集成。可是,在不同的手机上测试,滑动时你依然会发现几个问题:

而对于Fragment的设置相对较为麻烦,在启动的时候我们可以通过setCustomAnimation对其启动和回退动画进行统一设置。可是在回退的时候,却不能关闭某一次动画播放,导致了动画重复播放的问题。为了避免这个问题,Snake增加了wrapSnakeAnimationController两个接口,通过这两个接口联合使用就可以避免这个问题。

具体要怎么做呢?看这里:

public class BaseFragment extends Fragment implements SnakeAnimationController {
    private boolean mDisableAnimation;

    @Override
    public Animator onCreateAnimator(int transit, boolean enter, int nextAnim) {
        return Snake.wrap(super.onCreateAnimator(transit, enter, nextAnim), this);
    }

    @Override
    public void disableAnimation(boolean disable) {
        mDisableAnimation = disable;
    }

    @Override
    public boolean animationDisabled() {
        return mDisableAnimation;
    }
}

PS:重新onCreateAnimation的方式完全一致,Snakewrap接口也可以适用。

注意:这个操作强烈建议在Fragment基础父类中进行处理,通过这种方式你也可以自己调用disableAnimation接口控制回退动画的播放。

以上几个操作已经完全可以正常使用滑动关闭了。可是,你可能还有一些特殊的需求,下面我通过QA的方式来模拟六种使用场景,如果还有没有涵盖的使用场景,请在评论下方告诉我!

@EnableDragToClose(false)
public class FirstActivity extends BaseActivity {
if(条件a) {
  Snake.enableDragToClose(this, true);
} else if(条件b) {
  Snake.enableDragToClose(this, false);
}
  public static abstract class OnDragListener {
        public void onDragStart(View view) {}

        public void onDrag(View view, int left) {}

        public void onRelease(View view, float xVelocity) {}
    }
Fragment fragment = Snake.newProxy(xx.class, objA, objB);
<?xml version="1.0" encoding="utf-8"?>
<snake>
    <config>
        <!-- 设置为true,根Activity也能够滑动关闭,这很奇怪!不建议修改这个变量的默认值 -->
        <enable_for_root_activity>false</enable_for_root_activity>
        <!-- 设置为true,将监听当前页面所有位置往右快速滑动手势 -->
        <only_listen_to_fast_swipe>false</only_listen_to_fast_swipe>
        <!-- 快速滑动最低检测速度,不建议修改。过高会影响灵敏度,过低会导致误判 -->
        <min_velocity>2000</min_velocity>
        <!-- 设置为true,滑动时左侧边缘阴影将被隐藏, 这个变量的默认值也不建议修改 -->
        <hide_shadow_of_edge>false</hide_shadow_of_edge>
        <!-- 阴影边缘渐变色起始颜色 -->
        <shadow_start_color>#00000000</shadow_start_color>
        <!-- 阴影边缘渐变色结束颜色 -->
        <shadow_end_color>#55000000</shadow_end_color>
    </config>
</snake>

如果要对单个页面进行滑动样式修改,我们提供了@SetDragParameter注解:

    /**
     * 仅监听快速滑动关闭
     */
    boolean onlyListenToFastSwipe() default false;

    /**
     * 快速滑动最小检测速度
     */
    int minVelocity() default 2000;

    /**
     * 隐藏阴影边缘
     */
    boolean hideShadowOfEdge() default false;

    /**
     * 阴影起始颜色(阴影边缘隐藏后,该设置失效)
     */
    String shadowStartColor() default "#00000000";

    /**
     * 阴影边缘结束颜色(阴影边缘隐藏后,该设置失效)
     */
    String shadowEndColor() default "#50000000";

注意:xml配置文件名必须是snake.xml,配置文件应放置在assets目录下面。

场景七:针对单个页面逐一去开启滑动关闭功能实在太麻烦了,是否可以针对所有页面开启滑动关闭功能呢?
答:当然可以!首先,针对ActivityFragment你需要有一个统一的基类,使用方式与上文介绍完全一致。如果是Activity,先添加注解@EnableDragToClose,然后在onCreate方法中使用host接口对其进行托管,像这样:

@EnableDragToClose()
public class BaseActivity extends Activity {

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Snake.host(this);
 }

}

如果是Fragment,同样地,先添加注解@EnableDragToClose,然后在跳转到Fragment的时候使用Snake.newProxySnake.newProxySupport创建Fragment实例即可。

使用总结

为了让你对整个使用过程有一个更直观的了解,我用箭头对整个过程做一个简单的总结:

简单说明

这里容易混淆的一个概念就是:注解@EnableDragToCloseSnake.enableDragToClose接口。其实,这两个部分是有一定的区别的,注解是用于标记当前页面是否需要开启滑动关闭功能,如果需要开启,注解始终需要。但如果你希望当前页面始终关闭【滑动关闭】功能,你可以在注解中传入参数false,而如果你希望动态控制【滑动关闭】功能的开启或关闭,则需要使用Snake.enableDragToClose接口来控制。如果你没有添加注解到类头,直接使用接口开启滑动关闭功能,将会报错。

Snake版本兼容问题

Snake 0.1.0不兼容0.0.6极其以前版本,如果你使用了旧版本实现,建议暂时不要替换,在新的APP中强烈推荐使用0.1.0及其以上版本。

Android系统版本兼容问题

由于Android系统的一些限制,在低于21版本Activity滑动联动的实现上有一些问题。为了避免这个问题,我在低版本的使用上禁用了拖拽,仅使用快速滑动关闭当前页面。这里我推荐使用全FragmentActivity + 多Fragment设计。

在使用过程中,如果你有任何疑问,请点击下方链接参考Github官方文档:
https://github.com/yuanhoujun/Android_Slide_To_Close

新版本规划

特别鸣谢

感谢 言小诺01 同学提供图标设计。

学更多编程知识,扫描下方二维码关注欧阳锋工作室

欧阳锋工作室

PS:走过路过,不要错过,点个赞,不要钱哦 -_-

上一篇 下一篇

猜你喜欢

热点阅读