0%

Android-侧滑返回方案简析

前言

自从iOS提供了侧滑返回上一级页面功能之后,Android很多应用也开始跟风,美其名曰:保证体验上的统一。作为开发者,当然得研究一下如何实现。

方案1-透明activity

将activity背景色设置成透明,滑动时,将activity-content-view跟随侧滑。

优点

  • 原理易懂
  • 实现简单

缺点

实战

我们可以用如下代码实现一个简化版本的侧滑返回:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
public class SlideBackActivity extends AppCompatActivity {
private boolean mFinishAfterAnimate;
private float mLastDownPointX;
private boolean mIsSliding;
private View mContentView;
private int mScreenWidth;
private int mTouchSlop;
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.e("kkk", "SlideBackActivity-onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_slide_back);
mContentView = findViewById(Window.ID_ANDROID_CONTENT);
mTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop();
mScreenWidth = getResources().getDisplayMetrics().widthPixels;
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
final int action = ev.getAction() & MotionEvent.ACTION_MASK;
switch (action) {
case MotionEvent.ACTION_DOWN:
mLastDownPointX = ev.getRawX();
mFinishAfterAnimate = false;
mIsSliding = true;
break;
case MotionEvent.ACTION_MOVE:
final float curPointX = ev.getRawX();
if (mIsSliding) {
if(Math.abs(curPointX - mLastDownPointX) > mTouchSlop) {
mContentView.setX(Math.abs(curPointX - mLastDownPointX));
}
}
break;
case MotionEvent.ACTION_UP:
final float currentPointX = ev.getRawX();
if(Math.abs(currentPointX - mLastDownPointX) > 500) {
mFinishAfterAnimate = true;
animateContentView(Math.abs(currentPointX - mLastDownPointX), mScreenWidth);
} else {
mFinishAfterAnimate = false;
animateContentView(Math.abs(currentPointX - mLastDownPointX), 0);
}
mIsSliding = false;
break;
}
return super.dispatchTouchEvent(ev);
}
private void animateContentView(float start, float end) {
ObjectAnimator anim1 = ObjectAnimator.ofFloat(mContentView, "x", start, end);
AnimatorSet animSet = new AnimatorSet();
animSet.setInterpolator(new LinearInterpolator());
animSet.setDuration(100);
animSet.playTogether(anim1);
if (mFinishAfterAnimate) {
animSet.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
finish();
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
}
animSet.start();
}
@Override
public void finish() {
super.finish();
if (mFinishAfterAnimate) overridePendingTransition(0,0);
}
@Override
protected void onStart() {
Log.e("kkk", "SlideBackActivity-onStart");
super.onStart();
}
@Override
protected void onResume() {
Log.e("kkk", "SlideBackActivity-onResume");
super.onResume();
}
@Override
protected void onPause() {
Log.e("kkk", "SlideBackActivity-onPause");
super.onPause();
}
@Override
protected void onStop() {
Log.e("kkk", "SlideBackActivity-onStop");
super.onStop();
}
@Override
protected void onDestroy() {
Log.e("kkk", "SlideBackActivity-onDestroy");
super.onDestroy();
}
}

当然了,前提还是得把activity主题设置成透明

1
2
3
4
<style name="Transparent" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowIsTranslucent">true</item>
</style>

通过下方日志我们可以看到,启动SlideBackAcitvity时,上一个activity(main)-onStop方法没有走到,而退出SlideBackAcitvity后,上一个activity(main)-onStart方法也没有走到。

1
2
3
4
5
6
7
8
9
10
03-02 15:28:54.790 1531-1531/com.mason.swipebackdemo E/kkk: main-onStart
03-02 15:28:54.799 1531-1531/com.mason.swipebackdemo E/kkk: main-onResume
03-02 15:29:11.439 1531-1531/com.mason.swipebackdemo E/kkk: main-onPause
03-02 15:29:11.447 1531-1531/com.mason.swipebackdemo E/kkk: SlideBackActivity-onCreate
03-02 15:29:11.452 1531-1531/com.mason.swipebackdemo E/kkk: SlideBackActivity-onStart
03-02 15:29:11.453 1531-1531/com.mason.swipebackdemo E/kkk: SlideBackActivity-onResume
03-02 15:29:16.905 1531-1531/com.mason.swipebackdemo E/kkk: SlideBackActivity-onPause
03-02 15:29:16.924 1531-1531/com.mason.swipebackdemo E/kkk: main-onResume
03-02 15:29:16.966 1531-1531/com.mason.swipebackdemo E/kkk: SlideBackActivity-onStop
03-02 15:29:16.966 1531-1531/com.mason.swipebackdemo E/kkk: SlideBackActivity-onDestroy

开源方案

方案2-替换view

  1. 拿到上一个Avtivity-View的引用,并添加到当前activity-view下方。
  2. 滑动时,左侧加上阴影,当前activity-view跟随侧滑

优点

  1. 无需设置activity透明
  2. 不影响activity生命周期

缺点

实现相对复杂

开源方案

and_swipeback

SlideBack

结论

新闻采用的是方案2,一是对性能影响相比之下较小,二是有些统计依赖于activity生命周期。因现有开源方案并不能满足需要,最终还是选择自己实现一套。