├── .gitignore
├── README.md
├── build.gradle
├── edgeslidingback.iml
├── gif
├── 2017-06-04_20_09_56.gif
└── 2017-06-04_20_28_44.gif
├── proguard-rules.pro
└── src
└── main
├── AndroidManifest.xml
├── java
└── com
│ └── geejoe
│ └── edgeslidingback
│ ├── EdgeSlidingBackActivity.java
│ ├── EdgeSlidingBackFragment.java
│ └── EdgeSlidingBackLayout.java
└── res
├── anim
├── anim_slide_in.xml
└── anim_slide_out.xml
├── drawable
└── left_shadow.xml
└── values
├── strings.xml
└── styles.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # EdgeSlidingBack
2 | An Android library help app with edge sliding back like ios
3 |
4 | [  ](https://bintray.com/geejoe/maven/edgeslidingback/_latestVersion)
5 |
6 | ## 简介
7 |
8 | 这是一个仿ios边缘右滑返回的库,效果见动图:
9 |
10 | ### 普通Activity,内有一个TextView
11 | 
12 |
13 | ### 含有ListView和ViewPager的Activity
14 | 
15 |
16 | ## 依赖
17 |
18 | 本项目已同步到Jcenter,可直接引用依赖:
19 | ```Java
20 | compile 'com.geejoe:edgeslidingback:1.0.7'
21 | ```
22 |
23 | ## 使用方法
24 |
25 | 所有需要使用滑动返回的Activity须继承自EdgeSlidingBackActivity
26 | 需要关闭右滑返回可以在Activity的super.onCreate()方法之前执行setEnableSlidingBack(false);
27 |
28 | 另需要设置主题@style/AppTheme.Slide以便滑动时使下层Activity可见
29 | 此外还提供了无ActionBar的主题@style/AppTheme.Slide.NoActionBar:
30 |
31 | 例,如下设置:不需要使用滑动返回的Activity(如MainActivity),则单独设置主题
32 |
33 | ```xml
34 |
40 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | ```
50 |
51 | #### 重写Activity的onSlidingBack()方法,处理滑动返回销毁Activity前的工作,例如需要setResult、释放资源等工作
52 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 26
5 | buildToolsVersion '26.0.2'
6 |
7 | defaultConfig {
8 | minSdkVersion 19
9 | targetSdkVersion 26
10 | versionCode 1
11 | versionName "1.0"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | compileOptions {
20 | encoding "UTF-8"
21 | }
22 | }
23 |
24 | dependencies {
25 | compile fileTree(dir: 'libs', include: ['*.jar'])
26 | compile 'com.android.support:appcompat-v7:26.1.0'
27 | }
28 |
29 | ext {
30 | bintrayRepo = 'maven'
31 | bintrayName = 'edgeslidingback'
32 |
33 | publishedGroupId = 'com.geejoe'
34 | libraryName = 'EdgeSlidingBack'
35 | artifact = 'edgeslidingback'
36 |
37 | libraryDescription = 'An Android library help app with edge sliding back like ios'
38 |
39 | siteUrl = 'https://github.com/GeeJoe/EdgeSlidingBack'
40 | gitUrl = 'https://github.com/GeeJoe/EdgeSlidingBack.git'
41 |
42 | libraryVersion = '1.0.7'
43 |
44 | developerId = 'geejoe'
45 | developerName = 'GeeJoe'
46 | developerEmail = 'geejoe_developer@outlook.com'
47 |
48 | licenseName = 'The Apache Software License, Version 2.0'
49 | licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
50 | allLicenses = ["Apache-2.0"]
51 | }
52 |
53 | apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/installv1.gradle'
54 | apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/bintrayv1.gradle'
--------------------------------------------------------------------------------
/edgeslidingback.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | generateDebugSources
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 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
--------------------------------------------------------------------------------
/gif/2017-06-04_20_09_56.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeeJoe/EdgeSlidingBack/8e795297a92def288f74390c1e89592775c5ee37/gif/2017-06-04_20_09_56.gif
--------------------------------------------------------------------------------
/gif/2017-06-04_20_28_44.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeeJoe/EdgeSlidingBack/8e795297a92def288f74390c1e89592775c5ee37/gif/2017-06-04_20_28_44.gif
--------------------------------------------------------------------------------
/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in C:\MyPrograms\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/main/java/com/geejoe/edgeslidingback/EdgeSlidingBackActivity.java:
--------------------------------------------------------------------------------
1 | package com.geejoe.edgeslidingback;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v7.app.AppCompatActivity;
6 |
7 | /**
8 | * Created by JoeLee on 2017/6/3 0003 09:02.
9 | */
10 |
11 | public class EdgeSlidingBackActivity extends AppCompatActivity implements EdgeSlidingBackLayout.OnSlidingBackListener{
12 |
13 | private boolean enableSlidingBack = true;
14 |
15 | @Override
16 | protected void onCreate(@Nullable Bundle savedInstanceState) {
17 | super.onCreate(savedInstanceState);
18 | if (enableSlidingBack) {
19 | EdgeSlidingBackLayout edgeSlidingBackLayout = new EdgeSlidingBackLayout(this);
20 | edgeSlidingBackLayout.bindActivity(this);
21 | }
22 | }
23 |
24 | protected void setEnableSlidingBack(boolean enableSlidingBack) {
25 | this.enableSlidingBack = enableSlidingBack;
26 | }
27 |
28 | @Override
29 | public void onSlidingBack() {
30 |
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/com/geejoe/edgeslidingback/EdgeSlidingBackFragment.java:
--------------------------------------------------------------------------------
1 | package com.geejoe.edgeslidingback;
2 |
3 | import android.support.v4.app.Fragment;
4 |
5 | /**
6 | * Created by JoeLee on 2017/6/3 0003 09:02.
7 | */
8 |
9 | public class EdgeSlidingBackFragment extends Fragment {
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/com/geejoe/edgeslidingback/EdgeSlidingBackLayout.java:
--------------------------------------------------------------------------------
1 | package com.geejoe.edgeslidingback;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.drawable.Drawable;
6 | import android.support.v4.view.VelocityTrackerCompat;
7 | import android.util.AttributeSet;
8 | import android.util.DisplayMetrics;
9 | import android.util.Log;
10 | import android.view.MotionEvent;
11 | import android.view.VelocityTracker;
12 | import android.view.View;
13 | import android.view.ViewConfiguration;
14 | import android.view.ViewGroup;
15 | import android.view.Window;
16 | import android.widget.FrameLayout;
17 | import android.widget.Scroller;
18 |
19 | /**
20 | * Created by JoeLee on 2017/6/3 0003 09:00.
21 | */
22 |
23 | public class EdgeSlidingBackLayout extends FrameLayout {
24 |
25 | private EdgeSlidingBackActivity mActivity;
26 | private EdgeSlidingBackFragment mFragment;
27 |
28 | private Scroller mScroller;
29 |
30 | private int mScreenWidth;
31 | //可滑动返回的操作区域宽度
32 | private int mTouchAreaWidth;
33 | //有效滑动距离
34 | private int mTouchSlope;
35 |
36 | //解决滑动冲突
37 | private int mLastX;
38 | private int mLastY;
39 | private int mActionDownX;
40 |
41 | private VelocityTracker vt;
42 | private int mPointedId;
43 | private float mVelocityX;
44 | private float mMinVelocity;
45 |
46 | private Drawable mShadow;
47 | private int mShadowWidth;
48 |
49 | public EdgeSlidingBackLayout(Context context) {
50 | this(context, null, 0);
51 | }
52 |
53 | public EdgeSlidingBackLayout(Context context, AttributeSet attrs) {
54 | this(context, attrs, 0);
55 | }
56 |
57 | public EdgeSlidingBackLayout(Context context, AttributeSet attrs, int defStyleAttr) {
58 | super(context, attrs, defStyleAttr);
59 | init(context);
60 | }
61 |
62 | private void init(Context context) {
63 | mScroller = new Scroller(context);
64 | DisplayMetrics dm = context.getResources().getDisplayMetrics();
65 | mMinVelocity = (5000 * 440) / dm.densityDpi;
66 | mScreenWidth = dm.widthPixels;
67 | //屏幕宽度的十二分之一作为可滑动返回的操作区域宽度
68 | mTouchAreaWidth = mScreenWidth / 12;
69 | mTouchSlope = ViewConfiguration.get(context).getScaledTouchSlop();
70 | mShadow = context.getResources().getDrawable(R.drawable.left_shadow);
71 | mShadowWidth = (int) context.getResources().getDisplayMetrics().density * 16;
72 | }
73 |
74 | public void bindActivity(EdgeSlidingBackActivity activity) {
75 | this.mActivity = activity;
76 | //将EdgeSlidingBackLayout作为DecorView的唯一子布局
77 | Window window = mActivity.getWindow();
78 | ViewGroup decorView = (ViewGroup) window.getDecorView();
79 | View rootView = decorView.getChildAt(0);
80 | decorView.removeView(rootView);
81 | addView(rootView);
82 | decorView.addView(this);
83 | }
84 |
85 | public void bindFrgment(EdgeSlidingBackFragment fragment) {
86 | this.mFragment = fragment;
87 | // TODO
88 | }
89 |
90 | @Override
91 | public boolean onInterceptTouchEvent(MotionEvent ev) {
92 | boolean intercept = false;
93 | int x = (int) ev.getX();
94 | int y = (int) ev.getY();
95 | switch (ev.getAction()) {
96 | case MotionEvent.ACTION_DOWN:
97 | mActionDownX = (int) ev.getX();
98 | mLastX = x;
99 | mLastY = y;
100 | break;
101 | case MotionEvent.ACTION_MOVE:
102 | int deltaX = x - mLastX;
103 | int deltaY = y - mLastY;
104 | if (mActionDownX < mTouchAreaWidth && deltaX > mTouchSlope
105 | && Math.abs(deltaX) > Math.abs(deltaY)) {
106 | intercept = true;
107 | }
108 | break;
109 | case MotionEvent.ACTION_UP:
110 | intercept = false;
111 | break;
112 | }
113 | return intercept;
114 | }
115 |
116 | @Override
117 | public boolean onTouchEvent(MotionEvent event) {
118 | if (vt == null) {
119 | vt = VelocityTracker.obtain();
120 | }
121 | vt.addMovement(event);
122 | int x = (int) event.getX();
123 | int y = (int) event.getY();
124 | switch (event.getAction()) {
125 | case MotionEvent.ACTION_DOWN:
126 | mPointedId = event.getPointerId(0);
127 | mLastX = x;
128 | mLastY = y;
129 | break;
130 | case MotionEvent.ACTION_MOVE:
131 | vt.computeCurrentVelocity(1000);
132 | mVelocityX = VelocityTrackerCompat.getXVelocity(vt, mPointedId);
133 | int deltaX = x - mLastX;
134 | int deltaY = y - mLastY;
135 | if (mActionDownX < mTouchAreaWidth
136 | && Math.abs(deltaX) > Math.abs(deltaY)) {
137 | int moveX = -deltaX;
138 | if (-getScrollX() < 0) {
139 | scrollTo(0, 0);
140 | } else {
141 | scrollBy(moveX, 0);
142 | }
143 | }
144 | mLastX = x;
145 | mLastY = y;
146 | break;
147 | case MotionEvent.ACTION_UP:
148 | Log.d("EdgeSlidingBackLayout", "onTouchEvent()@EdgeSlidingBackLayout.java:144-->>" + "mVelocityX:" + mVelocityX);
149 | if (mVelocityX > mMinVelocity || -getScrollX() > mScreenWidth / 3) {
150 | scrollRightOut();
151 | } else {
152 | scrollResume();
153 | }
154 | break;
155 | }
156 | return true;
157 | }
158 |
159 | private void scrollResume() {
160 | int startX = getScrollX();
161 | int distance = -getScrollX();
162 | mScroller.startScroll(startX, 0, distance, 0, 300);
163 | invalidate();
164 | }
165 |
166 | private void scrollRightOut() {
167 | int startX = getScrollX();
168 | int distance = -mScreenWidth - startX;
169 | mScroller.startScroll(startX, 0, distance, 0, 300);
170 | invalidate();
171 | }
172 |
173 | @Override
174 | public void computeScroll() {
175 | if (mScroller.computeScrollOffset()) {
176 | scrollTo(mScroller.getCurrX(), 0);
177 | postInvalidate();
178 | } else if (-getScrollX() >= getWidth()) {
179 | //
180 | mActivity.onSlidingBack();
181 | mActivity.finish();
182 | mActivity.overridePendingTransition(R.anim.anim_slide_in, R.anim.anim_slide_out);
183 | Log.d("EdgeSlidingBackLayout", "computeScroll()@EdgeSlidingBackLayout.java:161-->>" + mActivity + "销毁");
184 | }
185 | }
186 |
187 | @Override
188 | protected void dispatchDraw(Canvas canvas) {
189 | super.dispatchDraw(canvas);
190 | drawShadow(canvas);
191 | }
192 |
193 | private void drawShadow(Canvas canvas) {
194 | mShadow.setBounds(0, 0, mShadowWidth, getHeight());
195 | canvas.save();
196 | canvas.translate(-mShadowWidth, 0);
197 | mShadow.draw(canvas);
198 | canvas.restore();
199 | }
200 |
201 | interface OnSlidingBackListener {
202 | void onSlidingBack();
203 | }
204 | }
--------------------------------------------------------------------------------
/src/main/res/anim/anim_slide_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/src/main/res/anim/anim_slide_out.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/src/main/res/drawable/left_shadow.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
7 |
8 |
--------------------------------------------------------------------------------
/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | EdgeSlidingBack
3 |
4 |
--------------------------------------------------------------------------------
/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
16 |
17 |
23 |
24 |
25 |
--------------------------------------------------------------------------------