├── .gitignore
├── README.md
├── SlidingShut.iml
├── app
├── app.iml
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── bamboy
│ │ └── slidingshut
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── bamboy
│ │ │ └── slidingshut
│ │ │ ├── AssignViewActivity.java
│ │ │ ├── ColorBackdropActivity.java
│ │ │ ├── InterceptFinishActivity.java
│ │ │ ├── MainActivity.java
│ │ │ ├── StartInstantlyActivity.java
│ │ │ ├── UpFinishActivity.java
│ │ │ └── baseactivity
│ │ │ ├── BamActivity.java
│ │ │ ├── BamFragmentActivity.java
│ │ │ ├── SlopeProgress.java
│ │ │ └── UtilBaseGesture.java
│ └── res
│ │ ├── anim
│ │ ├── act_left_in.xml
│ │ ├── act_left_out.xml
│ │ ├── act_right_in.xml
│ │ └── act_right_out.xml
│ │ ├── drawable
│ │ ├── ic_back.png
│ │ ├── ic_bamboy.png
│ │ ├── radius_background.xml
│ │ └── radius_link.xml
│ │ ├── layout
│ │ ├── activity_assign_view.xml
│ │ ├── activity_color_backdrop.xml
│ │ ├── activity_intercept_finish.xml
│ │ ├── activity_main.xml
│ │ ├── activity_start_instantly.xml
│ │ └── activity_up_finish.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── bamboy
│ └── slidingshut
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradlew
├── gradlew.bat
├── local.properties
├── picture
├── apk.jpg
├── gif01_upFinish.gif
├── gif02_startInstantly.gif
├── gif03_interceptFinish.gif
├── gif04_assignView.gif
└── gif05_colorBackdrop.gif
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | <<<<<<< HEAD
6 | # Files for the Dalvik VM
7 | *.dex
8 |
9 | # Java class files
10 | *.class
11 |
12 | # Generated files
13 | bin/
14 | gen/
15 |
16 | # Gradle files
17 | .gradle/
18 | .idea/
19 | gradle/
20 | build/
21 | /*/build/
22 |
23 | # Local configuration file (sdk path, etc)
24 | local.properties
25 |
26 | # Proguard folder generated by Eclipse
27 | proguard/
28 |
29 | # Log Files
30 | *.log
31 | app/app.iml
32 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SlidingShut 右滑关闭2.0
2 |
3 | ## 简介
4 | 很多APP中都会有右滑关闭功能,
5 | 尤其是在全面屏时代更显得尤为重要,
6 | 但是,
7 | Android 8.0禁止非全屏的Activity使用透明主题,
8 | 否则会引发:
9 | > Only fullscreen opaque activities can request orientation
10 |
11 | 这导致了体验最优的右滑关闭方案则不能再使用,
12 | 除非有微信那种黑科技。
13 |
14 | 手机QQ的右滑关闭虽然不需要透明主题,
15 | 但是没有实时反馈,
16 | 体验巨差,
17 | 那么就没有其他的选择了吗?
18 |
19 | 于是我总结了一下,
20 | 目前最多的有两种右滑方案:
21 |
22 | ## 1、以微信为代表的透明方案
23 | > 优点1:
24 | > 界面移动跟随手指,
25 | > 实时反馈。
26 | >
27 | > 优点2:
28 | > 拟物化,
29 | > 层级明确,
30 | > 视觉体验好。
31 | ———————————
32 | > 缺点1:
33 | > 由于涉及到滑动速度,
34 | > 要滑多快才会触发关闭,
35 | > 这阈值永远是个未知数,
36 | > 再加上使用右滑关闭的App越来越多,
37 | > 每个App的这个阈值都不一样,
38 | > 无形中增加了关闭失败的几率
39 | > 以及用户的思考成本。
40 | >
41 | > 缺点2:
42 | > 需要透明主题,
43 | > 不仅有可能会扰乱上一个Activity的生命周期,
44 | > 而且SDK 27中非全屏Activity不可用,
45 | > 否侧会crash。
46 |
47 |
48 | ## 2、以QQ为代表的滑动方向计算
49 | > 优点:
50 | > 不需要透明主题
51 | ———————————
52 | > 缺点1:
53 | > 没有任何反馈,
54 | > 用户无法知道当前手势是否可以触发关闭,
55 | > 误触率高。
56 | >
57 | > 缺点2:
58 | > 反应迟钝,
59 | > 由于需要手势完成才能获得完整手势,
60 | > 所以手指抬起后才会触发关闭,
61 | > 虽然微信也是抬起后关闭,
62 | > 但是视觉上和心理上却不存在此缺点。
63 | > 不过有个稍优点的方案,
64 | > 实时计算手势的,
65 | > 反应灵敏了许多,
66 | > 但却会增加误触几率。
67 | >
68 | > 缺点3:
69 | > 没有层级感,
70 | > 更不拟物化。
71 |
72 | 那么有没有其他的方案,
73 | 既不需要透明主题,
74 | 又能实时反馈?
75 |
76 | 当然,
77 | 既然我写了这篇帖子,
78 | 那么当然会给大家提供一种方案。
79 |
80 | ## 3:Bamboy右滑关闭方案
81 | > 优点1:
82 | > 不需要透明主题。
83 | >
84 | > 优点2:
85 | > 界面跟随手指,
86 | > 实时反馈,
87 | > 会不会关闭用户一目了然。
88 | >
89 | > 优点3:
90 | > 拟物化,
91 | > 视觉体验好。
92 | ———————————
93 | > 缺点:
94 | > 没有微信的那种方案层级感强。
95 |
96 |
97 | 废话不多说,
98 | 这就给大家展示一下效果吧:
99 |
100 | ## 一、抬起模式
101 | 顾名思义
102 | 滑动过程中圆环进度条跟随手指而充盈
103 | 当圆环圆满后
104 | 抬起手指后才会触发finish();
105 |
106 | 想要使用抬起模式
107 | 调用以下代码即可:
108 | > setUpFinish(true);
109 | > (注:默认为true,即默认抬起模式)
110 |
111 | 
112 |
113 | ## 二、即刻模式
114 | 与抬起模式相对应
115 | 只要圆环圆满就触发finish();
116 | 相比来说
117 | 即刻模式更敏捷
118 | 但却存在误触的情况
119 | 选择适合自己的
120 |
121 | 想要使用抬起模式
122 | 调用以下代码即可:
123 | > setUpFinish(false);
124 |
125 | 
126 |
127 | ## 三、兼容finish()被拦截的情况
128 | 当Activity中finish()方法被拦截时
129 | 已经移动的界面自动归位
130 | 归位后自动重新开启右滑关闭
131 |
132 | 
133 |
134 | ## 四、指定滑动View
135 | 看了上面几个动图
136 | 心细的朋友可能发现了
137 | 在界面移动时
138 | Activity左上角出现了一个白条条
139 | 这是因为TitleBar的颜色和界面的颜色不一致导致的
140 | 虽说无伤大雅
141 | 但作为一个视觉主义的程序员
142 | 这个小细节也是要优化的
143 | 所以我提供了只移动指定View功能
144 | 就是说不会整个界面都移动
145 | 你让他动的才会动
146 |
147 | 想要指定滑动View
148 | 调用以下代码即可:
149 | > setMoveView(rootView);
150 |
151 | 
152 |
153 | ## 五、圆环颜色自定义
154 | 不管是出于性能
155 | 还是出于可扩展性
156 | 这个圆环进度条是完全用Canvas画出来的
157 | 所以颜色当然是支持自定义的
158 | 比如界面背景色不是白色
159 | 而是主题色时
160 |
161 | 想要指定圆环颜色
162 | 调用以下代码即可:
163 | > int color = ContextCompat.getColor(context, R.color.white);
164 | > setProgressColor(color);
165 |
166 | 
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
--------------------------------------------------------------------------------
/SlidingShut.iml:
--------------------------------------------------------------------------------
1 |
2 |
11 | * Created by Bamboy on 2018/10/25. 12 | */ 13 | public class AssignViewActivity extends BamActivity { 14 | 15 | /** 16 | * Activity内容View 17 | * 【即TitleBar以下的内容】 18 | */ 19 | private RelativeLayout rl_root; 20 | 21 | @Override 22 | protected void onCreate(Bundle savedInstanceState) { 23 | super.onCreate(savedInstanceState); 24 | setContentView(R.layout.activity_assign_view); 25 | 26 | rl_root = findViewById(R.id.rl_root); 27 | 28 | // 指定只移动TitleBar以下的内容 29 | setMoveView(rl_root); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/bamboy/slidingshut/ColorBackdropActivity.java: -------------------------------------------------------------------------------- 1 | package com.bamboy.slidingshut; 2 | 3 | import android.os.Bundle; 4 | import android.support.v4.content.ContextCompat; 5 | 6 | import com.bamboy.slidingshut.baseactivity.BamActivity; 7 | 8 | /** 9 | * 彩色背景下改变进度条颜色示例 10 | *
11 | * Created by Bamboy on 2018/10/25. 12 | */ 13 | public class ColorBackdropActivity extends BamActivity { 14 | 15 | @Override 16 | protected void onCreate(Bundle savedInstanceState) { 17 | super.onCreate(savedInstanceState); 18 | setContentView(R.layout.activity_color_backdrop); 19 | 20 | // 设置进度条颜色 21 | setProgressColor(ContextCompat.getColor(this, R.color.white)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/bamboy/slidingshut/InterceptFinishActivity.java: -------------------------------------------------------------------------------- 1 | package com.bamboy.slidingshut; 2 | 3 | import android.animation.Animator; 4 | import android.animation.AnimatorListenerAdapter; 5 | import android.animation.ObjectAnimator; 6 | import android.os.Bundle; 7 | import android.view.View; 8 | import android.widget.Button; 9 | import android.widget.TextView; 10 | 11 | import com.bamboy.slidingshut.baseactivity.BamActivity; 12 | 13 | /** 14 | * 拦截finish()情况示例 15 | * 16 | * Created by Bamboy on 2018/11/5. 17 | */ 18 | public class InterceptFinishActivity extends BamActivity { 19 | 20 | /** 21 | * 菜单背景蒙层 22 | */ 23 | private View view_background; 24 | /** 25 | * 菜单 26 | */ 27 | private TextView tv_menu; 28 | /** 29 | * 打开菜单按钮 30 | */ 31 | private Button btn_open_menu; 32 | 33 | @Override 34 | protected void onCreate(Bundle savedInstanceState) { 35 | super.onCreate(savedInstanceState); 36 | setContentView(R.layout.activity_intercept_finish); 37 | 38 | view_background = findViewById(R.id.view_background); 39 | tv_menu = findViewById(R.id.tv_menu); 40 | btn_open_menu = findViewById(R.id.btn_open_menu); 41 | 42 | // 打开菜单按钮点击事件 43 | btn_open_menu.setOnClickListener(new View.OnClickListener() { 44 | @Override 45 | public void onClick(View view) { 46 | toggleMenu(); 47 | } 48 | }); 49 | 50 | // 展开菜单 51 | openMenu(); 52 | } 53 | 54 | /** 55 | * 切换菜单【展开/收起】状态 56 | */ 57 | private void toggleMenu() { 58 | if (tv_menu.getVisibility() == View.GONE) 59 | openMenu(); 60 | else if (tv_menu.getTranslationY() == 0) 61 | closeMenu(); 62 | } 63 | 64 | /** 65 | * 展开菜单 66 | */ 67 | private void openMenu() { 68 | if (tv_menu.getVisibility() != View.GONE) 69 | return; 70 | 71 | tv_menu.setAlpha(0); 72 | tv_menu.setVisibility(View.VISIBLE); 73 | view_background.setAlpha(0); 74 | view_background.setVisibility(View.VISIBLE); 75 | tv_menu.post(new Runnable() { 76 | @Override 77 | public void run() { 78 | 79 | int height = tv_menu.getHeight(); 80 | float btnTranslationY = btn_open_menu.getTranslationY(); 81 | 82 | tv_menu.setAlpha(1); 83 | ObjectAnimator.ofFloat(view_background, "alpha", 0, 0.7f).setDuration(300).start(); 84 | ObjectAnimator.ofFloat(tv_menu, "translationY", 0 - height, 0).setDuration(300).start(); 85 | ObjectAnimator.ofFloat(btn_open_menu, "translationY", btnTranslationY, btnTranslationY + height).setDuration(300).start(); 86 | } 87 | }); 88 | } 89 | 90 | /** 91 | * 收起菜单 92 | */ 93 | private void closeMenu() { 94 | if (tv_menu.getTranslationY() != 0) 95 | return; 96 | 97 | int height = tv_menu.getHeight(); 98 | float btnTranslationY = btn_open_menu.getTranslationY(); 99 | 100 | ObjectAnimator.ofFloat(view_background, "alpha", 0.7f, 0).setDuration(300).start(); 101 | ObjectAnimator anim = ObjectAnimator.ofFloat(tv_menu, "translationY", 0, 0 - height); 102 | anim.addListener(new AnimatorListenerAdapter() { 103 | @Override 104 | public void onAnimationEnd(Animator animation) { 105 | super.onAnimationEnd(animation); 106 | 107 | tv_menu.setVisibility(View.GONE); 108 | } 109 | }); 110 | anim.setDuration(300); 111 | anim.start(); 112 | ObjectAnimator.ofFloat(btn_open_menu, "translationY", btnTranslationY, btnTranslationY - height).setDuration(300).start(); 113 | } 114 | 115 | @Override 116 | public void finish() { 117 | if (tv_menu.getVisibility() == View.VISIBLE && tv_menu.getTranslationY() == 0) { 118 | closeMenu(); 119 | return; 120 | } 121 | super.finish(); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /app/src/main/java/com/bamboy/slidingshut/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.bamboy.slidingshut; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.view.View; 6 | 7 | import com.bamboy.slidingshut.baseactivity.BamActivity; 8 | 9 | /** 10 | * Created by Bamboy on 2018/10/24. 11 | */ 12 | public class MainActivity extends BamActivity { 13 | 14 | @Override 15 | protected void onCreate(Bundle savedInstanceState) { 16 | super.onCreate(savedInstanceState); 17 | setContentView(R.layout.activity_main); 18 | 19 | openSlideFinish(false); 20 | 21 | findViewById(R.id.btn_start_instantly).setOnClickListener(new View.OnClickListener() { 22 | @Override 23 | public void onClick(View view) { 24 | startActivity(new Intent(MainActivity.this, StartInstantlyActivity.class)); 25 | } 26 | }); 27 | 28 | findViewById(R.id.btn_start_up_finish).setOnClickListener(new View.OnClickListener() { 29 | @Override 30 | public void onClick(View view) { 31 | startActivity(new Intent(MainActivity.this, UpFinishActivity.class)); 32 | } 33 | }); 34 | 35 | findViewById(R.id.btn_intercept_finish).setOnClickListener(new View.OnClickListener() { 36 | @Override 37 | public void onClick(View view) { 38 | startActivity(new Intent(MainActivity.this, InterceptFinishActivity.class)); 39 | } 40 | }); 41 | 42 | findViewById(R.id.btn_assign_view).setOnClickListener(new View.OnClickListener() { 43 | @Override 44 | public void onClick(View view) { 45 | startActivity(new Intent(MainActivity.this, AssignViewActivity.class)); 46 | } 47 | }); 48 | 49 | findViewById(R.id.btn_color_backdrop).setOnClickListener(new View.OnClickListener() { 50 | @Override 51 | public void onClick(View view) { 52 | startActivity(new Intent(MainActivity.this, ColorBackdropActivity.class)); 53 | } 54 | }); 55 | 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/com/bamboy/slidingshut/StartInstantlyActivity.java: -------------------------------------------------------------------------------- 1 | package com.bamboy.slidingshut; 2 | 3 | import android.os.Bundle; 4 | 5 | import com.bamboy.slidingshut.baseactivity.BamActivity; 6 | 7 | /** 8 | * 即刻模式示例 9 | *
10 | * Created by Bamboy on 2018/10/25. 11 | */ 12 | public class StartInstantlyActivity extends BamActivity { 13 | 14 | @Override 15 | protected void onCreate(Bundle savedInstanceState) { 16 | super.onCreate(savedInstanceState); 17 | setContentView(R.layout.activity_start_instantly); 18 | 19 | setUpFinish(false); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/bamboy/slidingshut/UpFinishActivity.java: -------------------------------------------------------------------------------- 1 | package com.bamboy.slidingshut; 2 | 3 | import android.os.Bundle; 4 | 5 | import com.bamboy.slidingshut.baseactivity.BamActivity; 6 | 7 | /** 8 | * 抬起模式示例 9 | *
10 | * Created by Bamboy on 2018/10/25. 11 | */ 12 | public class UpFinishActivity extends BamActivity { 13 | 14 | @Override 15 | protected void onCreate(Bundle savedInstanceState) { 16 | super.onCreate(savedInstanceState); 17 | setContentView(R.layout.activity_up_finish); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/bamboy/slidingshut/baseactivity/BamActivity.java: -------------------------------------------------------------------------------- 1 | package com.bamboy.slidingshut.baseactivity; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.graphics.Color; 7 | import android.os.Build; 8 | import android.view.MotionEvent; 9 | import android.view.View; 10 | import android.view.Window; 11 | import android.view.WindowManager; 12 | import android.widget.ImageView; 13 | import android.widget.RelativeLayout; 14 | 15 | import com.bamboy.slidingshut.MainActivity; 16 | import com.bamboy.slidingshut.R; 17 | 18 | import java.lang.reflect.Field; 19 | 20 | /** 21 | * Activity基类 22 | *
23 | * Created by Bamboy on 2018/10/24. 24 | */ 25 | public class BamActivity extends Activity { 26 | /** 27 | * 触摸工具类 28 | */ 29 | private UtilBaseGesture mUtilGesture; 30 | /** 31 | * 标题栏 32 | */ 33 | protected RelativeLayout rl_title; 34 | /** 35 | * 标题栏关闭箭头 36 | */ 37 | protected ImageView iv_back; 38 | 39 | @Override 40 | public void setContentView(int layoutResID) { 41 | super.setContentView(layoutResID); 42 | 43 | rl_title = findViewById(R.id.rl_title); 44 | iv_back = findViewById(R.id.iv_back); 45 | 46 | /** 47 | * 如果是Android 4.4 以上,就兼容沉浸式 48 | */ 49 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 50 | try { 51 | // 初始化状态栏 52 | setImmerseTitleBar(); 53 | } catch (Exception e) { 54 | e.printStackTrace(); 55 | } 56 | } 57 | 58 | // 设置返回按钮点击事件 59 | if (iv_back != null) { 60 | iv_back.setOnClickListener(new View.OnClickListener() { 61 | @Override 62 | public void onClick(View view) { 63 | finish(); 64 | } 65 | }); 66 | } 67 | // 手势工具类 68 | mUtilGesture = new UtilBaseGesture(this); 69 | } 70 | 71 | //============================================================================================== 72 | //======================= 以 下 是 关 于 沉 浸 式 状 态 栏 ======================================== 73 | //============================================================================================== 74 | 75 | /** 76 | * 设置沉浸TitleBar 77 | */ 78 | private void setImmerseTitleBar() { 79 | 80 | Window window = getWindow(); 81 | window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, 82 | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 83 | 84 | // Android 7.0以上 去除状态栏半透明底色 85 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 86 | try { 87 | Class decorViewClazz = Class.forName("com.android.internal.policy.DecorView"); 88 | Field field = decorViewClazz.getDeclaredField("mSemiTransparentStatusBarColor"); 89 | field.setAccessible(true); 90 | field.setInt(window.getDecorView(), Color.TRANSPARENT); //改为透明 91 | } catch (Exception e) { 92 | e.printStackTrace(); 93 | } catch (Error e) { 94 | e.printStackTrace(); 95 | } 96 | } 97 | 98 | if (rl_title == null) { 99 | return; 100 | } 101 | 102 | int barHeight = getBarHeight(this); 103 | View fillingView = rl_title.findViewById(R.id.view_filling); 104 | if (barHeight <= 0 || fillingView == null) { 105 | return; 106 | } 107 | 108 | if (rl_title instanceof RelativeLayout) { 109 | fillingView.setLayoutParams( 110 | new RelativeLayout.LayoutParams(1, barHeight)); 111 | } 112 | } 113 | 114 | /** 115 | * 获取状态栏高度 116 | * 117 | * @param context 118 | * @return 状态栏高度 119 | */ 120 | public int getBarHeight(Context context) { 121 | int barHeight = -1; 122 | 123 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { 124 | barHeight = 0; 125 | } 126 | 127 | if (barHeight == -1) { 128 | Class> c = null; 129 | Object obj = null; 130 | Field field = null; 131 | int x = 0; 132 | 133 | try { 134 | c = Class.forName("com.android.internal.R$dimen"); 135 | obj = c.newInstance(); 136 | field = c.getField("status_bar_height"); 137 | x = Integer.parseInt(field.get(obj).toString()); 138 | barHeight = context.getResources().getDimensionPixelSize(x); 139 | 140 | } catch (Exception e1) { 141 | e1.printStackTrace(); 142 | return 0; 143 | } 144 | } 145 | return barHeight; 146 | } 147 | 148 | //============================================================================================== 149 | //======================= 以 下 是 关 于 手 势 右 滑 关 闭 ======================================== 150 | //============================================================================================== 151 | 152 | /** 153 | * 绑定手势 154 | */ 155 | public boolean dispatchTouchEvent(MotionEvent ev) { 156 | if (null != mUtilGesture && mUtilGesture.motionEvent(ev)) { 157 | return true; 158 | } 159 | return super.dispatchTouchEvent(ev); 160 | } 161 | 162 | /** 163 | * 开启滑动关闭界面 164 | * 165 | * @param open 166 | */ 167 | protected void openSlideFinish(boolean open) { 168 | if (mUtilGesture == null) { 169 | return; 170 | } 171 | mUtilGesture.openSlideFinish(open); 172 | } 173 | 174 | /** 175 | * 抬起关闭 176 | * 177 | * @param upFinish 【true:手指抬起后再关闭页面】 178 | * 【false:进度条圆满就立刻关闭页面】 179 | */ 180 | public void setUpFinish(boolean upFinish) { 181 | if (mUtilGesture == null) { 182 | return; 183 | } 184 | mUtilGesture.setUpFinish(upFinish); 185 | } 186 | 187 | /** 188 | * 设置进度条颜色 189 | */ 190 | public void setProgressColor(int color) { 191 | if (mUtilGesture != null) 192 | mUtilGesture.setProgressColor(color); 193 | } 194 | 195 | /** 196 | * 滑动View 197 | * 【滑动过程中会移动的View】 198 | */ 199 | public void setMoveView(View SlideView) { 200 | mUtilGesture.setRootView(SlideView); 201 | } 202 | 203 | //============================================================================================== 204 | //======================= 以 下 是 关 于 界 面 跳 转 动 画 ======================================== 205 | //============================================================================================== 206 | 207 | /** 208 | * 打开新Activity 209 | * 210 | * @param intent intent 211 | */ 212 | public void startActivity(Intent intent) { 213 | startActivity(intent, true); 214 | } 215 | 216 | /** 217 | * 打开新Activity 218 | * 219 | * @param intent intent 220 | * @param animIn 新Activity进入的动画 221 | * @param animOut 当前Activity退出的动画 222 | */ 223 | public void startActivity(Intent intent, int animIn, int animOut) { 224 | super.startActivity(intent); 225 | overridePendingTransition(animIn, animOut); 226 | } 227 | 228 | /** 229 | * 打开新的Activity 230 | * 231 | * @param intent intent 232 | * @param isAnim 是否开启过渡动画 233 | */ 234 | public void startActivity(Intent intent, boolean isAnim) { 235 | if (isAnim) { 236 | startActivity(intent, R.anim.act_right_in, R.anim.act_left_out); 237 | } else { 238 | super.startActivity(intent); 239 | } 240 | } 241 | 242 | 243 | @Override 244 | public void finish() { 245 | finish(true); 246 | } 247 | 248 | /** 249 | * 退出Activity 250 | * 251 | * @param animIn 老Activity进入的动画 252 | * @param animOut 当前Activity退出的动画 253 | */ 254 | public void finish(int animIn, int animOut) { 255 | super.finish(); 256 | if (false == this instanceof MainActivity) 257 | overridePendingTransition(animIn, animOut); 258 | } 259 | 260 | /** 261 | * 退出Activity 262 | * 263 | * @param isAnim 是否开启过渡动画 264 | */ 265 | public void finish(boolean isAnim) { 266 | if (isAnim) { 267 | finish(R.anim.act_left_in, R.anim.act_right_out); 268 | } else { 269 | super.finish(); 270 | } 271 | } 272 | } 273 | -------------------------------------------------------------------------------- /app/src/main/java/com/bamboy/slidingshut/baseactivity/BamFragmentActivity.java: -------------------------------------------------------------------------------- 1 | package com.bamboy.slidingshut.baseactivity; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.graphics.Color; 6 | import android.os.Build; 7 | import android.support.v4.app.FragmentActivity; 8 | import android.view.MotionEvent; 9 | import android.view.View; 10 | import android.view.Window; 11 | import android.view.WindowManager; 12 | import android.widget.ImageView; 13 | import android.widget.RelativeLayout; 14 | 15 | import com.bamboy.slidingshut.R; 16 | 17 | import java.lang.reflect.Field; 18 | 19 | /** 20 | * Created by Bamboy on 2018/10/24. 21 | */ 22 | public class BamFragmentActivity extends FragmentActivity { 23 | /** 24 | * 触摸工具类 25 | */ 26 | private UtilBaseGesture mUtilGesture; 27 | /** 28 | * 标题栏 29 | */ 30 | protected RelativeLayout rl_title; 31 | /** 32 | * 标题栏关闭箭头 33 | */ 34 | protected ImageView iv_back; 35 | 36 | @Override 37 | public void setContentView(int layoutResID) { 38 | super.setContentView(layoutResID); 39 | 40 | rl_title = findViewById(R.id.rl_title); 41 | iv_back = findViewById(R.id.iv_back); 42 | 43 | /** 44 | * 如果是Android 4.4 以上,就兼容沉浸式 45 | */ 46 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 47 | try { 48 | // 初始化状态栏 49 | setImmerseTitleBar(); 50 | } catch (Exception e) { 51 | e.printStackTrace(); 52 | } 53 | } 54 | 55 | // 设置返回按钮点击事件 56 | if (iv_back != null) { 57 | iv_back.setOnClickListener(new View.OnClickListener() { 58 | @Override 59 | public void onClick(View view) { 60 | finish(); 61 | } 62 | }); 63 | } 64 | // 手势工具类 65 | mUtilGesture = new UtilBaseGesture(this); 66 | } 67 | 68 | //============================================================================================== 69 | //======================= 以 下 是 关 于 沉 浸 式 状 态 栏 ======================================== 70 | //============================================================================================== 71 | 72 | /** 73 | * 设置沉浸TitleBar 74 | */ 75 | private void setImmerseTitleBar() { 76 | 77 | 78 | Window window = getWindow(); 79 | window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, 80 | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 81 | 82 | // Android 7.0以上 去除状态栏半透明底色 83 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 84 | try { 85 | Class decorViewClazz = Class.forName("com.android.internal.policy.DecorView"); 86 | Field field = decorViewClazz.getDeclaredField("mSemiTransparentStatusBarColor"); 87 | field.setAccessible(true); 88 | field.setInt(window.getDecorView(), Color.TRANSPARENT); //改为透明 89 | } catch (Exception e) { 90 | e.printStackTrace(); 91 | } catch (Error e) { 92 | e.printStackTrace(); 93 | } 94 | } 95 | 96 | if (rl_title == null) { 97 | return; 98 | } 99 | 100 | int barHeight = getBarHeight(this); 101 | View fillingView = rl_title.findViewById(R.id.view_filling); 102 | if (barHeight <= 0 || fillingView == null) { 103 | return; 104 | } 105 | 106 | if (rl_title instanceof RelativeLayout) { 107 | fillingView.setLayoutParams( 108 | new RelativeLayout.LayoutParams(1, barHeight)); 109 | } 110 | } 111 | 112 | /** 113 | * 获取状态栏高度 114 | * 115 | * @param context 116 | * @return 状态栏高度 117 | */ 118 | public int getBarHeight(Context context) { 119 | int barHeight = -1; 120 | 121 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { 122 | barHeight = 0; 123 | } 124 | 125 | if (barHeight == -1) { 126 | Class> c = null; 127 | Object obj = null; 128 | Field field = null; 129 | int x = 0; 130 | 131 | try { 132 | c = Class.forName("com.android.internal.R$dimen"); 133 | obj = c.newInstance(); 134 | field = c.getField("status_bar_height"); 135 | x = Integer.parseInt(field.get(obj).toString()); 136 | barHeight = context.getResources().getDimensionPixelSize(x); 137 | 138 | } catch (Exception e1) { 139 | e1.printStackTrace(); 140 | return 0; 141 | } 142 | } 143 | return barHeight; 144 | } 145 | 146 | //============================================================================================== 147 | //======================= 以 下 是 关 于 手 势 右 滑 关 闭 ======================================== 148 | //============================================================================================== 149 | 150 | /** 151 | * 绑定手势 152 | */ 153 | public boolean dispatchTouchEvent(MotionEvent ev) { 154 | if (null != mUtilGesture && mUtilGesture.motionEvent(ev)) { 155 | return true; 156 | } 157 | return super.dispatchTouchEvent(ev); 158 | } 159 | 160 | /** 161 | * 开启滑动关闭界面 162 | * 163 | * @param open 164 | */ 165 | protected void openSlideFinish(boolean open) { 166 | if (mUtilGesture == null) { 167 | return; 168 | } 169 | mUtilGesture.openSlideFinish(open); 170 | } 171 | 172 | /** 173 | * 抬起关闭 174 | * 175 | * @param upFinish 【true:手指抬起后再关闭页面】 176 | * 【false:进度条圆满就立刻关闭页面】 177 | */ 178 | public void setUpFinish(boolean upFinish) { 179 | if (mUtilGesture == null) { 180 | return; 181 | } 182 | mUtilGesture.setUpFinish(upFinish); 183 | } 184 | 185 | /** 186 | * 设置进度条颜色 187 | */ 188 | public void setProgressColor(int color) { 189 | if (mUtilGesture != null) 190 | mUtilGesture.setProgressColor(color); 191 | } 192 | 193 | /** 194 | * 滑动View 195 | * 【滑动过程中会移动的View】 196 | */ 197 | public void setMoveView(View SlideView) { 198 | mUtilGesture.setRootView(SlideView); 199 | } 200 | 201 | //============================================================================================== 202 | //======================= 以 下 是 关 于 界 面 跳 转 动 画 ======================================== 203 | //============================================================================================== 204 | 205 | /** 206 | * 打开新Activity 207 | * 208 | * @param intent intent 209 | */ 210 | public void startActivity(Intent intent) { 211 | startActivity(intent, true); 212 | } 213 | 214 | /** 215 | * 打开新Activity 216 | * 217 | * @param intent intent 218 | * @param animIn 新Activity进入的动画 219 | * @param animOut 当前Activity退出的动画 220 | */ 221 | public void startActivity(Intent intent, int animIn, int animOut) { 222 | super.startActivity(intent); 223 | overridePendingTransition(animIn, animOut); 224 | } 225 | 226 | /** 227 | * 打开新的Activity 228 | * 229 | * @param intent intent 230 | * @param isAnim 是否开启过渡动画 231 | */ 232 | public void startActivity(Intent intent, boolean isAnim) { 233 | if (isAnim) { 234 | startActivity(intent, R.anim.act_right_in, R.anim.act_left_out); 235 | } else { 236 | super.startActivity(intent); 237 | } 238 | } 239 | 240 | 241 | @Override 242 | public void finish() { 243 | finish(true); 244 | } 245 | 246 | /** 247 | * 退出Activity 248 | * 249 | * @param animIn 老Activity进入的动画 250 | * @param animOut 当前Activity退出的动画 251 | */ 252 | public void finish(int animIn, int animOut) { 253 | super.finish(); 254 | overridePendingTransition(animIn, animOut); 255 | } 256 | 257 | /** 258 | * 退出Activity 259 | * 260 | * @param isAnim 是否开启过渡动画 261 | */ 262 | public void finish(boolean isAnim) { 263 | if (isAnim) { 264 | finish(R.anim.act_left_in, R.anim.act_right_out); 265 | } else { 266 | super.finish(); 267 | } 268 | } 269 | } 270 | -------------------------------------------------------------------------------- /app/src/main/java/com/bamboy/slidingshut/baseactivity/SlopeProgress.java: -------------------------------------------------------------------------------- 1 | package com.bamboy.slidingshut.baseactivity; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Paint; 6 | import android.graphics.RectF; 7 | import android.support.annotation.Nullable; 8 | import android.support.v4.content.ContextCompat; 9 | import android.util.AttributeSet; 10 | import android.view.View; 11 | 12 | import com.bamboy.slidingshut.R; 13 | 14 | /** 15 | * 圆形进度条 16 | *
17 | * Created by Bamboy on 2018/10/18. 18 | */ 19 | public class SlopeProgress extends View { 20 | /** 21 | * 当前进度 22 | */ 23 | private int progress = 0; 24 | /** 25 | * 总进度 26 | */ 27 | private int maxProgress = 100; 28 | /** 29 | * 圆环颜色 30 | */ 31 | private int ringColor; 32 | /** 33 | * 直径 34 | */ 35 | private float diam = 100; 36 | /** 37 | * 线条 38 | */ 39 | private float line = 13; 40 | 41 | public SlopeProgress(Context context) { 42 | super(context); 43 | 44 | ringColor = ContextCompat.getColor(context, R.color.colorPrimary); 45 | } 46 | 47 | @Override 48 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 49 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 50 | int width = getMeasuredWidth(); 51 | int height = getMeasuredHeight(); 52 | 53 | int diameter = Math.min(width, height); 54 | 55 | line = diameter * 0.13f; 56 | diam = diameter - line * 2; 57 | } 58 | 59 | @Override 60 | protected void onDraw(Canvas canvas) { 61 | super.onDraw(canvas); 62 | 63 | int width = getMeasuredWidth(); 64 | int height = getMeasuredHeight(); 65 | float length = Math.min(width, height); 66 | 67 | // =============== 声明画笔 =============== 68 | // 初始化画笔 69 | Paint ringPaint = new Paint(); 70 | // 设置消除锯齿 71 | ringPaint.setAntiAlias(true); 72 | // 设置防抖,即边缘柔化 73 | ringPaint.setDither(true); 74 | // 设置颜色 75 | ringPaint.setColor(ringColor); 76 | // 设置实心 77 | ringPaint.setStyle(Paint.Style.STROKE); 78 | // 设置画笔的宽度 79 | ringPaint.setStrokeWidth(line); 80 | // 设置线条圆角 81 | ringPaint.setStrokeCap(Paint.Cap.ROUND); 82 | 83 | // =============== 画圆环 =============== 84 | // 进度 85 | float pro = (float) progress / (float) maxProgress; 86 | // 旋转角度 87 | float startAngle = 180 - (pro * 180); 88 | // 圆环进度 89 | float sweepAngle = pro * 360; 90 | // 计算内边距 91 | int padding = (int) ((length - diam) / 2); 92 | RectF oval = new RectF(padding, padding, padding + diam, padding + diam); 93 | 94 | // 绘制圆圈 95 | canvas.drawArc(oval, startAngle, sweepAngle, false, ringPaint); 96 | 97 | 98 | // =============== 画叉号 =============== 99 | // 修改透明度 100 | ringPaint.setAlpha(pro == 1 ? 255 : (int) (pro / 2.5 * 255)); 101 | // 修改画笔的宽度 102 | ringPaint.setStrokeWidth(line * 0.7f); 103 | 104 | // 线距离边缘的距离,值越小,叉号越大,值范围在 0 ~ 0.5 之间 105 | float linePadding = 0.373f; 106 | 107 | // 第一根直线的【起点/终点】坐标 108 | float lineStartX_1 = length * linePadding; 109 | float lineStartY_1 = length * linePadding; 110 | float lineEndX_1 = length * (1 - linePadding); 111 | float lineEndY_1 = length * (1 - linePadding); 112 | 113 | // 第二根直线的【起点/终点】坐标 114 | float lineStartX_2 = length * linePadding; 115 | float lineStartY_2 = length * (1 - linePadding); 116 | float lineEndX_2 = length * (1 - linePadding); 117 | float lineEndY_2 = length * linePadding; 118 | 119 | // 绘制直线 120 | canvas.drawLines(new float[]{ 121 | // 绘制一根直线 每四数字(两个点的坐标)确定一条线 122 | lineStartX_1, lineStartY_1, lineEndX_1, lineEndY_1, 123 | // 绘制第二根直线 每四数字(两个点的坐标)确定一条线 124 | lineStartX_2, lineStartY_2, lineEndX_2, lineEndY_2 125 | }, ringPaint); 126 | } 127 | 128 | /** 129 | * 总进度 130 | */ 131 | public int getMaxProgress() { 132 | return maxProgress; 133 | } 134 | 135 | /** 136 | * 总进度 137 | */ 138 | public void setMaxProgress(int maxProgress) { 139 | this.maxProgress = maxProgress; 140 | } 141 | 142 | /** 143 | * 设置颜色 144 | */ 145 | public void setRingColor(int ringColor) { 146 | if (ringColor != 0) 147 | this.ringColor = ringColor; 148 | } 149 | 150 | /** 151 | * 线条 152 | */ 153 | public float getLine() { 154 | return line; 155 | } 156 | 157 | /** 158 | * 线条 159 | */ 160 | public void setLine(float line) { 161 | this.line = line; 162 | } 163 | 164 | /** 165 | * 获取当前进度 166 | * 167 | * @return 168 | */ 169 | public int getProgress() { 170 | return progress; 171 | } 172 | 173 | /** 174 | * 设置进度 175 | * 176 | * @param progress 177 | */ 178 | public void setProgress(int progress) { 179 | if (progress < 0) { 180 | progress = 0; 181 | } 182 | if (progress > maxProgress) { 183 | progress = maxProgress; 184 | } 185 | 186 | this.progress = progress; 187 | invalidate(); 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /app/src/main/java/com/bamboy/slidingshut/baseactivity/UtilBaseGesture.java: -------------------------------------------------------------------------------- 1 | package com.bamboy.slidingshut.baseactivity; 2 | 3 | import android.animation.Animator; 4 | import android.animation.AnimatorListenerAdapter; 5 | import android.animation.ObjectAnimator; 6 | import android.app.Activity; 7 | import android.os.Build; 8 | import android.view.MotionEvent; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | 12 | /** 13 | * BamActivity触摸工具类 14 | *
15 | * Created by Bamboy on 2018/10/24. 16 | */ 17 | public class UtilBaseGesture { 18 | 19 | /** 20 | * 起始触点的X轴范围 21 | * 大于这个范围则不会触发右滑关闭 22 | */ 23 | public final static int SLIDE_SCREEN_WIDTH_SCALE = 30; 24 | 25 | private Activity mActivity; 26 | /** 27 | * 屏幕宽度 28 | */ 29 | private int mScreenWidth; 30 | /** 31 | * 滑动起点 32 | */ 33 | private int startSlidingX; 34 | /** 35 | * 界面移动距离 36 | */ 37 | private int move; 38 | /** 39 | * 移动最大值 40 | */ 41 | private int maxMove; 42 | /** 43 | * 移动与滑动的比例 44 | * 同样滑动距离的情况下,比例越大,界面移动越小 45 | */ 46 | private float moveScaling; 47 | 48 | /** 49 | * Activity的Layout的容器 50 | */ 51 | private ViewGroup rootGroup; 52 | /** 53 | * Activity的Layout的根View 54 | * 【滑动过程中会移动的View】 55 | */ 56 | private View rootView; 57 | /** 58 | * 滑动进度条 59 | */ 60 | private SlopeProgress mProgress; 61 | /** 62 | * 进度条宽度 63 | */ 64 | private int progressWidth; 65 | 66 | /** 67 | * 滑动关闭开关 68 | */ 69 | private boolean slideOpen = true; 70 | /** 71 | * 抬起关闭 72 | * 【true:手指抬起后再关闭页面】 73 | * 【false:进度条圆满就立刻关闭页面】 74 | */ 75 | private boolean upFinish = true; 76 | 77 | /** 78 | * 构造 79 | * 80 | * @param activity 81 | */ 82 | public UtilBaseGesture(Activity activity) { 83 | this.mActivity = activity; 84 | 85 | // 获取根布局,用于右滑关闭 86 | rootGroup = activity.findViewById(android.R.id.content); 87 | rootView = rootGroup.getChildAt(0); 88 | 89 | int width = activity.getWindowManager().getDefaultDisplay().getWidth(); 90 | int height = activity.getWindowManager().getDefaultDisplay().getHeight(); 91 | 92 | mScreenWidth = Math.min(width, height); 93 | maxMove = (int) (mScreenWidth * 0.06); 94 | moveScaling = 0.2f; 95 | progressWidth = mScreenWidth / 9; 96 | } 97 | 98 | /** 99 | * 初始化进度条 100 | */ 101 | private void initProgress() { 102 | mProgress = new SlopeProgress(mActivity); 103 | mProgress.setMaxProgress(100); 104 | 105 | ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(progressWidth, progressWidth); 106 | mProgress.setLayoutParams(params); 107 | 108 | if (rootGroup != null) 109 | rootGroup.addView(mProgress); 110 | } 111 | 112 | //============================================================================================== 113 | //======================= 以 下 是 关 于 属 性 方 法 ============================================= 114 | //============================================================================================== 115 | 116 | /** 117 | * 开启滑动关闭界面 118 | * 119 | * @param open 120 | */ 121 | public void openSlideFinish(boolean open) { 122 | slideOpen = open; 123 | } 124 | 125 | /** 126 | * 抬起关闭 127 | * 128 | * @param upFinish 【true:手指抬起后再关闭页面】 129 | * 【false:进度条圆满就立刻关闭页面】 130 | */ 131 | public void setUpFinish(boolean upFinish) { 132 | this.upFinish = upFinish; 133 | } 134 | 135 | /** 136 | * Activity的Layout的根View 137 | * 【滑动过程中会移动的View】 138 | */ 139 | public void setRootView(View rootView) { 140 | this.rootView = rootView; 141 | } 142 | 143 | /** 144 | * 获取移动距离 145 | * 146 | * @return 147 | */ 148 | public int getMove() { 149 | return move; 150 | } 151 | 152 | /** 153 | * 设置进度条颜色 154 | */ 155 | public void setProgressColor(int color) { 156 | if (mProgress == null) 157 | initProgress(); 158 | 159 | if (mProgress != null) 160 | mProgress.setRingColor(color); 161 | } 162 | 163 | /** 164 | * 设置移动距离 165 | * 166 | * @param move 167 | */ 168 | public void setMove(int move) { 169 | 170 | if (move > maxMove) 171 | move = (int) (maxMove + (move - maxMove) * 0.5f); 172 | 173 | rootView.setX(move); 174 | this.move = move; 175 | 176 | if (move > maxMove) 177 | move = maxMove; 178 | 179 | // 更新进度条 180 | mProgress.setProgress((int) (101 * ((float) move / (float) maxMove))); 181 | 182 | // 判断是否关闭Activity 183 | if (false == upFinish && mProgress.getProgress() >= mProgress.getMaxProgress()) { 184 | finish(); 185 | } 186 | } 187 | 188 | //============================================================================================== 189 | //======================= 以 下 是 关 于 手 势 触 摸 计 算 ======================================== 190 | //============================================================================================== 191 | 192 | /** 193 | * 处理触摸事件 194 | * 195 | * @param motionEvent 触摸事件 196 | */ 197 | public boolean motionEvent(MotionEvent motionEvent) { 198 | if (false == slideOpen) { 199 | return false; 200 | } 201 | try { 202 | // 触摸监听,用于监听手指运动 203 | switch (motionEvent.getAction()) { 204 | // 手指按下 205 | case MotionEvent.ACTION_DOWN: 206 | return actionDown(motionEvent); 207 | 208 | // 手指移动 209 | case MotionEvent.ACTION_MOVE: 210 | return actionMove(motionEvent); 211 | 212 | // 手指抬起 213 | case MotionEvent.ACTION_UP: 214 | return actionUp(motionEvent); 215 | 216 | default: 217 | break; 218 | } 219 | } catch (Exception e) { 220 | e.printStackTrace(); 221 | } 222 | return false; 223 | } 224 | 225 | /** 226 | * 手指按下 227 | * 228 | * @param motionEvent 229 | * @return 230 | */ 231 | private boolean actionDown(MotionEvent motionEvent) { 232 | // 计算X轴 233 | startSlidingX = (int) motionEvent.getX(); 234 | if (false == slideOpen || 235 | rootView == null || 236 | startSlidingX > mScreenWidth / SLIDE_SCREEN_WIDTH_SCALE) { 237 | return false; 238 | } 239 | 240 | // 添加进度条 241 | if (mProgress == null) { 242 | // 初始化进度条 243 | initProgress(); 244 | } 245 | 246 | // 设置背景色 247 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && rootView.getBackground() != null) { 248 | rootGroup.setBackground(rootView.getBackground()); 249 | } 250 | 251 | return true; 252 | } 253 | 254 | /** 255 | * 手指移动 256 | * 257 | * @param motionEvent 258 | * @return 259 | */ 260 | private boolean actionMove(MotionEvent motionEvent) { 261 | float nowX = motionEvent.getX(); 262 | if (false == slideOpen || 263 | rootView == null || 264 | startSlidingX > mScreenWidth / SLIDE_SCREEN_WIDTH_SCALE) { 265 | return false; 266 | } 267 | 268 | // 计算滑动距离 269 | float nowMove = (int) ((nowX > startSlidingX ? nowX - startSlidingX : 0) * moveScaling); 270 | 271 | // 更新移动位置 272 | setMove((int) nowMove); 273 | 274 | // 进度条的Y轴跟随手指, 275 | // 这里减去(mProgress.getHeight() * 0.7f) 276 | // 是因为手指触摸时实际触点和视觉触点不一致,所以要减小这个视觉误差 277 | mProgress.setTranslationY(motionEvent.getY() - mProgress.getHeight() * 0.7f); 278 | return true; 279 | } 280 | 281 | /** 282 | * 手指抬起 283 | * 284 | * @param motionEvent 285 | * @return 286 | */ 287 | private boolean actionUp(MotionEvent motionEvent) { 288 | if (false == slideOpen 289 | || rootView == null 290 | || rootView.getX() == 0 291 | || startSlidingX == mScreenWidth) 292 | return false; 293 | 294 | // 判断是否关闭Activity 295 | if (upFinish && mProgress.getProgress() >= mProgress.getMaxProgress()) { 296 | finish(); 297 | } else { 298 | ObjectAnimator.ofInt(this, "move", getMove(), 0).setDuration(200).start(); 299 | } 300 | return true; 301 | } 302 | 303 | private void finish() { 304 | slideOpen = false; 305 | startSlidingX = mScreenWidth; 306 | ObjectAnimator anim = ObjectAnimator.ofInt(this, "move", getMove(), 0); 307 | anim.setStartDelay(100); 308 | anim.setDuration(200); 309 | anim.addListener(new AnimatorListenerAdapter() { 310 | @Override 311 | public void onAnimationEnd(Animator animation) { 312 | super.onAnimationEnd(animation); 313 | 314 | slideOpen = true; 315 | } 316 | }); 317 | anim.start(); 318 | 319 | mActivity.finish(); 320 | } 321 | } 322 | -------------------------------------------------------------------------------- /app/src/main/res/anim/act_left_in.xml: -------------------------------------------------------------------------------- 1 | 2 |