T.trigger(delay: Long = 500, block: (T) -> Unit) {
46 | triggerDelay = delay
47 | if (triggerEnable()) {
48 | block(this)
49 | }
50 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/common/weikaiyun/util/ResUtils.kt:
--------------------------------------------------------------------------------
1 | package com.common.weikaiyun.util
2 |
3 | import android.graphics.drawable.Drawable
4 | import androidx.annotation.ColorRes
5 | import androidx.annotation.DrawableRes
6 | import androidx.appcompat.content.res.AppCompatResources
7 | import com.common.weikaiyun.demo.DemoApplication
8 |
9 | object ResUtils {
10 | fun getDrawable(@DrawableRes resId: Int): Drawable {
11 | return AppCompatResources.getDrawable(DemoApplication.context, resId)!!
12 | }
13 |
14 | fun getColor(@ColorRes resId: Int): Int {
15 | return DemoApplication.context.getColor(resId)
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_bottom_community.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikaiyun/SFragmentation/bd500d1fde6fa45651a6abd331c5b4ff4dc7acce/app/src/main/res/drawable/icon_bottom_community.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_bottom_community_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikaiyun/SFragmentation/bd500d1fde6fa45651a6abd331c5b4ff4dc7acce/app/src/main/res/drawable/icon_bottom_community_selected.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_bottom_homepage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikaiyun/SFragmentation/bd500d1fde6fa45651a6abd331c5b4ff4dc7acce/app/src/main/res/drawable/icon_bottom_homepage.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_bottom_homepage_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikaiyun/SFragmentation/bd500d1fde6fa45651a6abd331c5b4ff4dc7acce/app/src/main/res/drawable/icon_bottom_homepage_selected.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_bottom_mine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikaiyun/SFragmentation/bd500d1fde6fa45651a6abd331c5b4ff4dc7acce/app/src/main/res/drawable/icon_bottom_mine.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_bottom_mine_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikaiyun/SFragmentation/bd500d1fde6fa45651a6abd331c5b4ff4dc7acce/app/src/main/res/drawable/icon_bottom_mine_selected.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_bottom_remind.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikaiyun/SFragmentation/bd500d1fde6fa45651a6abd331c5b4ff4dc7acce/app/src/main/res/drawable/icon_bottom_remind.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_bottom_remind_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikaiyun/SFragmentation/bd500d1fde6fa45651a6abd331c5b4ff4dc7acce/app/src/main/res/drawable/icon_bottom_remind_selected.png
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_demo_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_community.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_demo.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
17 |
18 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_demo2.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
17 |
18 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_demo4.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
18 |
19 |
30 |
31 |
43 |
44 |
55 |
56 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_demo_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
16 |
17 |
24 |
25 |
36 |
37 |
46 |
47 |
57 |
58 |
59 |
68 |
69 |
78 |
79 |
89 |
90 |
91 |
100 |
101 |
110 |
111 |
121 |
122 |
123 |
133 |
134 |
142 |
143 |
154 |
155 |
156 |
157 |
158 |
159 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_home.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
19 |
20 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_mine.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_remind.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikaiyun/SFragmentation/bd500d1fde6fa45651a6abd331c5b4ff4dc7acce/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikaiyun/SFragmentation/bd500d1fde6fa45651a6abd331c5b4ff4dc7acce/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikaiyun/SFragmentation/bd500d1fde6fa45651a6abd331c5b4ff4dc7acce/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikaiyun/SFragmentation/bd500d1fde6fa45651a6abd331c5b4ff4dc7acce/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikaiyun/SFragmentation/bd500d1fde6fa45651a6abd331c5b4ff4dc7acce/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikaiyun/SFragmentation/bd500d1fde6fa45651a6abd331c5b4ff4dc7acce/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikaiyun/SFragmentation/bd500d1fde6fa45651a6abd331c5b4ff4dc7acce/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikaiyun/SFragmentation/bd500d1fde6fa45651a6abd331c5b4ff4dc7acce/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikaiyun/SFragmentation/bd500d1fde6fa45651a6abd331c5b4ff4dc7acce/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikaiyun/SFragmentation/bd500d1fde6fa45651a6abd331c5b4ff4dc7acce/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #6200EE
4 | #3700B3
5 | #03DAC5
6 |
7 | #979797
8 | #333333
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 1dp
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | weikaiyun
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
15 |
16 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/test/java/com/common/weikaiyun/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.common.weikaiyun
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | ext {
5 | versions = [
6 | kotlin : '1.5.0',
7 | kotlin_serialization : '1.0.0',
8 | kotlinx_coroutines : '1.3.9',
9 | core_ktx : '1.3.2',
10 | viewpager2 : '1.0.0',
11 | room : '2.2.5',
12 | appcompat : '1.2.0',
13 | fragment_version : '1.3.3',
14 | constraintlayout : '2.0.4',
15 | lifecycle : '2.2.0',
16 | debug_db : '1.0.6',
17 | ]
18 | }
19 |
20 | repositories {
21 | google()
22 | mavenCentral()
23 | }
24 |
25 | dependencies {
26 | classpath 'com.android.tools.build:gradle:4.1.2'
27 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}"
28 | classpath "org.jetbrains.kotlin:kotlin-serialization:${versions.kotlin}"
29 |
30 | classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
31 |
32 | // NOTE: Do not place your application dependencies here; they belong
33 | // in the individual module build.gradle files
34 | }
35 | }
36 |
37 | allprojects {
38 | repositories {
39 | google()
40 | mavenCentral()
41 | maven { url 'https://jitpack.io' }
42 | }
43 | }
44 |
45 | task clean(type: Delete) {
46 | delete rootProject.buildDir
47 | }
48 |
--------------------------------------------------------------------------------
/fragmentation/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/fragmentation/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'com.github.dcendents.android-maven'
3 |
4 | android {
5 | compileSdkVersion 30
6 |
7 | defaultConfig {
8 | minSdkVersion 19
9 | targetSdkVersion 30
10 | versionCode 1
11 | versionName "1.0"
12 |
13 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
14 | consumerProguardFiles "consumer-rules.pro"
15 | }
16 |
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 | }
24 |
25 | dependencies {
26 | implementation fileTree(dir: "libs", include: ["*.jar"])
27 | implementation "androidx.appcompat:appcompat:${versions.appcompat}"
28 | implementation "androidx.fragment:fragment:${versions.fragment_version}"
29 | testImplementation 'junit:junit:4.13'
30 | androidTestImplementation 'androidx.test.ext:junit:1.1.2'
31 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
32 | }
--------------------------------------------------------------------------------
/fragmentation/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikaiyun/SFragmentation/bd500d1fde6fa45651a6abd331c5b4ff4dc7acce/fragmentation/consumer-rules.pro
--------------------------------------------------------------------------------
/fragmentation/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/fragmentation/src/androidTest/java/com/weikaiyun/fragmentation/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.weikaiyun.fragmentation;
2 |
3 | import android.content.Context;
4 |
5 | import androidx.test.platform.app.InstrumentationRegistry;
6 | import androidx.test.ext.junit.runners.AndroidJUnit4;
7 |
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 |
11 | import static org.junit.Assert.*;
12 |
13 | /**
14 | * Instrumented test, which will execute on an Android device.
15 | *
16 | * @see Testing documentation
17 | */
18 | @RunWith(AndroidJUnit4.class)
19 | public class ExampleInstrumentedTest {
20 | @Test
21 | public void useAppContext() {
22 | // Context of the androidx.fragment.app under test.
23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
24 | assertEquals("com.weikaiyun.fragmentation.test", appContext.getPackageName());
25 | }
26 | }
--------------------------------------------------------------------------------
/fragmentation/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/fragmentation/src/main/java/com/weikaiyun/fragmentation/Fragmentation.java:
--------------------------------------------------------------------------------
1 | package com.weikaiyun.fragmentation;
2 |
3 | import androidx.annotation.IntDef;
4 |
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 |
8 | public class Fragmentation {
9 | /**
10 | * Dont display stack view.
11 | */
12 | public static final int NONE = 0;
13 | /**
14 | * Shake it to display stack view.
15 | */
16 | public static final int SHAKE = 1;
17 | /**
18 | * As a bubble display stack view.
19 | */
20 | public static final int BUBBLE = 2;
21 |
22 | static volatile Fragmentation INSTANCE;
23 |
24 | private boolean debug;
25 | private int mode = BUBBLE;
26 | int targetFragmentEnter, currentFragmentPopExit, currentFragmentPopEnter, targetFragmentExit;
27 |
28 |
29 | @IntDef({NONE, SHAKE, BUBBLE})
30 | @Retention(RetentionPolicy.SOURCE)
31 | @interface StackViewMode {
32 | }
33 |
34 | public static Fragmentation getDefault() {
35 | if (INSTANCE == null) {
36 | synchronized (Fragmentation.class) {
37 | if (INSTANCE == null) {
38 | INSTANCE = new Fragmentation(new FragmentationBuilder());
39 | }
40 | }
41 | }
42 | return INSTANCE;
43 | }
44 |
45 | Fragmentation(FragmentationBuilder builder) {
46 | debug = builder.debug;
47 | if (debug) {
48 | mode = builder.mode;
49 | } else {
50 | mode = NONE;
51 | }
52 |
53 | targetFragmentEnter = builder.targetFragmentEnter;
54 | currentFragmentPopExit = builder.currentFragmentPopExit;
55 | currentFragmentPopEnter = builder.currentFragmentPopEnter;
56 | targetFragmentExit = builder.targetFragmentExit;
57 | }
58 |
59 | public boolean isDebug() {
60 | return debug;
61 | }
62 |
63 | public void setDebug(boolean debug) {
64 | this.debug = debug;
65 | }
66 |
67 |
68 | public int getMode() {
69 | return mode;
70 | }
71 |
72 | public void setMode(@StackViewMode int mode) {
73 | this.mode = mode;
74 | }
75 |
76 | public static FragmentationBuilder builder() {
77 | return new FragmentationBuilder();
78 | }
79 |
80 | public static class FragmentationBuilder {
81 | private boolean debug;
82 | private int mode;
83 | private int targetFragmentEnter, currentFragmentPopExit, currentFragmentPopEnter, targetFragmentExit;
84 |
85 |
86 | /**
87 | * @param debug Suppressed Exception("Can not perform this action after onSaveInstanceState!") when debug=false
88 | */
89 | public FragmentationBuilder debug(boolean debug) {
90 | this.debug = debug;
91 | return this;
92 | }
93 |
94 | public FragmentationBuilder animation(int targetFragmentEnter, int currentFragmentPopExit, int currentFragmentPopEnter, int targetFragmentExit) {
95 | this.targetFragmentEnter = targetFragmentEnter;
96 | this.currentFragmentPopExit = currentFragmentPopExit;
97 | this.currentFragmentPopEnter = currentFragmentPopEnter;
98 | this.targetFragmentExit = targetFragmentExit;
99 | return this;
100 | }
101 |
102 | /**
103 | * Sets the mode to display the stack view
104 | *
105 | * None if debug(false).
106 | *
107 | * Default:NONE
108 | */
109 | public FragmentationBuilder stackViewMode(@StackViewMode int mode) {
110 | this.mode = mode;
111 | return this;
112 | }
113 |
114 | public Fragmentation install() {
115 | Fragmentation.INSTANCE = new Fragmentation(this);
116 | return Fragmentation.INSTANCE;
117 | }
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/fragmentation/src/main/java/com/weikaiyun/fragmentation/ISupportActivity.java:
--------------------------------------------------------------------------------
1 | package com.weikaiyun.fragmentation;
2 |
3 | import android.view.MotionEvent;
4 |
5 | import com.weikaiyun.fragmentation.animation.FragmentAnimator;
6 |
7 | public interface ISupportActivity {
8 |
9 | SupportActivityDelegate getSupportDelegate();
10 |
11 | ExtraTransaction extraTransaction();
12 |
13 | void post(Runnable runnable);
14 |
15 | void onBackPressed();
16 |
17 | void onBackPressedSupport();
18 |
19 | boolean dispatchTouchEvent(MotionEvent ev);
20 |
21 | FragmentAnimator getFragmentAnimator();
22 |
23 | void setFragmentAnimator(FragmentAnimator fragmentAnimator);
24 | }
25 |
--------------------------------------------------------------------------------
/fragmentation/src/main/java/com/weikaiyun/fragmentation/ISupportFragment.java:
--------------------------------------------------------------------------------
1 | package com.weikaiyun.fragmentation;
2 |
3 | import android.os.Bundle;
4 |
5 | import androidx.annotation.IntDef;
6 |
7 | import java.lang.annotation.Retention;
8 | import java.lang.annotation.RetentionPolicy;
9 |
10 | public interface ISupportFragment {
11 | // LaunchMode
12 | int STANDARD = 0;
13 | int SINGLETOP = 1;
14 | int SINGLETASK = 2;
15 |
16 | // ResultCode
17 | int RESULT_CANCELED = 0;
18 | int RESULT_OK = -1;
19 |
20 | @IntDef({STANDARD, SINGLETOP, SINGLETASK})
21 | @Retention(RetentionPolicy.SOURCE)
22 | public @interface LaunchMode {
23 | }
24 |
25 | SupportFragmentDelegate getSupportDelegate();
26 |
27 | ExtraTransaction extraTransaction();
28 |
29 | void post(Runnable runnable);
30 |
31 | void lazyInit();
32 |
33 | void setFragmentResult(int resultCode, Bundle bundle);
34 |
35 | void onFragmentResult(int requestCode, int resultCode, Bundle data);
36 |
37 | void onNewBundle(Bundle args);
38 |
39 | void putNewBundle(Bundle newBundle);
40 |
41 | boolean onBackPressedSupport();
42 |
43 | void onVisible();
44 |
45 | void onInvisible();
46 | }
47 |
--------------------------------------------------------------------------------
/fragmentation/src/main/java/com/weikaiyun/fragmentation/SupportActivity.java:
--------------------------------------------------------------------------------
1 | package com.weikaiyun.fragmentation;
2 |
3 | import android.os.Bundle;
4 | import android.view.MotionEvent;
5 |
6 | import androidx.annotation.DrawableRes;
7 | import androidx.annotation.NonNull;
8 | import androidx.annotation.Nullable;
9 | import androidx.appcompat.app.AppCompatActivity;
10 |
11 | import com.weikaiyun.fragmentation.animation.FragmentAnimator;
12 |
13 | /**
14 | * Base class for activities that use the support-based
15 | * {@link ISupportActivity} and
16 | * {@link AppCompatActivity} APIs.
17 | */
18 | abstract public class SupportActivity extends AppCompatActivity implements ISupportActivity {
19 | final SupportActivityDelegate mDelegate = new SupportActivityDelegate(this);
20 |
21 | @Override
22 | public SupportActivityDelegate getSupportDelegate() {
23 | return mDelegate;
24 | }
25 |
26 | /**
27 | * Perform some extra transactions.
28 | * 额外的事务:自定义Tag, 操作非回退栈Fragment
29 | */
30 | @Override
31 | public ExtraTransaction extraTransaction() {
32 | return mDelegate.extraTransaction();
33 | }
34 |
35 | @Override
36 | protected void onCreate(@Nullable Bundle savedInstanceState) {
37 | super.onCreate(savedInstanceState);
38 | mDelegate.onCreate(savedInstanceState);
39 | }
40 |
41 | @Override
42 | protected void onPostCreate(@Nullable Bundle savedInstanceState) {
43 | super.onPostCreate(savedInstanceState);
44 | mDelegate.onPostCreate(savedInstanceState);
45 | }
46 |
47 | @Override
48 | protected void onSaveInstanceState(@NonNull Bundle outState) {
49 | mDelegate.onSaveInstanceState(outState);
50 | super.onSaveInstanceState(outState);
51 | }
52 |
53 | @Override
54 | protected void onStart() {
55 | super.onStart();
56 | }
57 |
58 | @Override
59 | protected void onStop() {
60 | super.onStop();
61 |
62 | }
63 |
64 | @Override
65 | protected void onDestroy() {
66 | super.onDestroy();
67 | mDelegate.onDestroy();
68 | }
69 |
70 | /**
71 | * Get all fragments animation.
72 | *
73 | * @return FragmentAnimator
74 | */
75 | @Override
76 | public FragmentAnimator getFragmentAnimator() {
77 | return mDelegate.getFragmentAnimator();
78 | }
79 |
80 | /**
81 | * Set all fragments animation.
82 | * 设置Fragment内的全局动画
83 | */
84 | @Override
85 | public void setFragmentAnimator(FragmentAnimator fragmentAnimator) {
86 | mDelegate.setFragmentAnimator(fragmentAnimator);
87 | }
88 |
89 | /**
90 | * Note:super.dispatchTouchEvent(ev);
91 | */
92 | @Override
93 | public boolean dispatchTouchEvent(MotionEvent ev) {
94 | return super.dispatchTouchEvent(ev);
95 | }
96 |
97 | /**
98 | * 不建议复写该方法,请使用 {@link #onBackPressedSupport} 代替
99 | */
100 | @Override
101 | final public void onBackPressed() {
102 | mDelegate.onBackPressed();
103 | }
104 |
105 | /**
106 | * 该方法回调时机为,Activity回退栈内Fragment的数量 小于等于1 时,默认finish Activity
107 | * 请尽量复写该方法,避免复写onBackPress(),以保证SupportFragment内的onBackPressedSupport()回退事件正常执行
108 | */
109 | @Override
110 | public void onBackPressedSupport() {
111 | mDelegate.onBackPressedSupport();
112 | }
113 |
114 |
115 | @Override
116 | public void post(Runnable runnable) {
117 | mDelegate.post(runnable);
118 | }
119 |
120 |
121 | /**
122 | * 加载根Fragment, 即Activity内的第一个Fragment
123 | *
124 | * @param containerId 容器id
125 | * @param toFragment 目标Fragment
126 | */
127 | public void loadRootFragment(int containerId, @NonNull ISupportFragment toFragment) {
128 | mDelegate.loadRootFragment(containerId, toFragment);
129 | }
130 |
131 | /**
132 | * 加载多个同级根Fragment
133 | */
134 | public void loadMultipleRootFragment(int containerId, int showPosition, ISupportFragment... toFragments) {
135 | mDelegate.loadMultipleRootFragment(containerId, showPosition, toFragments);
136 | }
137 |
138 | /**
139 | * show一个Fragment,hide其他同栈所有Fragment
140 | * 使用该方法时,要确保同级栈内无多余的Fragment,(只有通过loadMultipleRootFragment()载入的Fragment)
141 | *
142 | * 建议使用更明确的{@link #showHideFragment(ISupportFragment, ISupportFragment)}
143 | *
144 | * @param showFragment 需要show的Fragment
145 | */
146 | public void showHideFragment(ISupportFragment showFragment) {
147 | mDelegate.showHideFragment(showFragment);
148 | }
149 |
150 | /**
151 | * show一个Fragment,hide一个Fragment
152 | */
153 | public void showHideFragment(ISupportFragment showFragment, ISupportFragment hideFragment) {
154 | mDelegate.showHideFragment(showFragment, hideFragment);
155 | }
156 |
157 | /**
158 | * It is recommended to use {@link SupportFragment#start(ISupportFragment)}.
159 | */
160 | public void start(ISupportFragment toFragment) {
161 | mDelegate.start(toFragment);
162 | }
163 |
164 | /**
165 | * It is recommended to use {@link SupportFragment#start(ISupportFragment, int)}.
166 | *
167 | * @param launchMode Similar to Activity's LaunchMode.
168 | */
169 | public void start(ISupportFragment toFragment, @ISupportFragment.LaunchMode int launchMode) {
170 | mDelegate.start(toFragment, launchMode);
171 | }
172 |
173 | /**
174 | * It is recommended to use {@link SupportFragment#startForResult(ISupportFragment, int)}.
175 | * Launch an fragment for which you would like a result when it popped.
176 | */
177 | public void startForResult(ISupportFragment toFragment, int requestCode) {
178 | mDelegate.startForResult(toFragment, requestCode);
179 | }
180 |
181 | /**
182 | * It is recommended to use {@link SupportFragment#startWithPop(ISupportFragment)}.
183 | * Start the target Fragment and pop itself
184 | */
185 | public void startWithPop(ISupportFragment toFragment) {
186 | mDelegate.startWithPop(toFragment);
187 | }
188 |
189 | /**
190 | * It is recommended to use {@link SupportFragment#startWithPopTo(ISupportFragment, Class, boolean)}.
191 | *
192 | * @see #popTo(Class, boolean)
193 | * +
194 | * @see #start(ISupportFragment)
195 | */
196 | public void startWithPopTo(ISupportFragment toFragment, Class> targetFragmentClass,
197 | boolean includeTargetFragment) {
198 |
199 | mDelegate.startWithPopTo(toFragment, targetFragmentClass, includeTargetFragment);
200 | }
201 |
202 |
203 | /**
204 | * It is recommended to use {@link SupportFragment#replaceFragment(ISupportFragment)}.
205 | */
206 | public void replaceFragment(ISupportFragment toFragment) {
207 | mDelegate.replaceFragment(toFragment);
208 | }
209 |
210 | /**
211 | * Pop the fragment.
212 | */
213 | public void pop() {
214 | mDelegate.pop();
215 | }
216 |
217 | /**
218 | * 出栈到目标fragment
219 | *
220 | * @param targetFragmentClass 目标fragment
221 | * @param includeTargetFragment 是否包含该fragment
222 | */
223 | public void popTo(Class> targetFragmentClass, boolean includeTargetFragment) {
224 | mDelegate.popTo(targetFragmentClass, includeTargetFragment);
225 | }
226 |
227 | /**
228 | * If you want to begin another FragmentTransaction immediately after popTo(), use this method.
229 | * 如果你想在出栈后, 立刻进行FragmentTransaction操作,请使用该方法
230 | */
231 | public void popTo(Class> targetFragmentClass, boolean includeTargetFragment,
232 | Runnable afterPopTransactionRunnable) {
233 |
234 | mDelegate.popTo(targetFragmentClass, includeTargetFragment, afterPopTransactionRunnable);
235 | }
236 |
237 | /**
238 | * 得到位于栈顶Fragment
239 | */
240 | public ISupportFragment getTopFragment() {
241 | return SupportHelper.getTopFragment(getSupportFragmentManager());
242 | }
243 |
244 | /**
245 | * 获取栈内的fragment对象
246 | */
247 | public T findFragment(Class fragmentClass) {
248 | return SupportHelper.findFragment(getSupportFragmentManager(), fragmentClass);
249 | }
250 |
251 | /**
252 | * 当Fragment根布局 没有 设定background属性时,
253 | * Fragmentation默认使用Theme的android:windowbackground作为Fragment的背景,
254 | * 可以通过该方法改变其内所有Fragment的默认背景。
255 | */
256 | public void setDefaultFragmentBackground(@DrawableRes int backgroundRes) {
257 | mDelegate.setDefaultFragmentBackground(backgroundRes);
258 | }
259 | }
260 |
--------------------------------------------------------------------------------
/fragmentation/src/main/java/com/weikaiyun/fragmentation/SupportActivityDelegate.java:
--------------------------------------------------------------------------------
1 | package com.weikaiyun.fragmentation;
2 |
3 | import android.os.Bundle;
4 |
5 | import androidx.annotation.DrawableRes;
6 | import androidx.annotation.NonNull;
7 | import androidx.annotation.Nullable;
8 | import androidx.core.app.ActivityCompat;
9 | import androidx.fragment.app.Fragment;
10 | import androidx.fragment.app.FragmentActivity;
11 | import androidx.fragment.app.FragmentManager;
12 |
13 | import com.weikaiyun.fragmentation.animation.FragmentAnimator;
14 | import com.weikaiyun.fragmentation.debug.DebugStackDelegate;
15 | import com.weikaiyun.fragmentation.queue.Action;
16 |
17 | import java.util.List;
18 |
19 | public class SupportActivityDelegate {
20 | private final ISupportActivity mSupport;
21 | private final FragmentActivity mActivity;
22 |
23 | private TransactionDelegate mTransactionDelegate;
24 |
25 | private final DebugStackDelegate mDebugStackDelegate;
26 |
27 | private int mDefaultFragmentBackground = 0;
28 |
29 | private FragmentAnimator mFragmentAnimator = new FragmentAnimator();
30 |
31 | static final String S_FRAGMENTATION_FRAGMENT_ANIMATOR = "s_fragmentation_fragment_animator";
32 |
33 | public SupportActivityDelegate(ISupportActivity support) {
34 | if (!(support instanceof FragmentActivity))
35 | throw new RuntimeException("Must extends FragmentActivity/AppCompatActivity");
36 | this.mSupport = support;
37 | this.mActivity = (FragmentActivity) support;
38 | this.mDebugStackDelegate = new DebugStackDelegate(this.mActivity);
39 | }
40 |
41 | /**
42 | * Perform some extra transactions.
43 | * 额外的事务:自定义Tag,操作非回退栈Fragment
44 | */
45 | public ExtraTransaction extraTransaction() {
46 |
47 | return new ExtraTransaction.ExtraTransactionImpl<>((FragmentActivity) mSupport,
48 | getTopFragment(), getTransactionDelegate(), true);
49 | }
50 |
51 | public void onCreate(@Nullable Bundle savedInstanceState) {
52 | if (savedInstanceState != null) {
53 | FragmentAnimator animator = savedInstanceState.getParcelable(S_FRAGMENTATION_FRAGMENT_ANIMATOR);
54 | if (animator != null) {
55 | mFragmentAnimator = animator;
56 | }
57 | }
58 | mTransactionDelegate = getTransactionDelegate();
59 | mDebugStackDelegate.onCreate(Fragmentation.getDefault().getMode());
60 | }
61 |
62 | public void onSaveInstanceState(@NonNull Bundle outState) {
63 | outState.putParcelable(S_FRAGMENTATION_FRAGMENT_ANIMATOR, mFragmentAnimator);
64 | }
65 |
66 | public void onPostCreate(@Nullable Bundle savedInstanceState) {
67 | mDebugStackDelegate.onPostCreate(Fragmentation.getDefault().getMode());
68 | }
69 |
70 | public void onDestroy() {
71 | mDebugStackDelegate.onDestroy();
72 | }
73 |
74 | public TransactionDelegate getTransactionDelegate() {
75 | if (mTransactionDelegate == null) {
76 | mTransactionDelegate = new TransactionDelegate(mSupport);
77 | }
78 | return mTransactionDelegate;
79 | }
80 |
81 | /**
82 | * Causes the Runnable r to be added to the action queue.
83 | *
84 | * The runnable will be run after all the previous action has been run.
85 | *
86 | * 前面的事务全部执行后 执行该Action
87 | */
88 | public void post(final Runnable runnable) {
89 | mTransactionDelegate.post(runnable);
90 | }
91 |
92 | /**
93 | * 不建议复写该方法,请使用 {@link #onBackPressedSupport} 代替
94 | */
95 | public void onBackPressed() {
96 | mTransactionDelegate.mActionQueue.enqueue(new Action(Action.ACTION_BACK) {
97 | @Override
98 | public void run() {
99 | // 获取activeFragment:即从栈顶开始 状态为show的那个Fragment
100 | ISupportFragment activeFragment =
101 | SupportHelper.getActiveFragment(getSupportFragmentManager());
102 |
103 | if (mTransactionDelegate.dispatchBackPressedEvent(activeFragment)) return;
104 |
105 | mSupport.onBackPressedSupport();
106 | }
107 | });
108 | }
109 |
110 | /**
111 | * 该方法回调时机为,Activity回退栈内Fragment的数量 小于等于1 时,默认finish Activity
112 | * 请尽量复写该方法,避免复写onBackPress(),以保证SupportFragment内的onBackPressedSupport()回退事件正常执行
113 | */
114 | public void onBackPressedSupport() {
115 | List list = SupportHelper.getActiveFragments(getSupportFragmentManager());
116 | int fragmentNum = 0;
117 | for (Fragment f : list) {
118 | if (f instanceof ISupportFragment
119 | && ((ISupportFragment) f).getSupportDelegate().isCanPop()
120 | && ((ISupportFragment) f).getSupportDelegate().isStartByFragmentation()) {
121 | fragmentNum++;
122 | }
123 | }
124 | if (fragmentNum > 0) {
125 | pop();
126 | } else {
127 | ActivityCompat.finishAfterTransition(mActivity);
128 | }
129 | }
130 |
131 | public FragmentAnimator getFragmentAnimator() {
132 | return mFragmentAnimator;
133 | }
134 |
135 | public void setFragmentAnimator(FragmentAnimator mFragmentAnimator) {
136 | this.mFragmentAnimator = mFragmentAnimator;
137 | }
138 |
139 | /**
140 | * 加载根Fragment, 即Activity内的第一个Fragment 或 Fragment内的第一个子Fragment
141 | */
142 |
143 | public void loadRootFragment(int containerId, ISupportFragment toFragment) {
144 |
145 | mTransactionDelegate.loadRootTransaction(getSupportFragmentManager(),
146 | containerId, toFragment);
147 | }
148 |
149 | /**
150 | * 加载多个同级根Fragment,类似Wechat, QQ主页的场景
151 | */
152 | public void loadMultipleRootFragment(int containerId, int showPosition, ISupportFragment... toFragments) {
153 |
154 | mTransactionDelegate.loadMultipleRootTransaction(getSupportFragmentManager(),
155 | containerId, showPosition, toFragments);
156 | }
157 |
158 | /**
159 | * 这个的使用必须要注意
160 | * show一个Fragment,hide其他同栈所有Fragment
161 | * 使用该方法时,要确保同级栈内无多余的Fragment,(只有通过loadMultipleRootFragment()载入的Fragment)
162 | *
163 | *
164 | * 建议使用更明确的{@link #showHideFragment(ISupportFragment, ISupportFragment)}
165 | *
166 | * @param showFragment 需要show的Fragment
167 | */
168 | public void showHideFragment(ISupportFragment showFragment) {
169 | showHideFragment(showFragment, null);
170 | }
171 |
172 | /**
173 | * show一个Fragment,hide一个Fragment
174 | *
175 | * @param showFragment 需要show的Fragment
176 | * @param hideFragment 需要hide的Fragment
177 | */
178 | public void showHideFragment(ISupportFragment showFragment, ISupportFragment hideFragment) {
179 |
180 | mTransactionDelegate.showHideFragment(getSupportFragmentManager(), showFragment, hideFragment);
181 | }
182 |
183 | public void start(ISupportFragment toFragment) {
184 | start(toFragment, ISupportFragment.STANDARD);
185 | }
186 |
187 | /**
188 | * @param launchMode Similar to Activity's LaunchMode.
189 | */
190 | public void start(ISupportFragment toFragment, @ISupportFragment.LaunchMode int launchMode) {
191 |
192 | mTransactionDelegate.dispatchStartTransaction(getSupportFragmentManager(),
193 | getTopFragment(), toFragment, 0, launchMode, TransactionDelegate.TYPE_ADD);
194 | }
195 |
196 | /**
197 | * Launch an fragment for which you would like a result when it popped.
198 | */
199 | public void startForResult(ISupportFragment toFragment, int requestCode) {
200 |
201 | mTransactionDelegate.dispatchStartTransaction(getSupportFragmentManager(),
202 | getTopFragment(), toFragment, requestCode, ISupportFragment.STANDARD,
203 | TransactionDelegate.TYPE_ADD_RESULT);
204 | }
205 |
206 | /**
207 | * Start the target Fragment and pop itself
208 | */
209 | public void startWithPop(ISupportFragment toFragment) {
210 | mTransactionDelegate.dispatchStartWithPopTransaction(getSupportFragmentManager(), getTopFragment(), toFragment);
211 | }
212 |
213 | public void startWithPopTo(ISupportFragment toFragment, Class> targetFragmentClass,
214 | boolean includeTargetFragment) {
215 |
216 | mTransactionDelegate.dispatchStartWithPopToTransaction(getSupportFragmentManager(),
217 | getTopFragment(), toFragment, targetFragmentClass.getName(), includeTargetFragment);
218 | }
219 |
220 | public void replaceFragment(ISupportFragment toFragment) {
221 |
222 | mTransactionDelegate.dispatchStartTransaction(getSupportFragmentManager(),
223 | getTopFragment(), toFragment, 0, ISupportFragment.STANDARD,
224 | TransactionDelegate.TYPE_REPLACE);
225 | }
226 |
227 | /**
228 | * Pop the child fragment.
229 | */
230 | public void pop() {
231 | mTransactionDelegate.pop(getSupportFragmentManager());
232 | }
233 |
234 | /**
235 | * Pop the last fragment transition from the manager's fragment
236 | * back stack.
237 | *
238 | * 出栈到目标fragment
239 | *
240 | * @param targetFragmentClass 目标fragment
241 | * @param includeTargetFragment 是否包含该fragment
242 | */
243 | public void popTo(Class> targetFragmentClass, boolean includeTargetFragment) {
244 | popTo(targetFragmentClass, includeTargetFragment, null);
245 | }
246 |
247 | /**
248 | * If you want to begin another FragmentTransaction immediately after popTo(), use this method.
249 | * 如果你想在出栈后, 立刻进行FragmentTransaction操作,请使用该方法
250 | */
251 |
252 | public void popTo(Class> targetFragmentClass, boolean includeTargetFragment,
253 | Runnable afterPopTransactionRunnable) {
254 |
255 | mTransactionDelegate.popTo(targetFragmentClass.getName(), includeTargetFragment,
256 | afterPopTransactionRunnable, getSupportFragmentManager());
257 | }
258 |
259 | private FragmentManager getSupportFragmentManager() {
260 | return mActivity.getSupportFragmentManager();
261 | }
262 |
263 | private ISupportFragment getTopFragment() {
264 | return SupportHelper.getTopFragment(getSupportFragmentManager());
265 | }
266 |
267 | /**
268 | * 当Fragment根布局 没有设定background属性时,
269 | * Fragmentation默认使用Theme的android:windowbackground作为Fragment的背景,
270 | * 可以通过该方法改变Fragment背景。
271 | */
272 | public void setDefaultFragmentBackground(@DrawableRes int backgroundRes) {
273 | mDefaultFragmentBackground = backgroundRes;
274 | }
275 |
276 | public int getDefaultFragmentBackground() {
277 | return mDefaultFragmentBackground;
278 | }
279 | }
280 |
--------------------------------------------------------------------------------
/fragmentation/src/main/java/com/weikaiyun/fragmentation/SupportFragment.java:
--------------------------------------------------------------------------------
1 | package com.weikaiyun.fragmentation;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.os.Bundle;
7 | import android.view.View;
8 | import android.view.animation.Animation;
9 | import android.view.animation.AnimationUtils;
10 |
11 | import androidx.annotation.NonNull;
12 | import androidx.annotation.Nullable;
13 | import androidx.fragment.app.Fragment;
14 |
15 |
16 | /**
17 | * Base class for activities that use the support-based
18 | * {@link ISupportFragment} and
19 | * {@link Fragment} APIs.
20 | */
21 | abstract public class SupportFragment extends Fragment implements ISupportFragment {
22 | final SupportFragmentDelegate mDelegate = new SupportFragmentDelegate(this);
23 | protected SupportActivity _mActivity;
24 |
25 | private boolean isLoaded;
26 |
27 | @Nullable
28 | @Override
29 | public Animation onCreateAnimation(final int transit, final boolean enter, int nextAnim) {
30 | if (nextAnim > 0) {
31 | Animation anim = AnimationUtils.loadAnimation(_mActivity, nextAnim);
32 | anim.setAnimationListener(new Animation.AnimationListener() {
33 | @Override
34 | public void onAnimationStart(Animation animation) {
35 |
36 | }
37 |
38 | @Override
39 | public void onAnimationEnd(Animation animation) {
40 | if (enter) {
41 | onEnterAnimationEnd();
42 | }
43 | }
44 |
45 | @Override
46 | public void onAnimationRepeat(Animation animation) {
47 |
48 | }
49 | });
50 |
51 | return anim;
52 | }
53 | return super.onCreateAnimation(transit, enter, nextAnim);
54 | }
55 |
56 | @Override
57 | public SupportFragmentDelegate getSupportDelegate() {
58 | return mDelegate;
59 | }
60 |
61 | /**
62 | * Perform some extra transactions.
63 | * 额外的事务:自定义Tag,添加SharedElement动画,操作非回退栈Fragment
64 | */
65 | @Override
66 | public ExtraTransaction extraTransaction() {
67 | return mDelegate.extraTransaction();
68 | }
69 |
70 | @Override
71 | public void onAttach(@NonNull Context context) {
72 | super.onAttach(context);
73 | mDelegate.onAttach(context);
74 | _mActivity = (SupportActivity) mDelegate.getActivity();
75 | }
76 |
77 | @Override
78 | public void onCreate(@Nullable Bundle savedInstanceState) {
79 | super.onCreate(savedInstanceState);
80 | mDelegate.onCreate(savedInstanceState);
81 | }
82 |
83 | @Override
84 | public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
85 | super.onViewCreated(view, savedInstanceState);
86 | mDelegate.onViewCreated(savedInstanceState);
87 | }
88 |
89 | @Override
90 | public void onSaveInstanceState(@NonNull Bundle outState) {
91 | super.onSaveInstanceState(outState);
92 | mDelegate.onSaveInstanceState(outState);
93 | }
94 |
95 | @Override
96 | public void onResume() {
97 | super.onResume();
98 | if (!getSupportDelegate().hasEnterAnimation) {
99 | onRealResume();
100 | }
101 | }
102 |
103 | @Override
104 | public void onPause() {
105 | super.onPause();
106 | getSupportDelegate().setVisible(false);
107 | onInvisible();
108 | }
109 |
110 | @Override
111 | public void lazyInit() {
112 |
113 | }
114 |
115 | @Override
116 | public void onVisible() {
117 |
118 | }
119 |
120 | @Override
121 | public void onInvisible() {
122 |
123 | }
124 |
125 | private void onEnterAnimationEnd() {
126 | onRealResume();
127 | getSupportDelegate().hasEnterAnimation = false;
128 | }
129 |
130 | private void onRealResume() {
131 | if (!isLoaded && !isHidden()) {
132 | lazyInit();
133 | isLoaded = true;
134 | }
135 |
136 | if (!isHidden()) {
137 | getSupportDelegate().setVisible(true);
138 | onVisible();
139 | }
140 | }
141 |
142 | @Override
143 | public void onDestroyView() {
144 | super.onDestroyView();
145 | isLoaded = false;
146 | }
147 |
148 | @Override
149 | public void onDestroy() {
150 | mDelegate.onDestroy();
151 | super.onDestroy();
152 | }
153 |
154 | /**
155 | * Causes the Runnable r to be added to the action queue.
156 | *
157 | * The runnable will be run after all the previous action has been run.
158 | *
159 | * 前面的事务全部执行后 执行该Action
160 | */
161 | @Override
162 | public void post(Runnable runnable) {
163 | mDelegate.post(runnable);
164 | }
165 |
166 | /**
167 | * 按返回键触发,前提是SupportActivity的onBackPressed()方法能被调用
168 | *
169 | * @return false则继续向上传递, true则消费掉该事件
170 | */
171 | @Override
172 | public boolean onBackPressedSupport() {
173 | return mDelegate.onBackPressedSupport();
174 | }
175 |
176 | /**
177 | * 类似 {@link Activity#setResult(int, Intent)}
178 | *
179 | * Similar to {@link Activity#setResult(int, Intent)}
180 | *
181 | * @see #startForResult(ISupportFragment, int)
182 | */
183 | @Override
184 | public void setFragmentResult(int resultCode, Bundle bundle) {
185 | mDelegate.setFragmentResult(resultCode, bundle);
186 | }
187 |
188 | /**
189 | * 类似Activity.onActivityResult(int, int, Intent)
190 | *
191 | * @see #startForResult(ISupportFragment, int)
192 | */
193 | @Override
194 | public void onFragmentResult(int requestCode, int resultCode, Bundle data) {
195 |
196 | }
197 |
198 | /**
199 | * 在start(TargetFragment,LaunchMode)时,启动模式为SingleTask/SingleTop, 回调TargetFragment的该方法
200 | * 类似 Activity.onNewIntent(Intent)
201 | *
202 | * @param args putNewBundle(Bundle newBundle)
203 | * @see #start(ISupportFragment, int)
204 | */
205 | @Override
206 | public void onNewBundle(Bundle args) {
207 |
208 | }
209 |
210 | /**
211 | * 添加NewBundle,用于启动模式为SingleTask/SingleTop时
212 | *
213 | * @see #start(ISupportFragment, int)
214 | */
215 | @Override
216 | public void putNewBundle(Bundle newBundle) {
217 | mDelegate.putNewBundle(newBundle);
218 | }
219 |
220 |
221 | /**
222 | * 隐藏软键盘
223 | */
224 | protected void hideSoftInput() {
225 | mDelegate.hideSoftInput();
226 | }
227 |
228 | /**
229 | * 显示软键盘
230 | */
231 | protected void showSoftInput(final View view) {
232 | mDelegate.showSoftInput(view);
233 | }
234 |
235 | /**
236 | * 加载根Fragment, 即Fragment内的第一个子Fragment
237 | *
238 | * @param containerId 容器id
239 | * @param toFragment 目标Fragment
240 | */
241 | public void loadRootFragment(int containerId, ISupportFragment toFragment) {
242 | mDelegate.loadRootFragment(containerId, toFragment);
243 | }
244 |
245 | /**
246 | * 加载多个同级根Fragment
247 | */
248 | public void loadMultipleRootFragment(int containerId, int showPosition, ISupportFragment... toFragments) {
249 | mDelegate.loadMultipleRootFragment(containerId, showPosition, toFragments);
250 | }
251 |
252 | /**
253 | * show一个Fragment,hide其他同栈所有Fragment
254 | * 使用该方法时,要确保同级栈内无多余的Fragment(只有通过loadMultipleRootFragment()载入的Fragment)
255 | *
256 | * 建议使用更明确的{@link #showHideFragment(ISupportFragment, ISupportFragment)}
257 | *
258 | * @param showFragment 需要show的Fragment
259 | */
260 | public void showHideFragment(ISupportFragment showFragment) {
261 | mDelegate.showHideFragment(showFragment);
262 | }
263 |
264 | /**
265 | * show一个Fragment,hide一个Fragment ; 主要用于类似微信主页那种 切换tab的情况
266 | */
267 | public void showHideFragment(ISupportFragment showFragment, ISupportFragment hideFragment) {
268 | mDelegate.showHideFragment(showFragment, hideFragment);
269 | }
270 |
271 | public void start(ISupportFragment toFragment) {
272 | mDelegate.start(toFragment);
273 | }
274 |
275 | /**
276 | * @param launchMode Similar to Activity's LaunchMode.
277 | */
278 | public void start(final ISupportFragment toFragment, @LaunchMode int launchMode) {
279 | mDelegate.start(toFragment, launchMode);
280 | }
281 |
282 | /**
283 | * Launch an fragment for which you would like a result when it popped.
284 | */
285 | public void startForResult(ISupportFragment toFragment, int requestCode) {
286 | mDelegate.startForResult(toFragment, requestCode);
287 | }
288 |
289 | /**
290 | * Start the target Fragment and pop itself
291 | */
292 | public void startWithPop(ISupportFragment toFragment) {
293 | mDelegate.startWithPop(toFragment);
294 | }
295 |
296 | /**
297 | * @see #popTo(Class, boolean)
298 | * +
299 | * @see #start(ISupportFragment)
300 | */
301 | public void startWithPopTo(ISupportFragment toFragment, Class> targetFragmentClass, boolean includeTargetFragment) {
302 | mDelegate.startWithPopTo(toFragment, targetFragmentClass, includeTargetFragment);
303 | }
304 |
305 |
306 |
307 | public void replaceFragment(ISupportFragment toFragment) {
308 | mDelegate.replaceFragment(toFragment);
309 | }
310 |
311 | public void pop() {
312 | mDelegate.pop();
313 | }
314 |
315 | public void popQuiet() {
316 | mDelegate.popQuiet();
317 | }
318 |
319 | /**
320 | * Pop the last fragment transition from the manager's fragment
321 | * back stack.
322 | *
323 | * 出栈到目标fragment
324 | *
325 | * @param targetFragmentClass 目标fragment
326 | * @param includeTargetFragment 是否包含该fragment
327 | */
328 | public void popTo(Class> targetFragmentClass, boolean includeTargetFragment) {
329 | mDelegate.popTo(targetFragmentClass, includeTargetFragment);
330 | }
331 |
332 | /**
333 | * If you want to begin another FragmentTransaction immediately after popTo(), use this method.
334 | * 如果你想在出栈后, 立刻进行FragmentTransaction操作,请使用该方法
335 | */
336 | public void popTo(Class> targetFragmentClass, boolean includeTargetFragment, Runnable afterPopTransactionRunnable) {
337 | mDelegate.popTo(targetFragmentClass, includeTargetFragment, afterPopTransactionRunnable);
338 | }
339 |
340 |
341 |
342 |
343 | public void startChild(ISupportFragment toFragment) {
344 | mDelegate.startChild(toFragment);
345 | }
346 |
347 | public void startChild(final ISupportFragment toFragment, @ISupportFragment.LaunchMode int launchMode) {
348 | mDelegate.startChild(toFragment, launchMode);
349 | }
350 |
351 | public void startChildForResult(ISupportFragment toFragment, int requestCode) {
352 | mDelegate.startChildForResult(toFragment, requestCode);
353 | }
354 |
355 | public void startChildWithPop(ISupportFragment toFragment) {
356 | mDelegate.startChildWithPop(toFragment);
357 | }
358 |
359 | public void replaceChildFragment(ISupportFragment toFragment) {
360 | mDelegate.replaceChildFragment(toFragment);
361 | }
362 |
363 | /**
364 | * Pop the child fragment.
365 | */
366 | public void popChild() {
367 | mDelegate.popChild();
368 | }
369 |
370 | public void popToChild(Class> targetFragmentClass, boolean includeTargetFragment) {
371 | mDelegate.popToChild(targetFragmentClass, includeTargetFragment);
372 | }
373 |
374 | public void popToChild(Class> targetFragmentClass, boolean includeTargetFragment, Runnable afterPopTransactionRunnable) {
375 | mDelegate.popToChild(targetFragmentClass, includeTargetFragment, afterPopTransactionRunnable);
376 | }
377 |
378 | /**
379 | * 得到位于栈顶Fragment
380 | */
381 | public ISupportFragment getTopFragment() {
382 | return SupportHelper.getTopFragment(getParentFragmentManager());
383 | }
384 |
385 | /**
386 | * 得到位于子栈顶Fragment
387 | */
388 | public ISupportFragment getTopChildFragment() {
389 | return SupportHelper.getTopFragment(getChildFragmentManager());
390 | }
391 |
392 | /**
393 | * @return 位于当前Fragment的前一个Fragment
394 | */
395 | public ISupportFragment getPreFragment() {
396 | return SupportHelper.getPreFragment(this);
397 | }
398 |
399 | /**
400 | * 获取栈内的fragment对象
401 | */
402 | public T findFragment(Class fragmentClass) {
403 | return SupportHelper.findFragment(getParentFragmentManager(), fragmentClass);
404 | }
405 |
406 | /**
407 | * 获取子栈内的fragment对象
408 | */
409 | public T findChildFragment(Class fragmentClass) {
410 | return SupportHelper.findFragment(getChildFragmentManager(), fragmentClass);
411 | }
412 | }
413 |
--------------------------------------------------------------------------------
/fragmentation/src/main/java/com/weikaiyun/fragmentation/SupportFragmentDelegate.java:
--------------------------------------------------------------------------------
1 | package com.weikaiyun.fragmentation;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.content.res.TypedArray;
7 | import android.os.Bundle;
8 | import android.view.View;
9 |
10 | import androidx.annotation.NonNull;
11 | import androidx.annotation.Nullable;
12 | import androidx.fragment.app.Fragment;
13 | import androidx.fragment.app.FragmentActivity;
14 | import androidx.fragment.app.FragmentManager;
15 |
16 | import com.weikaiyun.fragmentation.record.ResultRecord;
17 | import com.weikaiyun.fragmentation.record.TransactionRecord;
18 |
19 | public class SupportFragmentDelegate {
20 | static final String S_FRAGMENTATION_FRAGMENT_VISIBLE_PROP = "s_fragmentation_fragment_visible_prop";
21 | static final String S_FRAGMENTATION_FRAGMENT_POP_PROP = "s_fragmentation_fragment_pop_prop";
22 | static final String S_FRAGMENTATION_FRAGMENT_START_PROP = "s_fragmentation_fragment_start_prop";
23 |
24 | int mContainerId;
25 |
26 | private TransactionDelegate mTransactionDelegate;
27 | TransactionRecord mTransactionRecord;
28 | Bundle mNewBundle;
29 |
30 | private final ISupportFragment mSupportF;
31 | private final Fragment mFragment;
32 | protected FragmentActivity _mActivity;
33 | private ISupportActivity mSupport;
34 |
35 | private boolean isVisible = false;
36 |
37 | boolean hasEnterAnimation = false;
38 |
39 | private boolean canPop = true;
40 |
41 | private boolean startByFragmentation = false;
42 |
43 | public boolean hasEnterAnimation() {
44 | return hasEnterAnimation;
45 | }
46 |
47 | public void setHasEnterAnimation(boolean hasEnterAnimation) {
48 | this.hasEnterAnimation = hasEnterAnimation;
49 | }
50 |
51 | public void setCanPop(boolean canPop) {
52 | this.canPop = canPop;
53 | }
54 |
55 | public boolean isCanPop() {
56 | return canPop;
57 | }
58 |
59 | public boolean isStartByFragmentation() {
60 | return startByFragmentation;
61 | }
62 |
63 | public void setStartByFragmentation(boolean startByFragmentation) {
64 | this.startByFragmentation = startByFragmentation;
65 | }
66 |
67 | public void setVisible(boolean visible) {
68 | isVisible = visible;
69 | }
70 |
71 | public boolean isVisible() {
72 | return isVisible;
73 | }
74 |
75 | public SupportFragmentDelegate(ISupportFragment support) {
76 | if (!(support instanceof Fragment))
77 | throw new RuntimeException("Must extends Fragment");
78 | this.mSupportF = support;
79 | this.mFragment = (Fragment) support;
80 | }
81 |
82 | /**
83 | * Perform some extra transactions.
84 | * 额外的事务:自定义Tag,添加SharedElement动画,操作非回退栈Fragment
85 | */
86 | public ExtraTransaction extraTransaction() {
87 | if (mTransactionDelegate == null)
88 | throw new RuntimeException(mFragment.getClass().getSimpleName() + " not attach!");
89 |
90 | return new ExtraTransaction.ExtraTransactionImpl<>((FragmentActivity) mSupport,
91 | mSupportF, mTransactionDelegate, false);
92 | }
93 |
94 | public void onAttach(Context context) {
95 | if (context instanceof ISupportActivity) {
96 | this.mSupport = (ISupportActivity) context;
97 | this._mActivity = (FragmentActivity) context;
98 | mTransactionDelegate = mSupport.getSupportDelegate().getTransactionDelegate();
99 | } else {
100 | throw new RuntimeException(context.getClass().getSimpleName() + " must impl ISupportActivity!");
101 | }
102 | }
103 |
104 | public void onCreate(@Nullable Bundle savedInstanceState) {
105 | if(savedInstanceState != null) {
106 | startByFragmentation = savedInstanceState.getBoolean(S_FRAGMENTATION_FRAGMENT_START_PROP, false);
107 | isVisible = savedInstanceState.getBoolean(S_FRAGMENTATION_FRAGMENT_VISIBLE_PROP, false);
108 | canPop = savedInstanceState.getBoolean(S_FRAGMENTATION_FRAGMENT_POP_PROP, true);
109 | }
110 | Bundle bundle = mFragment.getArguments();
111 | if (bundle != null) {
112 | mContainerId = bundle.getInt(TransactionDelegate.FRAGMENTATION_ARG_CONTAINER);
113 | }
114 | }
115 |
116 | public void onViewCreated(@Nullable Bundle savedInstanceState) {
117 | View view = mFragment.getView();
118 | if (view != null) {
119 | setBackground(view);
120 | }
121 | }
122 |
123 | public void onSaveInstanceState(@NonNull Bundle outState) {
124 | outState.putBoolean(S_FRAGMENTATION_FRAGMENT_START_PROP, startByFragmentation);
125 | outState.putBoolean(S_FRAGMENTATION_FRAGMENT_POP_PROP, canPop);
126 | outState.putBoolean(S_FRAGMENTATION_FRAGMENT_VISIBLE_PROP, isVisible);
127 | }
128 |
129 | public void setBackground(View view) {
130 | if (view.getBackground() != null) {
131 | return;
132 | }
133 |
134 | int defaultBg = mSupport.getSupportDelegate().getDefaultFragmentBackground();
135 | if (defaultBg == 0) {
136 | int background = getWindowBackground();
137 | view.setBackgroundResource(background);
138 | } else {
139 | view.setBackgroundResource(defaultBg);
140 | }
141 | }
142 |
143 | private int getWindowBackground() {
144 | TypedArray a = _mActivity.getTheme().obtainStyledAttributes(new int[]{
145 | android.R.attr.windowBackground
146 | });
147 | int background = a.getResourceId(0, 0);
148 | a.recycle();
149 | return background;
150 | }
151 |
152 | public void onDestroy() {
153 | mTransactionDelegate.handleResultRecord(mFragment);
154 | }
155 |
156 | /**
157 | * Causes the Runnable r to be added to the action queue.
158 | *
159 | * The runnable will be run after all the previous action has been run.
160 | *
161 | * 前面的事务全部执行后 执行该Action
162 | */
163 | public void post(final Runnable runnable) {
164 | mTransactionDelegate.post(runnable);
165 | }
166 |
167 | /**
168 | * 类似 {@link Activity#setResult(int, Intent)}
169 | *
170 | * Similar to {@link Activity#setResult(int, Intent)}
171 | *
172 | * @see #startForResult(ISupportFragment, int)
173 | */
174 | public void setFragmentResult(int resultCode, Bundle bundle) {
175 | Bundle args = mFragment.getArguments();
176 | if (args == null || !args.containsKey(TransactionDelegate.FRAGMENTATION_ARG_RESULT_RECORD)) {
177 | return;
178 | }
179 |
180 | ResultRecord resultRecord = args.getParcelable(TransactionDelegate.FRAGMENTATION_ARG_RESULT_RECORD);
181 | if (resultRecord != null) {
182 | resultRecord.resultCode = resultCode;
183 | resultRecord.resultBundle = bundle;
184 | }
185 | }
186 |
187 | /**
188 | * 添加NewBundle,用于启动模式为SingleTask/SingleTop时
189 | *
190 | * @see #start(ISupportFragment, int)
191 | */
192 | public void putNewBundle(Bundle newBundle) {
193 | this.mNewBundle = newBundle;
194 | }
195 |
196 | /**
197 | * Back Event
198 | *
199 | * @return false则继续向上传递, true则消费掉该事件
200 | */
201 | public boolean onBackPressedSupport() {
202 | return false;
203 | }
204 |
205 |
206 | /**
207 | * 隐藏软键盘
208 | */
209 | public void hideSoftInput() {
210 | Activity activity = mFragment.getActivity();
211 | if (activity == null) return;
212 | View view = activity.getWindow().getDecorView();
213 | SupportHelper.hideSoftInput(view);
214 | }
215 |
216 | /**
217 | * 显示软键盘
218 | */
219 | public void showSoftInput(View view) {
220 | SupportHelper.showSoftInput(view);
221 | }
222 |
223 |
224 | /**
225 | * 加载根Fragment, 即Activity内的第一个Fragment 或 Fragment内的第一个子Fragment
226 | */
227 |
228 | public void loadRootFragment(int containerId, ISupportFragment toFragment) {
229 |
230 | mTransactionDelegate.loadRootTransaction(getChildFragmentManager(),
231 | containerId, toFragment);
232 | }
233 |
234 | /**
235 | * 加载多个同级根Fragment
236 | */
237 | public void loadMultipleRootFragment(int containerId, int showPosition,
238 | ISupportFragment... toFragments) {
239 |
240 | mTransactionDelegate.loadMultipleRootTransaction(getChildFragmentManager(),
241 | containerId, showPosition, toFragments);
242 | }
243 |
244 | /**
245 | * show一个Fragment,hide其他同栈所有Fragment
246 | * 使用该方法时,要确保同级栈内无多余的Fragment(只有通过loadMultipleRootFragment()载入的Fragment)
247 | *
248 | * 建议使用更明确的{@link #showHideFragment(ISupportFragment, ISupportFragment)}
249 | */
250 | public void showHideFragment(ISupportFragment showFragment) {
251 | showHideFragment(showFragment, null);
252 | }
253 |
254 | /**
255 | * show一个Fragment,hide一个Fragment
256 | */
257 | public void showHideFragment(ISupportFragment showFragment, ISupportFragment hideFragment) {
258 | mTransactionDelegate.showHideFragment(getChildFragmentManager(), showFragment, hideFragment);
259 | }
260 |
261 | public void start(ISupportFragment toFragment) {
262 | start(toFragment, ISupportFragment.STANDARD);
263 | }
264 |
265 | /**
266 | * @param launchMode Similar to Activity's LaunchMode.
267 | */
268 | public void start(final ISupportFragment toFragment, @ISupportFragment.LaunchMode int launchMode) {
269 |
270 | mTransactionDelegate.dispatchStartTransaction(mFragment.getParentFragmentManager(), mSupportF,
271 | toFragment, 0, launchMode, TransactionDelegate.TYPE_ADD);
272 | }
273 |
274 | /**
275 | * Launch an fragment for which you would like a result when it poped.
276 | */
277 | public void startForResult(ISupportFragment toFragment, int requestCode) {
278 |
279 | mTransactionDelegate.dispatchStartTransaction(mFragment.getParentFragmentManager(), mSupportF,
280 | toFragment, requestCode, ISupportFragment.STANDARD, TransactionDelegate.TYPE_ADD_RESULT);
281 | }
282 |
283 | /**
284 | * Start the target Fragment and pop itself
285 | */
286 | public void startWithPop(ISupportFragment toFragment) {
287 | mTransactionDelegate.dispatchStartWithPopTransaction(mFragment.getParentFragmentManager(), mSupportF, toFragment);
288 | }
289 |
290 | public void startWithPopTo(ISupportFragment toFragment, Class> targetFragmentClass,
291 | boolean includeTargetFragment) {
292 |
293 | mTransactionDelegate.dispatchStartWithPopToTransaction(mFragment.getParentFragmentManager(), mSupportF,
294 | toFragment, targetFragmentClass.getName(), includeTargetFragment);
295 | }
296 |
297 | public void replaceFragment(ISupportFragment toFragment) {
298 |
299 | mTransactionDelegate.dispatchStartTransaction(mFragment.getParentFragmentManager(), mSupportF,
300 | toFragment, 0, ISupportFragment.STANDARD,
301 | TransactionDelegate.TYPE_REPLACE);
302 | }
303 |
304 | public void startChild(ISupportFragment toFragment) {
305 | startChild(toFragment, ISupportFragment.STANDARD);
306 | }
307 |
308 | public void startChild(final ISupportFragment toFragment, @ISupportFragment.LaunchMode int launchMode) {
309 |
310 | mTransactionDelegate.dispatchStartTransaction(getChildFragmentManager(), getChildTopFragment(),
311 | toFragment, 0, launchMode, TransactionDelegate.TYPE_ADD);
312 | }
313 |
314 | public void startChildForResult(ISupportFragment toFragment, int requestCode) {
315 |
316 | mTransactionDelegate.dispatchStartTransaction(getChildFragmentManager(), getChildTopFragment(),
317 | toFragment, requestCode, ISupportFragment.STANDARD, TransactionDelegate.TYPE_ADD_RESULT);
318 | }
319 |
320 | public void startChildWithPop(ISupportFragment toFragment) {
321 | mTransactionDelegate.dispatchStartWithPopTransaction(getChildFragmentManager(), getChildTopFragment(), toFragment);
322 | }
323 |
324 | public void replaceChildFragment(ISupportFragment toFragment) {
325 | mTransactionDelegate.dispatchStartTransaction(getChildFragmentManager(), getChildTopFragment(),
326 | toFragment, 0, ISupportFragment.STANDARD, TransactionDelegate.TYPE_REPLACE);
327 | }
328 |
329 | public void pop() {
330 | mTransactionDelegate.pop(mFragment.getParentFragmentManager());
331 | }
332 |
333 | public void popQuiet() {
334 | mTransactionDelegate.popQuiet(mFragment.getParentFragmentManager());
335 | }
336 |
337 | /**
338 | * Pop the child fragment.
339 | */
340 | public void popChild() {
341 | mTransactionDelegate.pop(getChildFragmentManager());
342 | }
343 |
344 | /**
345 | * Pop the last fragment transition from the manager's fragment
346 | * back stack.
347 | *
348 | * 出栈到目标fragment
349 | *
350 | * @param targetFragmentClass 目标fragment
351 | * @param includeTargetFragment 是否包含该fragment
352 | */
353 | public void popTo(Class> targetFragmentClass, boolean includeTargetFragment) {
354 | popTo(targetFragmentClass, includeTargetFragment, null);
355 | }
356 |
357 | /**
358 | * If you want to begin another FragmentTransaction immediately after popTo(), use this method.
359 | * 如果你想在出栈后, 立刻进行FragmentTransaction操作,请使用该方法
360 | */
361 | public void popTo(Class> targetFragmentClass, boolean includeTargetFragment,
362 | Runnable afterPopTransactionRunnable) {
363 |
364 | mTransactionDelegate.popTo(targetFragmentClass.getName(), includeTargetFragment,
365 | afterPopTransactionRunnable, mFragment.getParentFragmentManager());
366 | }
367 |
368 | public void popToChild(Class> targetFragmentClass, boolean includeTargetFragment) {
369 | popToChild(targetFragmentClass, includeTargetFragment, null);
370 | }
371 |
372 | public void popToChild(Class> targetFragmentClass, boolean includeTargetFragment,
373 | Runnable afterPopTransactionRunnable) {
374 |
375 | mTransactionDelegate.popTo(targetFragmentClass.getName(), includeTargetFragment,
376 | afterPopTransactionRunnable, getChildFragmentManager());
377 | }
378 |
379 | private FragmentManager getChildFragmentManager() {
380 | return mFragment.getChildFragmentManager();
381 | }
382 |
383 | private ISupportFragment getChildTopFragment() {
384 | return SupportHelper.getTopFragment(getChildFragmentManager());
385 | }
386 |
387 | public FragmentActivity getActivity() {
388 | return _mActivity;
389 | }
390 | }
--------------------------------------------------------------------------------
/fragmentation/src/main/java/com/weikaiyun/fragmentation/SupportHelper.java:
--------------------------------------------------------------------------------
1 | package com.weikaiyun.fragmentation;
2 |
3 | import android.content.Context;
4 | import android.view.View;
5 | import android.view.inputmethod.InputMethodManager;
6 |
7 | import androidx.fragment.app.Fragment;
8 | import androidx.fragment.app.FragmentManager;
9 |
10 | import java.util.ArrayList;
11 | import java.util.List;
12 |
13 | public class SupportHelper {
14 | private static final long SHOW_SPACE = 200L;
15 |
16 | private SupportHelper() {
17 | }
18 |
19 | /**
20 | * 显示软键盘
21 | */
22 | public static void showSoftInput(final View view) {
23 | if (view == null || view.getContext() == null) return;
24 | final InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
25 | view.requestFocus();
26 | view.postDelayed(new Runnable() {
27 | @Override
28 | public void run() {
29 | imm.showSoftInput(view, InputMethodManager.SHOW_FORCED);
30 | }
31 | }, SHOW_SPACE);
32 | }
33 |
34 | /**
35 | * 隐藏软键盘
36 | */
37 | public static void hideSoftInput(View view) {
38 | if (view == null || view.getContext() == null) return;
39 | InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
40 | imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
41 | }
42 |
43 | /**
44 | * 获得栈顶SupportFragment
45 | */
46 | public static ISupportFragment getTopFragment(FragmentManager fragmentManager) {
47 | return getTopFragment(fragmentManager, 0);
48 | }
49 |
50 | public static ISupportFragment getTopFragment(FragmentManager fragmentManager, int containerId) {
51 | List fragmentList = getActiveFragments(fragmentManager);
52 | for (int i = fragmentList.size() - 1; i >= 0; i--) {
53 | Fragment fragment = fragmentList.get(i);
54 | if (fragment instanceof ISupportFragment) {
55 | ISupportFragment iFragment = (ISupportFragment) fragment;
56 | if (containerId == 0) return iFragment;
57 |
58 | if (containerId == iFragment.getSupportDelegate().mContainerId) {
59 | return iFragment;
60 | }
61 | }
62 | }
63 | return null;
64 | }
65 |
66 | /**
67 | * 获取目标Fragment的前一个SupportFragment
68 | *
69 | * @param fragment 目标Fragment
70 | */
71 | public static ISupportFragment getPreFragment(Fragment fragment) {
72 | FragmentManager fragmentManager = fragment.getParentFragmentManager();
73 |
74 | List fragmentList = getActiveFragments(fragmentManager);
75 | int index = fragmentList.indexOf(fragment);
76 | for (int i = index - 1; i >= 0; i--) {
77 | Fragment preFragment = fragmentList.get(i);
78 | if (preFragment instanceof ISupportFragment) {
79 | return (ISupportFragment) preFragment;
80 | }
81 | }
82 | return null;
83 | }
84 |
85 | /**
86 | * Same as fragmentManager.findFragmentByTag(fragmentClass.getName());
87 | * find Fragment from FragmentStack
88 | */
89 | @SuppressWarnings("unchecked")
90 | public static T findFragment(FragmentManager fragmentManager, Class fragmentClass) {
91 | return findStackFragment(fragmentClass, null, fragmentManager);
92 | }
93 |
94 | /**
95 | * Same as fragmentManager.findFragmentByTag(fragmentTag);
96 | *
97 | * find Fragment from FragmentStack
98 | */
99 | @SuppressWarnings("unchecked")
100 | public static T findFragment(FragmentManager fragmentManager, String fragmentTag) {
101 | return findStackFragment(null, fragmentTag, fragmentManager);
102 | }
103 |
104 | /**
105 | * 从栈顶开始,寻找FragmentManager以及其所有子栈, 直到找到状态为show & userVisible的Fragment
106 | */
107 | public static ISupportFragment getActiveFragment(FragmentManager fragmentManager) {
108 | return getActiveFragment(fragmentManager, null);
109 | }
110 |
111 | @SuppressWarnings("unchecked")
112 | static T findStackFragment(Class fragmentClass, String toFragmentTag, FragmentManager fragmentManager) {
113 | Fragment fragment = null;
114 |
115 | if (toFragmentTag == null) {
116 | List fragmentList = getActiveFragments(fragmentManager);
117 |
118 | int sizeChildFrgList = fragmentList.size();
119 |
120 | for (int i = sizeChildFrgList - 1; i >= 0; i--) {
121 | Fragment brotherFragment = fragmentList.get(i);
122 | if (brotherFragment instanceof ISupportFragment && brotherFragment.getClass().getName().equals(fragmentClass.getName())) {
123 | fragment = brotherFragment;
124 | break;
125 | }
126 | }
127 | } else {
128 | fragment = fragmentManager.findFragmentByTag(toFragmentTag);
129 | if (fragment == null) return null;
130 | }
131 | return (T) fragment;
132 | }
133 |
134 | private static ISupportFragment getActiveFragment(FragmentManager fragmentManager, ISupportFragment parentFragment) {
135 | List fragmentList = getActiveFragments(fragmentManager);
136 | for (int i = fragmentList.size() - 1; i >= 0; i--) {
137 | Fragment fragment = fragmentList.get(i);
138 | if (fragment instanceof ISupportFragment) {
139 | if (fragment.isResumed() && !fragment.isHidden()) {
140 | return getActiveFragment(fragment.getChildFragmentManager(), (ISupportFragment) fragment);
141 | }
142 | }
143 | }
144 | return parentFragment;
145 | }
146 |
147 | static List getWillPopFragments(FragmentManager fm, String targetTag, boolean includeTarget) {
148 | Fragment target = fm.findFragmentByTag(targetTag);
149 | List willPopFragments = new ArrayList<>();
150 |
151 | List fragmentList = getActiveFragments(fm);
152 |
153 | int size = fragmentList.size();
154 |
155 | int startIndex = -1;
156 | for (int i = size - 1; i >= 0; i--) {
157 | if (target == fragmentList.get(i)) {
158 | if (includeTarget) {
159 | startIndex = i;
160 | } else if (i + 1 < size) {
161 | startIndex = i + 1;
162 | }
163 | break;
164 | }
165 | }
166 |
167 | if (startIndex == -1) return willPopFragments;
168 |
169 | for (int i = size - 1; i >= startIndex; i--) {
170 | Fragment fragment = fragmentList.get(i);
171 | if (fragment != null && fragment.getView() != null) {
172 | willPopFragments.add(fragment);
173 | }
174 | }
175 | return willPopFragments;
176 | }
177 |
178 | public static List getActiveFragments(FragmentManager fragmentManager) {
179 | return fragmentManager.getFragments();
180 | }
181 | }
182 |
--------------------------------------------------------------------------------
/fragmentation/src/main/java/com/weikaiyun/fragmentation/animation/FragmentAnimator.java:
--------------------------------------------------------------------------------
1 | package com.weikaiyun.fragmentation.animation;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 |
6 | import androidx.annotation.AnimRes;
7 |
8 | /**
9 | * Fragment动画实体类
10 | */
11 | public class FragmentAnimator implements Parcelable {
12 | @AnimRes
13 | protected int targetFragmentEnter;
14 | @AnimRes
15 | protected int currentFragmentPopExit;
16 | @AnimRes
17 | protected int currentFragmentPopEnter;
18 | @AnimRes
19 | protected int targetFragmentExit;
20 |
21 | public FragmentAnimator() {
22 | }
23 |
24 | public FragmentAnimator(int targetFragmentEnter, int currentFragmentPopExit, int currentFragmentPopEnter, int targetFragmentExit) {
25 | this.targetFragmentEnter = targetFragmentEnter;
26 | this.currentFragmentPopExit = currentFragmentPopExit;
27 | this.currentFragmentPopEnter = currentFragmentPopEnter;
28 | this.targetFragmentExit = targetFragmentExit;
29 | }
30 |
31 | protected FragmentAnimator(Parcel in) {
32 | targetFragmentEnter = in.readInt();
33 | currentFragmentPopExit = in.readInt();
34 | currentFragmentPopEnter = in.readInt();
35 | targetFragmentExit = in.readInt();
36 | }
37 |
38 | public static final Creator CREATOR = new Creator() {
39 | @Override
40 | public FragmentAnimator createFromParcel(Parcel in) {
41 | return new FragmentAnimator(in);
42 | }
43 |
44 | @Override
45 | public FragmentAnimator[] newArray(int size) {
46 | return new FragmentAnimator[size];
47 | }
48 | };
49 |
50 | public int getTargetFragmentEnter() {
51 | return targetFragmentEnter;
52 | }
53 |
54 | public int getCurrentFragmentPopExit() {
55 | return currentFragmentPopExit;
56 | }
57 |
58 | public int getCurrentFragmentPopEnter() {
59 | return currentFragmentPopEnter;
60 | }
61 |
62 | public int getTargetFragmentExit() {
63 | return targetFragmentExit;
64 | }
65 |
66 | public FragmentAnimator setTargetFragmentEnter(int targetFragmentEnter) {
67 | this.targetFragmentEnter = targetFragmentEnter;
68 | return this;
69 | }
70 |
71 | public FragmentAnimator setCurrentFragmentPopExit(int currentFragmentPopExit) {
72 | this.currentFragmentPopExit = currentFragmentPopExit;
73 | return this;
74 | }
75 |
76 | public FragmentAnimator setCurrentFragmentPopEnter(int currentFragmentPopEnter) {
77 | this.currentFragmentPopEnter = currentFragmentPopEnter;
78 | return this;
79 | }
80 |
81 | public FragmentAnimator setTargetFragmentExit(int targetFragmentExit) {
82 | this.targetFragmentExit = targetFragmentExit;
83 | return this;
84 | }
85 |
86 | @Override
87 | public int describeContents() {
88 | return 0;
89 | }
90 |
91 | @Override
92 | public void writeToParcel(Parcel dest, int flags) {
93 | dest.writeInt(targetFragmentEnter);
94 | dest.writeInt(currentFragmentPopExit);
95 | dest.writeInt(currentFragmentPopEnter);
96 | dest.writeInt(targetFragmentExit);
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/fragmentation/src/main/java/com/weikaiyun/fragmentation/debug/DebugFragmentRecord.java:
--------------------------------------------------------------------------------
1 | package com.weikaiyun.fragmentation.debug;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | * 为了调试时 查看栈视图
7 | */
8 | public class DebugFragmentRecord {
9 | public CharSequence fragmentName;
10 | public List childFragmentRecord;
11 |
12 | public DebugFragmentRecord(CharSequence fragmentName, List childFragmentRecord) {
13 | this.fragmentName = fragmentName;
14 | this.childFragmentRecord = childFragmentRecord;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/fragmentation/src/main/java/com/weikaiyun/fragmentation/debug/DebugHierarchyViewContainer.java:
--------------------------------------------------------------------------------
1 | package com.weikaiyun.fragmentation.debug;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Color;
6 | import android.util.AttributeSet;
7 | import android.view.Gravity;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.widget.HorizontalScrollView;
11 | import android.widget.ImageView;
12 | import android.widget.LinearLayout;
13 | import android.widget.ScrollView;
14 | import android.widget.TextView;
15 | import android.widget.Toast;
16 |
17 | import androidx.annotation.NonNull;
18 |
19 | import com.weikaiyun.fragmentation.R;
20 |
21 | import java.util.List;
22 |
23 | public class DebugHierarchyViewContainer extends ScrollView {
24 | private Context mContext;
25 |
26 | private LinearLayout mLinearLayout;
27 | private LinearLayout mTitleLayout;
28 |
29 | private int mItemHeight;
30 | private int mPadding;
31 |
32 | public DebugHierarchyViewContainer(Context context) {
33 | super(context);
34 | initView(context);
35 | }
36 |
37 | public DebugHierarchyViewContainer(Context context, AttributeSet attrs) {
38 | super(context, attrs);
39 | initView(context);
40 | }
41 |
42 | public DebugHierarchyViewContainer(Context context, AttributeSet attrs, int defStyleAttr) {
43 | super(context, attrs, defStyleAttr);
44 | initView(context);
45 | }
46 |
47 | private void initView(Context context) {
48 | mContext = context;
49 | HorizontalScrollView hScrollView = new HorizontalScrollView(context);
50 | mLinearLayout = new LinearLayout(context);
51 | mLinearLayout.setOrientation(LinearLayout.VERTICAL);
52 | hScrollView.addView(mLinearLayout);
53 | addView(hScrollView);
54 |
55 | mItemHeight = dip2px(50);
56 | mPadding = dip2px(16);
57 | }
58 |
59 | private int dip2px(float dp) {
60 | float scale = mContext.getResources().getDisplayMetrics().density;
61 | return (int) (dp * scale + 0.5f);
62 | }
63 |
64 | public void bindFragmentRecords(List fragmentRecords) {
65 | mLinearLayout.removeAllViews();
66 | LinearLayout ll = getTitleLayout();
67 | mLinearLayout.addView(ll);
68 |
69 | if (fragmentRecords == null) return;
70 |
71 | DebugHierarchyViewContainer.this.setView(fragmentRecords, 0, null);
72 | }
73 |
74 | @NonNull
75 | private LinearLayout getTitleLayout() {
76 | if (mTitleLayout != null) return mTitleLayout;
77 |
78 | mTitleLayout = new LinearLayout(mContext);
79 | mTitleLayout.setPadding(dip2px(24), dip2px(24), 0, dip2px(8));
80 | mTitleLayout.setOrientation(LinearLayout.HORIZONTAL);
81 | ViewGroup.LayoutParams flParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
82 | mTitleLayout.setLayoutParams(flParams);
83 |
84 | TextView title = new TextView(mContext);
85 | title.setText(mContext.getClass().getSimpleName());
86 | title.setTextSize(20);
87 | title.setTextColor(Color.BLACK);
88 | LinearLayout.LayoutParams p = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
89 | p.gravity = Gravity.CENTER_VERTICAL;
90 | title.setLayoutParams(p);
91 | mTitleLayout.addView(title);
92 |
93 | ImageView img = new ImageView(mContext);
94 | img.setImageResource(R.drawable.fragmentation_help);
95 | LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
96 | params.leftMargin = dip2px(16);
97 | params.gravity = Gravity.CENTER_VERTICAL;
98 | img.setLayoutParams(params);
99 | mTitleLayout.setOnClickListener(new OnClickListener() {
100 | @Override
101 | public void onClick(View v) {
102 | Toast.makeText(mContext, R.string.fragmentation_stack_help, Toast.LENGTH_LONG).show();
103 | }
104 | });
105 | mTitleLayout.addView(img);
106 | return mTitleLayout;
107 | }
108 |
109 | private void setView(final List fragmentRecordList, final int hierarchy, final TextView tvItem) {
110 | for (int i = fragmentRecordList.size() - 1; i >= 0; i--) {
111 | DebugFragmentRecord child = fragmentRecordList.get(i);
112 | int tempHierarchy = hierarchy;
113 |
114 | final TextView childTvItem;
115 | childTvItem = getTextView(child, tempHierarchy);
116 | childTvItem.setTag(R.id.hierarchy, tempHierarchy);
117 |
118 | final List childFragmentRecord = child.childFragmentRecord;
119 | if (childFragmentRecord != null && childFragmentRecord.size() > 0) {
120 | tempHierarchy++;
121 | childTvItem.setCompoundDrawablesWithIntrinsicBounds(R.drawable.fragmentation_ic_right, 0, 0, 0);
122 | final int finalChildHierarchy = tempHierarchy;
123 | childTvItem.setOnClickListener(new OnClickListener() {
124 | @Override
125 | public void onClick(View v) {
126 | if (v.getTag(R.id.isexpand) != null) {
127 | boolean isExpand = (boolean) v.getTag(R.id.isexpand);
128 | if (isExpand) {
129 | childTvItem.setCompoundDrawablesWithIntrinsicBounds(R.drawable.fragmentation_ic_right, 0, 0, 0);
130 | DebugHierarchyViewContainer.this.removeView(finalChildHierarchy);
131 | } else {
132 | handleExpandView(childFragmentRecord, finalChildHierarchy, childTvItem);
133 |
134 | }
135 | v.setTag(R.id.isexpand, !isExpand);
136 | } else {
137 | childTvItem.setTag(R.id.isexpand, true);
138 | handleExpandView(childFragmentRecord, finalChildHierarchy, childTvItem);
139 | }
140 | }
141 | });
142 | } else {
143 | childTvItem.setPadding(childTvItem.getPaddingLeft() + mPadding, 0, mPadding, 0);
144 | }
145 |
146 | if (tvItem == null) {
147 | mLinearLayout.addView(childTvItem);
148 | } else {
149 | mLinearLayout.addView(childTvItem, mLinearLayout.indexOfChild(tvItem) + 1);
150 | }
151 | }
152 | }
153 |
154 | private void handleExpandView(List childFragmentRecord, int finalChildHierarchy, TextView childTvItem) {
155 | DebugHierarchyViewContainer.this.setView(childFragmentRecord, finalChildHierarchy, childTvItem);
156 | childTvItem.setCompoundDrawablesWithIntrinsicBounds(R.drawable.fragmentation_ic_expandable, 0, 0, 0);
157 | }
158 |
159 | private void removeView(int hierarchy) {
160 | int size = mLinearLayout.getChildCount();
161 | for (int i = size - 1; i >= 0; i--) {
162 | View view = mLinearLayout.getChildAt(i);
163 | if (view.getTag(R.id.hierarchy) != null && (int) view.getTag(R.id.hierarchy) >= hierarchy) {
164 | mLinearLayout.removeView(view);
165 | }
166 | }
167 | }
168 |
169 | private TextView getTextView(DebugFragmentRecord fragmentRecord, int hierarchy) {
170 | TextView tvItem = new TextView(mContext);
171 |
172 | ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, mItemHeight);
173 | tvItem.setLayoutParams(params);
174 | if (hierarchy == 0) {
175 | tvItem.setTextColor(Color.parseColor("#333333"));
176 | tvItem.setTextSize(16);
177 | }else {
178 | tvItem.setTextColor(Color.parseColor("#666666"));
179 | }
180 | tvItem.setGravity(Gravity.CENTER_VERTICAL);
181 | tvItem.setPadding((int) (mPadding + hierarchy * mPadding * 1.5), 0, mPadding, 0);
182 | tvItem.setCompoundDrawablePadding(mPadding / 2);
183 |
184 | TypedArray a = mContext.obtainStyledAttributes(new int[]{android.R.attr.selectableItemBackground});
185 | tvItem.setBackground(a.getDrawable(0));
186 | a.recycle();
187 |
188 | tvItem.setText(fragmentRecord.fragmentName);
189 |
190 | return tvItem;
191 | }
192 | }
193 |
--------------------------------------------------------------------------------
/fragmentation/src/main/java/com/weikaiyun/fragmentation/debug/DebugStackDelegate.java:
--------------------------------------------------------------------------------
1 | package com.weikaiyun.fragmentation.debug;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.hardware.Sensor;
6 | import android.hardware.SensorEvent;
7 | import android.hardware.SensorEventListener;
8 | import android.hardware.SensorManager;
9 | import android.util.TypedValue;
10 | import android.view.Gravity;
11 | import android.view.MotionEvent;
12 | import android.view.View;
13 | import android.view.ViewGroup;
14 | import android.widget.FrameLayout;
15 | import android.widget.ImageView;
16 |
17 | import androidx.annotation.NonNull;
18 | import androidx.appcompat.app.AlertDialog;
19 | import androidx.fragment.app.Fragment;
20 | import androidx.fragment.app.FragmentActivity;
21 |
22 | import com.weikaiyun.fragmentation.Fragmentation;
23 | import com.weikaiyun.fragmentation.ISupportFragment;
24 | import com.weikaiyun.fragmentation.R;
25 | import com.weikaiyun.fragmentation.SupportHelper;
26 |
27 | import java.util.ArrayList;
28 | import java.util.List;
29 |
30 | public class DebugStackDelegate implements SensorEventListener {
31 | private final FragmentActivity mActivity;
32 | private SensorManager mSensorManager;
33 | private AlertDialog mStackDialog;
34 |
35 | public DebugStackDelegate(FragmentActivity activity) {
36 | this.mActivity = activity;
37 | }
38 |
39 | public void onCreate(int mode) {
40 | if (mode != Fragmentation.SHAKE) return;
41 | mSensorManager = (SensorManager) mActivity.getSystemService(Context.SENSOR_SERVICE);
42 | mSensorManager.registerListener(this,
43 | mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
44 | SensorManager.SENSOR_DELAY_NORMAL);
45 | }
46 |
47 | @SuppressLint("ClickableViewAccessibility")
48 | public void onPostCreate(int mode) {
49 | if (mode != Fragmentation.BUBBLE) return;
50 | View root = mActivity.findViewById(android.R.id.content);
51 | if (root instanceof FrameLayout) {
52 | FrameLayout content = (FrameLayout) root;
53 | final ImageView stackView = new ImageView(mActivity);
54 | stackView.setImageResource(R.drawable.fragmentation_ic_stack);
55 | FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
56 | params.gravity = Gravity.END;
57 | final int dp18 = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 18, mActivity.getResources().getDisplayMetrics());
58 | params.topMargin = dp18 * 7;
59 | params.rightMargin = dp18;
60 | stackView.setLayoutParams(params);
61 | content.addView(stackView);
62 | stackView.setOnTouchListener(new StackViewTouchListener(stackView, dp18 / 4));
63 | stackView.setOnClickListener(new View.OnClickListener() {
64 | @Override
65 | public void onClick(View v) {
66 | showFragmentStackHierarchyView();
67 | }
68 | });
69 | }
70 | }
71 |
72 | public void onDestroy() {
73 | if (mSensorManager != null) {
74 | mSensorManager.unregisterListener(this);
75 | }
76 | }
77 |
78 | @Override
79 | public void onSensorChanged(SensorEvent event) {
80 | int sensorType = event.sensor.getType();
81 | float[] values = event.values;
82 | if (sensorType == Sensor.TYPE_ACCELEROMETER) {
83 | int value = 12;
84 | if ((Math.abs(values[0]) >= value || Math.abs(values[1]) >= value || Math.abs(values[2]) >= value)) {
85 | showFragmentStackHierarchyView();
86 | }
87 | }
88 | }
89 |
90 | @Override
91 | public void onAccuracyChanged(Sensor sensor, int accuracy) {
92 | }
93 |
94 | /**
95 | * 调试相关:以dialog形式 显示 栈视图
96 | */
97 | public void showFragmentStackHierarchyView() {
98 | if (mStackDialog != null && mStackDialog.isShowing()) return;
99 | DebugHierarchyViewContainer container = new DebugHierarchyViewContainer(mActivity);
100 | container.bindFragmentRecords(getFragmentRecords());
101 | container.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
102 | mStackDialog = new AlertDialog.Builder(mActivity)
103 | .setView(container)
104 | .setPositiveButton(android.R.string.cancel, null)
105 | .setCancelable(true)
106 | .create();
107 | mStackDialog.show();
108 | }
109 |
110 |
111 |
112 | private List getFragmentRecords() {
113 | List fragmentRecordList = new ArrayList<>();
114 |
115 | List fragmentList = SupportHelper.getActiveFragments(mActivity.getSupportFragmentManager());
116 |
117 | if (fragmentList.size() < 1) return null;
118 |
119 | for (Fragment fragment : fragmentList) {
120 | addDebugFragmentRecord(fragmentRecordList, fragment);
121 | }
122 | return fragmentRecordList;
123 | }
124 |
125 | private List getChildFragmentRecords(Fragment parentFragment) {
126 | List fragmentRecords = new ArrayList<>();
127 |
128 | List fragmentList = SupportHelper.getActiveFragments(parentFragment.getChildFragmentManager());
129 | if (fragmentList.size() < 1) return null;
130 |
131 | for (int i = fragmentList.size() - 1; i >= 0; i--) {
132 | Fragment fragment = fragmentList.get(i);
133 | addDebugFragmentRecord(fragmentRecords, fragment);
134 | }
135 | return fragmentRecords;
136 | }
137 |
138 | private void addDebugFragmentRecord(List fragmentRecords, Fragment fragment) {
139 | if (fragment != null) {
140 | CharSequence name = fragment.getClass().getSimpleName();
141 |
142 | if (fragment instanceof ISupportFragment && ((ISupportFragment)fragment).getSupportDelegate().isVisible()) {
143 | name = span(name, " ☀");
144 | }
145 |
146 | fragmentRecords.add(new DebugFragmentRecord(name, getChildFragmentRecords(fragment)));
147 | }
148 | }
149 |
150 | @NonNull
151 | private CharSequence span(CharSequence name, String str) {
152 | name = name + str;
153 | return name;
154 | }
155 |
156 | private static class StackViewTouchListener implements View.OnTouchListener {
157 | private final View stackView;
158 | private float dX, dY = 0f;
159 | private float downX, downY = 0f;
160 | private boolean isClickState;
161 | private final int clickLimitValue;
162 |
163 | StackViewTouchListener(View stackView, int clickLimitValue) {
164 | this.stackView = stackView;
165 | this.clickLimitValue = clickLimitValue;
166 | }
167 |
168 | @Override
169 | public boolean onTouch(View v, MotionEvent event) {
170 | float X = event.getRawX();
171 | float Y = event.getRawY();
172 | switch (event.getAction()) {
173 | case MotionEvent.ACTION_DOWN:
174 | isClickState = true;
175 | downX = X;
176 | downY = Y;
177 | dX = stackView.getX() - event.getRawX();
178 | dY = stackView.getY() - event.getRawY();
179 | break;
180 | case MotionEvent.ACTION_MOVE:
181 | if (Math.abs(X - downX) < clickLimitValue && Math.abs(Y - downY) < clickLimitValue && isClickState) {
182 | isClickState = true;
183 | } else {
184 | isClickState = false;
185 | stackView.setX(event.getRawX() + dX);
186 | stackView.setY(event.getRawY() + dY);
187 | }
188 | break;
189 | case MotionEvent.ACTION_CANCEL:
190 | case MotionEvent.ACTION_UP:
191 | if (X - downX < clickLimitValue && isClickState) {
192 | stackView.performClick();
193 | }
194 | break;
195 | default:
196 | return false;
197 | }
198 | return true;
199 | }
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/fragmentation/src/main/java/com/weikaiyun/fragmentation/queue/Action.java:
--------------------------------------------------------------------------------
1 | package com.weikaiyun.fragmentation.queue;
2 |
3 | import androidx.fragment.app.FragmentManager;
4 |
5 | public abstract class Action {
6 | public static final long DEFAULT_POP_TIME = 320L;
7 |
8 | public static final int ACTION_NORMAL = 0;
9 | public static final int ACTION_POP = 1;
10 | public static final int ACTION_BACK = 2;
11 | public static final int ACTION_LOAD = 3;
12 |
13 | public FragmentManager fragmentManager;
14 | public int action = ACTION_NORMAL;
15 | public long duration = 0;
16 |
17 | public Action() {
18 | }
19 |
20 | public Action(int action) {
21 | this.action = action;
22 | }
23 |
24 | public Action(int action, FragmentManager fragmentManager) {
25 | this(action);
26 | this.fragmentManager = fragmentManager;
27 | }
28 |
29 | public abstract void run();
30 | }
31 |
--------------------------------------------------------------------------------
/fragmentation/src/main/java/com/weikaiyun/fragmentation/queue/ActionQueue.java:
--------------------------------------------------------------------------------
1 | package com.weikaiyun.fragmentation.queue;
2 |
3 | import android.os.Handler;
4 | import android.os.Looper;
5 |
6 | import java.util.LinkedList;
7 | import java.util.Queue;
8 |
9 | public class ActionQueue {
10 | private final Queue mQueue = new LinkedList<>();
11 | private final Handler mMainHandler;
12 |
13 | public ActionQueue(Handler mainHandler) {
14 | this.mMainHandler = mainHandler;
15 | }
16 |
17 | public void enqueue(final Action action) {
18 | if (isThrottleBACK(action)) return;
19 |
20 | if (action.action == Action.ACTION_LOAD && mQueue.isEmpty()
21 | && Thread.currentThread() == Looper.getMainLooper().getThread()) {
22 | action.run();
23 | return;
24 | }
25 |
26 | mMainHandler.post(new Runnable() {
27 | @Override
28 | public void run() {
29 | enqueueAction(action);
30 | }
31 | });
32 | }
33 |
34 | private void enqueueAction(Action action) {
35 | mQueue.add(action);
36 | if (mQueue.size() == 1) {
37 | handleAction();
38 | }
39 | }
40 |
41 | private void handleAction() {
42 | if (mQueue.isEmpty()) return;
43 |
44 | Action action = mQueue.peek();
45 | assert action != null;
46 | action.run();
47 |
48 | executeNextAction(action);
49 | }
50 |
51 | private void executeNextAction(Action action) {
52 | if (action.action == Action.ACTION_POP) {
53 | action.duration = Action.DEFAULT_POP_TIME;
54 | }
55 |
56 | mMainHandler.postDelayed(new Runnable() {
57 | @Override
58 | public void run() {
59 | mQueue.poll();
60 | handleAction();
61 | }
62 | }, action.duration);
63 | }
64 |
65 | private boolean isThrottleBACK(Action action) {
66 | if (action.action == Action.ACTION_BACK) {
67 | Action head = mQueue.peek();
68 | return head != null && head.action == Action.ACTION_POP;
69 | }
70 | return false;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/fragmentation/src/main/java/com/weikaiyun/fragmentation/record/ResultRecord.java:
--------------------------------------------------------------------------------
1 | package com.weikaiyun.fragmentation.record;
2 |
3 | import android.os.Bundle;
4 | import android.os.Parcel;
5 | import android.os.Parcelable;
6 |
7 | public final class ResultRecord implements Parcelable {
8 | public int requestCode;
9 | public int resultCode = 0;
10 | public Bundle resultBundle;
11 |
12 | public ResultRecord() {
13 | }
14 |
15 | protected ResultRecord(Parcel in) {
16 | requestCode = in.readInt();
17 | resultCode = in.readInt();
18 | resultBundle = in.readBundle(getClass().getClassLoader());
19 | }
20 |
21 | public static final Creator CREATOR = new Creator() {
22 | @Override
23 | public ResultRecord createFromParcel(Parcel in) {
24 | return new ResultRecord(in);
25 | }
26 |
27 | @Override
28 | public ResultRecord[] newArray(int size) {
29 | return new ResultRecord[size];
30 | }
31 | };
32 |
33 | @Override
34 | public int describeContents() {
35 | return 0;
36 | }
37 |
38 | @Override
39 | public void writeToParcel(Parcel dest, int flags) {
40 | dest.writeInt(requestCode);
41 | dest.writeInt(resultCode);
42 | dest.writeBundle(resultBundle);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/fragmentation/src/main/java/com/weikaiyun/fragmentation/record/TransactionRecord.java:
--------------------------------------------------------------------------------
1 | package com.weikaiyun.fragmentation.record;
2 |
3 | public final class TransactionRecord {
4 | public String tag;
5 | public int targetFragmentEnter = Integer.MIN_VALUE;
6 | public int currentFragmentPopExit = Integer.MIN_VALUE;
7 | public int currentFragmentPopEnter = Integer.MIN_VALUE;
8 | public int targetFragmentExit = Integer.MIN_VALUE;
9 | }
10 |
--------------------------------------------------------------------------------
/fragmentation/src/main/res/anim/h_fragment_enter.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
--------------------------------------------------------------------------------
/fragmentation/src/main/res/anim/h_fragment_exit.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
9 |
--------------------------------------------------------------------------------
/fragmentation/src/main/res/anim/h_fragment_pop_enter.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
7 |
--------------------------------------------------------------------------------
/fragmentation/src/main/res/anim/h_fragment_pop_exit.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
--------------------------------------------------------------------------------
/fragmentation/src/main/res/anim/v_fragment_enter.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
23 |
28 |
32 |
--------------------------------------------------------------------------------
/fragmentation/src/main/res/anim/v_fragment_exit.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
22 |
28 |
32 |
--------------------------------------------------------------------------------
/fragmentation/src/main/res/anim/v_fragment_pop_enter.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
21 |
25 |
--------------------------------------------------------------------------------
/fragmentation/src/main/res/anim/v_fragment_pop_exit.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
22 |
26 |
--------------------------------------------------------------------------------
/fragmentation/src/main/res/drawable-xxhdpi/fragmentation_help.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikaiyun/SFragmentation/bd500d1fde6fa45651a6abd331c5b4ff4dc7acce/fragmentation/src/main/res/drawable-xxhdpi/fragmentation_help.png
--------------------------------------------------------------------------------
/fragmentation/src/main/res/drawable-xxhdpi/fragmentation_ic_expandable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikaiyun/SFragmentation/bd500d1fde6fa45651a6abd331c5b4ff4dc7acce/fragmentation/src/main/res/drawable-xxhdpi/fragmentation_ic_expandable.png
--------------------------------------------------------------------------------
/fragmentation/src/main/res/drawable-xxhdpi/fragmentation_ic_right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikaiyun/SFragmentation/bd500d1fde6fa45651a6abd331c5b4ff4dc7acce/fragmentation/src/main/res/drawable-xxhdpi/fragmentation_ic_right.png
--------------------------------------------------------------------------------
/fragmentation/src/main/res/drawable-xxhdpi/fragmentation_ic_stack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikaiyun/SFragmentation/bd500d1fde6fa45651a6abd331c5b4ff4dc7acce/fragmentation/src/main/res/drawable-xxhdpi/fragmentation_ic_stack.png
--------------------------------------------------------------------------------
/fragmentation/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/fragmentation/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Stack
3 | ☀: Visible
4 |
5 |
--------------------------------------------------------------------------------
/fragmentation/src/test/java/com/weikaiyun/fragmentation/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.weikaiyun.fragmentation;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/fragmentation_swipeback/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/fragmentation_swipeback/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'com.github.dcendents.android-maven'
3 |
4 | android {
5 | compileSdkVersion 30
6 |
7 | defaultConfig {
8 | minSdkVersion 19
9 | targetSdkVersion 30
10 | versionCode 1
11 | versionName "1.0"
12 |
13 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
14 | consumerProguardFiles "consumer-rules.pro"
15 | }
16 |
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 | }
24 |
25 | dependencies {
26 | implementation fileTree(dir: "libs", include: ["*.jar"])
27 | compileOnly "androidx.appcompat:appcompat:${versions.appcompat}"
28 | compileOnly project(':fragmentation')
29 | testImplementation 'junit:junit:4.13'
30 | androidTestImplementation 'androidx.test.ext:junit:1.1.2'
31 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
32 | }
--------------------------------------------------------------------------------
/fragmentation_swipeback/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikaiyun/SFragmentation/bd500d1fde6fa45651a6abd331c5b4ff4dc7acce/fragmentation_swipeback/consumer-rules.pro
--------------------------------------------------------------------------------
/fragmentation_swipeback/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
23 | # Fragmentation
24 | -keepclasseswithmembernames class androidx.customview.widget.ViewDragHelper{ *; }
--------------------------------------------------------------------------------
/fragmentation_swipeback/src/androidTest/java/com/weikaiyun/fragmentation_swipeback/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.weikaiyun.fragmentation_swipeback;
2 |
3 | import android.content.Context;
4 |
5 | import androidx.test.platform.app.InstrumentationRegistry;
6 | import androidx.test.ext.junit.runners.AndroidJUnit4;
7 |
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 |
11 | import static org.junit.Assert.*;
12 |
13 | /**
14 | * Instrumented test, which will execute on an Android device.
15 | *
16 | * @see Testing documentation
17 | */
18 | @RunWith(AndroidJUnit4.class)
19 | public class ExampleInstrumentedTest {
20 | @Test
21 | public void useAppContext() {
22 | // Context of the app under test.
23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
24 | assertEquals("com.weikaiyun.fragmentation_swipeback.test", appContext.getPackageName());
25 | }
26 | }
--------------------------------------------------------------------------------
/fragmentation_swipeback/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/fragmentation_swipeback/src/main/java/com/weikaiyun/fragmentation_swipeback/SwipeBackActivity.java:
--------------------------------------------------------------------------------
1 |
2 | package com.weikaiyun.fragmentation_swipeback;
3 |
4 | import android.os.Bundle;
5 |
6 | import com.weikaiyun.fragmentation.SupportActivity;
7 | import com.weikaiyun.fragmentation.SwipeBackLayout;
8 | import com.weikaiyun.fragmentation_swipeback.core.ISwipeBackActivity;
9 | import com.weikaiyun.fragmentation_swipeback.core.SwipeBackActivityDelegate;
10 |
11 | abstract public class SwipeBackActivity extends SupportActivity implements ISwipeBackActivity {
12 | final SwipeBackActivityDelegate mDelegate = new SwipeBackActivityDelegate(this);
13 |
14 | @Override
15 | protected void onCreate(Bundle savedInstanceState) {
16 | super.onCreate(savedInstanceState);
17 | mDelegate.onCreate(savedInstanceState);
18 | }
19 |
20 | @Override
21 | protected void onPostCreate(Bundle savedInstanceState) {
22 | super.onPostCreate(savedInstanceState);
23 | mDelegate.onPostCreate(savedInstanceState);
24 | }
25 |
26 | @Override
27 | public SwipeBackLayout getSwipeBackLayout() {
28 | return mDelegate.getSwipeBackLayout();
29 | }
30 |
31 | /**
32 | * 是否可滑动
33 | * @param enable
34 | */
35 | @Override
36 | public void setSwipeBackEnable(boolean enable) {
37 | mDelegate.setSwipeBackEnable(enable);
38 | }
39 |
40 | @Override
41 | public void setEdgeLevel(SwipeBackLayout.EdgeLevel edgeLevel) {
42 | mDelegate.setEdgeLevel(edgeLevel);
43 | }
44 |
45 | @Override
46 | public void setEdgeLevel(int widthPixel) {
47 | mDelegate.setEdgeLevel(widthPixel);
48 | }
49 |
50 | /**
51 | * 限制SwipeBack的条件,默认栈内Fragment数 <= 1时 , 优先滑动退出Activity , 而不是Fragment
52 | *
53 | * @return true: Activity优先滑动退出; false: Fragment优先滑动退出
54 | */
55 | @Override
56 | public boolean swipeBackPriority() {
57 | return mDelegate.swipeBackPriority();
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/fragmentation_swipeback/src/main/java/com/weikaiyun/fragmentation_swipeback/SwipeBackFragment.java:
--------------------------------------------------------------------------------
1 | package com.weikaiyun.fragmentation_swipeback;
2 |
3 | import android.os.Bundle;
4 | import android.view.View;
5 |
6 | import androidx.annotation.FloatRange;
7 | import androidx.annotation.Nullable;
8 |
9 | import com.weikaiyun.fragmentation.SupportFragment;
10 | import com.weikaiyun.fragmentation.SwipeBackLayout;
11 | import com.weikaiyun.fragmentation_swipeback.core.ISwipeBackFragment;
12 | import com.weikaiyun.fragmentation_swipeback.core.SwipeBackFragmentDelegate;
13 |
14 |
15 | abstract public class SwipeBackFragment extends SupportFragment implements ISwipeBackFragment {
16 | final SwipeBackFragmentDelegate mDelegate = new SwipeBackFragmentDelegate(this);
17 |
18 | @Override
19 | public void onCreate(@Nullable Bundle savedInstanceState) {
20 | super.onCreate(savedInstanceState);
21 | mDelegate.onCreate(savedInstanceState);
22 | }
23 |
24 | @Override
25 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
26 | super.onViewCreated(view, savedInstanceState);
27 | mDelegate.onViewCreated(view, savedInstanceState);
28 | }
29 |
30 | @Override
31 | public View attachToSwipeBack(View view) {
32 | return mDelegate.attachToSwipeBack(view);
33 | }
34 |
35 |
36 | public SwipeBackLayout getSwipeBackLayout() {
37 | return mDelegate.getSwipeBackLayout();
38 | }
39 |
40 | /**
41 | * 是否可滑动
42 | *
43 | * @param enable
44 | */
45 | public void setSwipeBackEnable(boolean enable) {
46 | mDelegate.setSwipeBackEnable(enable);
47 | }
48 |
49 | @Override
50 | public void setEdgeLevel(SwipeBackLayout.EdgeLevel edgeLevel) {
51 | mDelegate.setEdgeLevel(edgeLevel);
52 | }
53 |
54 | @Override
55 | public void setEdgeLevel(int widthPixel) {
56 | mDelegate.setEdgeLevel(widthPixel);
57 | }
58 |
59 | /**
60 | * Set the offset of the parallax slip.
61 | */
62 | public void setParallaxOffset(@FloatRange(from = 0.0f, to = 1.0f) float offset) {
63 | mDelegate.setParallaxOffset(offset);
64 | }
65 | }
--------------------------------------------------------------------------------
/fragmentation_swipeback/src/main/java/com/weikaiyun/fragmentation_swipeback/core/ISwipeBackActivity.java:
--------------------------------------------------------------------------------
1 | package com.weikaiyun.fragmentation_swipeback.core;
2 |
3 | import com.weikaiyun.fragmentation.SwipeBackLayout;
4 |
5 | public interface ISwipeBackActivity {
6 |
7 | SwipeBackLayout getSwipeBackLayout();
8 |
9 | void setSwipeBackEnable(boolean enable);
10 |
11 | void setEdgeLevel(SwipeBackLayout.EdgeLevel edgeLevel);
12 |
13 | void setEdgeLevel(int widthPixel);
14 |
15 | /**
16 | * 限制SwipeBack的条件,默认栈内Fragment数 <= 1时 , 优先滑动退出Activity , 而不是Fragment
17 | *
18 | * @return true: Activity可以滑动退出, 并且总是优先; false: Fragment优先滑动退出
19 | */
20 | boolean swipeBackPriority();
21 | }
22 |
--------------------------------------------------------------------------------
/fragmentation_swipeback/src/main/java/com/weikaiyun/fragmentation_swipeback/core/ISwipeBackFragment.java:
--------------------------------------------------------------------------------
1 | package com.weikaiyun.fragmentation_swipeback.core;
2 |
3 | import android.view.View;
4 |
5 | import androidx.annotation.FloatRange;
6 |
7 | import com.weikaiyun.fragmentation.SwipeBackLayout;
8 |
9 | public interface ISwipeBackFragment {
10 |
11 | View attachToSwipeBack(View view);
12 |
13 | SwipeBackLayout getSwipeBackLayout();
14 |
15 | void setSwipeBackEnable(boolean enable);
16 |
17 | void setEdgeLevel(SwipeBackLayout.EdgeLevel edgeLevel);
18 |
19 | void setEdgeLevel(int widthPixel);
20 |
21 | /**
22 | * Set the offset of the parallax slip.
23 | */
24 | void setParallaxOffset(@FloatRange(from = 0.0f, to = 1.0f) float offset);
25 | }
26 |
--------------------------------------------------------------------------------
/fragmentation_swipeback/src/main/java/com/weikaiyun/fragmentation_swipeback/core/SwipeBackActivityDelegate.java:
--------------------------------------------------------------------------------
1 | package com.weikaiyun.fragmentation_swipeback.core;
2 |
3 | import android.graphics.Color;
4 | import android.graphics.drawable.ColorDrawable;
5 | import android.os.Bundle;
6 | import android.view.ViewGroup;
7 |
8 | import androidx.fragment.app.Fragment;
9 | import androidx.fragment.app.FragmentActivity;
10 |
11 | import com.weikaiyun.fragmentation.ISupportActivity;
12 | import com.weikaiyun.fragmentation.ISupportFragment;
13 | import com.weikaiyun.fragmentation.SupportHelper;
14 | import com.weikaiyun.fragmentation.SwipeBackLayout;
15 |
16 | import java.util.List;
17 |
18 | public class SwipeBackActivityDelegate {
19 | private final FragmentActivity mActivity;
20 | private SwipeBackLayout mSwipeBackLayout;
21 |
22 | public SwipeBackActivityDelegate(ISwipeBackActivity swipeBackActivity) {
23 | if (!(swipeBackActivity instanceof FragmentActivity) || !(swipeBackActivity instanceof ISupportActivity))
24 | throw new RuntimeException("Must extends FragmentActivity/AppCompatActivity and implements ISupportActivity");
25 | mActivity = (FragmentActivity) swipeBackActivity;
26 | }
27 |
28 | public void onCreate(Bundle savedInstanceState) {
29 | onActivityCreate();
30 | }
31 |
32 | public void onPostCreate(Bundle savedInstanceState) {
33 | mSwipeBackLayout.attachToActivity(mActivity);
34 | }
35 |
36 | public SwipeBackLayout getSwipeBackLayout() {
37 | return mSwipeBackLayout;
38 | }
39 |
40 | public void setSwipeBackEnable(boolean enable) {
41 | mSwipeBackLayout.setEnableGesture(enable);
42 | }
43 |
44 | public void setEdgeLevel(SwipeBackLayout.EdgeLevel edgeLevel) {
45 | mSwipeBackLayout.setEdgeLevel(edgeLevel);
46 | }
47 |
48 | public void setEdgeLevel(int widthPixel) {
49 | mSwipeBackLayout.setEdgeLevel(widthPixel);
50 | }
51 |
52 | public boolean swipeBackPriority() {
53 | List list = SupportHelper.getActiveFragments(mActivity.getSupportFragmentManager());
54 | int fragmentNum = 0;
55 | for (Fragment f : list) {
56 | if (f instanceof ISupportFragment
57 | && ((ISupportFragment) f).getSupportDelegate().isCanPop()
58 | && ((ISupportFragment) f).getSupportDelegate().isStartByFragmentation()) {
59 | fragmentNum++;
60 | }
61 | }
62 | return fragmentNum <= 0;
63 | }
64 |
65 | private void onActivityCreate() {
66 | mActivity.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
67 | mActivity.getWindow().getDecorView().setBackgroundColor(Color.TRANSPARENT);
68 | mSwipeBackLayout = new SwipeBackLayout(mActivity);
69 | ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
70 | mSwipeBackLayout.setLayoutParams(params);
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/fragmentation_swipeback/src/main/java/com/weikaiyun/fragmentation_swipeback/core/SwipeBackFragmentDelegate.java:
--------------------------------------------------------------------------------
1 | package com.weikaiyun.fragmentation_swipeback.core;
2 |
3 | import android.graphics.Color;
4 | import android.os.Bundle;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 |
8 | import androidx.annotation.FloatRange;
9 | import androidx.annotation.Nullable;
10 | import androidx.fragment.app.Fragment;
11 |
12 | import com.weikaiyun.fragmentation.ISupportFragment;
13 | import com.weikaiyun.fragmentation.SwipeBackLayout;
14 |
15 | public class SwipeBackFragmentDelegate {
16 | private final Fragment mFragment;
17 | private final ISupportFragment mSupport;
18 | private SwipeBackLayout mSwipeBackLayout;
19 |
20 | public SwipeBackFragmentDelegate(ISwipeBackFragment swipeBackFragment) {
21 | if (!(swipeBackFragment instanceof Fragment) || !(swipeBackFragment instanceof ISupportFragment))
22 | throw new RuntimeException("Must extends Fragment and implements ISupportFragment!");
23 | mFragment = (Fragment) swipeBackFragment;
24 | mSupport = (ISupportFragment) swipeBackFragment;
25 | }
26 |
27 | public void onCreate(@Nullable Bundle savedInstanceState) {
28 | onFragmentCreate();
29 | }
30 |
31 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
32 | if (view instanceof SwipeBackLayout) {
33 | View childView = ((SwipeBackLayout) view).getChildAt(0);
34 | mSupport.getSupportDelegate().setBackground(childView);
35 | } else {
36 | mSupport.getSupportDelegate().setBackground(view);
37 | }
38 | }
39 |
40 | public View attachToSwipeBack(View view) {
41 | mSwipeBackLayout.attachToFragment(mSupport, view);
42 | return mSwipeBackLayout;
43 | }
44 |
45 | public void setEdgeLevel(SwipeBackLayout.EdgeLevel edgeLevel) {
46 | mSwipeBackLayout.setEdgeLevel(edgeLevel);
47 | }
48 |
49 | public void setEdgeLevel(int widthPixel) {
50 | mSwipeBackLayout.setEdgeLevel(widthPixel);
51 | }
52 |
53 | public SwipeBackLayout getSwipeBackLayout() {
54 | return mSwipeBackLayout;
55 | }
56 |
57 | public void setSwipeBackEnable(boolean enable) {
58 | mSwipeBackLayout.setEnableGesture(enable);
59 | }
60 |
61 | /**
62 | * Set the offset of the parallax slip.
63 | */
64 | public void setParallaxOffset(@FloatRange(from = 0.0f, to = 1.0f) float offset) {
65 | mSwipeBackLayout.setParallaxOffset(offset);
66 | }
67 |
68 | private void onFragmentCreate() {
69 | if (mFragment.getContext() == null) return;
70 |
71 | mSwipeBackLayout = new SwipeBackLayout(mFragment.getContext());
72 | ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
73 | mSwipeBackLayout.setLayoutParams(params);
74 | mSwipeBackLayout.setBackgroundColor(Color.TRANSPARENT);
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/fragmentation_swipeback/src/main/res/drawable-xhdpi/shadow_bottom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikaiyun/SFragmentation/bd500d1fde6fa45651a6abd331c5b4ff4dc7acce/fragmentation_swipeback/src/main/res/drawable-xhdpi/shadow_bottom.png
--------------------------------------------------------------------------------
/fragmentation_swipeback/src/main/res/drawable-xhdpi/shadow_left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikaiyun/SFragmentation/bd500d1fde6fa45651a6abd331c5b4ff4dc7acce/fragmentation_swipeback/src/main/res/drawable-xhdpi/shadow_left.png
--------------------------------------------------------------------------------
/fragmentation_swipeback/src/main/res/drawable-xhdpi/shadow_right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikaiyun/SFragmentation/bd500d1fde6fa45651a6abd331c5b4ff4dc7acce/fragmentation_swipeback/src/main/res/drawable-xhdpi/shadow_right.png
--------------------------------------------------------------------------------
/fragmentation_swipeback/src/test/java/com/weikaiyun/fragmentation_swipeback/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.weikaiyun.fragmentation_swipeback;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your androidx.fragment.app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 | # Kotlin code style for this project: "official" or "obsolete":
21 | kotlin.code.style=official
22 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikaiyun/SFragmentation/bd500d1fde6fa45651a6abd331c5b4ff4dc7acce/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Oct 15 14:23:54 CST 2020
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':fragmentation_swipeback'
2 | include ':app', ':fragmentation'
3 |
--------------------------------------------------------------------------------