Commit 556ee8b2a75d0fb8c69c32c6da8f3325e509b8b2

Authored by YangShuai
1 parent d1cb2a91

1 优化基类,fragment支持侧滑返回

Showing 61 changed files with 6844 additions and 199 deletions
app/strike/src/main/java/com/cnlive/strike/MainActivity.java
@@ -24,7 +24,7 @@ public class MainActivity extends AppCompatActivity { @@ -24,7 +24,7 @@ public class MainActivity extends AppCompatActivity {
24 protected void onCreate(@Nullable Bundle savedInstanceState) { 24 protected void onCreate(@Nullable Bundle savedInstanceState) {
25 super.onCreate(savedInstanceState); 25 super.onCreate(savedInstanceState);
26 setContentView(R.layout.activity_main); 26 setContentView(R.layout.activity_main);
27 - findViewById(R.id.go_to).setOnClickListener(view -> startActivity(new Intent(this, LoginActivity.class)) ); 27 + findViewById(R.id.go_to).setOnClickListener(view -> startActivity(new Intent(this, DemoActivity.class)) );
28 findViewById(R.id.to_img).setOnClickListener(view -> startActivity(new Intent(this, ImgActivity.class)) ); 28 findViewById(R.id.to_img).setOnClickListener(view -> startActivity(new Intent(this, ImgActivity.class)) );
29 } 29 }
30 30
app/strike/src/main/java/com/cnlive/strike/MyActivity.java
@@ -13,7 +13,6 @@ public class MyActivity extends BaseActivity { @@ -13,7 +13,6 @@ public class MyActivity extends BaseActivity {
13 13
14 @Override 14 @Override
15 protected void initView() { 15 protected void initView() {
16 - setOpenSwipBack(true);  
17 getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new MyFragment()).commitAllowingStateLoss(); 16 getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new MyFragment()).commitAllowingStateLoss();
18 } 17 }
19 18
app/strike/src/main/java/com/cnlive/strike/MyFragment.java
@@ -19,6 +19,8 @@ import com.cnlive.strike.network.BaseRequest; @@ -19,6 +19,8 @@ import com.cnlive.strike.network.BaseRequest;
19 import com.cnlive.strike.network.api.ApiService; 19 import com.cnlive.strike.network.api.ApiService;
20 import com.cnlive.strike.network.bean.LetHimNoSeeBean; 20 import com.cnlive.strike.network.bean.LetHimNoSeeBean;
21 import com.cnlive.strike.network.bean.TestBean; 21 import com.cnlive.strike.network.bean.TestBean;
  22 +import com.me.yokeyword.fragmentation.anim.DefaultVerticalAnimator;
  23 +import com.me.yokeyword.fragmentation.anim.FragmentAnimator;
22 24
23 import androidx.annotation.NonNull; 25 import androidx.annotation.NonNull;
24 import androidx.annotation.Nullable; 26 import androidx.annotation.Nullable;
@@ -31,23 +33,21 @@ import io.reactivex.functions.Function; @@ -31,23 +33,21 @@ import io.reactivex.functions.Function;
31 33
32 34
33 public class MyFragment extends BaseFragment<MyFragmentView, MyPresenter> { 35 public class MyFragment extends BaseFragment<MyFragmentView, MyPresenter> {
34 - private View view;  
35 public TextView textView; 36 public TextView textView;
36 37
37 - @Nullable  
38 @Override 38 @Override
39 - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {  
40 - view = inflater.inflate(R.layout.activity_main1, container, false);  
41 - textView = view.findViewById(R.id.tv1);  
42 - return view; 39 + protected int getViewLayoutId() {
  40 + return R.layout.activity_main1;
43 } 41 }
44 42
45 @Override 43 @Override
46 protected void initView() { 44 protected void initView() {
47 super.initView(); 45 super.initView();
  46 + setSwipeBackEnable(true);
48 setStatusBarColor(R.color.green, 0); 47 setStatusBarColor(R.color.green, 0);
49 setStatusBarTextColor(StatusBarConfig.BLACK); 48 setStatusBarTextColor(StatusBarConfig.BLACK);
50 - view.findViewById(R.id.btn_test2).setOnClickListener(new View.OnClickListener() { 49 + textView = baseView.findViewById(R.id.tv1);
  50 + baseView.findViewById(R.id.btn_test2).setOnClickListener(new View.OnClickListener() {
51 @Override 51 @Override
52 public void onClick(View v) { 52 public void onClick(View v) {
53 requestPermission(010001, "测试", new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, new OnPermissionResponseListener() { 53 requestPermission(010001, "测试", new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, new OnPermissionResponseListener() {
@@ -63,23 +63,24 @@ public class MyFragment extends BaseFragment&lt;MyFragmentView, MyPresenter&gt; { @@ -63,23 +63,24 @@ public class MyFragment extends BaseFragment&lt;MyFragmentView, MyPresenter&gt; {
63 }); 63 });
64 } 64 }
65 }); 65 });
66 - view.findViewById(R.id.btn_test1).setOnClickListener(new View.OnClickListener() { 66 + baseView.findViewById(R.id.btn_test1).setOnClickListener(new View.OnClickListener() {
67 @Override 67 @Override
68 public void onClick(View v) { 68 public void onClick(View v) {
69 - requestPermission(new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, new OnPermissionResponseListener() {  
70 - @Override  
71 - public void onSuccess(String[] permissions) {  
72 - Log.e(TAG, "onSuccess: ");  
73 - }  
74 -  
75 - @Override  
76 - public void onFail() {  
77 - Log.e(TAG, "onFail: ");  
78 - }  
79 - }); 69 +// requestPermission(new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, new OnPermissionResponseListener() {
  70 +// @Override
  71 +// public void onSuccess(String[] permissions) {
  72 +// Log.e(TAG, "onSuccess: ");
  73 +// }
  74 +//
  75 +// @Override
  76 +// public void onFail() {
  77 +// Log.e(TAG, "onFail: ");
  78 +// }
  79 +// });
  80 + startForResult(new MyFragment1(),1001);
80 } 81 }
81 }); 82 });
82 - view.findViewById(R.id.btn_test).setOnClickListener(new View.OnClickListener() { 83 + baseView.findViewById(R.id.btn_test).setOnClickListener(new View.OnClickListener() {
83 @Override 84 @Override
84 public void onClick(View v) { 85 public void onClick(View v) {
85 //单个请求 86 //单个请求
@@ -144,4 +145,17 @@ public class MyFragment extends BaseFragment&lt;MyFragmentView, MyPresenter&gt; { @@ -144,4 +145,17 @@ public class MyFragment extends BaseFragment&lt;MyFragmentView, MyPresenter&gt; {
144 getPresenter().setData("hha"); 145 getPresenter().setData("hha");
145 getMvpView().setData("test"); 146 getMvpView().setData("test");
146 } 147 }
  148 +
  149 + @Override
  150 + public FragmentAnimator onCreateFragmentAnimator() {
  151 + return new DefaultVerticalAnimator();
  152 + }
  153 +
  154 + @Override
  155 + public void onFragmentResult(int requestCode, int resultCode, Bundle data) {
  156 + super.onFragmentResult(requestCode, resultCode, data);
  157 + if (requestCode==1001){
  158 + setStatusBarColor(R.color.green,0);
  159 + }
  160 + }
147 } 161 }
app/strike/src/main/java/com/cnlive/strike/MyFragment1.java
@@ -14,13 +14,11 @@ import com.cnlive.core.libs.base.util.StatusBarConfig; @@ -14,13 +14,11 @@ import com.cnlive.core.libs.base.util.StatusBarConfig;
14 14
15 15
16 public class MyFragment1 extends BaseFragment { 16 public class MyFragment1 extends BaseFragment {
17 - private View view;  
18 17
19 - @Nullable 18 +
20 @Override 19 @Override
21 - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {  
22 - view = inflater.inflate(R.layout.fragment_main1, container, false);  
23 - return view; 20 + protected int getViewLayoutId() {
  21 + return R.layout.fragment_main1;
24 } 22 }
25 23
26 @Override 24 @Override
@@ -28,5 +26,6 @@ public class MyFragment1 extends BaseFragment { @@ -28,5 +26,6 @@ public class MyFragment1 extends BaseFragment {
28 super.initView(); 26 super.initView();
29 setStatusBarColor(R.color.qmui_config_color_red, 0); 27 setStatusBarColor(R.color.qmui_config_color_red, 0);
30 setStatusBarTextColor(StatusBarConfig.BLACK); 28 setStatusBarTextColor(StatusBarConfig.BLACK);
  29 +
31 } 30 }
32 } 31 }
app/strike/src/main/java/com/cnlive/strike/demo/activity/DemoActivity.java
@@ -7,7 +7,9 @@ import android.view.View; @@ -7,7 +7,9 @@ import android.view.View;
7 import com.cnlive.core.libs.base.frame.activity.BaseActivity; 7 import com.cnlive.core.libs.base.frame.activity.BaseActivity;
8 import com.cnlive.core.libs.base.interfaces.OnPermissionResponseListener; 8 import com.cnlive.core.libs.base.interfaces.OnPermissionResponseListener;
9 import com.cnlive.core.libs.base.util.StatusBarConfig; 9 import com.cnlive.core.libs.base.util.StatusBarConfig;
  10 +import com.cnlive.strike.MyFragment;
10 import com.cnlive.strike.R; 11 import com.cnlive.strike.R;
  12 +import com.cnlive.strike.base.BuildConfig;
11 13
12 /** 14 /**
13 * 继承BaseActivity 15 * 继承BaseActivity
@@ -19,10 +21,10 @@ public class DemoActivity extends BaseActivity { @@ -19,10 +21,10 @@ public class DemoActivity extends BaseActivity {
19 * 21 *
20 * @return 22 * @return
21 */ 23 */
22 - @Override  
23 - protected int getViewLayoutId() {  
24 - return R.layout.activity_demo_main;  
25 - } 24 +// @Override
  25 +// protected int getViewLayoutId() {
  26 +// return R.layout.activity_demo_main;
  27 +// }
26 28
27 /** 29 /**
28 * 设置binding布局 30 * 设置binding布局
@@ -30,16 +32,16 @@ public class DemoActivity extends BaseActivity { @@ -30,16 +32,16 @@ public class DemoActivity extends BaseActivity {
30 * 32 *
31 * @return 33 * @return
32 */ 34 */
33 - @Override  
34 - protected int getBindLayoutId() {  
35 - return super.getBindLayoutId();  
36 - } 35 +// @Override
  36 +// protected int getBindLayoutId() {
  37 +// return super.getBindLayoutId();
  38 +// }
37 39
38 - @Override  
39 - protected void initBindingData() {  
40 - super.initBindingData();  
41 -// binding=(你的bingding)baseBinding;  
42 - } 40 +// @Override
  41 +// protected void initBindingData() {
  42 +// super.initBindingData();
  43 +//// binding=(你的bingding)baseBinding;
  44 +// }
43 45
44 /** 46 /**
45 * 初始化intent传递参数 47 * 初始化intent传递参数
@@ -55,8 +57,8 @@ public class DemoActivity extends BaseActivity { @@ -55,8 +57,8 @@ public class DemoActivity extends BaseActivity {
55 @Override 57 @Override
56 protected void initView() { 58 protected void initView() {
57 super.initView(); 59 super.initView();
58 - //是指是否可以侧滑返回,默认禁用  
59 - setOpenSwipBack(true); 60 + //是指是否可以侧滑返回,默认禁用d
  61 +// setSwipeBackEnable(true);
60 //设置状态栏字体颜色 62 //设置状态栏字体颜色
61 setStatusBarTextColor(StatusBarConfig.WHITE); 63 setStatusBarTextColor(StatusBarConfig.WHITE);
62 //设置状态栏颜色 64 //设置状态栏颜色
@@ -75,6 +77,8 @@ public class DemoActivity extends BaseActivity { @@ -75,6 +77,8 @@ public class DemoActivity extends BaseActivity {
75 //px2dp 77 //px2dp
76 px2dp(10); 78 px2dp(10);
77 79
  80 + loadRootFragment(R.id.fl_container, new MyFragment());
  81 +
78 // String[] permissions = new String[]{Manifest.permission.ACCESS_FINE_LOCATION, 82 // String[] permissions = new String[]{Manifest.permission.ACCESS_FINE_LOCATION,
79 // Manifest.permission.ACCESS_COARSE_LOCATION}; 83 // Manifest.permission.ACCESS_COARSE_LOCATION};
80 // //请求权限(默认提示语的) 84 // //请求权限(默认提示语的)
@@ -114,39 +118,30 @@ public class DemoActivity extends BaseActivity { @@ -114,39 +118,30 @@ public class DemoActivity extends BaseActivity {
114 // } 118 // }
115 // }); 119 // });
116 120
117 - findViewById(R.id.go_to1).setOnClickListener(new View.OnClickListener() {  
118 - @Override  
119 - public void onClick(View v) {  
120 - logError("Ada");  
121 - requestPermission(new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, new OnPermissionResponseListener() {  
122 - @Override  
123 - public void onSuccess(String[] permissions) {  
124 - Log.e(TAG, "onSuccess: ");  
125 - }  
126 -  
127 - @Override  
128 - public void onFail() {  
129 - Log.e(TAG, "onFail: ");  
130 - }  
131 - });  
132 - }  
133 - });  
134 - findViewById(R.id.go_to2).setOnClickListener(new View.OnClickListener() {  
135 - @Override  
136 - public void onClick(View v) {  
137 - requestPermission(10010, "拒绝我了", new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, new OnPermissionResponseListener() {  
138 - @Override  
139 - public void onSuccess(String[] permissions) {  
140 - Log.e(TAG, "onSuccess: ");  
141 - }  
142 -  
143 - @Override  
144 - public void onFail() {  
145 - Log.e(TAG, "onFail: ");  
146 - }  
147 - });  
148 - }  
149 - }); 121 +// findViewById(R.id.go_to1).setOnClickListener(new View.OnClickListener() {
  122 +// @Override
  123 +// public void onClick(View v) {
  124 +// logError("Ada");
  125 +// loadRootFragment(R.id.fl_container,new MyFragment());
  126 +//// start(new MyFragment());
  127 +// }
  128 +// });
  129 +// findViewById(R.id.go_to2).setOnClickListener(new View.OnClickListener() {
  130 +// @Override
  131 +// public void onClick(View v) {
  132 +// requestPermission(10010, "拒绝我了", new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, new OnPermissionResponseListener() {
  133 +// @Override
  134 +// public void onSuccess(String[] permissions) {
  135 +// Log.e(TAG, "onSuccess: ");
  136 +// }
  137 +//
  138 +// @Override
  139 +// public void onFail() {
  140 +// Log.e(TAG, "onFail: ");
  141 +// }
  142 +// });
  143 +// }
  144 +// });
150 } 145 }
151 146
152 /** 147 /**
@@ -157,5 +152,4 @@ public class DemoActivity extends BaseActivity { @@ -157,5 +152,4 @@ public class DemoActivity extends BaseActivity {
157 super.initData(); 152 super.initData();
158 } 153 }
159 154
160 -  
161 } 155 }
app/strike/src/main/res/values/styles.xml
@@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
2 2
3 <!-- Base application theme. --> 3 <!-- Base application theme. -->
4 <style name="AppTheme" parent="QMUI.Compat.NoActionBar"> 4 <style name="AppTheme" parent="QMUI.Compat.NoActionBar">
  5 + <item name="android:windowIsTranslucent">true</item>
5 <!-- Customize your theme here. --> 6 <!-- Customize your theme here. -->
6 <item name="colorPrimary">@color/colorPrimary</item> 7 <item name="colorPrimary">@color/colorPrimary</item>
7 <item name="colorPrimaryDark">@color/colorPrimaryDark</item> 8 <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
config.gradle
@@ -25,7 +25,7 @@ ext { @@ -25,7 +25,7 @@ ext {
25 ] 25 ]
26 26
27 androidx = [ 27 androidx = [
28 - appcompat : "androidx.appcompat:appcompat:1.1.0+", 28 + appcompat : "androidx.appcompat:appcompat:1.1.0",
29 constraintlayout: "androidx.constraintlayout:constraintlayout:1.1.3", 29 constraintlayout: "androidx.constraintlayout:constraintlayout:1.1.3",
30 multidex : "androidx.multidex:multidex:2.0.1" 30 multidex : "androidx.multidex:multidex:2.0.1"
31 ] 31 ]
@@ -47,6 +47,12 @@ ext { @@ -47,6 +47,12 @@ ext {
47 ] 47 ]
48 48
49 library = [ 49 library = [
  50 +
  51 + //fragment滑动返回( https://github.com/YoKeyword/Fragmentation ,源码导入修改)
  52 + fragmentation_swipeback : 'me.yokeyword:fragmentationx-swipeback:1.0.2',
  53 + //对fragment进行管理( https://github.com/YoKeyword/Fragmentation ,源码导入修改)
  54 + fragmentationx : 'me.yokeyword:fragmentationx:1.0.2',
  55 + //log日志
50 logger : 'com.orhanobut:logger:2.2.0', 56 logger : 'com.orhanobut:logger:2.2.0',
51 // //空祖对话框 https://github.com/kongzue/DialogV3 57 // //空祖对话框 https://github.com/kongzue/DialogV3
52 // kongzueDailog : 'com.kongzue.dialog_v3x:dialog:3.1.6', 58 // kongzueDailog : 'com.kongzue.dialog_v3x:dialog:3.1.6',
@@ -101,31 +107,33 @@ ext { @@ -101,31 +107,33 @@ ext {
101 // ] 107 // ]
102 //基础三方库 108 //基础三方库
103 base_librarys = [ 109 base_librarys = [
104 - library.logger,  
105 - //对话框 110 +// library.fragmentation_swipeback,
  111 +// library.fragmentationx,
  112 +library.logger,
  113 +//对话框
106 // library.kongzueDailog, 114 // library.kongzueDailog,
107 - //视讯云加密库  
108 - library.libCnencipher,  
109 - //视频库  
110 - library.libVideoQiniu,  
111 - //视讯云播放器  
112 - library.libCnVideo,  
113 - //权限  
114 - library.easypermissions,  
115 - //EvenBus  
116 - library.eventBus,  
117 - //QMUI  
118 - library.qmui,  
119 - library.qmui_arch,  
120 - //mvp 115 +//视讯云加密库
  116 +library.libCnencipher,
  117 +//视频库
  118 +library.libVideoQiniu,
  119 +//视讯云播放器
  120 +library.libCnVideo,
  121 +//权限
  122 +library.easypermissions,
  123 +//EvenBus
  124 +library.eventBus,
  125 +//QMUI
  126 +library.qmui,
  127 +library.qmui_arch,
  128 +//mvp
121 // library.mvp, 129 // library.mvp,
122 // library.mvp_lce, 130 // library.mvp_lce,
123 // library.mvp_nullobject_presenter, 131 // library.mvp_nullobject_presenter,
124 // library.mvp_viewstate, 132 // library.mvp_viewstate,
125 - //图片加载Glide  
126 - glide.api,  
127 - glide.transformations,  
128 - //兼容旧版 133 +//图片加载Glide
  134 +glide.api,
  135 +glide.transformations,
  136 +//兼容旧版
129 // library.supportV4, 137 // library.supportV4,
130 // library.appcompatV7, 138 // library.appcompatV7,
131 // library.design, 139 // library.design,
@@ -133,26 +141,26 @@ ext { @@ -133,26 +141,26 @@ ext {
133 // library.recyclerviewV7, 141 // library.recyclerviewV7,
134 // library.cardviewV7, 142 // library.cardviewV7,
135 // library.dataBinding, 143 // library.dataBinding,
136 - //使用androidx  
137 - androidx.appcompat,  
138 - androidx.constraintlayout,  
139 - androidx.multidex,  
140 - //其他库  
141 - library.rxjava,  
142 - library.rxandroid,  
143 - library.retrofit,  
144 - library.retrofitConverterGson,  
145 - library.retrofitAdapterRxjava2,  
146 - library.okhttp,  
147 - library.okhttpLoggingInterceptor,  
148 - library.greendao,  
149 - //管理rxjava生命周期 144 +//使用androidx
  145 +androidx.appcompat,
  146 +androidx.constraintlayout,
  147 +androidx.multidex,
  148 +//其他库
  149 +library.rxjava,
  150 +library.rxandroid,
  151 +library.retrofit,
  152 +library.retrofitConverterGson,
  153 +library.retrofitAdapterRxjava2,
  154 +library.okhttp,
  155 +library.okhttpLoggingInterceptor,
  156 +library.greendao,
  157 +//管理rxjava生命周期
150 // library.rx 158 // library.rx
151 - router.api, 159 +router.api,
152 160
153 - test.junit,  
154 - test.runner,  
155 - test.espresso 161 +test.junit,
  162 +test.runner,
  163 +test.espresso
156 ] 164 ]
157 165
158 base_compilers = [ 166 base_compilers = [
core/base/src/main/java/androidx/fragment/app/FragmentationMagician.java 0 → 100644
  1 +package androidx.fragment.app;
  2 +
  3 +
  4 +import java.util.List;
  5 +
  6 +/**
  7 + * Created by YoKey on 16/1/22.
  8 + */
  9 +public class FragmentationMagician {
  10 +
  11 + public static boolean isStateSaved(FragmentManager fragmentManager) {
  12 + if (!(fragmentManager instanceof FragmentManagerImpl))
  13 + return false;
  14 + try {
  15 + FragmentManagerImpl fragmentManagerImpl = (FragmentManagerImpl) fragmentManager;
  16 + return fragmentManagerImpl.isStateSaved();
  17 + } catch (Exception e) {
  18 + e.printStackTrace();
  19 + }
  20 + return false;
  21 + }
  22 +
  23 + /**
  24 + * Like {@link FragmentManager#popBackStack()}} but allows the commit to be executed after an
  25 + * activity's state is saved. This is dangerous because the action can
  26 + * be lost if the activity needs to later be restored from its state, so
  27 + * this should only be used for cases where it is okay for the UI state
  28 + * to change unexpectedly on the user.
  29 + */
  30 + public static void popBackStackAllowingStateLoss(final FragmentManager fragmentManager) {
  31 + FragmentationMagician.hookStateSaved(fragmentManager, new Runnable() {
  32 + @Override
  33 + public void run() {
  34 + fragmentManager.popBackStack();
  35 + }
  36 + });
  37 + }
  38 +
  39 + /**
  40 + * Like {@link FragmentManager#popBackStackImmediate()}} but allows the commit to be executed after an
  41 + * activity's state is saved.
  42 + */
  43 + public static void popBackStackImmediateAllowingStateLoss(final FragmentManager fragmentManager) {
  44 + FragmentationMagician.hookStateSaved(fragmentManager, new Runnable() {
  45 + @Override
  46 + public void run() {
  47 + fragmentManager.popBackStackImmediate();
  48 + }
  49 + });
  50 + }
  51 +
  52 + /**
  53 + * Like {@link FragmentManager#popBackStackImmediate(String, int)}} but allows the commit to be executed after an
  54 + * activity's state is saved.
  55 + */
  56 + public static void popBackStackAllowingStateLoss(final FragmentManager fragmentManager, final String name, final int flags) {
  57 + FragmentationMagician.hookStateSaved(fragmentManager, new Runnable() {
  58 + @Override
  59 + public void run() {
  60 + fragmentManager.popBackStack(name, flags);
  61 + }
  62 + });
  63 + }
  64 +
  65 + /**
  66 + * Like {@link FragmentManager#executePendingTransactions()} but allows the commit to be executed after an
  67 + * activity's state is saved.
  68 + */
  69 + public static void executePendingTransactionsAllowingStateLoss(final FragmentManager fragmentManager) {
  70 + FragmentationMagician.hookStateSaved(fragmentManager, new Runnable() {
  71 + @Override
  72 + public void run() {
  73 + fragmentManager.executePendingTransactions();
  74 + }
  75 + });
  76 + }
  77 +
  78 + public static List<Fragment> getActiveFragments(FragmentManager fragmentManager) {
  79 + return fragmentManager.getFragments();
  80 + }
  81 +
  82 + private static void hookStateSaved(FragmentManager fragmentManager, Runnable runnable) {
  83 + if (!(fragmentManager instanceof FragmentManagerImpl)) return;
  84 +
  85 + FragmentManagerImpl fragmentManagerImpl = (FragmentManagerImpl) fragmentManager;
  86 + if (isStateSaved(fragmentManager)) {
  87 + boolean tempStateSaved = fragmentManagerImpl.mStateSaved;
  88 + boolean tempStopped = fragmentManagerImpl.mStopped;
  89 + fragmentManagerImpl.mStateSaved = false;
  90 + fragmentManagerImpl.mStopped = false;
  91 +
  92 + runnable.run();
  93 +
  94 + fragmentManagerImpl.mStopped = tempStopped;
  95 + fragmentManagerImpl.mStateSaved = tempStateSaved;
  96 + } else {
  97 + runnable.run();
  98 + }
  99 + }
  100 +}
0 \ No newline at end of file 101 \ No newline at end of file
core/base/src/main/java/com/cnlive/core/libs/base/frame/activity/BaseActivity.java
@@ -14,12 +14,14 @@ import android.provider.Settings; @@ -14,12 +14,14 @@ import android.provider.Settings;
14 import android.text.TextUtils; 14 import android.text.TextUtils;
15 import android.util.DisplayMetrics; 15 import android.util.DisplayMetrics;
16 import android.view.Display; 16 import android.view.Display;
  17 +import android.view.MotionEvent;
17 import android.view.View; 18 import android.view.View;
18 import android.view.Window; 19 import android.view.Window;
19 import android.view.WindowManager; 20 import android.view.WindowManager;
20 import android.view.inputmethod.InputMethodManager; 21 import android.view.inputmethod.InputMethodManager;
21 22
22 import androidx.annotation.ColorRes; 23 import androidx.annotation.ColorRes;
  24 +import androidx.annotation.DrawableRes;
23 import androidx.annotation.IntRange; 25 import androidx.annotation.IntRange;
24 import androidx.annotation.NonNull; 26 import androidx.annotation.NonNull;
25 import androidx.annotation.Nullable; 27 import androidx.annotation.Nullable;
@@ -31,6 +33,7 @@ import androidx.databinding.DataBindingUtil; @@ -31,6 +33,7 @@ import androidx.databinding.DataBindingUtil;
31 import androidx.databinding.ViewDataBinding; 33 import androidx.databinding.ViewDataBinding;
32 34
33 import com.alibaba.android.arouter.launcher.ARouter; 35 import com.alibaba.android.arouter.launcher.ARouter;
  36 +import com.cnlive.core.libs.base.application.AppConfig;
34 import com.cnlive.core.libs.base.frame.presenter.BasePresenter; 37 import com.cnlive.core.libs.base.frame.presenter.BasePresenter;
35 import com.cnlive.core.libs.base.frame.view.BaseView; 38 import com.cnlive.core.libs.base.frame.view.BaseView;
36 import com.cnlive.core.libs.base.interfaces.OnPermissionResponseListener; 39 import com.cnlive.core.libs.base.interfaces.OnPermissionResponseListener;
@@ -39,27 +42,36 @@ import com.cnlive.core.libs.base.util.AppManager; @@ -39,27 +42,36 @@ import com.cnlive.core.libs.base.util.AppManager;
39 import com.cnlive.core.libs.base.util.ReflectUtil; 42 import com.cnlive.core.libs.base.util.ReflectUtil;
40 import com.cnlive.core.libs.base.util.StatusBarConfig; 43 import com.cnlive.core.libs.base.util.StatusBarConfig;
41 import com.cnlive.core.libs.base.util.StatusBarUtil; 44 import com.cnlive.core.libs.base.util.StatusBarUtil;
42 -import com.cnlive.core.libs.base.util.swipeback.util.SwipeBackActivityBase;  
43 -import com.cnlive.core.libs.base.util.swipeback.util.SwipeBackActivityHelper;  
44 -import com.cnlive.core.libs.base.util.swipeback.util.SwipeBackLayout;  
45 -import com.cnlive.core.libs.base.util.swipeback.util.SwipeBackUtil; 45 +import com.cnlive.strike.base.R;
46 import com.hannesdorfmann.mosby3.mvp.MvpActivity; 46 import com.hannesdorfmann.mosby3.mvp.MvpActivity;
  47 +import com.me.yokeyword.fragmentation.ExtraTransaction;
  48 +import com.me.yokeyword.fragmentation.Fragmentation;
  49 +import com.me.yokeyword.fragmentation.ISupportActivity;
  50 +import com.me.yokeyword.fragmentation.ISupportFragment;
  51 +import com.me.yokeyword.fragmentation.SupportActivityDelegate;
  52 +import com.me.yokeyword.fragmentation.SupportHelper;
  53 +import com.me.yokeyword.fragmentation.SwipeBackLayout;
  54 +import com.me.yokeyword.fragmentation.anim.FragmentAnimator;
  55 +import com.me.yokeyword.fragmentation_swipeback.core.ISwipeBackActivity;
  56 +import com.me.yokeyword.fragmentation_swipeback.core.SwipeBackActivityDelegate;
47 import com.orhanobut.logger.Logger; 57 import com.orhanobut.logger.Logger;
48 58
49 import java.lang.reflect.Field; 59 import java.lang.reflect.Field;
50 import java.util.ArrayList; 60 import java.util.ArrayList;
51 import java.util.List; 61 import java.util.List;
52 62
  63 +
53 /** 64 /**
54 * @author ys 65 * @author ys
55 * 基类 activity 66 * 基类 activity
  67 + * SwipeBackActivityBase,
56 */ 68 */
57 -public abstract class BaseActivity<V extends BaseView, P extends BasePresenter<V>> extends MvpActivity<V, P> implements SwipeBackActivityBase { 69 +public abstract class BaseActivity<V extends BaseView, P extends BasePresenter<V>> extends MvpActivity<V, P> implements ISupportActivity, ISwipeBackActivity {
58 private V view; 70 private V view;
59 private P presenter; 71 private P presenter;
60 public ViewDataBinding baseBinding; 72 public ViewDataBinding baseBinding;
61 //获取TAG的activity名称 73 //获取TAG的activity名称
62 - protected final String TAG = this.getClass().getSimpleName(); 74 + public final String TAG = this.getClass().getSimpleName();
63 //是否显示标题栏 75 //是否显示标题栏
64 private boolean isShowTitle = true; 76 private boolean isShowTitle = true;
65 //是否显示状态栏 77 //是否显示状态栏
@@ -76,9 +88,12 @@ public abstract class BaseActivity&lt;V extends BaseView, P extends BasePresenter&lt;V @@ -76,9 +88,12 @@ public abstract class BaseActivity&lt;V extends BaseView, P extends BasePresenter&lt;V
76 private int USER_SET_REQUEST_CODE_PERMISSION = -0x00099;//用户设置的权限请求码 88 private int USER_SET_REQUEST_CODE_PERMISSION = -0x00099;//用户设置的权限请求码
77 private String defaultDefinePermissionTip = "需要必要的权限才可以正常使用该功能,您已拒绝获得该权限。\n如果需要重新授权,您可以点击“允许”按钮进入系统设置进行授权";//默认拒绝的权限提示语 89 private String defaultDefinePermissionTip = "需要必要的权限才可以正常使用该功能,您已拒绝获得该权限。\n如果需要重新授权,您可以点击“允许”按钮进入系统设置进行授权";//默认拒绝的权限提示语
78 private String userSetDefinePermissionTip = "";//用户设置的权限提示语 90 private String userSetDefinePermissionTip = "";//用户设置的权限提示语
79 - private SwipeBackActivityHelper mHelper;//侧滑返回 91 + // private SwipeBackActivityHelper mHelper;//侧滑返回
80 private boolean isOpenSwipBack = false; 92 private boolean isOpenSwipBack = false;
81 - private AlertDialog alertDialog; 93 + //fragmnet管理
  94 + private final SupportActivityDelegate mDelegate = new SupportActivityDelegate(this);
  95 + //fragment侧滑
  96 + private final SwipeBackActivityDelegate mSwipeDelegate = new SwipeBackActivityDelegate(this);
82 97
83 @Override 98 @Override
84 protected void onCreate(@Nullable Bundle savedInstanceState) { 99 protected void onCreate(@Nullable Bundle savedInstanceState) {
@@ -88,8 +103,17 @@ public abstract class BaseActivity&lt;V extends BaseView, P extends BasePresenter&lt;V @@ -88,8 +103,17 @@ public abstract class BaseActivity&lt;V extends BaseView, P extends BasePresenter&lt;V
88 } else if (0 != getViewLayoutId()) { 103 } else if (0 != getViewLayoutId()) {
89 setContentView(getViewLayoutId()); 104 setContentView(getViewLayoutId());
90 } 105 }
  106 + //两种视图都没有设置,就加载默认跟视图,用于fragment切换
  107 + if (0 == getBindLayoutId() && 0 == getViewLayoutId()) {
  108 + setContentView(R.layout.base_activity_main);
  109 + }
91 context = this; 110 context = this;
92 me = this; 111 me = this;
  112 + //fragment管理
  113 + mDelegate.onCreate(savedInstanceState);
  114 + mSwipeDelegate.onCreate(savedInstanceState);
  115 + //是否开启滑动返回
  116 + setSwipeBackEnable(isOpenSwipBack);
93 this.savedInstanceState = savedInstanceState; 117 this.savedInstanceState = savedInstanceState;
94 //路由参数初始化 118 //路由参数初始化
95 ARouter.getInstance().inject(this); 119 ARouter.getInstance().inject(this);
@@ -118,16 +142,11 @@ public abstract class BaseActivity&lt;V extends BaseView, P extends BasePresenter&lt;V @@ -118,16 +142,11 @@ public abstract class BaseActivity&lt;V extends BaseView, P extends BasePresenter&lt;V
118 initView(); 142 initView();
119 //设置数据 143 //设置数据
120 initData(); 144 initData();
121 - //是否开启滑动返回  
122 - if (isOpenSwipBack) {  
123 - mHelper = new SwipeBackActivityHelper(this);  
124 - mHelper.onActivityCreate();  
125 - }  
126 -  
127 - }  
128 -  
129 - protected void setOpenSwipBack(boolean isOpen) {  
130 - isOpenSwipBack = isOpen; 145 +// if (isOpenSwipBack) {
  146 +// mHelper = new SwipeBackActivityHelper(this);
  147 +// mHelper.onActivityCreate();
  148 +//
  149 +// }
131 } 150 }
132 151
133 152
@@ -151,6 +170,10 @@ public abstract class BaseActivity&lt;V extends BaseView, P extends BasePresenter&lt;V @@ -151,6 +170,10 @@ public abstract class BaseActivity&lt;V extends BaseView, P extends BasePresenter&lt;V
151 170
152 } 171 }
153 172
  173 + public boolean isOpenSwipBack() {
  174 + return isOpenSwipBack;
  175 + }
  176 +
154 /** 177 /**
155 * 设置是否显示标题栏 178 * 设置是否显示标题栏
156 * 179 *
@@ -242,9 +265,10 @@ public abstract class BaseActivity&lt;V extends BaseView, P extends BasePresenter&lt;V @@ -242,9 +265,10 @@ public abstract class BaseActivity&lt;V extends BaseView, P extends BasePresenter&lt;V
242 265
243 @Override 266 @Override
244 protected void onDestroy() { 267 protected void onDestroy() {
  268 + mDelegate.onDestroy();
245 super.onDestroy(); 269 super.onDestroy();
246 - if (null != alertDialog) {  
247 - alertDialog.dismiss(); 270 + if (null != baseBinding) {
  271 + baseBinding.unbind();
248 } 272 }
249 //activity管理 273 //activity管理
250 AppManager.getInstance().deleteActivity(me); 274 AppManager.getInstance().deleteActivity(me);
@@ -258,15 +282,15 @@ public abstract class BaseActivity&lt;V extends BaseView, P extends BasePresenter&lt;V @@ -258,15 +282,15 @@ public abstract class BaseActivity&lt;V extends BaseView, P extends BasePresenter&lt;V
258 * @param color 282 * @param color
259 * @param statusBarAlpha 283 * @param statusBarAlpha
260 */ 284 */
261 - protected void setStatusBarColor(@ColorRes int color,  
262 - @IntRange(from = 0, to = 255) int statusBarAlpha) { 285 + public void setStatusBarColor(@ColorRes int color,
  286 + @IntRange(from = 0, to = 255) int statusBarAlpha) {
263 StatusBarUtil.setColor(this, ContextCompat.getColor(this, color), statusBarAlpha); 287 StatusBarUtil.setColor(this, ContextCompat.getColor(this, color), statusBarAlpha);
264 } 288 }
265 289
266 /** 290 /**
267 * 设置状态栏字体颜色 291 * 设置状态栏字体颜色
268 */ 292 */
269 - protected void setStatusBarTextColor(int type) { 293 + public void setStatusBarTextColor(int type) {
270 if (type == StatusBarConfig.BLACK) { 294 if (type == StatusBarConfig.BLACK) {
271 StatusBarUtil.setStatusBarWrite(this); 295 StatusBarUtil.setStatusBarWrite(this);
272 } else if (type == StatusBarConfig.WHITE) { 296 } else if (type == StatusBarConfig.WHITE) {
@@ -615,33 +639,36 @@ public abstract class BaseActivity&lt;V extends BaseView, P extends BasePresenter&lt;V @@ -615,33 +639,36 @@ public abstract class BaseActivity&lt;V extends BaseView, P extends BasePresenter&lt;V
615 @Override 639 @Override
616 protected void onPostCreate(Bundle savedInstanceState) { 640 protected void onPostCreate(Bundle savedInstanceState) {
617 super.onPostCreate(savedInstanceState); 641 super.onPostCreate(savedInstanceState);
618 - if (null != mHelper) {  
619 - mHelper.onPostCreate();  
620 - }  
621 - }  
622 -  
623 - @Override  
624 - public SwipeBackLayout getSwipeBackLayout() {  
625 - if (null != mHelper) {  
626 - return mHelper.getSwipeBackLayout();  
627 - }  
628 - return null;  
629 - }  
630 -  
631 - @Override  
632 - public void setSwipeBackEnable(boolean enable) {  
633 - if (null != getSwipeBackLayout()) {  
634 - getSwipeBackLayout().setEnableGesture(enable);  
635 - }  
636 - }  
637 -  
638 - @Override  
639 - public void scrollToFinishActivity() {  
640 - if (null != mHelper) {  
641 - SwipeBackUtil.convertActivityToTranslucent(this);  
642 - getSwipeBackLayout().scrollToFinishActivity();  
643 - }  
644 - } 642 +// if (null != mHelper) {
  643 +// mHelper.onPostCreate();
  644 +// }
  645 + mDelegate.onPostCreate(savedInstanceState);
  646 + mSwipeDelegate.onPostCreate(savedInstanceState);
  647 +
  648 + }
  649 +
  650 +// @Override
  651 +// public SwipeBackLayout getSwipeBackLayout() {
  652 +// if (null != mHelper) {
  653 +// return mHelper.getSwipeBackLayout();
  654 +// }
  655 +// return null;
  656 +// }
  657 +//
  658 +// @Override
  659 +// public void setSwipeBackEnable(boolean enable) {
  660 +// if (null != getSwipeBackLayout()) {
  661 +// getSwipeBackLayout().setEnableGesture(enable);
  662 +// }
  663 +// }
  664 +
  665 +// @Override
  666 +// public void scrollToFinishActivity() {
  667 +// if (null != mHelper) {
  668 +// SwipeBackUtil.convertActivityToTranslucent(this);
  669 +// getSwipeBackLayout().scrollToFinishActivity();
  670 +// }
  671 +// }
645 672
646 673
647 public void logError(Object info) { 674 public void logError(Object info) {
@@ -671,4 +698,278 @@ public abstract class BaseActivity&lt;V extends BaseView, P extends BasePresenter&lt;V @@ -671,4 +698,278 @@ public abstract class BaseActivity&lt;V extends BaseView, P extends BasePresenter&lt;V
671 public void logXml(String xml) { 698 public void logXml(String xml) {
672 Logger.xml(xml); 699 Logger.xml(xml);
673 } 700 }
  701 +
  702 + /*****************************fragment管理****************************************/
  703 + @Override
  704 + public SupportActivityDelegate getSupportDelegate() {
  705 + return mDelegate;
  706 + }
  707 +
  708 + /**
  709 + * Perform some extra transactions.
  710 + * 额外的事务:自定义Tag,添加SharedElement动画,操作非回退栈Fragment
  711 + */
  712 + @Override
  713 + public ExtraTransaction extraTransaction() {
  714 + return mDelegate.extraTransaction();
  715 + }
  716 +
  717 + /**
  718 + * Note: return mDelegate.dispatchTouchEvent(ev) || super.dispatchTouchEvent(ev);
  719 + */
  720 + @Override
  721 + public boolean dispatchTouchEvent(MotionEvent ev) {
  722 + return mDelegate.dispatchTouchEvent(ev) || super.dispatchTouchEvent(ev);
  723 + }
  724 +
  725 + /**
  726 + * 不建议复写该方法,请使用 {@link #onBackPressedSupport} 代替
  727 + */
  728 + @Override
  729 + public void onBackPressed() {
  730 + mDelegate.onBackPressed();
  731 + }
  732 +
  733 + /**
  734 + * 该方法回调时机为,Activity回退栈内Fragment的数量 小于等于1 时,默认finish Activity
  735 + * 请尽量复写该方法,避免复写onBackPress(),以保证SupportFragment内的onBackPressedSupport()回退事件正常执行
  736 + */
  737 + @Override
  738 + public void onBackPressedSupport() {
  739 + mDelegate.onBackPressedSupport();
  740 + }
  741 +
  742 + /**
  743 + * 获取设置的全局动画 copy
  744 + *
  745 + * @return FragmentAnimator
  746 + */
  747 + @Override
  748 + public FragmentAnimator getFragmentAnimator() {
  749 + return mDelegate.getFragmentAnimator();
  750 + }
  751 +
  752 + /**
  753 + * Set all fragments animation.
  754 + * 设置Fragment内的全局动画
  755 + */
  756 + @Override
  757 + public void setFragmentAnimator(FragmentAnimator fragmentAnimator) {
  758 + mDelegate.setFragmentAnimator(fragmentAnimator);
  759 + }
  760 +
  761 + /**
  762 + * Set all fragments animation.
  763 + * 构建Fragment转场动画
  764 + * <p/>
  765 + * 如果是在Activity内实现,则构建的是Activity内所有Fragment的转场动画,
  766 + * 如果是在Fragment内实现,则构建的是该Fragment的转场动画,此时优先级 > Activity的onCreateFragmentAnimator()
  767 + *
  768 + * @return FragmentAnimator对象
  769 + */
  770 + @Override
  771 + public FragmentAnimator onCreateFragmentAnimator() {
  772 + return mDelegate.onCreateFragmentAnimator();
  773 + }
  774 +
  775 + @Override
  776 + public void post(Runnable runnable) {
  777 + mDelegate.post(runnable);
  778 + }
  779 +
  780 + /****************************************以下为可选方法(Optional methods)******************************************************/
  781 +
  782 + /**
  783 + * 加载根Fragment, 即Activity内的第一个Fragment 或 Fragment内的第一个子Fragment
  784 + *
  785 + * @param containerId 容器id
  786 + * @param toFragment 目标Fragment
  787 + */
  788 + public void loadRootFragment(int containerId, @NonNull ISupportFragment toFragment) {
  789 + mDelegate.loadRootFragment(containerId, toFragment);
  790 + }
  791 +
  792 + public void loadRootFragment(int containerId, ISupportFragment toFragment, boolean addToBackStack, boolean allowAnimation) {
  793 + mDelegate.loadRootFragment(containerId, toFragment, addToBackStack, allowAnimation);
  794 + }
  795 +
  796 + /**
  797 + * 加载多个同级根Fragment,类似Wechat, QQ主页的场景
  798 + */
  799 + public void loadMultipleRootFragment(int containerId, int showPosition, ISupportFragment... toFragments) {
  800 + mDelegate.loadMultipleRootFragment(containerId, showPosition, toFragments);
  801 + }
  802 +
  803 + /**
  804 + * show一个Fragment,hide其他同栈所有Fragment
  805 + * 使用该方法时,要确保同级栈内无多余的Fragment,(只有通过loadMultipleRootFragment()载入的Fragment)
  806 + * <p>
  807 + * 建议使用更明确的{@link #showHideFragment(ISupportFragment, ISupportFragment)}
  808 + *
  809 + * @param showFragment 需要show的Fragment
  810 + */
  811 + public void showHideFragment(ISupportFragment showFragment) {
  812 + mDelegate.showHideFragment(showFragment);
  813 + }
  814 +
  815 + /**
  816 + * show一个Fragment,hide一个Fragment ; 主要用于类似微信主页那种 切换tab的情况
  817 + */
  818 + public void showHideFragment(ISupportFragment showFragment, ISupportFragment hideFragment) {
  819 + mDelegate.showHideFragment(showFragment, hideFragment);
  820 + }
  821 +
  822 + /**
  823 + * It is recommended to use {@link SupportFragment#start(ISupportFragment)}.
  824 + */
  825 + public void start(ISupportFragment toFragment) {
  826 + mDelegate.start(toFragment);
  827 + }
  828 +
  829 + /**
  830 + * It is recommended to use {@link SupportFragment#start(ISupportFragment, int)}.
  831 + *
  832 + * @param launchMode Similar to Activity's LaunchMode.
  833 + */
  834 + public void start(ISupportFragment toFragment, @ISupportFragment.LaunchMode int launchMode) {
  835 + mDelegate.start(toFragment, launchMode);
  836 + }
  837 +
  838 + /**
  839 + * It is recommended to use {@link SupportFragment#startForResult(ISupportFragment, int)}.
  840 + * Launch an fragment for which you would like a result when it poped.
  841 + */
  842 + public void startForResult(ISupportFragment toFragment, int requestCode) {
  843 + mDelegate.startForResult(toFragment, requestCode);
  844 + }
  845 +
  846 + /**
  847 + * It is recommended to use {@link SupportFragment#startWithPop(ISupportFragment)}.
  848 + * Start the target Fragment and pop itself
  849 + */
  850 + public void startWithPop(ISupportFragment toFragment) {
  851 + mDelegate.startWithPop(toFragment);
  852 + }
  853 +
  854 + /**
  855 + * It is recommended to use {@link SupportFragment#startWithPopTo(ISupportFragment, Class, boolean)}.
  856 + *
  857 + * @see #popTo(Class, boolean)
  858 + * +
  859 + * @see #start(ISupportFragment)
  860 + */
  861 + public void startWithPopTo(ISupportFragment toFragment, Class<?> targetFragmentClass, boolean includeTargetFragment) {
  862 + mDelegate.startWithPopTo(toFragment, targetFragmentClass, includeTargetFragment);
  863 + }
  864 +
  865 + /**
  866 + * It is recommended to use {@link SupportFragment#replaceFragment(ISupportFragment, boolean)}.
  867 + */
  868 + public void replaceFragment(ISupportFragment toFragment, boolean addToBackStack) {
  869 + mDelegate.replaceFragment(toFragment, addToBackStack);
  870 + }
  871 +
  872 + /**
  873 + * Pop the fragment.
  874 + */
  875 + public void pop() {
  876 + mDelegate.pop();
  877 + }
  878 +
  879 + /**
  880 + * Pop the last fragment transition from the manager's fragment
  881 + * back stack.
  882 + * <p>
  883 + * 出栈到目标fragment
  884 + *
  885 + * @param targetFragmentClass 目标fragment
  886 + * @param includeTargetFragment 是否包含该fragment
  887 + */
  888 + public void popTo(Class<?> targetFragmentClass, boolean includeTargetFragment) {
  889 + mDelegate.popTo(targetFragmentClass, includeTargetFragment);
  890 + }
  891 +
  892 + /**
  893 + * If you want to begin another FragmentTransaction immediately after popTo(), use this method.
  894 + * 如果你想在出栈后, 立刻进行FragmentTransaction操作,请使用该方法
  895 + */
  896 + public void popTo(Class<?> targetFragmentClass, boolean includeTargetFragment, Runnable afterPopTransactionRunnable) {
  897 + mDelegate.popTo(targetFragmentClass, includeTargetFragment, afterPopTransactionRunnable);
  898 + }
  899 +
  900 + public void popTo(Class<?> targetFragmentClass, boolean includeTargetFragment, Runnable afterPopTransactionRunnable, int popAnim) {
  901 + mDelegate.popTo(targetFragmentClass, includeTargetFragment, afterPopTransactionRunnable, popAnim);
  902 + }
  903 +
  904 + /**
  905 + * 当Fragment根布局 没有 设定background属性时,
  906 + * Fragmentation默认使用Theme的android:windowbackground作为Fragment的背景,
  907 + * 可以通过该方法改变其内所有Fragment的默认背景。
  908 + */
  909 + public void setDefaultFragmentBackground(@DrawableRes int backgroundRes) {
  910 + mDelegate.setDefaultFragmentBackground(backgroundRes);
  911 + }
  912 +
  913 + /**
  914 + * 得到位于栈顶Fragment
  915 + */
  916 + public ISupportFragment getTopFragment() {
  917 + return SupportHelper.getTopFragment(getSupportFragmentManager());
  918 + }
  919 +
  920 + /**
  921 + * 获取栈内的fragment对象
  922 + */
  923 + public <T extends ISupportFragment> T findFragment(Class<T> fragmentClass) {
  924 + return SupportHelper.findFragment(getSupportFragmentManager(), fragmentClass);
  925 + }
  926 +
  927 +
  928 + /**
  929 + * 显示fragment栈视图
  930 + */
  931 + public void showFragmetStackView() {
  932 + Fragmentation.builder()
  933 + // show stack view. Mode: BUBBLE, SHAKE, NONE
  934 + .stackViewMode(Fragmentation.BUBBLE)
  935 + .debug(AppConfig.isDebug())
  936 + .install();
  937 + }
  938 +/***********************************滑动返回********************************************/
  939 + /**
  940 + * 是否可滑动
  941 + *
  942 + * @param enable
  943 + */
  944 + @Override
  945 + public void setSwipeBackEnable(boolean enable) {
  946 + isOpenSwipBack = enable;
  947 + mSwipeDelegate.setSwipeBackEnable(enable);
  948 + }
  949 +
  950 + @Override
  951 + public void setEdgeLevel(SwipeBackLayout.EdgeLevel edgeLevel) {
  952 + mSwipeDelegate.setEdgeLevel(edgeLevel);
  953 + }
  954 +
  955 + @Override
  956 + public void setEdgeLevel(int widthPixel) {
  957 + mSwipeDelegate.setEdgeLevel(widthPixel);
  958 + }
  959 +
  960 + /**
  961 + * 限制SwipeBack的条件,默认栈内Fragment数 <= 1时 , 优先滑动退出Activity , 而不是Fragment
  962 + *
  963 + * @return true: Activity优先滑动退出; false: Fragment优先滑动退出
  964 + */
  965 + @Override
  966 + public boolean swipeBackPriority() {
  967 + return mSwipeDelegate.swipeBackPriority();
  968 + }
  969 +
  970 + @Override
  971 + public SwipeBackLayout getSwipeBackLayout() {
  972 + return mSwipeDelegate.getSwipeBackLayout();
  973 + }
  974 +
674 } 975 }
675 \ No newline at end of file 976 \ No newline at end of file
core/base/src/main/java/com/cnlive/core/libs/base/frame/fragment/BaseFragment.java
1 package com.cnlive.core.libs.base.frame.fragment; 1 package com.cnlive.core.libs.base.frame.fragment;
2 2
  3 +import android.app.Activity;
  4 +import android.content.Intent;
3 import android.os.Bundle; 5 import android.os.Bundle;
4 import android.view.LayoutInflater; 6 import android.view.LayoutInflater;
5 import android.view.View; 7 import android.view.View;
6 import android.view.ViewGroup; 8 import android.view.ViewGroup;
  9 +import android.view.animation.Animation;
7 import android.view.inputmethod.InputMethodManager; 10 import android.view.inputmethod.InputMethodManager;
8 11
9 import androidx.annotation.ColorRes; 12 import androidx.annotation.ColorRes;
  13 +import androidx.annotation.FloatRange;
10 import androidx.annotation.IntRange; 14 import androidx.annotation.IntRange;
11 import androidx.annotation.NonNull; 15 import androidx.annotation.NonNull;
12 import androidx.annotation.Nullable; 16 import androidx.annotation.Nullable;
@@ -24,6 +28,16 @@ import com.cnlive.core.libs.base.util.ReflectUtil; @@ -24,6 +28,16 @@ import com.cnlive.core.libs.base.util.ReflectUtil;
24 import com.cnlive.core.libs.base.frame.view.BaseView; 28 import com.cnlive.core.libs.base.frame.view.BaseView;
25 import com.cnlive.core.libs.base.util.StatusBarConfig; 29 import com.cnlive.core.libs.base.util.StatusBarConfig;
26 import com.cnlive.core.libs.base.util.StatusBarUtil; 30 import com.cnlive.core.libs.base.util.StatusBarUtil;
  31 +import com.me.yokeyword.fragmentation.ExtraTransaction;
  32 +import com.me.yokeyword.fragmentation.ISupportFragment;
  33 +import com.me.yokeyword.fragmentation.SupportFragmentDelegate;
  34 +import com.me.yokeyword.fragmentation.SupportHelper;
  35 +import com.me.yokeyword.fragmentation.SwipeBackLayout;
  36 +import com.me.yokeyword.fragmentation.anim.FragmentAnimator;
  37 +import com.me.yokeyword.fragmentation_swipeback.core.ISwipeBackFragment;
  38 +import com.me.yokeyword.fragmentation_swipeback.core.SwipeBackFragmentDelegate;
  39 +import com.orhanobut.logger.Logger;
  40 +
27 41
28 import static android.content.Context.INPUT_METHOD_SERVICE; 42 import static android.content.Context.INPUT_METHOD_SERVICE;
29 43
@@ -34,19 +48,26 @@ import static android.content.Context.INPUT_METHOD_SERVICE; @@ -34,19 +48,26 @@ import static android.content.Context.INPUT_METHOD_SERVICE;
34 * @param <P> 48 * @param <P>
35 * @author ys 49 * @author ys
36 */ 50 */
37 -public abstract class BaseFragment<V extends BaseView, P extends BasePresenter<V>> extends com.hannesdorfmann.mosby3.mvp.MvpFragment<V, P> { 51 +public abstract class BaseFragment<V extends BaseView, P extends BasePresenter<V>> extends com.hannesdorfmann.mosby3.mvp.MvpFragment<V, P> implements ISupportFragment, ISwipeBackFragment {
38 private V view; 52 private V view;
39 private P presenter; 53 private P presenter;
40 - protected final String TAG = this.getClass().getSimpleName(); 54 + public final String TAG = this.getClass().getSimpleName();
41 public ViewDataBinding baseBinding; 55 public ViewDataBinding baseBinding;
42 public View baseView; 56 public View baseView;
43 public BaseActivity me; 57 public BaseActivity me;
  58 + //fragment管理
  59 + private final SupportFragmentDelegate mDelegate = new SupportFragmentDelegate(this);
  60 + //fragment滑动返回
  61 + private final SwipeBackFragmentDelegate mSwipeDelegate = new SwipeBackFragmentDelegate(this);
44 62
45 @Override 63 @Override
46 public void onCreate(Bundle savedInstanceState) { 64 public void onCreate(Bundle savedInstanceState) {
47 super.onCreate(savedInstanceState); 65 super.onCreate(savedInstanceState);
48 if (getActivity() == null) return; 66 if (getActivity() == null) return;
49 me = (BaseActivity) getActivity(); 67 me = (BaseActivity) getActivity();
  68 + mDelegate.onCreate(savedInstanceState);
  69 + mSwipeDelegate.onCreate(savedInstanceState);
  70 + setSwipeBackEnable(me.isOpenSwipBack());
50 ARouter.getInstance().inject(this); 71 ARouter.getInstance().inject(this);
51 initFragmentStyle(); 72 initFragmentStyle();
52 initParams(); 73 initParams();
@@ -57,10 +78,18 @@ public abstract class BaseFragment&lt;V extends BaseView, P extends BasePresenter&lt;V @@ -57,10 +78,18 @@ public abstract class BaseFragment&lt;V extends BaseView, P extends BasePresenter&lt;V
57 public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 78 public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
58 if (0 != getBindLayoutId()) { 79 if (0 != getBindLayoutId()) {
59 baseBinding = DataBindingUtil.inflate(inflater, getBindLayoutId(), container, false); 80 baseBinding = DataBindingUtil.inflate(inflater, getBindLayoutId(), container, false);
60 - return baseBinding.getRoot(); 81 + if (me.isOpenSwipBack()) {
  82 + return attachToSwipeBack(baseBinding.getRoot());
  83 + } else {
  84 + return baseBinding.getRoot();
  85 + }
61 } else if (0 != getViewLayoutId()) { 86 } else if (0 != getViewLayoutId()) {
62 baseView = inflater.inflate(getViewLayoutId(), container, false); 87 baseView = inflater.inflate(getViewLayoutId(), container, false);
63 - return baseView; 88 + if (me.isOpenSwipBack()) {
  89 + return attachToSwipeBack(baseView);
  90 + } else {
  91 + return baseView;
  92 + }
64 } 93 }
65 return super.onCreateView(inflater, container, savedInstanceState); 94 return super.onCreateView(inflater, container, savedInstanceState);
66 } 95 }
@@ -68,6 +97,7 @@ public abstract class BaseFragment&lt;V extends BaseView, P extends BasePresenter&lt;V @@ -68,6 +97,7 @@ public abstract class BaseFragment&lt;V extends BaseView, P extends BasePresenter&lt;V
68 @Override 97 @Override
69 public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 98 public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
70 super.onViewCreated(view, savedInstanceState); 99 super.onViewCreated(view, savedInstanceState);
  100 + mSwipeDelegate.onViewCreated(view, savedInstanceState);
71 if (null != getMvpView() && null != getPresenter()) { 101 if (null != getMvpView() && null != getPresenter()) {
72 initBindingData(); 102 initBindingData();
73 initView(); 103 initView();
@@ -153,48 +183,40 @@ public abstract class BaseFragment&lt;V extends BaseView, P extends BasePresenter&lt;V @@ -153,48 +183,40 @@ public abstract class BaseFragment&lt;V extends BaseView, P extends BasePresenter&lt;V
153 */ 183 */
154 protected void setStatusBarColor(@ColorRes int color, 184 protected void setStatusBarColor(@ColorRes int color,
155 @IntRange(from = 0, to = 255) int statusBarAlpha) { 185 @IntRange(from = 0, to = 255) int statusBarAlpha) {
156 - StatusBarUtil.setColor(getActivity(), ContextCompat.getColor(getActivity(), color), statusBarAlpha); 186 + me.setStatusBarColor(color, statusBarAlpha);
157 } 187 }
158 188
159 - /**  
160 - * 设置状态栏字体颜色  
161 - */  
162 - protected void setStatusBarTextColor(int type) {  
163 - if (type == StatusBarConfig.BLACK) {  
164 - StatusBarUtil.setStatusBarWrite(getActivity());  
165 - } else if (type == StatusBarConfig.WHITE) {  
166 - StatusBarUtil.setStatusBarDarkMode(getActivity()); 189 + @Override
  190 + public void onDestroy() {
  191 + mDelegate.onDestroy();
  192 + mSwipeDelegate.onDestroyView();
  193 + super.onDestroy();
  194 + if (null != baseBinding) {
  195 + baseBinding.unbind();
167 } 196 }
168 } 197 }
169 198
170 /** 199 /**
171 - * 隐藏软键盘 200 + * 设置状态栏字体颜色
172 */ 201 */
173 - public void hideSoftInput() {  
174 - InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(INPUT_METHOD_SERVICE);  
175 - if (getActivity().getCurrentFocus() != null && null != imm) {  
176 - imm.hideSoftInputFromWindow(getActivity().getCurrentFocus().getWindowToken(), 0);  
177 - } 202 + protected void setStatusBarTextColor(int type) {
  203 + me.setStatusBarTextColor(type);
178 } 204 }
179 205
  206 +
180 /** 207 /**
181 * 显示软键盘 208 * 显示软键盘
182 */ 209 */
183 public void showSoftInput() { 210 public void showSoftInput() {
184 - InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(INPUT_METHOD_SERVICE);  
185 - if (getActivity().getCurrentFocus() != null && null != imm) {  
186 - imm.showSoftInputFromInputMethod(getActivity().getCurrentFocus().getWindowToken(), 0);  
187 - } 211 + me.showSoftInput();
188 } 212 }
189 213
190 - /**  
191 - * 显示软键盘  
192 - */  
193 - public void showSoftInput(View view) {  
194 - // InputMethodManager.SHOW_FORCED);  
195 - InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(INPUT_METHOD_SERVICE);  
196 - imm.showSoftInput(view, InputMethodManager.SHOW_FORCED);  
197 - } 214 +// /**
  215 +// * 显示软键盘
  216 +// */
  217 +// public void showSoftInput(View view) {
  218 +// me.showSoftInput(view);
  219 +// }
198 220
199 221
200 /*********************************************************/ 222 /*********************************************************/
@@ -238,4 +260,475 @@ public abstract class BaseFragment&lt;V extends BaseView, P extends BasePresenter&lt;V @@ -238,4 +260,475 @@ public abstract class BaseFragment&lt;V extends BaseView, P extends BasePresenter&lt;V
238 return me.checkPermissions(permission); 260 return me.checkPermissions(permission);
239 } 261 }
240 262
  263 + /************************************fragment管理********************************************/
  264 + @Override
  265 + public SupportFragmentDelegate getSupportDelegate() {
  266 + return mDelegate;
  267 + }
  268 +
  269 + /**
  270 + * Perform some extra transactions.
  271 + * 额外的事务:自定义Tag,添加SharedElement动画,操作非回退栈Fragment
  272 + */
  273 + @Override
  274 + public ExtraTransaction extraTransaction() {
  275 + return mDelegate.extraTransaction();
  276 + }
  277 +
  278 + @Override
  279 + public void onAttach(Activity activity) {
  280 + super.onAttach(activity);
  281 + mDelegate.onAttach(activity);
  282 + me = (BaseActivity) mDelegate.getActivity();
  283 + }
  284 +
  285 + @Override
  286 + public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
  287 + return mDelegate.onCreateAnimation(transit, enter, nextAnim);
  288 + }
  289 +
  290 + @Override
  291 + public void onActivityCreated(@Nullable Bundle savedInstanceState) {
  292 + super.onActivityCreated(savedInstanceState);
  293 + mDelegate.onActivityCreated(savedInstanceState);
  294 + }
  295 +
  296 + @Override
  297 + public void onSaveInstanceState(Bundle outState) {
  298 + super.onSaveInstanceState(outState);
  299 + mDelegate.onSaveInstanceState(outState);
  300 + }
  301 +
  302 + @Override
  303 + public void onResume() {
  304 + super.onResume();
  305 + mDelegate.onResume();
  306 + }
  307 +
  308 + @Override
  309 + public void onPause() {
  310 + super.onPause();
  311 + mDelegate.onPause();
  312 + }
  313 +
  314 + @Override
  315 + public void onDestroyView() {
  316 + mDelegate.onDestroyView();
  317 + super.onDestroyView();
  318 + }
  319 +
  320 + @Override
  321 + public void onHiddenChanged(boolean hidden) {
  322 + super.onHiddenChanged(hidden);
  323 + mDelegate.onHiddenChanged(hidden);
  324 + mSwipeDelegate.onHiddenChanged(hidden);
  325 + }
  326 +
  327 + @Override
  328 + public void setUserVisibleHint(boolean isVisibleToUser) {
  329 + super.setUserVisibleHint(isVisibleToUser);
  330 + mDelegate.setUserVisibleHint(isVisibleToUser);
  331 + }
  332 +
  333 + /*************************************log******************************************/
  334 + public void logError(Object info) {
  335 + Logger.e(TAG, info);
  336 + }
  337 +
  338 + public void logDebug(Object info) {
  339 + Logger.d(TAG, info);
  340 + }
  341 +
  342 + public void logWarn(Object info) {
  343 + Logger.w(TAG, info);
  344 + }
  345 +
  346 + public void logInfo(Object info) {
  347 + Logger.i(TAG, info);
  348 + }
  349 +
  350 + public void logVerbose(Object info) {
  351 + Logger.v(TAG, info);
  352 + }
  353 +
  354 + public void logJson(String json) {
  355 + Logger.json(json);
  356 + }
  357 +
  358 + public void logXml(String xml) {
  359 + Logger.xml(xml);
  360 + }
  361 +/*********************************fragment 管理******************************************/
  362 + /**
  363 + * Causes the Runnable r to be added to the action queue.
  364 + * <p>
  365 + * The runnable will be run after all the previous action has been run.
  366 + * <p>
  367 + * 前面的事务全部执行后 执行该Action
  368 + *
  369 + * @deprecated Use {@link #post(Runnable)} instead.
  370 + */
  371 + @Deprecated
  372 + @Override
  373 + public void enqueueAction(Runnable runnable) {
  374 + mDelegate.enqueueAction(runnable);
  375 + }
  376 +
  377 + /**
  378 + * Causes the Runnable r to be added to the action queue.
  379 + * <p>
  380 + * The runnable will be run after all the previous action has been run.
  381 + * <p>
  382 + * 前面的事务全部执行后 执行该Action
  383 + */
  384 + @Override
  385 + public void post(Runnable runnable) {
  386 + mDelegate.post(runnable);
  387 + }
  388 +
  389 + /**
  390 + * Called when the enter-animation end.
  391 + * 入栈动画 结束时,回调
  392 + */
  393 + @Override
  394 + public void onEnterAnimationEnd(Bundle savedInstanceState) {
  395 + mDelegate.onEnterAnimationEnd(savedInstanceState);
  396 + }
  397 +
  398 +
  399 + /**
  400 + * Lazy initial,Called when fragment is first called.
  401 + * <p>
  402 + * 同级下的 懒加载 + ViewPager下的懒加载 的结合回调方法
  403 + */
  404 + @Override
  405 + public void onLazyInitView(@Nullable Bundle savedInstanceState) {
  406 + mDelegate.onLazyInitView(savedInstanceState);
  407 + }
  408 +
  409 + /**
  410 + * Called when the fragment is visible.
  411 + * 当Fragment对用户可见时回调
  412 + * <p>
  413 + * Is the combination of [onHiddenChanged() + onResume()/onPause() + setUserVisibleHint()]
  414 + */
  415 + @Override
  416 + public void onSupportVisible() {
  417 + mDelegate.onSupportVisible();
  418 + }
  419 +
  420 + /**
  421 + * Called when the fragment is invivible.
  422 + * <p>
  423 + * Is the combination of [onHiddenChanged() + onResume()/onPause() + setUserVisibleHint()]
  424 + */
  425 + @Override
  426 + public void onSupportInvisible() {
  427 + mDelegate.onSupportInvisible();
  428 + }
  429 +
  430 + /**
  431 + * Return true if the fragment has been supportVisible.
  432 + */
  433 + @Override
  434 + final public boolean isSupportVisible() {
  435 + return mDelegate.isSupportVisible();
  436 + }
  437 +
  438 + /**
  439 + * Set fragment animation with a higher priority than the ISupportActivity
  440 + * 设定当前Fragmemt动画,优先级比在SupportActivity里高
  441 + */
  442 + @Override
  443 + public FragmentAnimator onCreateFragmentAnimator() {
  444 + return mDelegate.onCreateFragmentAnimator();
  445 + }
  446 +
  447 + /**
  448 + * 获取设置的全局动画 copy
  449 + *
  450 + * @return FragmentAnimator
  451 + */
  452 + @Override
  453 + public FragmentAnimator getFragmentAnimator() {
  454 + return mDelegate.getFragmentAnimator();
  455 + }
  456 +
  457 + /**
  458 + * 设置Fragment内的全局动画
  459 + */
  460 + @Override
  461 + public void setFragmentAnimator(FragmentAnimator fragmentAnimator) {
  462 + mDelegate.setFragmentAnimator(fragmentAnimator);
  463 + }
  464 +
  465 + /**
  466 + * 按返回键触发,前提是SupportActivity的onBackPressed()方法能被调用
  467 + *
  468 + * @return false则继续向上传递, true则消费掉该事件
  469 + */
  470 + @Override
  471 + public boolean onBackPressedSupport() {
  472 + return mDelegate.onBackPressedSupport();
  473 + }
  474 +
  475 + /**
  476 + * 类似 {@link Activity#setResult(int, Intent)}
  477 + * <p>
  478 + * Similar to {@link Activity#setResult(int, Intent)}
  479 + *
  480 + * @see #startForResult(ISupportFragment, int)
  481 + */
  482 + @Override
  483 + public void setFragmentResult(int resultCode, Bundle bundle) {
  484 + mDelegate.setFragmentResult(resultCode, bundle);
  485 + }
  486 +
  487 + /**
  488 + * 类似 {@link Activity#onActivityResult(int, int, Intent)}
  489 + * <p>
  490 + * Similar to {@link Activity#onActivityResult(int, int, Intent)}
  491 + *
  492 + * @see #startForResult(ISupportFragment, int)
  493 + */
  494 + @Override
  495 + public void onFragmentResult(int requestCode, int resultCode, Bundle data) {
  496 + mDelegate.onFragmentResult(requestCode, resultCode, data);
  497 + }
  498 +
  499 + /**
  500 + * 在start(TargetFragment,LaunchMode)时,启动模式为SingleTask/SingleTop, 回调TargetFragment的该方法
  501 + * 类似 {@link Activity#onNewIntent(Intent)}
  502 + * <p>
  503 + * Similar to {@link Activity#onNewIntent(Intent)}
  504 + *
  505 + * @param args putNewBundle(Bundle newBundle)
  506 + * @see #start(ISupportFragment, int)
  507 + */
  508 + @Override
  509 + public void onNewBundle(Bundle args) {
  510 + mDelegate.onNewBundle(args);
  511 + }
  512 +
  513 + /**
  514 + * 添加NewBundle,用于启动模式为SingleTask/SingleTop时
  515 + *
  516 + * @see #start(ISupportFragment, int)
  517 + */
  518 + @Override
  519 + public void putNewBundle(Bundle newBundle) {
  520 + mDelegate.putNewBundle(newBundle);
  521 + }
  522 +
  523 +
  524 + /****************************************以下为可选方法(Optional methods)******************************************************/
  525 +
  526 + /**
  527 + * 隐藏软键盘
  528 + */
  529 + protected void hideSoftInput() {
  530 + mDelegate.hideSoftInput();
  531 + }
  532 +
  533 + /**
  534 + * 显示软键盘,调用该方法后,会在onPause时自动隐藏软键盘
  535 + */
  536 + protected void showSoftInput(final View view) {
  537 + mDelegate.showSoftInput(view);
  538 + }
  539 +
  540 + /**
  541 + * 加载根Fragment, 即Activity内的第一个Fragment 或 Fragment内的第一个子Fragment
  542 + *
  543 + * @param containerId 容器id
  544 + * @param toFragment 目标Fragment
  545 + */
  546 + public void loadRootFragment(int containerId, ISupportFragment toFragment) {
  547 + mDelegate.loadRootFragment(containerId, toFragment);
  548 + }
  549 +
  550 + public void loadRootFragment(int containerId, ISupportFragment toFragment, boolean addToBackStack, boolean allowAnim) {
  551 + mDelegate.loadRootFragment(containerId, toFragment, addToBackStack, allowAnim);
  552 + }
  553 +
  554 + /**
  555 + * 加载多个同级根Fragment,类似Wechat, QQ主页的场景
  556 + */
  557 + public void loadMultipleRootFragment(int containerId, int showPosition, ISupportFragment... toFragments) {
  558 + mDelegate.loadMultipleRootFragment(containerId, showPosition, toFragments);
  559 + }
  560 +
  561 + /**
  562 + * show一个Fragment,hide其他同栈所有Fragment
  563 + * 使用该方法时,要确保同级栈内无多余的Fragment,(只有通过loadMultipleRootFragment()载入的Fragment)
  564 + * <p>
  565 + * 建议使用更明确的{@link #showHideFragment(ISupportFragment, ISupportFragment)}
  566 + *
  567 + * @param showFragment 需要show的Fragment
  568 + */
  569 + public void showHideFragment(ISupportFragment showFragment) {
  570 + mDelegate.showHideFragment(showFragment);
  571 + }
  572 +
  573 + /**
  574 + * show一个Fragment,hide一个Fragment ; 主要用于类似微信主页那种 切换tab的情况
  575 + */
  576 + public void showHideFragment(ISupportFragment showFragment, ISupportFragment hideFragment) {
  577 + mDelegate.showHideFragment(showFragment, hideFragment);
  578 + }
  579 +
  580 + public void start(ISupportFragment toFragment) {
  581 + mDelegate.start(toFragment);
  582 + }
  583 +
  584 + /**
  585 + * @param launchMode Similar to Activity's LaunchMode.
  586 + */
  587 + public void start(final ISupportFragment toFragment, @LaunchMode int launchMode) {
  588 + mDelegate.start(toFragment, launchMode);
  589 + }
  590 +
  591 + /**
  592 + * Launch an fragment for which you would like a result when it poped.
  593 + */
  594 + public void startForResult(ISupportFragment toFragment, int requestCode) {
  595 + mDelegate.startForResult(toFragment, requestCode);
  596 + }
  597 +
  598 + /**
  599 + * Start the target Fragment and pop itself
  600 + */
  601 + public void startWithPop(ISupportFragment toFragment) {
  602 + mDelegate.startWithPop(toFragment);
  603 + }
  604 +
  605 + /**
  606 + * @see #popTo(Class, boolean)
  607 + * +
  608 + * @see #start(ISupportFragment)
  609 + */
  610 + public void startWithPopTo(ISupportFragment toFragment, Class<?> targetFragmentClass, boolean includeTargetFragment) {
  611 + mDelegate.startWithPopTo(toFragment, targetFragmentClass, includeTargetFragment);
  612 + }
  613 +
  614 +
  615 + public void replaceFragment(ISupportFragment toFragment, boolean addToBackStack) {
  616 + mDelegate.replaceFragment(toFragment, addToBackStack);
  617 + }
  618 +
  619 + public void pop() {
  620 + mDelegate.pop();
  621 + }
  622 +
  623 + /**
  624 + * Pop the child fragment.
  625 + */
  626 + public void popChild() {
  627 + mDelegate.popChild();
  628 + }
  629 +
  630 + /**
  631 + * Pop the last fragment transition from the manager's fragment
  632 + * back stack.
  633 + * <p>
  634 + * 出栈到目标fragment
  635 + *
  636 + * @param targetFragmentClass 目标fragment
  637 + * @param includeTargetFragment 是否包含该fragment
  638 + */
  639 + public void popTo(Class<?> targetFragmentClass, boolean includeTargetFragment) {
  640 + mDelegate.popTo(targetFragmentClass, includeTargetFragment);
  641 + }
  642 +
  643 + /**
  644 + * If you want to begin another FragmentTransaction immediately after popTo(), use this method.
  645 + * 如果你想在出栈后, 立刻进行FragmentTransaction操作,请使用该方法
  646 + */
  647 + public void popTo(Class<?> targetFragmentClass, boolean includeTargetFragment, Runnable afterPopTransactionRunnable) {
  648 + mDelegate.popTo(targetFragmentClass, includeTargetFragment, afterPopTransactionRunnable);
  649 + }
  650 +
  651 + public void popTo(Class<?> targetFragmentClass, boolean includeTargetFragment, Runnable afterPopTransactionRunnable, int popAnim) {
  652 + mDelegate.popTo(targetFragmentClass, includeTargetFragment, afterPopTransactionRunnable, popAnim);
  653 + }
  654 +
  655 + public void popToChild(Class<?> targetFragmentClass, boolean includeTargetFragment) {
  656 + mDelegate.popToChild(targetFragmentClass, includeTargetFragment);
  657 + }
  658 +
  659 + public void popToChild(Class<?> targetFragmentClass, boolean includeTargetFragment, Runnable afterPopTransactionRunnable) {
  660 + mDelegate.popToChild(targetFragmentClass, includeTargetFragment, afterPopTransactionRunnable);
  661 + }
  662 +
  663 + public void popToChild(Class<?> targetFragmentClass, boolean includeTargetFragment, Runnable afterPopTransactionRunnable, int popAnim) {
  664 + mDelegate.popToChild(targetFragmentClass, includeTargetFragment, afterPopTransactionRunnable, popAnim);
  665 + }
  666 +
  667 + /**
  668 + * 得到位于栈顶Fragment
  669 + */
  670 + public ISupportFragment getTopFragment() {
  671 + return SupportHelper.getTopFragment(getFragmentManager());
  672 + }
  673 +
  674 + public ISupportFragment getTopChildFragment() {
  675 + return SupportHelper.getTopFragment(getChildFragmentManager());
  676 + }
  677 +
  678 + /**
  679 + * @return 位于当前Fragment的前一个Fragment
  680 + */
  681 + public ISupportFragment getPreFragment() {
  682 + return SupportHelper.getPreFragment(this);
  683 + }
  684 +
  685 + /**
  686 + * 获取栈内的fragment对象
  687 + */
  688 + public <T extends ISupportFragment> T findFragment(Class<T> fragmentClass) {
  689 + return SupportHelper.findFragment(getFragmentManager(), fragmentClass);
  690 + }
  691 +
  692 + /**
  693 + * 获取栈内的fragment对象
  694 + */
  695 + public <T extends ISupportFragment> T findChildFragment(Class<T> fragmentClass) {
  696 + return SupportHelper.findFragment(getChildFragmentManager(), fragmentClass);
  697 + }
  698 +
  699 + /*****************************侧滑返回************************************/
  700 + @Override
  701 + public View attachToSwipeBack(View view) {
  702 + return mSwipeDelegate.attachToSwipeBack(view);
  703 + }
  704 +
  705 + public SwipeBackLayout getSwipeBackLayout() {
  706 + return mSwipeDelegate.getSwipeBackLayout();
  707 + }
  708 +
  709 + /**
  710 + * 是否可滑动
  711 + *
  712 + * @param enable
  713 + */
  714 + public void setSwipeBackEnable(boolean enable) {
  715 + mSwipeDelegate.setSwipeBackEnable(enable);
  716 + }
  717 +
  718 + @Override
  719 + public void setEdgeLevel(SwipeBackLayout.EdgeLevel edgeLevel) {
  720 + mSwipeDelegate.setEdgeLevel(edgeLevel);
  721 + }
  722 +
  723 + @Override
  724 + public void setEdgeLevel(int widthPixel) {
  725 + mSwipeDelegate.setEdgeLevel(widthPixel);
  726 + }
  727 +
  728 + /**
  729 + * Set the offset of the parallax slip.
  730 + */
  731 + public void setParallaxOffset(@FloatRange(from = 0.0f, to = 1.0f) float offset) {
  732 + mSwipeDelegate.setParallaxOffset(offset);
  733 + }
241 } 734 }
core/base/src/main/java/com/cnlive/core/libs/base/frame/presenter/BasePresenter.java
@@ -2,6 +2,7 @@ package com.cnlive.core.libs.base.frame.presenter; @@ -2,6 +2,7 @@ package com.cnlive.core.libs.base.frame.presenter;
2 2
3 import com.cnlive.core.libs.base.frame.view.BaseView; 3 import com.cnlive.core.libs.base.frame.view.BaseView;
4 import com.hannesdorfmann.mosby3.mvp.MvpBasePresenter; 4 import com.hannesdorfmann.mosby3.mvp.MvpBasePresenter;
  5 +import com.orhanobut.logger.Logger;
5 6
6 public class BasePresenter<V extends BaseView> extends MvpBasePresenter<V> { 7 public class BasePresenter<V extends BaseView> extends MvpBasePresenter<V> {
7 protected final String TAG = this.getClass().getSimpleName(); 8 protected final String TAG = this.getClass().getSimpleName();
@@ -17,4 +18,32 @@ public class BasePresenter&lt;V extends BaseView&gt; extends MvpBasePresenter&lt;V&gt; { @@ -17,4 +18,32 @@ public class BasePresenter&lt;V extends BaseView&gt; extends MvpBasePresenter&lt;V&gt; {
17 // public V getView() { 18 // public V getView() {
18 // return super.getView(); 19 // return super.getView();
19 // } 20 // }
  21 +
  22 + public void logError(Object info) {
  23 + Logger.e(TAG, info);
  24 + }
  25 +
  26 + public void logDebug(Object info) {
  27 + Logger.d(TAG, info);
  28 + }
  29 +
  30 + public void logWarn(Object info) {
  31 + Logger.w(TAG, info);
  32 + }
  33 +
  34 + public void logInfo(Object info) {
  35 + Logger.i(TAG, info);
  36 + }
  37 +
  38 + public void logVerbose(Object info) {
  39 + Logger.v(TAG, info);
  40 + }
  41 +
  42 + public void logJson(String json) {
  43 + Logger.json(json);
  44 + }
  45 +
  46 + public void logXml(String xml) {
  47 + Logger.xml(xml);
  48 + }
20 } 49 }
core/base/src/main/java/com/cnlive/core/libs/base/frame/view/BaseView.java
1 package com.cnlive.core.libs.base.frame.view; 1 package com.cnlive.core.libs.base.frame.view;
2 2
3 import com.hannesdorfmann.mosby3.mvp.MvpView; 3 import com.hannesdorfmann.mosby3.mvp.MvpView;
  4 +import com.orhanobut.logger.Logger;
4 5
5 /** 6 /**
6 * @author ys 7 * @author ys
@@ -22,4 +23,32 @@ public class BaseView implements MvpView { @@ -22,4 +23,32 @@ public class BaseView implements MvpView {
22 } 23 }
23 return false; 24 return false;
24 } 25 }
  26 +
  27 + public void logError(Object info) {
  28 + Logger.e(TAG, info);
  29 + }
  30 +
  31 + public void logDebug(Object info) {
  32 + Logger.d(TAG, info);
  33 + }
  34 +
  35 + public void logWarn(Object info) {
  36 + Logger.w(TAG, info);
  37 + }
  38 +
  39 + public void logInfo(Object info) {
  40 + Logger.i(TAG, info);
  41 + }
  42 +
  43 + public void logVerbose(Object info) {
  44 + Logger.v(TAG, info);
  45 + }
  46 +
  47 + public void logJson(String json) {
  48 + Logger.json(json);
  49 + }
  50 +
  51 + public void logXml(String xml) {
  52 + Logger.xml(xml);
  53 + }
25 } 54 }
core/base/src/main/java/com/me/yokeyword/fragmentation/ExtraTransaction.java 0 → 100644
  1 +package com.me.yokeyword.fragmentation;
  2 +
  3 +import android.os.Build;
  4 +import android.view.View;
  5 +
  6 +import androidx.annotation.AnimRes;
  7 +import androidx.annotation.AnimatorRes;
  8 +import androidx.annotation.RequiresApi;
  9 +import androidx.fragment.app.Fragment;
  10 +import androidx.fragment.app.FragmentActivity;
  11 +import androidx.fragment.app.FragmentManager;
  12 +
  13 +import com.me.yokeyword.fragmentation.helper.internal.TransactionRecord;
  14 +
  15 +import java.util.ArrayList;
  16 +
  17 +
  18 +/**
  19 + * Created by YoKey on 16/11/24.
  20 + */
  21 +public abstract class ExtraTransaction {
  22 +
  23 + /**
  24 + * @param tag Optional tag name for the fragment, to later retrieve the
  25 + * fragment with {@link SupportHelper#findFragment(FragmentManager, String)}
  26 + * , pop(String)
  27 + * or FragmentManager.findFragmentByTag(String).
  28 + */
  29 + public abstract ExtraTransaction setTag(String tag);
  30 +
  31 + /**
  32 + * Set specific animation resources to run for the fragments that are
  33 + * entering and exiting in this transaction. These animations will not be
  34 + * played when popping the back stack.
  35 + */
  36 + public abstract ExtraTransaction setCustomAnimations(@AnimatorRes @AnimRes int targetFragmentEnter,
  37 + @AnimatorRes @AnimRes int currentFragmentPopExit);
  38 +
  39 + /**
  40 + * Set specific animation resources to run for the fragments that are
  41 + * entering and exiting in this transaction. The <code>currentFragmentPopEnter</code>
  42 + * and <code>targetFragmentExit</code> animations will be played for targetFragmentEnter/currentFragmentPopExit
  43 + * operations specifically when popping the back stack.
  44 + */
  45 + public abstract ExtraTransaction setCustomAnimations(@AnimatorRes @AnimRes int targetFragmentEnter,
  46 + @AnimatorRes @AnimRes int currentFragmentPopExit,
  47 + @AnimatorRes @AnimRes int currentFragmentPopEnter,
  48 + @AnimatorRes @AnimRes int targetFragmentExit);
  49 +
  50 + /**
  51 + * Used with custom Transitions to map a View from a removed or hidden
  52 + * Fragment to a View from a shown or added Fragment.
  53 + * <var>sharedElement</var> must have a unique transitionName in the View hierarchy.
  54 + *
  55 + * @param sharedElement A View in a disappearing Fragment to match with a View in an
  56 + * appearing Fragment.
  57 + * @param sharedName The transitionName for a View in an appearing Fragment to match to the shared
  58 + * element.
  59 + * @see Fragment#setSharedElementReturnTransition(Object)
  60 + * @see Fragment#setSharedElementEnterTransition(Object)
  61 + */
  62 + @RequiresApi(Build.VERSION_CODES.LOLLIPOP_MR1)
  63 + public abstract ExtraTransaction addSharedElement(View sharedElement, String sharedName);
  64 +
  65 + public abstract void loadRootFragment(int containerId, ISupportFragment toFragment);
  66 +
  67 + public abstract void loadRootFragment(int containerId, ISupportFragment toFragment, boolean addToBackStack, boolean allowAnim);
  68 +
  69 + public abstract void start(ISupportFragment toFragment);
  70 +
  71 + public abstract void startDontHideSelf(ISupportFragment toFragment);
  72 +
  73 + public abstract void startDontHideSelf(ISupportFragment toFragment, @ISupportFragment.LaunchMode int launchMode);
  74 +
  75 + public abstract void start(ISupportFragment toFragment, @ISupportFragment.LaunchMode int launchMode);
  76 +
  77 + public abstract void startForResult(ISupportFragment toFragment, int requestCode);
  78 +
  79 + public abstract void startForResultDontHideSelf(ISupportFragment toFragment, int requestCode);
  80 +
  81 + public abstract void startWithPop(ISupportFragment toFragment);
  82 +
  83 + public abstract void startWithPopTo(ISupportFragment toFragment, String targetFragmentTag, boolean includeTargetFragment);
  84 +
  85 + public abstract void replace(ISupportFragment toFragment);
  86 +
  87 + /**
  88 + * 使用setTag()自定义Tag时,使用下面popTo()/popToChild()出栈
  89 + *
  90 + * @param targetFragmentTag 通过setTag()设置的tag
  91 + * @param includeTargetFragment 是否包含目标(Tag为targetFragmentTag)Fragment
  92 + */
  93 + public abstract void popTo(String targetFragmentTag, boolean includeTargetFragment);
  94 +
  95 + public abstract void popTo(String targetFragmentTag, boolean includeTargetFragment, Runnable afterPopTransactionRunnable, int popAnim);
  96 +
  97 + public abstract void popToChild(String targetFragmentTag, boolean includeTargetFragment);
  98 +
  99 + public abstract void popToChild(String targetFragmentTag, boolean includeTargetFragment, Runnable afterPopTransactionRunnable, int popAnim);
  100 +
  101 + /**
  102 + * Don't add this extraTransaction to the back stack.
  103 + */
  104 + public abstract DontAddToBackStackTransaction dontAddToBackStack();
  105 +
  106 + /**
  107 + * 使用dontAddToBackStack() 加载Fragment时, 使用remove()移除Fragment
  108 + */
  109 + public abstract void remove(ISupportFragment fragment, boolean showPreFragment);
  110 +
  111 + public interface DontAddToBackStackTransaction {
  112 + /**
  113 + * add() + hide(preFragment)
  114 + */
  115 + void start(ISupportFragment toFragment);
  116 +
  117 + /**
  118 + * Only add()
  119 + */
  120 + void add(ISupportFragment toFragment);
  121 +
  122 + /**
  123 + * replace()
  124 + */
  125 + void replace(ISupportFragment toFragment);
  126 + }
  127 +
  128 + /**
  129 + * Impl
  130 + */
  131 + final static class ExtraTransactionImpl<T extends ISupportFragment> extends ExtraTransaction implements DontAddToBackStackTransaction {
  132 + private FragmentActivity mActivity;
  133 + private T mSupportF;
  134 + private Fragment mFragment;
  135 + private TransactionDelegate mTransactionDelegate;
  136 + private boolean mFromActivity;
  137 + private TransactionRecord mRecord;
  138 +
  139 + ExtraTransactionImpl(FragmentActivity activity, T supportF, TransactionDelegate transactionDelegate, boolean fromActivity) {
  140 + this.mActivity = activity;
  141 + this.mSupportF = supportF;
  142 + this.mFragment = (Fragment) supportF;
  143 + this.mTransactionDelegate = transactionDelegate;
  144 + this.mFromActivity = fromActivity;
  145 + mRecord = new TransactionRecord();
  146 + }
  147 +
  148 + @Override
  149 + public ExtraTransaction setTag(String tag) {
  150 + mRecord.tag = tag;
  151 + return this;
  152 + }
  153 +
  154 + @Override
  155 + public ExtraTransaction setCustomAnimations(@AnimRes int targetFragmentEnter
  156 + , @AnimRes int currentFragmentPopExit) {
  157 + mRecord.targetFragmentEnter = targetFragmentEnter;
  158 + mRecord.currentFragmentPopExit = currentFragmentPopExit;
  159 + mRecord.currentFragmentPopEnter = 0;
  160 + mRecord.targetFragmentExit = 0;
  161 + return this;
  162 + }
  163 +
  164 + @Override
  165 + public ExtraTransaction setCustomAnimations(@AnimRes int targetFragmentEnter,
  166 + @AnimRes int currentFragmentPopExit,
  167 + @AnimRes int currentFragmentPopEnter,
  168 + @AnimRes int targetFragmentExit) {
  169 + mRecord.targetFragmentEnter = targetFragmentEnter;
  170 + mRecord.currentFragmentPopExit = currentFragmentPopExit;
  171 + mRecord.currentFragmentPopEnter = currentFragmentPopEnter;
  172 + mRecord.targetFragmentExit = targetFragmentExit;
  173 + return this;
  174 + }
  175 +
  176 + @Override
  177 + public ExtraTransaction addSharedElement(View sharedElement, String sharedName) {
  178 + if (mRecord.sharedElementList == null) {
  179 + mRecord.sharedElementList = new ArrayList<>();
  180 + }
  181 + mRecord.sharedElementList.add(new TransactionRecord.SharedElement(sharedElement, sharedName));
  182 + return this;
  183 + }
  184 +
  185 + @Override
  186 + public void loadRootFragment(int containerId, ISupportFragment toFragment) {
  187 + loadRootFragment(containerId, toFragment, true, false);
  188 + }
  189 +
  190 + @Override
  191 + public void loadRootFragment(int containerId, ISupportFragment toFragment, boolean addToBackStack, boolean allowAnim) {
  192 + toFragment.getSupportDelegate().mTransactionRecord = mRecord;
  193 + mTransactionDelegate.loadRootTransaction(getFragmentManager(), containerId, toFragment, addToBackStack, allowAnim);
  194 + }
  195 +
  196 + @Override
  197 + public DontAddToBackStackTransaction dontAddToBackStack() {
  198 + mRecord.dontAddToBackStack = true;
  199 + return this;
  200 + }
  201 +
  202 + @Override
  203 + public void remove(ISupportFragment fragment, boolean showPreFragment) {
  204 + mTransactionDelegate.remove(getFragmentManager(), (Fragment) fragment, showPreFragment);
  205 + }
  206 +
  207 + @Override
  208 + public void popTo(String targetFragmentTag, boolean includeTargetFragment) {
  209 + popTo(targetFragmentTag, includeTargetFragment, null, TransactionDelegate.DEFAULT_POPTO_ANIM);
  210 + }
  211 +
  212 + @Override
  213 + public void popTo(String targetFragmentTag, boolean includeTargetFragment, Runnable afterPopTransactionRunnable, int popAnim) {
  214 + mTransactionDelegate.popTo(targetFragmentTag, includeTargetFragment, afterPopTransactionRunnable, getFragmentManager(), popAnim);
  215 + }
  216 +
  217 + @Override
  218 + public void popToChild(String targetFragmentTag, boolean includeTargetFragment) {
  219 + popToChild(targetFragmentTag, includeTargetFragment, null, TransactionDelegate.DEFAULT_POPTO_ANIM);
  220 + }
  221 +
  222 + @Override
  223 + public void popToChild(String targetFragmentTag, boolean includeTargetFragment, Runnable afterPopTransactionRunnable, int popAnim) {
  224 + if (mFromActivity) {
  225 + popTo(targetFragmentTag, includeTargetFragment, afterPopTransactionRunnable, popAnim);
  226 + } else {
  227 + mTransactionDelegate.popTo(targetFragmentTag, includeTargetFragment, afterPopTransactionRunnable, mFragment.getChildFragmentManager(), popAnim);
  228 + }
  229 + }
  230 +
  231 + @Override
  232 + public void add(ISupportFragment toFragment) {
  233 + toFragment.getSupportDelegate().mTransactionRecord = mRecord;
  234 + mTransactionDelegate.dispatchStartTransaction(getFragmentManager(), mSupportF, toFragment, 0, ISupportFragment.STANDARD, TransactionDelegate.TYPE_ADD_WITHOUT_HIDE);
  235 + }
  236 +
  237 + @Override
  238 + public void start(ISupportFragment toFragment) {
  239 + start(toFragment, ISupportFragment.STANDARD);
  240 + }
  241 +
  242 + @Override
  243 + public void startDontHideSelf(ISupportFragment toFragment) {
  244 + toFragment.getSupportDelegate().mTransactionRecord = mRecord;
  245 + mTransactionDelegate.dispatchStartTransaction(getFragmentManager(), mSupportF, toFragment, 0, ISupportFragment.STANDARD, TransactionDelegate.TYPE_ADD_WITHOUT_HIDE);
  246 + }
  247 +
  248 + @Override
  249 + public void startDontHideSelf(ISupportFragment toFragment, @ISupportFragment.LaunchMode int launchMode) {
  250 + toFragment.getSupportDelegate().mTransactionRecord = mRecord;
  251 + mTransactionDelegate.dispatchStartTransaction(getFragmentManager(), mSupportF, toFragment, 0, launchMode, TransactionDelegate.TYPE_ADD_WITHOUT_HIDE);
  252 + }
  253 +
  254 + @Override
  255 + public void start(ISupportFragment toFragment, @ISupportFragment.LaunchMode int launchMode) {
  256 + toFragment.getSupportDelegate().mTransactionRecord = mRecord;
  257 + mTransactionDelegate.dispatchStartTransaction(getFragmentManager(), mSupportF, toFragment, 0, launchMode, TransactionDelegate.TYPE_ADD);
  258 + }
  259 +
  260 + @Override
  261 + public void startForResult(ISupportFragment toFragment, int requestCode) {
  262 + toFragment.getSupportDelegate().mTransactionRecord = mRecord;
  263 + mTransactionDelegate.dispatchStartTransaction(getFragmentManager(), mSupportF, toFragment, requestCode, ISupportFragment.STANDARD, TransactionDelegate.TYPE_ADD_RESULT);
  264 + }
  265 +
  266 + @Override
  267 + public void startForResultDontHideSelf(ISupportFragment toFragment, int requestCode) {
  268 + toFragment.getSupportDelegate().mTransactionRecord = mRecord;
  269 + mTransactionDelegate.dispatchStartTransaction(getFragmentManager(), mSupportF, toFragment, requestCode, ISupportFragment.STANDARD, TransactionDelegate.TYPE_ADD_RESULT_WITHOUT_HIDE);
  270 + }
  271 +
  272 + @Override
  273 + public void startWithPop(ISupportFragment toFragment) {
  274 + toFragment.getSupportDelegate().mTransactionRecord = mRecord;
  275 + mTransactionDelegate.startWithPop(getFragmentManager(), mSupportF, toFragment);
  276 + }
  277 +
  278 + @Override
  279 + public void startWithPopTo(ISupportFragment toFragment, String targetFragmentTag, boolean includeTargetFragment) {
  280 + toFragment.getSupportDelegate().mTransactionRecord = mRecord;
  281 + mTransactionDelegate.startWithPopTo(getFragmentManager(), mSupportF, toFragment, targetFragmentTag, includeTargetFragment);
  282 + }
  283 +
  284 + @Override
  285 + public void replace(ISupportFragment toFragment) {
  286 + toFragment.getSupportDelegate().mTransactionRecord = mRecord;
  287 + mTransactionDelegate.dispatchStartTransaction(getFragmentManager(), mSupportF, toFragment, 0, ISupportFragment.STANDARD, TransactionDelegate.TYPE_REPLACE);
  288 + }
  289 +
  290 + private FragmentManager getFragmentManager() {
  291 + if (mFragment == null) {
  292 + return mActivity.getSupportFragmentManager();
  293 + }
  294 + return mFragment.getFragmentManager();
  295 + }
  296 + }
  297 +}
core/base/src/main/java/com/me/yokeyword/fragmentation/Fragmentation.java 0 → 100644
  1 +package com.me.yokeyword.fragmentation;
  2 +
  3 +import androidx.annotation.IntDef;
  4 +
  5 +import com.me.yokeyword.fragmentation.helper.ExceptionHandler;
  6 +
  7 +import java.lang.annotation.Retention;
  8 +import java.lang.annotation.RetentionPolicy;
  9 +
  10 +
  11 +/**
  12 + * Created by YoKey on 17/2/5.
  13 + */
  14 +public class Fragmentation {
  15 + /**
  16 + * Dont display stack view.
  17 + */
  18 + public static final int NONE = 0;
  19 + /**
  20 + * Shake it to display stack view.
  21 + */
  22 + public static final int SHAKE = 1;
  23 + /**
  24 + * As a bubble display stack view.
  25 + */
  26 + public static final int BUBBLE = 2;
  27 +
  28 + static volatile Fragmentation INSTANCE;
  29 +
  30 + private boolean debug;
  31 + private int mode = BUBBLE;
  32 + private ExceptionHandler handler;
  33 +
  34 + @IntDef({NONE, SHAKE, BUBBLE})
  35 + @Retention(RetentionPolicy.SOURCE)
  36 + @interface StackViewMode {
  37 + }
  38 +
  39 + public static Fragmentation getDefault() {
  40 + if (INSTANCE == null) {
  41 + synchronized (Fragmentation.class) {
  42 + if (INSTANCE == null) {
  43 + INSTANCE = new Fragmentation(new FragmentationBuilder());
  44 + }
  45 + }
  46 + }
  47 + return INSTANCE;
  48 + }
  49 +
  50 + Fragmentation(FragmentationBuilder builder) {
  51 + debug = builder.debug;
  52 + if (debug) {
  53 + mode = builder.mode;
  54 + } else {
  55 + mode = NONE;
  56 + }
  57 + handler = builder.handler;
  58 + }
  59 +
  60 + public boolean isDebug() {
  61 + return debug;
  62 + }
  63 +
  64 + public void setDebug(boolean debug) {
  65 + this.debug = debug;
  66 + }
  67 +
  68 + public ExceptionHandler getHandler() {
  69 + return handler;
  70 + }
  71 +
  72 + public void setHandler(ExceptionHandler handler) {
  73 + this.handler = handler;
  74 + }
  75 +
  76 + public int getMode() {
  77 + return mode;
  78 + }
  79 +
  80 + public void setMode(@StackViewMode int mode) {
  81 + this.mode = mode;
  82 + }
  83 +
  84 + public static FragmentationBuilder builder() {
  85 + return new FragmentationBuilder();
  86 + }
  87 +
  88 + public static class FragmentationBuilder {
  89 + private boolean debug;
  90 + private int mode;
  91 + private ExceptionHandler handler;
  92 +
  93 + /**
  94 + * @param debug Suppressed Exception("Can not perform this action after onSaveInstanceState!") when debug=false
  95 + */
  96 + public FragmentationBuilder debug(boolean debug) {
  97 + this.debug = debug;
  98 + return this;
  99 + }
  100 +
  101 + /**
  102 + * Sets the mode to display the stack view
  103 + * <p>
  104 + * None if debug(false).
  105 + * <p>
  106 + * Default:NONE
  107 + */
  108 + public FragmentationBuilder stackViewMode(@StackViewMode int mode) {
  109 + this.mode = mode;
  110 + return this;
  111 + }
  112 +
  113 + /**
  114 + * @param handler Handled Exception("Can not perform this action after onSaveInstanceState!") when debug=false.
  115 + */
  116 + public FragmentationBuilder handleException(ExceptionHandler handler) {
  117 + this.handler = handler;
  118 + return this;
  119 + }
  120 +
  121 + public Fragmentation install() {
  122 + Fragmentation.INSTANCE = new Fragmentation(this);
  123 + return Fragmentation.INSTANCE;
  124 + }
  125 + }
  126 +}
core/base/src/main/java/com/me/yokeyword/fragmentation/ISupportActivity.java 0 → 100644
  1 +package com.me.yokeyword.fragmentation;
  2 +
  3 +import android.view.MotionEvent;
  4 +
  5 +import com.me.yokeyword.fragmentation.anim.FragmentAnimator;
  6 +
  7 +
  8 +/**
  9 + * Created by YoKey on 17/6/13.
  10 + */
  11 +
  12 +public interface ISupportActivity {
  13 + SupportActivityDelegate getSupportDelegate();
  14 +
  15 + ExtraTransaction extraTransaction();
  16 +
  17 + FragmentAnimator getFragmentAnimator();
  18 +
  19 + void setFragmentAnimator(FragmentAnimator fragmentAnimator);
  20 +
  21 + FragmentAnimator onCreateFragmentAnimator();
  22 +
  23 + void post(Runnable runnable);
  24 +
  25 + void onBackPressed();
  26 +
  27 + void onBackPressedSupport();
  28 +
  29 + boolean dispatchTouchEvent(MotionEvent ev);
  30 +}
core/base/src/main/java/com/me/yokeyword/fragmentation/ISupportFragment.java 0 → 100644
  1 +package com.me.yokeyword.fragmentation;
  2 +
  3 +import android.os.Bundle;
  4 +
  5 +import androidx.annotation.IntDef;
  6 +import androidx.annotation.Nullable;
  7 +
  8 +import com.me.yokeyword.fragmentation.anim.FragmentAnimator;
  9 +
  10 +import java.lang.annotation.Retention;
  11 +import java.lang.annotation.RetentionPolicy;
  12 +
  13 +
  14 +/**
  15 + * Created by YoKey on 17/6/23.
  16 + */
  17 +
  18 +public interface ISupportFragment {
  19 + // LaunchMode
  20 + int STANDARD = 0;
  21 + int SINGLETOP = 1;
  22 + int SINGLETASK = 2;
  23 +
  24 + // ResultCode
  25 + int RESULT_CANCELED = 0;
  26 + int RESULT_OK = -1;
  27 +
  28 + @IntDef({STANDARD, SINGLETOP, SINGLETASK})
  29 + @Retention(RetentionPolicy.SOURCE)
  30 + public @interface LaunchMode {
  31 + }
  32 +
  33 + SupportFragmentDelegate getSupportDelegate();
  34 +
  35 + ExtraTransaction extraTransaction();
  36 +
  37 + void enqueueAction(Runnable runnable);
  38 +
  39 + void post(Runnable runnable);
  40 +
  41 + void onEnterAnimationEnd(@Nullable Bundle savedInstanceState);
  42 +
  43 + void onLazyInitView(@Nullable Bundle savedInstanceState);
  44 +
  45 + void onSupportVisible();
  46 +
  47 + void onSupportInvisible();
  48 +
  49 + boolean isSupportVisible();
  50 +
  51 + FragmentAnimator onCreateFragmentAnimator();
  52 +
  53 + FragmentAnimator getFragmentAnimator();
  54 +
  55 + void setFragmentAnimator(FragmentAnimator fragmentAnimator);
  56 +
  57 + void setFragmentResult(int resultCode, Bundle bundle);
  58 +
  59 + void onFragmentResult(int requestCode, int resultCode, Bundle data);
  60 +
  61 + void onNewBundle(Bundle args);
  62 +
  63 + void putNewBundle(Bundle newBundle);
  64 +
  65 + boolean onBackPressedSupport();
  66 +}
core/base/src/main/java/com/me/yokeyword/fragmentation/SupportActivity.java 0 → 100644
  1 +package com.me.yokeyword.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.me.yokeyword.fragmentation.anim.FragmentAnimator;
  12 +
  13 +
  14 +/**
  15 + * Base class for activities that use the support-based
  16 + * {@link ISupportActivity} and
  17 + * {@link AppCompatActivity} APIs.
  18 + * <p>
  19 + * Created by YoKey on 17/6/20.
  20 + */
  21 +public class SupportActivity extends AppCompatActivity implements ISupportActivity {
  22 + final SupportActivityDelegate mDelegate = new SupportActivityDelegate(this);
  23 +
  24 + @Override
  25 + public SupportActivityDelegate getSupportDelegate() {
  26 + return mDelegate;
  27 + }
  28 +
  29 + /**
  30 + * Perform some extra transactions.
  31 + * 额外的事务:自定义Tag,添加SharedElement动画,操作非回退栈Fragment
  32 + */
  33 + @Override
  34 + public ExtraTransaction extraTransaction() {
  35 + return mDelegate.extraTransaction();
  36 + }
  37 +
  38 + @Override
  39 + protected void onCreate(@Nullable Bundle savedInstanceState) {
  40 + super.onCreate(savedInstanceState);
  41 + mDelegate.onCreate(savedInstanceState);
  42 + }
  43 +
  44 + @Override
  45 + protected void onPostCreate(@Nullable Bundle savedInstanceState) {
  46 + super.onPostCreate(savedInstanceState);
  47 + mDelegate.onPostCreate(savedInstanceState);
  48 + }
  49 +
  50 + @Override
  51 + protected void onDestroy() {
  52 + mDelegate.onDestroy();
  53 + super.onDestroy();
  54 + }
  55 +
  56 + /**
  57 + * Note: return mDelegate.dispatchTouchEvent(ev) || super.dispatchTouchEvent(ev);
  58 + */
  59 + @Override
  60 + public boolean dispatchTouchEvent(MotionEvent ev) {
  61 + return mDelegate.dispatchTouchEvent(ev) || super.dispatchTouchEvent(ev);
  62 + }
  63 +
  64 + /**
  65 + * 不建议复写该方法,请使用 {@link #onBackPressedSupport} 代替
  66 + */
  67 + @Override
  68 + final public void onBackPressed() {
  69 + mDelegate.onBackPressed();
  70 + }
  71 +
  72 + /**
  73 + * 该方法回调时机为,Activity回退栈内Fragment的数量 小于等于1 时,默认finish Activity
  74 + * 请尽量复写该方法,避免复写onBackPress(),以保证SupportFragment内的onBackPressedSupport()回退事件正常执行
  75 + */
  76 + @Override
  77 + public void onBackPressedSupport() {
  78 + mDelegate.onBackPressedSupport();
  79 + }
  80 +
  81 + /**
  82 + * 获取设置的全局动画 copy
  83 + *
  84 + * @return FragmentAnimator
  85 + */
  86 + @Override
  87 + public FragmentAnimator getFragmentAnimator() {
  88 + return mDelegate.getFragmentAnimator();
  89 + }
  90 +
  91 + /**
  92 + * Set all fragments animation.
  93 + * 设置Fragment内的全局动画
  94 + */
  95 + @Override
  96 + public void setFragmentAnimator(FragmentAnimator fragmentAnimator) {
  97 + mDelegate.setFragmentAnimator(fragmentAnimator);
  98 + }
  99 +
  100 + /**
  101 + * Set all fragments animation.
  102 + * 构建Fragment转场动画
  103 + * <p/>
  104 + * 如果是在Activity内实现,则构建的是Activity内所有Fragment的转场动画,
  105 + * 如果是在Fragment内实现,则构建的是该Fragment的转场动画,此时优先级 > Activity的onCreateFragmentAnimator()
  106 + *
  107 + * @return FragmentAnimator对象
  108 + */
  109 + @Override
  110 + public FragmentAnimator onCreateFragmentAnimator() {
  111 + return mDelegate.onCreateFragmentAnimator();
  112 + }
  113 +
  114 + @Override
  115 + public void post(Runnable runnable) {
  116 + mDelegate.post(runnable);
  117 + }
  118 +
  119 + /****************************************以下为可选方法(Optional methods)******************************************************/
  120 +
  121 + /**
  122 + * 加载根Fragment, 即Activity内的第一个Fragment 或 Fragment内的第一个子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 + public void loadRootFragment(int containerId, ISupportFragment toFragment, boolean addToBackStack, boolean allowAnimation) {
  132 + mDelegate.loadRootFragment(containerId, toFragment, addToBackStack, allowAnimation);
  133 + }
  134 +
  135 + /**
  136 + * 加载多个同级根Fragment,类似Wechat, QQ主页的场景
  137 + */
  138 + public void loadMultipleRootFragment(int containerId, int showPosition, ISupportFragment... toFragments) {
  139 + mDelegate.loadMultipleRootFragment(containerId, showPosition, toFragments);
  140 + }
  141 +
  142 + /**
  143 + * show一个Fragment,hide其他同栈所有Fragment
  144 + * 使用该方法时,要确保同级栈内无多余的Fragment,(只有通过loadMultipleRootFragment()载入的Fragment)
  145 + * <p>
  146 + * 建议使用更明确的{@link #showHideFragment(ISupportFragment, ISupportFragment)}
  147 + *
  148 + * @param showFragment 需要show的Fragment
  149 + */
  150 + public void showHideFragment(ISupportFragment showFragment) {
  151 + mDelegate.showHideFragment(showFragment);
  152 + }
  153 +
  154 + /**
  155 + * show一个Fragment,hide一个Fragment ; 主要用于类似微信主页那种 切换tab的情况
  156 + */
  157 + public void showHideFragment(ISupportFragment showFragment, ISupportFragment hideFragment) {
  158 + mDelegate.showHideFragment(showFragment, hideFragment);
  159 + }
  160 +
  161 + /**
  162 + * It is recommended to use {@link SupportFragment#start(ISupportFragment)}.
  163 + */
  164 + public void start(ISupportFragment toFragment) {
  165 + mDelegate.start(toFragment);
  166 + }
  167 +
  168 + /**
  169 + * It is recommended to use {@link SupportFragment#start(ISupportFragment, int)}.
  170 + *
  171 + * @param launchMode Similar to Activity's LaunchMode.
  172 + */
  173 + public void start(ISupportFragment toFragment, @ISupportFragment.LaunchMode int launchMode) {
  174 + mDelegate.start(toFragment, launchMode);
  175 + }
  176 +
  177 + /**
  178 + * It is recommended to use {@link SupportFragment#startForResult(ISupportFragment, int)}.
  179 + * Launch an fragment for which you would like a result when it poped.
  180 + */
  181 + public void startForResult(ISupportFragment toFragment, int requestCode) {
  182 + mDelegate.startForResult(toFragment, requestCode);
  183 + }
  184 +
  185 + /**
  186 + * It is recommended to use {@link SupportFragment#startWithPop(ISupportFragment)}.
  187 + * Start the target Fragment and pop itself
  188 + */
  189 + public void startWithPop(ISupportFragment toFragment) {
  190 + mDelegate.startWithPop(toFragment);
  191 + }
  192 +
  193 + /**
  194 + * It is recommended to use {@link SupportFragment#startWithPopTo(ISupportFragment, Class, boolean)}.
  195 + *
  196 + * @see #popTo(Class, boolean)
  197 + * +
  198 + * @see #start(ISupportFragment)
  199 + */
  200 + public void startWithPopTo(ISupportFragment toFragment, Class<?> targetFragmentClass, boolean includeTargetFragment) {
  201 + mDelegate.startWithPopTo(toFragment, targetFragmentClass, includeTargetFragment);
  202 + }
  203 +
  204 + /**
  205 + * It is recommended to use {@link SupportFragment#replaceFragment(ISupportFragment, boolean)}.
  206 + */
  207 + public void replaceFragment(ISupportFragment toFragment, boolean addToBackStack) {
  208 + mDelegate.replaceFragment(toFragment, addToBackStack);
  209 + }
  210 +
  211 + /**
  212 + * Pop the fragment.
  213 + */
  214 + public void pop() {
  215 + mDelegate.pop();
  216 + }
  217 +
  218 + /**
  219 + * Pop the last fragment transition from the manager's fragment
  220 + * back stack.
  221 + * <p>
  222 + * 出栈到目标fragment
  223 + *
  224 + * @param targetFragmentClass 目标fragment
  225 + * @param includeTargetFragment 是否包含该fragment
  226 + */
  227 + public void popTo(Class<?> targetFragmentClass, boolean includeTargetFragment) {
  228 + mDelegate.popTo(targetFragmentClass, includeTargetFragment);
  229 + }
  230 +
  231 + /**
  232 + * If you want to begin another FragmentTransaction immediately after popTo(), use this method.
  233 + * 如果你想在出栈后, 立刻进行FragmentTransaction操作,请使用该方法
  234 + */
  235 + public void popTo(Class<?> targetFragmentClass, boolean includeTargetFragment, Runnable afterPopTransactionRunnable) {
  236 + mDelegate.popTo(targetFragmentClass, includeTargetFragment, afterPopTransactionRunnable);
  237 + }
  238 +
  239 + public void popTo(Class<?> targetFragmentClass, boolean includeTargetFragment, Runnable afterPopTransactionRunnable, int popAnim) {
  240 + mDelegate.popTo(targetFragmentClass, includeTargetFragment, afterPopTransactionRunnable, popAnim);
  241 + }
  242 +
  243 + /**
  244 + * 当Fragment根布局 没有 设定background属性时,
  245 + * Fragmentation默认使用Theme的android:windowbackground作为Fragment的背景,
  246 + * 可以通过该方法改变其内所有Fragment的默认背景。
  247 + */
  248 + public void setDefaultFragmentBackground(@DrawableRes int backgroundRes) {
  249 + mDelegate.setDefaultFragmentBackground(backgroundRes);
  250 + }
  251 +
  252 + /**
  253 + * 得到位于栈顶Fragment
  254 + */
  255 + public ISupportFragment getTopFragment() {
  256 + return SupportHelper.getTopFragment(getSupportFragmentManager());
  257 + }
  258 +
  259 + /**
  260 + * 获取栈内的fragment对象
  261 + */
  262 + public <T extends ISupportFragment> T findFragment(Class<T> fragmentClass) {
  263 + return SupportHelper.findFragment(getSupportFragmentManager(), fragmentClass);
  264 + }
  265 +}
core/base/src/main/java/com/me/yokeyword/fragmentation/SupportActivityDelegate.java 0 → 100644
  1 +package com.me.yokeyword.fragmentation;
  2 +
  3 +import android.os.Bundle;
  4 +import android.view.MotionEvent;
  5 +
  6 +import androidx.annotation.DrawableRes;
  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 +import androidx.fragment.app.FragmentationMagician;
  13 +
  14 +import com.me.yokeyword.fragmentation.anim.DefaultVerticalAnimator;
  15 +import com.me.yokeyword.fragmentation.anim.FragmentAnimator;
  16 +import com.me.yokeyword.fragmentation.debug.DebugStackDelegate;
  17 +import com.me.yokeyword.fragmentation.queue.Action;
  18 +
  19 +public class SupportActivityDelegate {
  20 + private ISupportActivity mSupport;
  21 + private FragmentActivity mActivity;
  22 +
  23 + boolean mPopMultipleNoAnim = false;
  24 + boolean mFragmentClickable = true;
  25 +
  26 + private TransactionDelegate mTransactionDelegate;
  27 + private FragmentAnimator mFragmentAnimator;
  28 + private int mDefaultFragmentBackground = 0;
  29 + private DebugStackDelegate mDebugStackDelegate;
  30 +
  31 + public SupportActivityDelegate(ISupportActivity support) {
  32 + if (!(support instanceof FragmentActivity))
  33 + throw new RuntimeException("Must extends FragmentActivity/AppCompatActivity");
  34 + this.mSupport = support;
  35 + this.mActivity = (FragmentActivity) support;
  36 + this.mDebugStackDelegate = new DebugStackDelegate(this.mActivity);
  37 + }
  38 +
  39 + /**
  40 + * Perform some extra transactions.
  41 + * 额外的事务:自定义Tag,添加SharedElement动画,操作非回退栈Fragment
  42 + */
  43 + public ExtraTransaction extraTransaction() {
  44 + return new ExtraTransaction.ExtraTransactionImpl<>((FragmentActivity) mSupport, getTopFragment(), getTransactionDelegate(), true);
  45 + }
  46 +
  47 + public void onCreate(@Nullable Bundle savedInstanceState) {
  48 + mTransactionDelegate = getTransactionDelegate();
  49 + mFragmentAnimator = mSupport.onCreateFragmentAnimator();
  50 + mDebugStackDelegate.onCreate(Fragmentation.getDefault().getMode());
  51 + }
  52 +
  53 + public TransactionDelegate getTransactionDelegate() {
  54 + if (mTransactionDelegate == null) {
  55 + mTransactionDelegate = new TransactionDelegate(mSupport);
  56 + }
  57 + return mTransactionDelegate;
  58 + }
  59 +
  60 + public void onPostCreate(@Nullable Bundle savedInstanceState) {
  61 + mDebugStackDelegate.onPostCreate(Fragmentation.getDefault().getMode());
  62 + }
  63 +
  64 + /**
  65 + * 获取设置的全局动画 copy
  66 + *
  67 + * @return FragmentAnimator
  68 + */
  69 + public FragmentAnimator getFragmentAnimator() {
  70 + return mFragmentAnimator.copy();
  71 + }
  72 +
  73 + /**
  74 + * Set all fragments animation.
  75 + * 设置Fragment内的全局动画
  76 + */
  77 + public void setFragmentAnimator(FragmentAnimator fragmentAnimator) {
  78 + this.mFragmentAnimator = fragmentAnimator;
  79 +
  80 + for (Fragment fragment : FragmentationMagician.getActiveFragments(getSupportFragmentManager())) {
  81 + if (fragment instanceof ISupportFragment) {
  82 + ISupportFragment iF = (ISupportFragment) fragment;
  83 + SupportFragmentDelegate delegate = iF.getSupportDelegate();
  84 + if (delegate.mAnimByActivity) {
  85 + delegate.mFragmentAnimator = fragmentAnimator.copy();
  86 + if (delegate.mAnimHelper != null) {
  87 + delegate.mAnimHelper.notifyChanged(delegate.mFragmentAnimator);
  88 + }
  89 + }
  90 + }
  91 + }
  92 + }
  93 +
  94 + /**
  95 + * Set all fragments animation.
  96 + * 构建Fragment转场动画
  97 + * <p/>
  98 + * 如果是在Activity内实现,则构建的是Activity内所有Fragment的转场动画,
  99 + * 如果是在Fragment内实现,则构建的是该Fragment的转场动画,此时优先级 > Activity的onCreateFragmentAnimator()
  100 + *
  101 + * @return FragmentAnimator对象
  102 + */
  103 + public FragmentAnimator onCreateFragmentAnimator() {
  104 + return new DefaultVerticalAnimator();
  105 + }
  106 +
  107 + /**
  108 + * 当Fragment根布局 没有 设定background属性时,
  109 + * Fragmentation默认使用Theme的android:windowbackground作为Fragment的背景,
  110 + * 可以通过该方法改变Fragment背景。
  111 + */
  112 + public void setDefaultFragmentBackground(@DrawableRes int backgroundRes) {
  113 + mDefaultFragmentBackground = backgroundRes;
  114 + }
  115 +
  116 + public int getDefaultFragmentBackground() {
  117 + return mDefaultFragmentBackground;
  118 + }
  119 +
  120 + /**
  121 + * 显示栈视图dialog,调试时使用
  122 + */
  123 + public void showFragmentStackHierarchyView() {
  124 + mDebugStackDelegate.showFragmentStackHierarchyView();
  125 + }
  126 +
  127 + /**
  128 + * 显示栈视图日志,调试时使用
  129 + */
  130 + public void logFragmentStackHierarchy(String TAG) {
  131 + mDebugStackDelegate.logFragmentRecords(TAG);
  132 + }
  133 +
  134 + /**
  135 + * Causes the Runnable r to be added to the action queue.
  136 + * <p>
  137 + * The runnable will be run after all the previous action has been run.
  138 + * <p>
  139 + * 前面的事务全部执行后 执行该Action
  140 + */
  141 + public void post(final Runnable runnable) {
  142 + mTransactionDelegate.post(runnable);
  143 + }
  144 +
  145 + /**
  146 + * 不建议复写该方法,请使用 {@link #onBackPressedSupport} 代替
  147 + */
  148 + public void onBackPressed() {
  149 + mTransactionDelegate.mActionQueue.enqueue(new Action(Action.ACTION_BACK) {
  150 + @Override
  151 + public void run() {
  152 + if (!mFragmentClickable) {
  153 + mFragmentClickable = true;
  154 + }
  155 +
  156 + // 获取activeFragment:即从栈顶开始 状态为show的那个Fragment
  157 + ISupportFragment activeFragment = SupportHelper.getActiveFragment(getSupportFragmentManager());
  158 + if (mTransactionDelegate.dispatchBackPressedEvent(activeFragment)) return;
  159 +
  160 + mSupport.onBackPressedSupport();
  161 + }
  162 + });
  163 + }
  164 +
  165 + /**
  166 + * 该方法回调时机为,Activity回退栈内Fragment的数量 小于等于1 时,默认finish Activity
  167 + * 请尽量复写该方法,避免复写onBackPress(),以保证SupportFragment内的onBackPressedSupport()回退事件正常执行
  168 + */
  169 + public void onBackPressedSupport() {
  170 + if (getSupportFragmentManager().getBackStackEntryCount() > 1) {
  171 + pop();
  172 + } else {
  173 + ActivityCompat.finishAfterTransition(mActivity);
  174 + }
  175 + }
  176 +
  177 + public void onDestroy() {
  178 + mDebugStackDelegate.onDestroy();
  179 + }
  180 +
  181 + public boolean dispatchTouchEvent(MotionEvent ev) {
  182 + // 防抖动(防止点击速度过快)
  183 + return !mFragmentClickable;
  184 + }
  185 +
  186 + /**********************************************************************************************/
  187 +
  188 + /**
  189 + * 加载根Fragment, 即Activity内的第一个Fragment 或 Fragment内的第一个子Fragment
  190 + */
  191 + public void loadRootFragment(int containerId, ISupportFragment toFragment) {
  192 + loadRootFragment(containerId, toFragment, true, false);
  193 + }
  194 +
  195 + public void loadRootFragment(int containerId, ISupportFragment toFragment, boolean addToBackStack, boolean allowAnimation) {
  196 + mTransactionDelegate.loadRootTransaction(getSupportFragmentManager(), containerId, toFragment, addToBackStack, allowAnimation);
  197 + }
  198 +
  199 + /**
  200 + * 加载多个同级根Fragment,类似Wechat, QQ主页的场景
  201 + */
  202 + public void loadMultipleRootFragment(int containerId, int showPosition, ISupportFragment... toFragments) {
  203 + mTransactionDelegate.loadMultipleRootTransaction(getSupportFragmentManager(), containerId, showPosition, toFragments);
  204 + }
  205 +
  206 + /**
  207 + * show一个Fragment,hide其他同栈所有Fragment
  208 + * 使用该方法时,要确保同级栈内无多余的Fragment,(只有通过loadMultipleRootFragment()载入的Fragment)
  209 + * <p>
  210 + * 建议使用更明确的{@link #showHideFragment(ISupportFragment, ISupportFragment)}
  211 + *
  212 + * @param showFragment 需要show的Fragment
  213 + */
  214 + public void showHideFragment(ISupportFragment showFragment) {
  215 + showHideFragment(showFragment, null);
  216 + }
  217 +
  218 + /**
  219 + * show一个Fragment,hide一个Fragment ; 主要用于类似微信主页那种 切换tab的情况
  220 + *
  221 + * @param showFragment 需要show的Fragment
  222 + * @param hideFragment 需要hide的Fragment
  223 + */
  224 + public void showHideFragment(ISupportFragment showFragment, ISupportFragment hideFragment) {
  225 + mTransactionDelegate.showHideFragment(getSupportFragmentManager(), showFragment, hideFragment);
  226 + }
  227 +
  228 + public void start(ISupportFragment toFragment) {
  229 + start(toFragment, ISupportFragment.STANDARD);
  230 + }
  231 +
  232 + /**
  233 + * @param launchMode Similar to Activity's LaunchMode.
  234 + */
  235 + public void start(ISupportFragment toFragment, @ISupportFragment.LaunchMode int launchMode) {
  236 + mTransactionDelegate.dispatchStartTransaction(getSupportFragmentManager(), getTopFragment(), toFragment, 0, launchMode, TransactionDelegate.TYPE_ADD);
  237 + }
  238 +
  239 + /**
  240 + * Launch an fragment for which you would like a result when it poped.
  241 + */
  242 + public void startForResult(ISupportFragment toFragment, int requestCode) {
  243 + mTransactionDelegate.dispatchStartTransaction(getSupportFragmentManager(), getTopFragment(), toFragment, requestCode, ISupportFragment.STANDARD, TransactionDelegate.TYPE_ADD_RESULT);
  244 + }
  245 +
  246 + /**
  247 + * Start the target Fragment and pop itself
  248 + */
  249 + public void startWithPop(ISupportFragment toFragment) {
  250 + mTransactionDelegate.startWithPop(getSupportFragmentManager(), getTopFragment(), toFragment);
  251 + }
  252 +
  253 + public void startWithPopTo(ISupportFragment toFragment, Class<?> targetFragmentClass, boolean includeTargetFragment) {
  254 + mTransactionDelegate.startWithPopTo(getSupportFragmentManager(), getTopFragment(), toFragment, targetFragmentClass.getName(), includeTargetFragment);
  255 + }
  256 +
  257 + public void replaceFragment(ISupportFragment toFragment, boolean addToBackStack) {
  258 + mTransactionDelegate.dispatchStartTransaction(getSupportFragmentManager(), getTopFragment(), toFragment, 0, ISupportFragment.STANDARD, addToBackStack ? TransactionDelegate.TYPE_REPLACE : TransactionDelegate.TYPE_REPLACE_DONT_BACK);
  259 + }
  260 +
  261 + /**
  262 + * Pop the child fragment.
  263 + */
  264 + public void pop() {
  265 + mTransactionDelegate.pop(getSupportFragmentManager());
  266 + }
  267 +
  268 + /**
  269 + * Pop the last fragment transition from the manager's fragment
  270 + * back stack.
  271 + * <p>
  272 + * 出栈到目标fragment
  273 + *
  274 + * @param targetFragmentClass 目标fragment
  275 + * @param includeTargetFragment 是否包含该fragment
  276 + */
  277 + public void popTo(Class<?> targetFragmentClass, boolean includeTargetFragment) {
  278 + popTo(targetFragmentClass, includeTargetFragment, null);
  279 + }
  280 +
  281 + /**
  282 + * If you want to begin another FragmentTransaction immediately after popTo(), use this method.
  283 + * 如果你想在出栈后, 立刻进行FragmentTransaction操作,请使用该方法
  284 + */
  285 + public void popTo(Class<?> targetFragmentClass, boolean includeTargetFragment, Runnable afterPopTransactionRunnable) {
  286 + popTo(targetFragmentClass, includeTargetFragment, afterPopTransactionRunnable, TransactionDelegate.DEFAULT_POPTO_ANIM);
  287 + }
  288 +
  289 + public void popTo(Class<?> targetFragmentClass, boolean includeTargetFragment, Runnable afterPopTransactionRunnable, int popAnim) {
  290 + mTransactionDelegate.popTo(targetFragmentClass.getName(), includeTargetFragment, afterPopTransactionRunnable, getSupportFragmentManager(), popAnim);
  291 + }
  292 +
  293 + private FragmentManager getSupportFragmentManager() {
  294 + return mActivity.getSupportFragmentManager();
  295 + }
  296 +
  297 + private ISupportFragment getTopFragment() {
  298 + return SupportHelper.getTopFragment(getSupportFragmentManager());
  299 + }
  300 +}
core/base/src/main/java/com/me/yokeyword/fragmentation/SupportFragment.java 0 → 100644
  1 +package com.me.yokeyword.fragmentation;
  2 +
  3 +import android.app.Activity;
  4 +import android.content.Intent;
  5 +import android.os.Bundle;
  6 +import android.view.View;
  7 +import android.view.animation.Animation;
  8 +
  9 +import androidx.annotation.Nullable;
  10 +import androidx.fragment.app.Fragment;
  11 +
  12 +import com.me.yokeyword.fragmentation.anim.FragmentAnimator;
  13 +
  14 +
  15 +/**
  16 + * Base class for activities that use the support-based
  17 + * {@link ISupportFragment} and
  18 + * {@link Fragment} APIs.
  19 + * Created by YoKey on 17/6/22.
  20 + */
  21 +public class SupportFragment extends Fragment implements ISupportFragment {
  22 + final SupportFragmentDelegate mDelegate = new SupportFragmentDelegate(this);
  23 + protected SupportActivity _mActivity;
  24 +
  25 + @Override
  26 + public SupportFragmentDelegate getSupportDelegate() {
  27 + return mDelegate;
  28 + }
  29 +
  30 + /**
  31 + * Perform some extra transactions.
  32 + * 额外的事务:自定义Tag,添加SharedElement动画,操作非回退栈Fragment
  33 + */
  34 + @Override
  35 + public ExtraTransaction extraTransaction() {
  36 + return mDelegate.extraTransaction();
  37 + }
  38 +
  39 + @Override
  40 + public void onAttach(Activity activity) {
  41 + super.onAttach(activity);
  42 + mDelegate.onAttach(activity);
  43 + _mActivity = (SupportActivity) mDelegate.getActivity();
  44 + }
  45 +
  46 + @Override
  47 + public void onCreate(@Nullable Bundle savedInstanceState) {
  48 + super.onCreate(savedInstanceState);
  49 + mDelegate.onCreate(savedInstanceState);
  50 + }
  51 +
  52 + @Override
  53 + public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
  54 + return mDelegate.onCreateAnimation(transit, enter, nextAnim);
  55 + }
  56 +
  57 + @Override
  58 + public void onActivityCreated(@Nullable Bundle savedInstanceState) {
  59 + super.onActivityCreated(savedInstanceState);
  60 + mDelegate.onActivityCreated(savedInstanceState);
  61 + }
  62 +
  63 + @Override
  64 + public void onSaveInstanceState(Bundle outState) {
  65 + super.onSaveInstanceState(outState);
  66 + mDelegate.onSaveInstanceState(outState);
  67 + }
  68 +
  69 + @Override
  70 + public void onResume() {
  71 + super.onResume();
  72 + mDelegate.onResume();
  73 + }
  74 +
  75 + @Override
  76 + public void onPause() {
  77 + super.onPause();
  78 + mDelegate.onPause();
  79 + }
  80 +
  81 + @Override
  82 + public void onDestroyView() {
  83 + mDelegate.onDestroyView();
  84 + super.onDestroyView();
  85 + }
  86 +
  87 + @Override
  88 + public void onDestroy() {
  89 + mDelegate.onDestroy();
  90 + super.onDestroy();
  91 + }
  92 +
  93 + @Override
  94 + public void onHiddenChanged(boolean hidden) {
  95 + super.onHiddenChanged(hidden);
  96 + mDelegate.onHiddenChanged(hidden);
  97 + }
  98 +
  99 + @Override
  100 + public void setUserVisibleHint(boolean isVisibleToUser) {
  101 + super.setUserVisibleHint(isVisibleToUser);
  102 + mDelegate.setUserVisibleHint(isVisibleToUser);
  103 + }
  104 +
  105 + /**
  106 + * Causes the Runnable r to be added to the action queue.
  107 + * <p>
  108 + * The runnable will be run after all the previous action has been run.
  109 + * <p>
  110 + * 前面的事务全部执行后 执行该Action
  111 + *
  112 + * @deprecated Use {@link #post(Runnable)} instead.
  113 + */
  114 + @Deprecated
  115 + @Override
  116 + public void enqueueAction(Runnable runnable) {
  117 + mDelegate.enqueueAction(runnable);
  118 + }
  119 +
  120 + /**
  121 + * Causes the Runnable r to be added to the action queue.
  122 + * <p>
  123 + * The runnable will be run after all the previous action has been run.
  124 + * <p>
  125 + * 前面的事务全部执行后 执行该Action
  126 + */
  127 + @Override
  128 + public void post(Runnable runnable) {
  129 + mDelegate.post(runnable);
  130 + }
  131 +
  132 + /**
  133 + * Called when the enter-animation end.
  134 + * 入栈动画 结束时,回调
  135 + */
  136 + @Override
  137 + public void onEnterAnimationEnd(Bundle savedInstanceState) {
  138 + mDelegate.onEnterAnimationEnd(savedInstanceState);
  139 + }
  140 +
  141 +
  142 + /**
  143 + * Lazy initial,Called when fragment is first called.
  144 + * <p>
  145 + * 同级下的 懒加载 + ViewPager下的懒加载 的结合回调方法
  146 + */
  147 + @Override
  148 + public void onLazyInitView(@Nullable Bundle savedInstanceState) {
  149 + mDelegate.onLazyInitView(savedInstanceState);
  150 + }
  151 +
  152 + /**
  153 + * Called when the fragment is visible.
  154 + * 当Fragment对用户可见时回调
  155 + * <p>
  156 + * Is the combination of [onHiddenChanged() + onResume()/onPause() + setUserVisibleHint()]
  157 + */
  158 + @Override
  159 + public void onSupportVisible() {
  160 + mDelegate.onSupportVisible();
  161 + }
  162 +
  163 + /**
  164 + * Called when the fragment is invivible.
  165 + * <p>
  166 + * Is the combination of [onHiddenChanged() + onResume()/onPause() + setUserVisibleHint()]
  167 + */
  168 + @Override
  169 + public void onSupportInvisible() {
  170 + mDelegate.onSupportInvisible();
  171 + }
  172 +
  173 + /**
  174 + * Return true if the fragment has been supportVisible.
  175 + */
  176 + @Override
  177 + final public boolean isSupportVisible() {
  178 + return mDelegate.isSupportVisible();
  179 + }
  180 +
  181 + /**
  182 + * Set fragment animation with a higher priority than the ISupportActivity
  183 + * 设定当前Fragmemt动画,优先级比在SupportActivity里高
  184 + */
  185 + @Override
  186 + public FragmentAnimator onCreateFragmentAnimator() {
  187 + return mDelegate.onCreateFragmentAnimator();
  188 + }
  189 +
  190 + /**
  191 + * 获取设置的全局动画 copy
  192 + *
  193 + * @return FragmentAnimator
  194 + */
  195 + @Override
  196 + public FragmentAnimator getFragmentAnimator() {
  197 + return mDelegate.getFragmentAnimator();
  198 + }
  199 +
  200 + /**
  201 + * 设置Fragment内的全局动画
  202 + */
  203 + @Override
  204 + public void setFragmentAnimator(FragmentAnimator fragmentAnimator) {
  205 + mDelegate.setFragmentAnimator(fragmentAnimator);
  206 + }
  207 +
  208 + /**
  209 + * 按返回键触发,前提是SupportActivity的onBackPressed()方法能被调用
  210 + *
  211 + * @return false则继续向上传递, true则消费掉该事件
  212 + */
  213 + @Override
  214 + public boolean onBackPressedSupport() {
  215 + return mDelegate.onBackPressedSupport();
  216 + }
  217 +
  218 + /**
  219 + * 类似 {@link Activity#setResult(int, Intent)}
  220 + * <p>
  221 + * Similar to {@link Activity#setResult(int, Intent)}
  222 + *
  223 + * @see #startForResult(ISupportFragment, int)
  224 + */
  225 + @Override
  226 + public void setFragmentResult(int resultCode, Bundle bundle) {
  227 + mDelegate.setFragmentResult(resultCode, bundle);
  228 + }
  229 +
  230 + /**
  231 + * 类似 {@link Activity#onActivityResult(int, int, Intent)}
  232 + * <p>
  233 + * Similar to {@link Activity#onActivityResult(int, int, Intent)}
  234 + *
  235 + * @see #startForResult(ISupportFragment, int)
  236 + */
  237 + @Override
  238 + public void onFragmentResult(int requestCode, int resultCode, Bundle data) {
  239 + mDelegate.onFragmentResult(requestCode, resultCode, data);
  240 + }
  241 +
  242 + /**
  243 + * 在start(TargetFragment,LaunchMode)时,启动模式为SingleTask/SingleTop, 回调TargetFragment的该方法
  244 + * 类似 {@link Activity#onNewIntent(Intent)}
  245 + * <p>
  246 + * Similar to {@link Activity#onNewIntent(Intent)}
  247 + *
  248 + * @param args putNewBundle(Bundle newBundle)
  249 + * @see #start(ISupportFragment, int)
  250 + */
  251 + @Override
  252 + public void onNewBundle(Bundle args) {
  253 + mDelegate.onNewBundle(args);
  254 + }
  255 +
  256 + /**
  257 + * 添加NewBundle,用于启动模式为SingleTask/SingleTop时
  258 + *
  259 + * @see #start(ISupportFragment, int)
  260 + */
  261 + @Override
  262 + public void putNewBundle(Bundle newBundle) {
  263 + mDelegate.putNewBundle(newBundle);
  264 + }
  265 +
  266 +
  267 + /****************************************以下为可选方法(Optional methods)******************************************************/
  268 +
  269 + /**
  270 + * 隐藏软键盘
  271 + */
  272 + protected void hideSoftInput() {
  273 + mDelegate.hideSoftInput();
  274 + }
  275 +
  276 + /**
  277 + * 显示软键盘,调用该方法后,会在onPause时自动隐藏软键盘
  278 + */
  279 + protected void showSoftInput(final View view) {
  280 + mDelegate.showSoftInput(view);
  281 + }
  282 +
  283 + /**
  284 + * 加载根Fragment, 即Activity内的第一个Fragment 或 Fragment内的第一个子Fragment
  285 + *
  286 + * @param containerId 容器id
  287 + * @param toFragment 目标Fragment
  288 + */
  289 + public void loadRootFragment(int containerId, ISupportFragment toFragment) {
  290 + mDelegate.loadRootFragment(containerId, toFragment);
  291 + }
  292 +
  293 + public void loadRootFragment(int containerId, ISupportFragment toFragment, boolean addToBackStack, boolean allowAnim) {
  294 + mDelegate.loadRootFragment(containerId, toFragment, addToBackStack, allowAnim);
  295 + }
  296 +
  297 + /**
  298 + * 加载多个同级根Fragment,类似Wechat, QQ主页的场景
  299 + */
  300 + public void loadMultipleRootFragment(int containerId, int showPosition, ISupportFragment... toFragments) {
  301 + mDelegate.loadMultipleRootFragment(containerId, showPosition, toFragments);
  302 + }
  303 +
  304 + /**
  305 + * show一个Fragment,hide其他同栈所有Fragment
  306 + * 使用该方法时,要确保同级栈内无多余的Fragment,(只有通过loadMultipleRootFragment()载入的Fragment)
  307 + * <p>
  308 + * 建议使用更明确的{@link #showHideFragment(ISupportFragment, ISupportFragment)}
  309 + *
  310 + * @param showFragment 需要show的Fragment
  311 + */
  312 + public void showHideFragment(ISupportFragment showFragment) {
  313 + mDelegate.showHideFragment(showFragment);
  314 + }
  315 +
  316 + /**
  317 + * show一个Fragment,hide一个Fragment ; 主要用于类似微信主页那种 切换tab的情况
  318 + */
  319 + public void showHideFragment(ISupportFragment showFragment, ISupportFragment hideFragment) {
  320 + mDelegate.showHideFragment(showFragment, hideFragment);
  321 + }
  322 +
  323 + public void start(ISupportFragment toFragment) {
  324 + mDelegate.start(toFragment);
  325 + }
  326 +
  327 + /**
  328 + * @param launchMode Similar to Activity's LaunchMode.
  329 + */
  330 + public void start(final ISupportFragment toFragment, @LaunchMode int launchMode) {
  331 + mDelegate.start(toFragment, launchMode);
  332 + }
  333 +
  334 + /**
  335 + * Launch an fragment for which you would like a result when it poped.
  336 + */
  337 + public void startForResult(ISupportFragment toFragment, int requestCode) {
  338 + mDelegate.startForResult(toFragment, requestCode);
  339 + }
  340 +
  341 + /**
  342 + * Start the target Fragment and pop itself
  343 + */
  344 + public void startWithPop(ISupportFragment toFragment) {
  345 + mDelegate.startWithPop(toFragment);
  346 + }
  347 +
  348 + /**
  349 + * @see #popTo(Class, boolean)
  350 + * +
  351 + * @see #start(ISupportFragment)
  352 + */
  353 + public void startWithPopTo(ISupportFragment toFragment, Class<?> targetFragmentClass, boolean includeTargetFragment) {
  354 + mDelegate.startWithPopTo(toFragment, targetFragmentClass, includeTargetFragment);
  355 + }
  356 +
  357 +
  358 + public void replaceFragment(ISupportFragment toFragment, boolean addToBackStack) {
  359 + mDelegate.replaceFragment(toFragment, addToBackStack);
  360 + }
  361 +
  362 + public void pop() {
  363 + mDelegate.pop();
  364 + }
  365 +
  366 + /**
  367 + * Pop the child fragment.
  368 + */
  369 + public void popChild() {
  370 + mDelegate.popChild();
  371 + }
  372 +
  373 + /**
  374 + * Pop the last fragment transition from the manager's fragment
  375 + * back stack.
  376 + * <p>
  377 + * 出栈到目标fragment
  378 + *
  379 + * @param targetFragmentClass 目标fragment
  380 + * @param includeTargetFragment 是否包含该fragment
  381 + */
  382 + public void popTo(Class<?> targetFragmentClass, boolean includeTargetFragment) {
  383 + mDelegate.popTo(targetFragmentClass, includeTargetFragment);
  384 + }
  385 +
  386 + /**
  387 + * If you want to begin another FragmentTransaction immediately after popTo(), use this method.
  388 + * 如果你想在出栈后, 立刻进行FragmentTransaction操作,请使用该方法
  389 + */
  390 + public void popTo(Class<?> targetFragmentClass, boolean includeTargetFragment, Runnable afterPopTransactionRunnable) {
  391 + mDelegate.popTo(targetFragmentClass, includeTargetFragment, afterPopTransactionRunnable);
  392 + }
  393 +
  394 + public void popTo(Class<?> targetFragmentClass, boolean includeTargetFragment, Runnable afterPopTransactionRunnable, int popAnim) {
  395 + mDelegate.popTo(targetFragmentClass, includeTargetFragment, afterPopTransactionRunnable, popAnim);
  396 + }
  397 +
  398 + public void popToChild(Class<?> targetFragmentClass, boolean includeTargetFragment) {
  399 + mDelegate.popToChild(targetFragmentClass, includeTargetFragment);
  400 + }
  401 +
  402 + public void popToChild(Class<?> targetFragmentClass, boolean includeTargetFragment, Runnable afterPopTransactionRunnable) {
  403 + mDelegate.popToChild(targetFragmentClass, includeTargetFragment, afterPopTransactionRunnable);
  404 + }
  405 +
  406 + public void popToChild(Class<?> targetFragmentClass, boolean includeTargetFragment, Runnable afterPopTransactionRunnable, int popAnim) {
  407 + mDelegate.popToChild(targetFragmentClass, includeTargetFragment, afterPopTransactionRunnable, popAnim);
  408 + }
  409 +
  410 + /**
  411 + * 得到位于栈顶Fragment
  412 + */
  413 + public ISupportFragment getTopFragment() {
  414 + return SupportHelper.getTopFragment(getFragmentManager());
  415 + }
  416 +
  417 + public ISupportFragment getTopChildFragment() {
  418 + return SupportHelper.getTopFragment(getChildFragmentManager());
  419 + }
  420 +
  421 + /**
  422 + * @return 位于当前Fragment的前一个Fragment
  423 + */
  424 + public ISupportFragment getPreFragment() {
  425 + return SupportHelper.getPreFragment(this);
  426 + }
  427 +
  428 + /**
  429 + * 获取栈内的fragment对象
  430 + */
  431 + public <T extends ISupportFragment> T findFragment(Class<T> fragmentClass) {
  432 + return SupportHelper.findFragment(getFragmentManager(), fragmentClass);
  433 + }
  434 +
  435 + /**
  436 + * 获取栈内的fragment对象
  437 + */
  438 + public <T extends ISupportFragment> T findChildFragment(Class<T> fragmentClass) {
  439 + return SupportHelper.findFragment(getChildFragmentManager(), fragmentClass);
  440 + }
  441 +}
core/base/src/main/java/com/me/yokeyword/fragmentation/SupportFragmentDelegate.java 0 → 100644
  1 +package com.me.yokeyword.fragmentation;
  2 +
  3 +import android.app.Activity;
  4 +import android.content.Intent;
  5 +import android.content.res.TypedArray;
  6 +import android.os.Bundle;
  7 +import android.os.Handler;
  8 +import android.os.Looper;
  9 +import android.view.View;
  10 +import android.view.animation.Animation;
  11 +import android.view.animation.AnimationUtils;
  12 +
  13 +import androidx.annotation.Nullable;
  14 +import androidx.fragment.app.Fragment;
  15 +import androidx.fragment.app.FragmentActivity;
  16 +import androidx.fragment.app.FragmentManager;
  17 +import androidx.fragment.app.FragmentTransaction;
  18 +
  19 +import com.me.yokeyword.fragmentation.anim.FragmentAnimator;
  20 +import com.me.yokeyword.fragmentation.helper.internal.AnimatorHelper;
  21 +import com.me.yokeyword.fragmentation.helper.internal.ResultRecord;
  22 +import com.me.yokeyword.fragmentation.helper.internal.TransactionRecord;
  23 +import com.me.yokeyword.fragmentation.helper.internal.VisibleDelegate;
  24 +
  25 +
  26 +public class SupportFragmentDelegate {
  27 + private static final long NOT_FOUND_ANIM_TIME = 300L;
  28 +
  29 + static final int STATUS_UN_ROOT = 0;
  30 + static final int STATUS_ROOT_ANIM_DISABLE = 1;
  31 + static final int STATUS_ROOT_ANIM_ENABLE = 2;
  32 +
  33 + private int mRootStatus = STATUS_UN_ROOT;
  34 +
  35 + private boolean mIsSharedElement;
  36 + FragmentAnimator mFragmentAnimator;
  37 + AnimatorHelper mAnimHelper;
  38 + boolean mLockAnim;
  39 + private int mCustomEnterAnim = Integer.MIN_VALUE, mCustomExitAnim = Integer.MIN_VALUE, mCustomPopExitAnim = Integer.MIN_VALUE;
  40 +
  41 + private Handler mHandler;
  42 + private boolean mFirstCreateView = true;
  43 + private boolean mReplaceMode;
  44 + private boolean mIsHidden = true;
  45 + int mContainerId;
  46 +
  47 + private TransactionDelegate mTransactionDelegate;
  48 + TransactionRecord mTransactionRecord;
  49 + // SupportVisible
  50 + private VisibleDelegate mVisibleDelegate;
  51 + Bundle mNewBundle;
  52 + private Bundle mSaveInstanceState;
  53 +
  54 + private ISupportFragment mSupportF;
  55 + private Fragment mFragment;
  56 + protected FragmentActivity _mActivity;
  57 + private ISupportActivity mSupport;
  58 + boolean mAnimByActivity = true;
  59 + EnterAnimListener mEnterAnimListener;
  60 +
  61 + private boolean mRootViewClickable;
  62 +
  63 + public SupportFragmentDelegate(ISupportFragment support) {
  64 + if (!(support instanceof Fragment))
  65 + throw new RuntimeException("Must extends Fragment");
  66 + this.mSupportF = support;
  67 + this.mFragment = (Fragment) support;
  68 + }
  69 +
  70 + /**
  71 + * Perform some extra transactions.
  72 + * 额外的事务:自定义Tag,添加SharedElement动画,操作非回退栈Fragment
  73 + */
  74 + public ExtraTransaction extraTransaction() {
  75 + if (mTransactionDelegate == null)
  76 + throw new RuntimeException(mFragment.getClass().getSimpleName() + " not attach!");
  77 +
  78 + return new ExtraTransaction.ExtraTransactionImpl<>((FragmentActivity) mSupport, mSupportF, mTransactionDelegate, false);
  79 + }
  80 +
  81 + public void onAttach(Activity activity) {
  82 + if (activity instanceof ISupportActivity) {
  83 + this.mSupport = (ISupportActivity) activity;
  84 + this._mActivity = (FragmentActivity) activity;
  85 + mTransactionDelegate = mSupport.getSupportDelegate().getTransactionDelegate();
  86 + } else {
  87 + throw new RuntimeException(activity.getClass().getSimpleName() + " must impl ISupportActivity!");
  88 + }
  89 + }
  90 +
  91 + public void onCreate(@Nullable Bundle savedInstanceState) {
  92 + getVisibleDelegate().onCreate(savedInstanceState);
  93 +
  94 + Bundle bundle = mFragment.getArguments();
  95 + if (bundle != null) {
  96 + mRootStatus = bundle.getInt(TransactionDelegate.FRAGMENTATION_ARG_ROOT_STATUS, STATUS_UN_ROOT);
  97 + mIsSharedElement = bundle.getBoolean(TransactionDelegate.FRAGMENTATION_ARG_IS_SHARED_ELEMENT, false);
  98 + mContainerId = bundle.getInt(TransactionDelegate.FRAGMENTATION_ARG_CONTAINER);
  99 + mReplaceMode = bundle.getBoolean(TransactionDelegate.FRAGMENTATION_ARG_REPLACE, false);
  100 + mCustomEnterAnim = bundle.getInt(TransactionDelegate.FRAGMENTATION_ARG_CUSTOM_ENTER_ANIM, Integer.MIN_VALUE);
  101 + mCustomExitAnim = bundle.getInt(TransactionDelegate.FRAGMENTATION_ARG_CUSTOM_EXIT_ANIM, Integer.MIN_VALUE);
  102 + mCustomPopExitAnim = bundle.getInt(TransactionDelegate.FRAGMENTATION_ARG_CUSTOM_POP_EXIT_ANIM, Integer.MIN_VALUE);
  103 + }
  104 +
  105 + if (savedInstanceState == null) {
  106 + getFragmentAnimator();
  107 + } else {
  108 + savedInstanceState.setClassLoader(getClass().getClassLoader());
  109 + mSaveInstanceState = savedInstanceState;
  110 + mFragmentAnimator = savedInstanceState.getParcelable(TransactionDelegate.FRAGMENTATION_STATE_SAVE_ANIMATOR);
  111 + mIsHidden = savedInstanceState.getBoolean(TransactionDelegate.FRAGMENTATION_STATE_SAVE_IS_HIDDEN);
  112 + mContainerId = savedInstanceState.getInt(TransactionDelegate.FRAGMENTATION_ARG_CONTAINER);
  113 + }
  114 +
  115 + mAnimHelper = new AnimatorHelper(_mActivity.getApplicationContext(), mFragmentAnimator);
  116 +
  117 + final Animation enter = getEnterAnim();
  118 + if (enter == null) return;
  119 +
  120 + getEnterAnim().setAnimationListener(new Animation.AnimationListener() {
  121 +
  122 + @Override
  123 + public void onAnimationStart(Animation animation) {
  124 + mSupport.getSupportDelegate().mFragmentClickable = false; // 开启防抖动
  125 +
  126 + mHandler.postDelayed(new Runnable() {
  127 + @Override
  128 + public void run() {
  129 + mSupport.getSupportDelegate().mFragmentClickable = true;
  130 + }
  131 + }, enter.getDuration());
  132 + }
  133 +
  134 + @Override
  135 + public void onAnimationEnd(Animation animation) {
  136 + }
  137 +
  138 + @Override
  139 + public void onAnimationRepeat(Animation animation) {
  140 +
  141 + }
  142 + });
  143 + }
  144 +
  145 + public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
  146 + if ((mSupport.getSupportDelegate().mPopMultipleNoAnim || mLockAnim)) {
  147 + if (transit == FragmentTransaction.TRANSIT_FRAGMENT_CLOSE && enter) {
  148 + return mAnimHelper.getNoneAnimFixed();
  149 + }
  150 + return mAnimHelper.getNoneAnim();
  151 + }
  152 + if (transit == FragmentTransaction.TRANSIT_FRAGMENT_OPEN) {
  153 + if (enter) {
  154 + Animation enterAnim;
  155 + if (mRootStatus == STATUS_ROOT_ANIM_DISABLE) {
  156 + enterAnim = mAnimHelper.getNoneAnim();
  157 + } else {
  158 + enterAnim = mAnimHelper.enterAnim;
  159 + fixAnimationListener(enterAnim);
  160 + }
  161 + return enterAnim;
  162 + } else {
  163 + return mAnimHelper.popExitAnim;
  164 + }
  165 + } else if (transit == FragmentTransaction.TRANSIT_FRAGMENT_CLOSE) {
  166 + return enter ? mAnimHelper.popEnterAnim : mAnimHelper.exitAnim;
  167 + } else {
  168 + if (mIsSharedElement && enter) {
  169 + compatSharedElements();
  170 + }
  171 +
  172 + if (!enter) {
  173 + return mAnimHelper.compatChildFragmentExitAnim(mFragment);
  174 + }
  175 +
  176 + return null;
  177 + }
  178 + }
  179 +
  180 + public void onSaveInstanceState(Bundle outState) {
  181 + getVisibleDelegate().onSaveInstanceState(outState);
  182 + outState.putParcelable(TransactionDelegate.FRAGMENTATION_STATE_SAVE_ANIMATOR, mFragmentAnimator);
  183 + outState.putBoolean(TransactionDelegate.FRAGMENTATION_STATE_SAVE_IS_HIDDEN, mFragment.isHidden());
  184 + outState.putInt(TransactionDelegate.FRAGMENTATION_ARG_CONTAINER, mContainerId);
  185 + }
  186 +
  187 + public void onActivityCreated(@Nullable Bundle savedInstanceState) {
  188 + getVisibleDelegate().onActivityCreated(savedInstanceState);
  189 +
  190 + View view = mFragment.getView();
  191 + if (view != null) {
  192 + mRootViewClickable = view.isClickable();
  193 + view.setClickable(true);
  194 + setBackground(view);
  195 + }
  196 +
  197 +
  198 + if (savedInstanceState != null
  199 + || mRootStatus == STATUS_ROOT_ANIM_DISABLE
  200 + || (mFragment.getTag() != null && mFragment.getTag().startsWith("android:switcher:"))
  201 + || (mReplaceMode && !mFirstCreateView)) {
  202 + notifyEnterAnimEnd();
  203 + } else if (mCustomEnterAnim != Integer.MIN_VALUE) {
  204 + fixAnimationListener(mCustomEnterAnim == 0 ?
  205 + mAnimHelper.getNoneAnim() : AnimationUtils.loadAnimation(_mActivity, mCustomEnterAnim));
  206 + }
  207 +
  208 + if (mFirstCreateView) {
  209 + mFirstCreateView = false;
  210 + }
  211 + }
  212 +
  213 + public void onResume() {
  214 + getVisibleDelegate().onResume();
  215 + }
  216 +
  217 + public void onPause() {
  218 + getVisibleDelegate().onPause();
  219 + }
  220 +
  221 + public void onDestroyView() {
  222 + mSupport.getSupportDelegate().mFragmentClickable = true;
  223 + getVisibleDelegate().onDestroyView();
  224 + getHandler().removeCallbacks(mNotifyEnterAnimEndRunnable);
  225 + }
  226 +
  227 + public void onDestroy() {
  228 + mTransactionDelegate.handleResultRecord(mFragment);
  229 + }
  230 +
  231 + public void onHiddenChanged(boolean hidden) {
  232 + getVisibleDelegate().onHiddenChanged(hidden);
  233 + }
  234 +
  235 + public void setUserVisibleHint(boolean isVisibleToUser) {
  236 + getVisibleDelegate().setUserVisibleHint(isVisibleToUser);
  237 + }
  238 +
  239 + /**
  240 + * Causes the Runnable r to be added to the action queue.
  241 + * <p>
  242 + * The runnable will be run after all the previous action has been run.
  243 + * <p>
  244 + * 前面的事务全部执行后 执行该Action
  245 + *
  246 + * @deprecated Use {@link #post(Runnable)} instead.
  247 + */
  248 + @Deprecated
  249 + public void enqueueAction(Runnable runnable) {
  250 + post(runnable);
  251 + }
  252 +
  253 + /**
  254 + * Causes the Runnable r to be added to the action queue.
  255 + * <p>
  256 + * The runnable will be run after all the previous action has been run.
  257 + * <p>
  258 + * 前面的事务全部执行后 执行该Action
  259 + */
  260 + public void post(final Runnable runnable) {
  261 + mTransactionDelegate.post(runnable);
  262 + }
  263 +
  264 + /**
  265 + * Called when the enter-animation end.
  266 + * 入栈动画 结束时,回调
  267 + */
  268 + public void onEnterAnimationEnd(Bundle savedInstanceState) {
  269 + }
  270 +
  271 + /**
  272 + * Lazy initial,Called when fragment is first visible.
  273 + * <p>
  274 + * 同级下的 懒加载 + ViewPager下的懒加载 的结合回调方法
  275 + */
  276 + public void onLazyInitView(@Nullable Bundle savedInstanceState) {
  277 + }
  278 +
  279 + /**
  280 + * Called when the fragment is visible.
  281 + * <p>
  282 + * 当Fragment对用户可见时回调
  283 + * <p>
  284 + * Is the combination of [onHiddenChanged() + onResume()/onPause() + setUserVisibleHint()]
  285 + */
  286 + public void onSupportVisible() {
  287 + }
  288 +
  289 + /**
  290 + * Called when the fragment is invivible.
  291 + * <p>
  292 + * Is the combination of [onHiddenChanged() + onResume()/onPause() + setUserVisibleHint()]
  293 + */
  294 + public void onSupportInvisible() {
  295 + }
  296 +
  297 + /**
  298 + * Return true if the fragment has been supportVisible.
  299 + */
  300 + final public boolean isSupportVisible() {
  301 + return getVisibleDelegate().isSupportVisible();
  302 + }
  303 +
  304 + /**
  305 + * Set fragment animation with a higher priority than the ISupportActivity
  306 + * 设定当前Fragmemt动画,优先级比在ISupportActivity里高
  307 + */
  308 + public FragmentAnimator onCreateFragmentAnimator() {
  309 + return mSupport.getFragmentAnimator();
  310 + }
  311 +
  312 + /**
  313 + * 获取设置的全局动画
  314 + *
  315 + * @return FragmentAnimator
  316 + */
  317 + public FragmentAnimator getFragmentAnimator() {
  318 + if (mSupport == null)
  319 + throw new RuntimeException("Fragment has not been attached to Activity!");
  320 +
  321 + if (mFragmentAnimator == null) {
  322 + mFragmentAnimator = mSupportF.onCreateFragmentAnimator();
  323 + if (mFragmentAnimator == null) {
  324 + mFragmentAnimator = mSupport.getFragmentAnimator();
  325 + }
  326 + }
  327 + return mFragmentAnimator;
  328 + }
  329 +
  330 + /**
  331 + * Set the fragment animation.
  332 + */
  333 + public void setFragmentAnimator(FragmentAnimator fragmentAnimator) {
  334 + this.mFragmentAnimator = fragmentAnimator;
  335 + if (mAnimHelper != null) {
  336 + mAnimHelper.notifyChanged(fragmentAnimator);
  337 + }
  338 + mAnimByActivity = false;
  339 + }
  340 +
  341 + /**
  342 + * 类似 {@link Activity#setResult(int, Intent)}
  343 + * <p>
  344 + * Similar to {@link Activity#setResult(int, Intent)}
  345 + *
  346 + * @see #startForResult(ISupportFragment, int)
  347 + */
  348 + public void setFragmentResult(int resultCode, Bundle bundle) {
  349 + Bundle args = mFragment.getArguments();
  350 + if (args == null || !args.containsKey(TransactionDelegate.FRAGMENTATION_ARG_RESULT_RECORD)) {
  351 + return;
  352 + }
  353 +
  354 + ResultRecord resultRecord = args.getParcelable(TransactionDelegate.FRAGMENTATION_ARG_RESULT_RECORD);
  355 + if (resultRecord != null) {
  356 + resultRecord.resultCode = resultCode;
  357 + resultRecord.resultBundle = bundle;
  358 + }
  359 + }
  360 +
  361 + /**
  362 + * 类似 {@link Activity#onActivityResult(int, int, Intent)}
  363 + * <p>
  364 + * Similar to {@link Activity#onActivityResult(int, int, Intent)}
  365 + *
  366 + * @see #startForResult(ISupportFragment, int)
  367 + */
  368 + public void onFragmentResult(int requestCode, int resultCode, Bundle data) {
  369 + }
  370 +
  371 + /**
  372 + * 在start(TargetFragment,LaunchMode)时,启动模式为SingleTask/SingleTop, 回调TargetFragment的该方法
  373 + * 类似 {@link Activity#onNewIntent(Intent)}
  374 + * <p>
  375 + * Similar to {@link Activity#onNewIntent(Intent)}
  376 + *
  377 + * @param args putNewBundle(Bundle newBundle)
  378 + * @see #start(ISupportFragment, int)
  379 + */
  380 + public void onNewBundle(Bundle args) {
  381 + }
  382 +
  383 + /**
  384 + * 添加NewBundle,用于启动模式为SingleTask/SingleTop时
  385 + *
  386 + * @see #start(ISupportFragment, int)
  387 + */
  388 + public void putNewBundle(Bundle newBundle) {
  389 + this.mNewBundle = newBundle;
  390 + }
  391 +
  392 + /**
  393 + * Back Event
  394 + *
  395 + * @return false则继续向上传递, true则消费掉该事件
  396 + */
  397 + public boolean onBackPressedSupport() {
  398 + return false;
  399 + }
  400 +
  401 + /**********************************************************************************************/
  402 +
  403 + /**
  404 + * 隐藏软键盘
  405 + */
  406 + public void hideSoftInput() {
  407 + Activity activity = mFragment.getActivity();
  408 + if (activity == null) return;
  409 + View view = activity.getWindow().getDecorView();
  410 + SupportHelper.hideSoftInput(view);
  411 + }
  412 +
  413 + /**
  414 + * 显示软键盘,调用该方法后,会在onPause时自动隐藏软键盘
  415 + */
  416 + public void showSoftInput(View view) {
  417 + SupportHelper.showSoftInput(view);
  418 + }
  419 +
  420 +
  421 + /**
  422 + * 加载根Fragment, 即Activity内的第一个Fragment 或 Fragment内的第一个子Fragment
  423 + */
  424 + public void loadRootFragment(int containerId, ISupportFragment toFragment) {
  425 + loadRootFragment(containerId, toFragment, true, false);
  426 + }
  427 +
  428 + public void loadRootFragment(int containerId, ISupportFragment toFragment, boolean addToBackStack, boolean allowAnim) {
  429 + mTransactionDelegate.loadRootTransaction(getChildFragmentManager(), containerId, toFragment, addToBackStack, allowAnim);
  430 + }
  431 +
  432 + /**
  433 + * 加载多个同级根Fragment,类似Wechat, QQ主页的场景
  434 + */
  435 + public void loadMultipleRootFragment(int containerId, int showPosition, ISupportFragment... toFragments) {
  436 + mTransactionDelegate.loadMultipleRootTransaction(getChildFragmentManager(), containerId, showPosition, toFragments);
  437 + }
  438 +
  439 + /**
  440 + * show一个Fragment,hide其他同栈所有Fragment
  441 + * 使用该方法时,要确保同级栈内无多余的Fragment,(只有通过loadMultipleRootFragment()载入的Fragment)
  442 + * <p>
  443 + * 建议使用更明确的{@link #showHideFragment(ISupportFragment, ISupportFragment)}
  444 + */
  445 + public void showHideFragment(ISupportFragment showFragment) {
  446 + showHideFragment(showFragment, null);
  447 + }
  448 +
  449 + /**
  450 + * show一个Fragment,hide一个Fragment ; 主要用于类似微信主页那种 切换tab的情况
  451 + */
  452 + public void showHideFragment(ISupportFragment showFragment, ISupportFragment hideFragment) {
  453 + mTransactionDelegate.showHideFragment(getChildFragmentManager(), showFragment, hideFragment);
  454 + }
  455 +
  456 + public void start(ISupportFragment toFragment) {
  457 + start(toFragment, ISupportFragment.STANDARD);
  458 + }
  459 +
  460 + /**
  461 + * @param launchMode Similar to Activity's LaunchMode.
  462 + */
  463 + public void start(final ISupportFragment toFragment, @ISupportFragment.LaunchMode int launchMode) {
  464 + mTransactionDelegate.dispatchStartTransaction(mFragment.getFragmentManager(), mSupportF, toFragment, 0, launchMode, TransactionDelegate.TYPE_ADD);
  465 + }
  466 +
  467 + /**
  468 + * Launch an fragment for which you would like a result when it poped.
  469 + */
  470 + public void startForResult(ISupportFragment toFragment, int requestCode) {
  471 + mTransactionDelegate.dispatchStartTransaction(mFragment.getFragmentManager(), mSupportF, toFragment, requestCode, ISupportFragment.STANDARD, TransactionDelegate.TYPE_ADD_RESULT);
  472 + }
  473 +
  474 + /**
  475 + * Start the target Fragment and pop itself
  476 + */
  477 + public void startWithPop(ISupportFragment toFragment) {
  478 + mTransactionDelegate.startWithPop(mFragment.getFragmentManager(), mSupportF, toFragment);
  479 + }
  480 +
  481 + public void startWithPopTo(ISupportFragment toFragment, Class<?> targetFragmentClass, boolean includeTargetFragment) {
  482 + mTransactionDelegate.startWithPopTo(mFragment.getFragmentManager(), mSupportF, toFragment, targetFragmentClass.getName(), includeTargetFragment);
  483 + }
  484 +
  485 + public void replaceFragment(ISupportFragment toFragment, boolean addToBackStack) {
  486 + mTransactionDelegate.dispatchStartTransaction(mFragment.getFragmentManager(), mSupportF, toFragment, 0, ISupportFragment.STANDARD, addToBackStack ? TransactionDelegate.TYPE_REPLACE : TransactionDelegate.TYPE_REPLACE_DONT_BACK);
  487 + }
  488 +
  489 + public void startChild(ISupportFragment toFragment) {
  490 + startChild(toFragment, ISupportFragment.STANDARD);
  491 + }
  492 +
  493 + public void startChild(final ISupportFragment toFragment, @ISupportFragment.LaunchMode int launchMode) {
  494 + mTransactionDelegate.dispatchStartTransaction(getChildFragmentManager(), getTopFragment(), toFragment, 0, launchMode, TransactionDelegate.TYPE_ADD);
  495 + }
  496 +
  497 + public void startChildForResult(ISupportFragment toFragment, int requestCode) {
  498 + mTransactionDelegate.dispatchStartTransaction(getChildFragmentManager(), getTopFragment(), toFragment, requestCode, ISupportFragment.STANDARD, TransactionDelegate.TYPE_ADD_RESULT);
  499 + }
  500 +
  501 + public void startChildWithPop(ISupportFragment toFragment) {
  502 + mTransactionDelegate.startWithPop(getChildFragmentManager(), getTopFragment(), toFragment);
  503 + }
  504 +
  505 + public void replaceChildFragment(ISupportFragment toFragment, boolean addToBackStack) {
  506 + mTransactionDelegate.dispatchStartTransaction(getChildFragmentManager(), getTopFragment(), toFragment, 0, ISupportFragment.STANDARD, addToBackStack ? TransactionDelegate.TYPE_REPLACE : TransactionDelegate.TYPE_REPLACE_DONT_BACK);
  507 + }
  508 +
  509 + public void pop() {
  510 + mTransactionDelegate.pop(mFragment.getFragmentManager());
  511 + }
  512 +
  513 + /**
  514 + * Pop the child fragment.
  515 + */
  516 + public void popChild() {
  517 + mTransactionDelegate.pop(getChildFragmentManager());
  518 + }
  519 +
  520 + /**
  521 + * Pop the last fragment transition from the manager's fragment
  522 + * back stack.
  523 + * <p>
  524 + * 出栈到目标fragment
  525 + *
  526 + * @param targetFragmentClass 目标fragment
  527 + * @param includeTargetFragment 是否包含该fragment
  528 + */
  529 + public void popTo(Class<?> targetFragmentClass, boolean includeTargetFragment) {
  530 + popTo(targetFragmentClass, includeTargetFragment, null);
  531 + }
  532 +
  533 + /**
  534 + * If you want to begin another FragmentTransaction immediately after popTo(), use this method.
  535 + * 如果你想在出栈后, 立刻进行FragmentTransaction操作,请使用该方法
  536 + */
  537 + public void popTo(Class<?> targetFragmentClass, boolean includeTargetFragment, Runnable afterPopTransactionRunnable) {
  538 + popTo(targetFragmentClass, includeTargetFragment, afterPopTransactionRunnable, TransactionDelegate.DEFAULT_POPTO_ANIM);
  539 + }
  540 +
  541 + public void popTo(Class<?> targetFragmentClass, boolean includeTargetFragment, Runnable afterPopTransactionRunnable, int popAnim) {
  542 + mTransactionDelegate.popTo(targetFragmentClass.getName(), includeTargetFragment, afterPopTransactionRunnable, mFragment.getFragmentManager(), popAnim);
  543 + }
  544 +
  545 + public void popToChild(Class<?> targetFragmentClass, boolean includeTargetFragment) {
  546 + popToChild(targetFragmentClass, includeTargetFragment, null);
  547 + }
  548 +
  549 + public void popToChild(Class<?> targetFragmentClass, boolean includeTargetFragment, Runnable afterPopTransactionRunnable) {
  550 + popToChild(targetFragmentClass, includeTargetFragment, afterPopTransactionRunnable, TransactionDelegate.DEFAULT_POPTO_ANIM);
  551 + }
  552 +
  553 + public void popToChild(Class<?> targetFragmentClass, boolean includeTargetFragment, Runnable afterPopTransactionRunnable, int popAnim) {
  554 + mTransactionDelegate.popTo(targetFragmentClass.getName(), includeTargetFragment, afterPopTransactionRunnable, getChildFragmentManager(), popAnim);
  555 + }
  556 +
  557 + public void popQuiet() {
  558 + mTransactionDelegate.popQuiet(mFragment.getFragmentManager(), mFragment);
  559 + }
  560 +
  561 + private FragmentManager getChildFragmentManager() {
  562 + return mFragment.getChildFragmentManager();
  563 + }
  564 +
  565 + private ISupportFragment getTopFragment() {
  566 + return SupportHelper.getTopFragment(getChildFragmentManager());
  567 + }
  568 +
  569 + private void fixAnimationListener(Animation enterAnim) {
  570 + // AnimationListener is not reliable.
  571 + getHandler().postDelayed(mNotifyEnterAnimEndRunnable, enterAnim.getDuration());
  572 + mSupport.getSupportDelegate().mFragmentClickable = true;
  573 +
  574 + if (mEnterAnimListener != null) {
  575 + getHandler().post(new Runnable() {
  576 + @Override
  577 + public void run() {
  578 + mEnterAnimListener.onEnterAnimStart();
  579 + mEnterAnimListener = null;
  580 + }
  581 + });
  582 + }
  583 + }
  584 +
  585 + private Runnable mNotifyEnterAnimEndRunnable = new Runnable() {
  586 + @Override
  587 + public void run() {
  588 + if (mFragment == null) return;
  589 + mSupportF.onEnterAnimationEnd(mSaveInstanceState);
  590 +
  591 + if (mRootViewClickable) return;
  592 + final View view = mFragment.getView();
  593 + if (view == null) return;
  594 + ISupportFragment preFragment = SupportHelper.getPreFragment(mFragment);
  595 + if (preFragment == null) return;
  596 +
  597 + long prePopExitDuration = preFragment.getSupportDelegate().getPopExitAnimDuration();
  598 + long enterDuration = getEnterAnimDuration();
  599 +
  600 + mHandler.postDelayed(new Runnable() {
  601 + @Override
  602 + public void run() {
  603 + view.setClickable(false);
  604 + }
  605 + }, prePopExitDuration - enterDuration);
  606 + }
  607 + };
  608 +
  609 + private void compatSharedElements() {
  610 + notifyEnterAnimEnd();
  611 + }
  612 +
  613 + public void setBackground(View view) {
  614 + if ((mFragment.getTag() != null && mFragment.getTag().startsWith("android:switcher:")) ||
  615 + mRootStatus != STATUS_UN_ROOT ||
  616 + view.getBackground() != null) {
  617 + return;
  618 + }
  619 +
  620 + int defaultBg = mSupport.getSupportDelegate().getDefaultFragmentBackground();
  621 + if (defaultBg == 0) {
  622 + int background = getWindowBackground();
  623 + view.setBackgroundResource(background);
  624 + } else {
  625 + view.setBackgroundResource(defaultBg);
  626 + }
  627 + }
  628 +
  629 + private int getWindowBackground() {
  630 + TypedArray a = _mActivity.getTheme().obtainStyledAttributes(new int[]{
  631 + android.R.attr.windowBackground
  632 + });
  633 + int background = a.getResourceId(0, 0);
  634 + a.recycle();
  635 + return background;
  636 + }
  637 +
  638 + private void notifyEnterAnimEnd() {
  639 + getHandler().post(mNotifyEnterAnimEndRunnable);
  640 + mSupport.getSupportDelegate().mFragmentClickable = true;
  641 + }
  642 +
  643 + private Handler getHandler() {
  644 + if (mHandler == null) {
  645 + mHandler = new Handler(Looper.getMainLooper());
  646 + }
  647 + return mHandler;
  648 + }
  649 +
  650 + public VisibleDelegate getVisibleDelegate() {
  651 + if (mVisibleDelegate == null) {
  652 + mVisibleDelegate = new VisibleDelegate(mSupportF);
  653 + }
  654 + return mVisibleDelegate;
  655 + }
  656 +
  657 + public FragmentActivity getActivity() {
  658 + return _mActivity;
  659 + }
  660 +
  661 + private Animation getEnterAnim() {
  662 + if (mCustomEnterAnim == Integer.MIN_VALUE) {
  663 + if (mAnimHelper != null && mAnimHelper.enterAnim != null) {
  664 + return mAnimHelper.enterAnim;
  665 + }
  666 + } else {
  667 + try {
  668 + return AnimationUtils.loadAnimation(_mActivity, mCustomEnterAnim);
  669 + } catch (Exception e) {
  670 + e.printStackTrace();
  671 + }
  672 + }
  673 + return null;
  674 + }
  675 +
  676 + private long getEnterAnimDuration() {
  677 + Animation enter = getEnterAnim();
  678 + if (enter != null) {
  679 + return enter.getDuration();
  680 + }
  681 + return NOT_FOUND_ANIM_TIME;
  682 + }
  683 +
  684 + public long getExitAnimDuration() {
  685 + if (mCustomExitAnim == Integer.MIN_VALUE) {
  686 + if (mAnimHelper != null && mAnimHelper.exitAnim != null) {
  687 + return mAnimHelper.exitAnim.getDuration();
  688 + }
  689 + } else {
  690 + try {
  691 + return AnimationUtils.loadAnimation(_mActivity, mCustomExitAnim).getDuration();
  692 + } catch (Exception e) {
  693 + e.printStackTrace();
  694 + }
  695 +
  696 + }
  697 + return NOT_FOUND_ANIM_TIME;
  698 + }
  699 +
  700 + private long getPopExitAnimDuration() {
  701 + if (mCustomPopExitAnim == Integer.MIN_VALUE) {
  702 + if (mAnimHelper != null && mAnimHelper.popExitAnim != null) {
  703 + return mAnimHelper.popExitAnim.getDuration();
  704 + }
  705 + } else {
  706 + try {
  707 + return AnimationUtils.loadAnimation(_mActivity, mCustomPopExitAnim).getDuration();
  708 + } catch (Exception e) {
  709 + e.printStackTrace();
  710 + }
  711 +
  712 + }
  713 + return NOT_FOUND_ANIM_TIME;
  714 + }
  715 +
  716 + @Nullable
  717 + Animation getExitAnim() {
  718 + if (mCustomExitAnim == Integer.MIN_VALUE) {
  719 + if (mAnimHelper != null && mAnimHelper.exitAnim != null) {
  720 + return mAnimHelper.exitAnim;
  721 + }
  722 + } else {
  723 + try {
  724 + return AnimationUtils.loadAnimation(_mActivity, mCustomExitAnim);
  725 + } catch (Exception e) {
  726 + e.printStackTrace();
  727 + }
  728 + }
  729 + return null;
  730 + }
  731 +
  732 + interface EnterAnimListener {
  733 + void onEnterAnimStart();
  734 + }
  735 +}
0 \ No newline at end of file 736 \ No newline at end of file
core/base/src/main/java/com/me/yokeyword/fragmentation/SupportHelper.java 0 → 100644
  1 +package com.me.yokeyword.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 +import androidx.fragment.app.FragmentationMagician;
  10 +
  11 +import java.util.ArrayList;
  12 +import java.util.List;
  13 +
  14 +/**
  15 + * Created by YoKey on 17/6/13.
  16 + */
  17 +
  18 +public class SupportHelper {
  19 + private static final long SHOW_SPACE = 200L;
  20 +
  21 + private SupportHelper() {
  22 + }
  23 +
  24 + /**
  25 + * 显示软键盘
  26 + */
  27 + public static void showSoftInput(final View view) {
  28 + if (view == null || view.getContext() == null) return;
  29 + final InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
  30 + view.requestFocus();
  31 + view.postDelayed(new Runnable() {
  32 + @Override
  33 + public void run() {
  34 + imm.showSoftInput(view, InputMethodManager.SHOW_FORCED);
  35 + }
  36 + }, SHOW_SPACE);
  37 + }
  38 +
  39 + /**
  40 + * 隐藏软键盘
  41 + */
  42 + public static void hideSoftInput(View view) {
  43 + if (view == null || view.getContext() == null) return;
  44 + InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
  45 + imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
  46 + }
  47 +
  48 + /**
  49 + * 显示栈视图dialog,调试时使用
  50 + */
  51 + public static void showFragmentStackHierarchyView(ISupportActivity support) {
  52 + support.getSupportDelegate().showFragmentStackHierarchyView();
  53 + }
  54 +
  55 + /**
  56 + * 显示栈视图日志,调试时使用
  57 + */
  58 + public static void logFragmentStackHierarchy(ISupportActivity support, String TAG) {
  59 + support.getSupportDelegate().logFragmentStackHierarchy(TAG);
  60 + }
  61 +
  62 + /**
  63 + * 获得栈顶SupportFragment
  64 + */
  65 + public static ISupportFragment getTopFragment(FragmentManager fragmentManager) {
  66 + return getTopFragment(fragmentManager, 0);
  67 + }
  68 +
  69 + public static ISupportFragment getTopFragment(FragmentManager fragmentManager, int containerId) {
  70 + List<Fragment> fragmentList = FragmentationMagician.getActiveFragments(fragmentManager);
  71 + if (fragmentList == null) return null;
  72 +
  73 + for (int i = fragmentList.size() - 1; i >= 0; i--) {
  74 + Fragment fragment = fragmentList.get(i);
  75 + if (fragment instanceof ISupportFragment) {
  76 + ISupportFragment iFragment = (ISupportFragment) fragment;
  77 + if (containerId == 0) return iFragment;
  78 +
  79 + if (containerId == iFragment.getSupportDelegate().mContainerId) {
  80 + return iFragment;
  81 + }
  82 + }
  83 + }
  84 + return null;
  85 + }
  86 +
  87 + /**
  88 + * 获取目标Fragment的前一个SupportFragment
  89 + *
  90 + * @param fragment 目标Fragment
  91 + */
  92 + public static ISupportFragment getPreFragment(Fragment fragment) {
  93 + FragmentManager fragmentManager = fragment.getFragmentManager();
  94 + if (fragmentManager == null) return null;
  95 +
  96 + List<Fragment> fragmentList = FragmentationMagician.getActiveFragments(fragmentManager);
  97 + if (fragmentList == null) return null;
  98 +
  99 + int index = fragmentList.indexOf(fragment);
  100 + for (int i = index - 1; i >= 0; i--) {
  101 + Fragment preFragment = fragmentList.get(i);
  102 + if (preFragment instanceof ISupportFragment) {
  103 + return (ISupportFragment) preFragment;
  104 + }
  105 + }
  106 + return null;
  107 + }
  108 +
  109 + /**
  110 + * Same as fragmentManager.findFragmentByTag(fragmentClass.getName());
  111 + * find Fragment from FragmentStack
  112 + */
  113 + @SuppressWarnings("unchecked")
  114 + public static <T extends ISupportFragment> T findFragment(FragmentManager fragmentManager, Class<T> fragmentClass) {
  115 + return findStackFragment(fragmentClass, null, fragmentManager);
  116 + }
  117 +
  118 + /**
  119 + * Same as fragmentManager.findFragmentByTag(fragmentTag);
  120 + * <p>
  121 + * find Fragment from FragmentStack
  122 + */
  123 + @SuppressWarnings("unchecked")
  124 + public static <T extends ISupportFragment> T findFragment(FragmentManager fragmentManager, String fragmentTag) {
  125 + return findStackFragment(null, fragmentTag, fragmentManager);
  126 + }
  127 +
  128 + /**
  129 + * 从栈顶开始,寻找FragmentManager以及其所有子栈, 直到找到状态为show & userVisible的Fragment
  130 + */
  131 + public static ISupportFragment getActiveFragment(FragmentManager fragmentManager) {
  132 + return getActiveFragment(fragmentManager, null);
  133 + }
  134 +
  135 + @SuppressWarnings("unchecked")
  136 + static <T extends ISupportFragment> T findStackFragment(Class<T> fragmentClass, String toFragmentTag, FragmentManager fragmentManager) {
  137 + Fragment fragment = null;
  138 +
  139 + if (toFragmentTag == null) {
  140 + List<Fragment> fragmentList = FragmentationMagician.getActiveFragments(fragmentManager);
  141 + if (fragmentList == null) return null;
  142 +
  143 + int sizeChildFrgList = fragmentList.size();
  144 +
  145 + for (int i = sizeChildFrgList - 1; i >= 0; i--) {
  146 + Fragment brotherFragment = fragmentList.get(i);
  147 + if (brotherFragment instanceof ISupportFragment && brotherFragment.getClass().getName().equals(fragmentClass.getName())) {
  148 + fragment = brotherFragment;
  149 + break;
  150 + }
  151 + }
  152 + } else {
  153 + fragment = fragmentManager.findFragmentByTag(toFragmentTag);
  154 + if (fragment == null) return null;
  155 + }
  156 + return (T) fragment;
  157 + }
  158 +
  159 + private static ISupportFragment getActiveFragment(FragmentManager fragmentManager, ISupportFragment parentFragment) {
  160 + List<Fragment> fragmentList = FragmentationMagician.getActiveFragments(fragmentManager);
  161 + if (fragmentList == null) {
  162 + return parentFragment;
  163 + }
  164 + for (int i = fragmentList.size() - 1; i >= 0; i--) {
  165 + Fragment fragment = fragmentList.get(i);
  166 + if (fragment instanceof ISupportFragment) {
  167 + if (fragment.isResumed() && !fragment.isHidden() && fragment.getUserVisibleHint()) {
  168 + return getActiveFragment(fragment.getChildFragmentManager(), (ISupportFragment) fragment);
  169 + }
  170 + }
  171 + }
  172 + return parentFragment;
  173 + }
  174 +
  175 + /**
  176 + * Get the topFragment from BackStack
  177 + */
  178 + public static ISupportFragment getBackStackTopFragment(FragmentManager fragmentManager) {
  179 + return getBackStackTopFragment(fragmentManager, 0);
  180 + }
  181 +
  182 + /**
  183 + * Get the topFragment from BackStack
  184 + */
  185 + public static ISupportFragment getBackStackTopFragment(FragmentManager fragmentManager, int containerId) {
  186 + int count = fragmentManager.getBackStackEntryCount();
  187 +
  188 + for (int i = count - 1; i >= 0; i--) {
  189 + FragmentManager.BackStackEntry entry = fragmentManager.getBackStackEntryAt(i);
  190 + Fragment fragment = fragmentManager.findFragmentByTag(entry.getName());
  191 + if (fragment instanceof ISupportFragment) {
  192 + ISupportFragment supportFragment = (ISupportFragment) fragment;
  193 + if (containerId == 0) return supportFragment;
  194 +
  195 + if (containerId == supportFragment.getSupportDelegate().mContainerId) {
  196 + return supportFragment;
  197 + }
  198 + }
  199 + }
  200 + return null;
  201 + }
  202 +
  203 + @SuppressWarnings("unchecked")
  204 + static <T extends ISupportFragment> T findBackStackFragment(Class<T> fragmentClass, String toFragmentTag, FragmentManager fragmentManager) {
  205 + int count = fragmentManager.getBackStackEntryCount();
  206 +
  207 + if (toFragmentTag == null) {
  208 + toFragmentTag = fragmentClass.getName();
  209 + }
  210 +
  211 + for (int i = count - 1; i >= 0; i--) {
  212 + FragmentManager.BackStackEntry entry = fragmentManager.getBackStackEntryAt(i);
  213 +
  214 + if (toFragmentTag.equals(entry.getName())) {
  215 + Fragment fragment = fragmentManager.findFragmentByTag(entry.getName());
  216 + if (fragment instanceof ISupportFragment) {
  217 + return (T) fragment;
  218 + }
  219 + }
  220 + }
  221 + return null;
  222 + }
  223 +
  224 + static List<Fragment> getWillPopFragments(FragmentManager fm, String targetTag, boolean includeTarget) {
  225 + Fragment target = fm.findFragmentByTag(targetTag);
  226 + List<Fragment> willPopFragments = new ArrayList<>();
  227 +
  228 + List<Fragment> fragmentList = FragmentationMagician.getActiveFragments(fm);
  229 + if (fragmentList == null) return willPopFragments;
  230 +
  231 + int size = fragmentList.size();
  232 +
  233 + int startIndex = -1;
  234 + for (int i = size - 1; i >= 0; i--) {
  235 + if (target == fragmentList.get(i)) {
  236 + if (includeTarget) {
  237 + startIndex = i;
  238 + } else if (i + 1 < size) {
  239 + startIndex = i + 1;
  240 + }
  241 + break;
  242 + }
  243 + }
  244 +
  245 + if (startIndex == -1) return willPopFragments;
  246 +
  247 + for (int i = size - 1; i >= startIndex; i--) {
  248 + Fragment fragment = fragmentList.get(i);
  249 + if (fragment != null && fragment.getView() != null) {
  250 + willPopFragments.add(fragment);
  251 + }
  252 + }
  253 + return willPopFragments;
  254 + }
  255 +}
core/base/src/main/java/com/me/yokeyword/fragmentation/SwipeBackLayout.java 0 → 100644
  1 +package com.me.yokeyword.fragmentation;
  2 +
  3 +import android.content.Context;
  4 +import android.content.res.TypedArray;
  5 +import android.graphics.Canvas;
  6 +import android.graphics.Rect;
  7 +import android.graphics.drawable.Drawable;
  8 +import android.util.AttributeSet;
  9 +import android.util.DisplayMetrics;
  10 +import android.view.MotionEvent;
  11 +import android.view.View;
  12 +import android.view.ViewGroup;
  13 +import android.view.WindowManager;
  14 +import android.widget.FrameLayout;
  15 +
  16 +import androidx.annotation.FloatRange;
  17 +import androidx.annotation.IntDef;
  18 +import androidx.core.view.ViewCompat;
  19 +import androidx.customview.widget.ViewDragHelper;
  20 +import androidx.fragment.app.Fragment;
  21 +import androidx.fragment.app.FragmentActivity;
  22 +import androidx.fragment.app.FragmentationMagician;
  23 +
  24 +import com.cnlive.strike.base.R;
  25 +import com.me.yokeyword.fragmentation_swipeback.core.ISwipeBackActivity;
  26 +
  27 +import java.lang.annotation.Retention;
  28 +import java.lang.annotation.RetentionPolicy;
  29 +import java.lang.reflect.Field;
  30 +import java.util.ArrayList;
  31 +import java.util.List;
  32 +
  33 +
  34 +/**
  35 + * Thx https://github.com/ikew0ng/SwipeBackLayout.
  36 + * <p>
  37 + * Created by YoKey on 16/4/19.
  38 + */
  39 +public class SwipeBackLayout extends FrameLayout {
  40 + /**
  41 + * Edge flag indicating that the left edge should be affected.
  42 + */
  43 + public static final int EDGE_LEFT = ViewDragHelper.EDGE_LEFT;
  44 +
  45 + /**
  46 + * Edge flag indicating that the right edge should be affected.
  47 + */
  48 + public static final int EDGE_RIGHT = ViewDragHelper.EDGE_RIGHT;
  49 +
  50 + public static final int EDGE_ALL = EDGE_LEFT | EDGE_RIGHT;
  51 +
  52 +
  53 + /**
  54 + * A view is not currently being dragged or animating as a result of a
  55 + * fling/snap.
  56 + */
  57 + public static final int STATE_IDLE = ViewDragHelper.STATE_IDLE;
  58 +
  59 + /**
  60 + * A view is currently being dragged. The position is currently changing as
  61 + * a result of user input or simulated user input.
  62 + */
  63 + public static final int STATE_DRAGGING = ViewDragHelper.STATE_DRAGGING;
  64 +
  65 + /**
  66 + * A view is currently settling into place as a result of a fling or
  67 + * predefined non-interactive motion.
  68 + */
  69 + public static final int STATE_SETTLING = ViewDragHelper.STATE_SETTLING;
  70 +
  71 + /**
  72 + * A view is currently drag finished.
  73 + */
  74 + public static final int STATE_FINISHED = 3;
  75 +
  76 + private static final int DEFAULT_SCRIM_COLOR = 0x99000000;
  77 + private static final float DEFAULT_PARALLAX = 0.33f;
  78 + private static final int FULL_ALPHA = 255;
  79 + private static final float DEFAULT_SCROLL_THRESHOLD = 0.4f;
  80 + private static final int OVERSCROLL_DISTANCE = 10;
  81 +
  82 + private float mScrollFinishThreshold = DEFAULT_SCROLL_THRESHOLD;
  83 +
  84 + private ViewDragHelper mHelper;
  85 +
  86 + private float mScrollPercent;
  87 + private float mScrimOpacity;
  88 +
  89 + private FragmentActivity mActivity;
  90 + private View mContentView;
  91 + private ISupportFragment mFragment;
  92 + private Fragment mPreFragment;
  93 +
  94 + private Drawable mShadowLeft;
  95 + private Drawable mShadowRight;
  96 + private Rect mTmpRect = new Rect();
  97 +
  98 + private int mEdgeFlag;
  99 + private boolean mEnable = true;
  100 + private int mCurrentSwipeOrientation;
  101 + private float mParallaxOffset = DEFAULT_PARALLAX;
  102 +
  103 + private boolean mCallOnDestroyView;
  104 +
  105 + private boolean mInLayout;
  106 +
  107 + private int mContentLeft;
  108 + private int mContentTop;
  109 + private float mSwipeAlpha = 0.5f;
  110 +
  111 + /**
  112 + * The set of listeners to be sent events through.
  113 + */
  114 + private List<OnSwipeListener> mListeners;
  115 +
  116 + private Context mContext;
  117 +
  118 + public enum EdgeLevel {
  119 + MAX, MIN, MED
  120 + }
  121 +
  122 + public SwipeBackLayout(Context context) {
  123 + this(context, null);
  124 + }
  125 +
  126 + public SwipeBackLayout(Context context, AttributeSet attrs) {
  127 + this(context, attrs, 0);
  128 + }
  129 +
  130 + public SwipeBackLayout(Context context, AttributeSet attrs, int defStyleAttr) {
  131 + super(context, attrs, defStyleAttr);
  132 + this.mContext = context;
  133 + init();
  134 + }
  135 +
  136 + private void init() {
  137 + mHelper = ViewDragHelper.create(this, new ViewDragCallback());
  138 + setShadow(R.drawable.shadow_left, EDGE_LEFT);
  139 + setEdgeOrientation(EDGE_LEFT);
  140 + }
  141 +
  142 + /**
  143 + * Get ViewDragHelper
  144 + */
  145 + public ViewDragHelper getViewDragHelper() {
  146 + return mHelper;
  147 + }
  148 +
  149 + /**
  150 + * 滑动中,上一个页面View的阴影透明度
  151 + *
  152 + * @param alpha 0.0f:无阴影, 1.0f:较重的阴影, 默认:0.5f
  153 + */
  154 + public void setSwipeAlpha(@FloatRange(from = 0.0f, to = 1.0f) float alpha) {
  155 + this.mSwipeAlpha = alpha;
  156 + }
  157 +
  158 + /**
  159 + * Set scroll threshold, we will close the activity, when scrollPercent over
  160 + * this value
  161 + *
  162 + * @param threshold
  163 + */
  164 + public void setScrollThresHold(@FloatRange(from = 0.0f, to = 1.0f) float threshold) {
  165 + if (threshold >= 1.0f || threshold <= 0) {
  166 + throw new IllegalArgumentException("Threshold value should be between 0 and 1.0");
  167 + }
  168 + mScrollFinishThreshold = threshold;
  169 + }
  170 +
  171 + public void setParallaxOffset(float offset) {
  172 + this.mParallaxOffset = offset;
  173 + }
  174 +
  175 + /**
  176 + * Enable edge tracking for the selected edges of the parent view.
  177 + * The callback's {@link ViewDragHelper.Callback#onEdgeTouched(int, int)} and
  178 + * {@link ViewDragHelper.Callback#onEdgeDragStarted(int, int)} methods will only be invoked
  179 + * for edges for which edge tracking has been enabled.
  180 + *
  181 + * @param orientation Combination of edge flags describing the edges to watch
  182 + * @see #EDGE_LEFT
  183 + * @see #EDGE_RIGHT
  184 + */
  185 + public void setEdgeOrientation(@EdgeOrientation int orientation) {
  186 + mEdgeFlag = orientation;
  187 + mHelper.setEdgeTrackingEnabled(orientation);
  188 +
  189 + if (orientation == EDGE_RIGHT || orientation == EDGE_ALL) {
  190 + setShadow(R.drawable.shadow_right, EDGE_RIGHT);
  191 + }
  192 + }
  193 +
  194 + @IntDef({EDGE_LEFT, EDGE_RIGHT, EDGE_ALL})
  195 + @Retention(RetentionPolicy.SOURCE)
  196 + public @interface EdgeOrientation {
  197 + }
  198 +
  199 + /**
  200 + * Set a drawable used for edge shadow.
  201 + */
  202 + public void setShadow(Drawable shadow, int edgeFlag) {
  203 + if ((edgeFlag & EDGE_LEFT) != 0) {
  204 + mShadowLeft = shadow;
  205 + } else if ((edgeFlag & EDGE_RIGHT) != 0) {
  206 + mShadowRight = shadow;
  207 + }
  208 + invalidate();
  209 + }
  210 +
  211 + /**
  212 + * Set a drawable used for edge shadow.
  213 + */
  214 + public void setShadow(int resId, int edgeFlag) {
  215 + setShadow(getResources().getDrawable(resId), edgeFlag);
  216 + }
  217 +
  218 + /**
  219 + * Add a callback to be invoked when a swipe event is sent to this view.
  220 + *
  221 + * @param listener the swipe listener to attach to this view
  222 + */
  223 + public void addSwipeListener(OnSwipeListener listener) {
  224 + if (mListeners == null) {
  225 + mListeners = new ArrayList<>();
  226 + }
  227 + mListeners.add(listener);
  228 + }
  229 +
  230 + /**
  231 + * Removes a listener from the set of listeners
  232 + *
  233 + * @param listener
  234 + */
  235 + public void removeSwipeListener(OnSwipeListener listener) {
  236 + if (mListeners == null) {
  237 + return;
  238 + }
  239 + mListeners.remove(listener);
  240 + }
  241 +
  242 + public interface OnSwipeListener {
  243 + /**
  244 + * Invoke when state change
  245 + *
  246 + * @param state flag to describe scroll state
  247 + * @see #STATE_IDLE
  248 + * @see #STATE_DRAGGING
  249 + * @see #STATE_SETTLING
  250 + * @see #STATE_FINISHED
  251 + */
  252 + void onDragStateChange(int state);
  253 +
  254 + /**
  255 + * Invoke when edge touched
  256 + *
  257 + * @param oritentationEdgeFlag edge flag describing the edge being touched
  258 + * @see #EDGE_LEFT
  259 + * @see #EDGE_RIGHT
  260 + */
  261 + void onEdgeTouch(int oritentationEdgeFlag);
  262 +
  263 + /**
  264 + * Invoke when scroll percent over the threshold for the first time
  265 + *
  266 + * @param scrollPercent scroll percent of this view
  267 + */
  268 + void onDragScrolled(float scrollPercent);
  269 + }
  270 +
  271 + @Override
  272 + protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
  273 + boolean isDrawView = child == mContentView;
  274 + boolean drawChild = super.drawChild(canvas, child, drawingTime);
  275 + if (isDrawView && mScrimOpacity > 0 && mHelper.getViewDragState() != ViewDragHelper.STATE_IDLE) {
  276 + drawShadow(canvas, child);
  277 + drawScrim(canvas, child);
  278 + }
  279 + return drawChild;
  280 + }
  281 +
  282 + private void drawShadow(Canvas canvas, View child) {
  283 + final Rect childRect = mTmpRect;
  284 + child.getHitRect(childRect);
  285 +
  286 + if ((mCurrentSwipeOrientation & EDGE_LEFT) != 0) {
  287 + mShadowLeft.setBounds(childRect.left - mShadowLeft.getIntrinsicWidth(), childRect.top, childRect.left, childRect.bottom);
  288 + mShadowLeft.setAlpha((int) (mScrimOpacity * FULL_ALPHA));
  289 + mShadowLeft.draw(canvas);
  290 + } else if ((mCurrentSwipeOrientation & EDGE_RIGHT) != 0) {
  291 + mShadowRight.setBounds(childRect.right, childRect.top, childRect.right + mShadowRight.getIntrinsicWidth(), childRect.bottom);
  292 + mShadowRight.setAlpha((int) (mScrimOpacity * FULL_ALPHA));
  293 + mShadowRight.draw(canvas);
  294 + }
  295 + }
  296 +
  297 + private void drawScrim(Canvas canvas, View child) {
  298 + final int baseAlpha = (DEFAULT_SCRIM_COLOR & 0xff000000) >>> 24;
  299 + final int alpha = (int) (baseAlpha * mScrimOpacity * mSwipeAlpha);
  300 + final int color = alpha << 24;
  301 +
  302 + if ((mCurrentSwipeOrientation & EDGE_LEFT) != 0) {
  303 + canvas.clipRect(0, 0, child.getLeft(), getHeight());
  304 + } else if ((mCurrentSwipeOrientation & EDGE_RIGHT) != 0) {
  305 + canvas.clipRect(child.getRight(), 0, getRight(), getHeight());
  306 + }
  307 + canvas.drawColor(color);
  308 + }
  309 +
  310 + @Override
  311 + protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
  312 + mInLayout = true;
  313 + if (mContentView != null) {
  314 + mContentView.layout(mContentLeft, mContentTop,
  315 + mContentLeft + mContentView.getMeasuredWidth(),
  316 + mContentTop + mContentView.getMeasuredHeight());
  317 + }
  318 + mInLayout = false;
  319 + }
  320 +
  321 + @Override
  322 + public void requestLayout() {
  323 + if (!mInLayout) {
  324 + super.requestLayout();
  325 + }
  326 + }
  327 +
  328 + @Override
  329 + public void computeScroll() {
  330 + mScrimOpacity = 1 - mScrollPercent;
  331 + if (mScrimOpacity >= 0) {
  332 + if (mHelper.continueSettling(true)) {
  333 + ViewCompat.postInvalidateOnAnimation(this);
  334 + }
  335 +
  336 + if (mPreFragment != null && mPreFragment.getView() != null) {
  337 + if (mCallOnDestroyView) {
  338 + mPreFragment.getView().setX(0);
  339 + return;
  340 + }
  341 +
  342 + if (mHelper.getCapturedView() != null) {
  343 + int leftOffset = (int) ((mHelper.getCapturedView().getLeft() - getWidth()) * mParallaxOffset * mScrimOpacity);
  344 + mPreFragment.getView().setX(leftOffset > 0 ? 0 : leftOffset);
  345 + }
  346 + }
  347 + }
  348 + }
  349 +
  350 + /**
  351 + * hide
  352 + */
  353 + public void internalCallOnDestroyView() {
  354 + mCallOnDestroyView = true;
  355 + }
  356 +
  357 + public void setFragment(final ISupportFragment fragment, View view) {
  358 + this.mFragment = fragment;
  359 + mContentView = view;
  360 + }
  361 +
  362 + public void hiddenFragment() {
  363 + if (mPreFragment != null && mPreFragment.getView() != null) {
  364 + mPreFragment.getView().setVisibility(GONE);
  365 + }
  366 + }
  367 +
  368 + public void attachToActivity(FragmentActivity activity) {
  369 + mActivity = activity;
  370 + TypedArray a = activity.getTheme().obtainStyledAttributes(new int[]{
  371 + android.R.attr.windowBackground
  372 + });
  373 + int background = a.getResourceId(0, 0);
  374 + a.recycle();
  375 +
  376 + ViewGroup decor = (ViewGroup) activity.getWindow().getDecorView();
  377 + ViewGroup decorChild = (ViewGroup) decor.getChildAt(0);
  378 + decorChild.setBackgroundResource(background);
  379 + decor.removeView(decorChild);
  380 + addView(decorChild);
  381 + setContentView(decorChild);
  382 + decor.addView(this);
  383 + }
  384 +
  385 + public void attachToFragment(ISupportFragment fragment, View view) {
  386 + addView(view);
  387 + setFragment(fragment, view);
  388 + }
  389 +
  390 + private void setContentView(View view) {
  391 + mContentView = view;
  392 + }
  393 +
  394 + public void setEnableGesture(boolean enable) {
  395 + mEnable = enable;
  396 + }
  397 +
  398 + public void setEdgeLevel(EdgeLevel edgeLevel) {
  399 + validateEdgeLevel(-1, edgeLevel);
  400 + }
  401 +
  402 + public void setEdgeLevel(int widthPixel) {
  403 + validateEdgeLevel(widthPixel, null);
  404 + }
  405 +
  406 + private void validateEdgeLevel(int widthPixel, EdgeLevel edgeLevel) {
  407 + try {
  408 + DisplayMetrics metrics = new DisplayMetrics();
  409 + WindowManager windowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
  410 + windowManager.getDefaultDisplay().getMetrics(metrics);
  411 + Field mEdgeSize = mHelper.getClass().getDeclaredField("mEdgeSize");
  412 + mEdgeSize.setAccessible(true);
  413 + if (widthPixel >= 0) {
  414 + mEdgeSize.setInt(mHelper, widthPixel);
  415 + } else {
  416 + if (edgeLevel == EdgeLevel.MAX) {
  417 + mEdgeSize.setInt(mHelper, metrics.widthPixels);
  418 + } else if (edgeLevel == EdgeLevel.MED) {
  419 + mEdgeSize.setInt(mHelper, metrics.widthPixels / 2);
  420 + } else {
  421 + mEdgeSize.setInt(mHelper, ((int) (20 * metrics.density + 0.5f)));
  422 + }
  423 + }
  424 + } catch (NoSuchFieldException e) {
  425 + e.printStackTrace();
  426 + } catch (IllegalAccessException e) {
  427 + e.printStackTrace();
  428 + }
  429 + }
  430 +
  431 + private class ViewDragCallback extends ViewDragHelper.Callback {
  432 +
  433 + @Override
  434 + public boolean tryCaptureView(View child, int pointerId) {
  435 + boolean dragEnable = mHelper.isEdgeTouched(mEdgeFlag, pointerId);
  436 + if (dragEnable) {
  437 + if (mHelper.isEdgeTouched(EDGE_LEFT, pointerId)) {
  438 + mCurrentSwipeOrientation = EDGE_LEFT;
  439 + } else if (mHelper.isEdgeTouched(EDGE_RIGHT, pointerId)) {
  440 + mCurrentSwipeOrientation = EDGE_RIGHT;
  441 + }
  442 +
  443 + if (mListeners != null) {
  444 + for (OnSwipeListener listener : mListeners) {
  445 + listener.onEdgeTouch(mCurrentSwipeOrientation);
  446 + }
  447 + }
  448 +
  449 + if (mPreFragment == null) {
  450 + if (mFragment != null) {
  451 + List<Fragment> fragmentList = FragmentationMagician.getActiveFragments(((Fragment) mFragment).getFragmentManager());
  452 + if (fragmentList != null && fragmentList.size() > 1) {
  453 + int index = fragmentList.indexOf(mFragment);
  454 + for (int i = index - 1; i >= 0; i--) {
  455 + Fragment fragment = fragmentList.get(i);
  456 + if (fragment != null && fragment.getView() != null) {
  457 + fragment.getView().setVisibility(VISIBLE);
  458 + mPreFragment = fragment;
  459 + break;
  460 + }
  461 + }
  462 + }
  463 + }
  464 + } else {
  465 + View preView = mPreFragment.getView();
  466 + if (preView != null && preView.getVisibility() != VISIBLE) {
  467 + preView.setVisibility(VISIBLE);
  468 + }
  469 + }
  470 + }
  471 + return dragEnable;
  472 + }
  473 +
  474 + @Override
  475 + public int clampViewPositionHorizontal(View child, int left, int dx) {
  476 + int ret = 0;
  477 + if ((mCurrentSwipeOrientation & EDGE_LEFT) != 0) {
  478 + ret = Math.min(child.getWidth(), Math.max(left, 0));
  479 + } else if ((mCurrentSwipeOrientation & EDGE_RIGHT) != 0) {
  480 + ret = Math.min(0, Math.max(left, -child.getWidth()));
  481 + }
  482 + return ret;
  483 + }
  484 +
  485 + @Override
  486 + public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
  487 + super.onViewPositionChanged(changedView, left, top, dx, dy);
  488 +
  489 + if ((mCurrentSwipeOrientation & EDGE_LEFT) != 0) {
  490 + mScrollPercent = Math.abs((float) left / (mContentView.getWidth() + mShadowLeft.getIntrinsicWidth()));
  491 + } else if ((mCurrentSwipeOrientation & EDGE_RIGHT) != 0) {
  492 + mScrollPercent = Math.abs((float) left / (mContentView.getWidth() + mShadowRight.getIntrinsicWidth()));
  493 + }
  494 + mContentLeft = left;
  495 + mContentTop = top;
  496 + invalidate();
  497 +
  498 + if (mListeners != null && mHelper.getViewDragState() == STATE_DRAGGING && mScrollPercent <= 1 && mScrollPercent > 0) {
  499 + for (OnSwipeListener listener : mListeners) {
  500 + listener.onDragScrolled(mScrollPercent);
  501 + }
  502 + }
  503 +
  504 + if (mScrollPercent > 1) {
  505 + if (mFragment != null) {
  506 + if (mCallOnDestroyView) return;
  507 +
  508 + if (!((Fragment) mFragment).isDetached()) {
  509 + onDragFinished();
  510 + mFragment.getSupportDelegate().popQuiet();
  511 + }
  512 + } else {
  513 + if (!mActivity.isFinishing()) {
  514 + onDragFinished();
  515 + mActivity.finish();
  516 + mActivity.overridePendingTransition(0, 0);
  517 + }
  518 + }
  519 + }
  520 + }
  521 +
  522 + @Override
  523 + public int getViewHorizontalDragRange(View child) {
  524 + if (mFragment != null) {
  525 + return 1;
  526 + }
  527 + if (mActivity instanceof ISwipeBackActivity && ((ISwipeBackActivity) mActivity).swipeBackPriority()) {
  528 + return 1;
  529 + }
  530 + return 0;
  531 + }
  532 +
  533 + @Override
  534 + public void onViewReleased(View releasedChild, float xvel, float yvel) {
  535 + final int childWidth = releasedChild.getWidth();
  536 +
  537 + int left = 0, top = 0;
  538 + if ((mCurrentSwipeOrientation & EDGE_LEFT) != 0) {
  539 + left = xvel > 0 || xvel == 0 && mScrollPercent > mScrollFinishThreshold ? (childWidth
  540 + + mShadowLeft.getIntrinsicWidth() + OVERSCROLL_DISTANCE) : 0;
  541 + } else if ((mCurrentSwipeOrientation & EDGE_RIGHT) != 0) {
  542 + left = xvel < 0 || xvel == 0 && mScrollPercent > mScrollFinishThreshold ? -(childWidth
  543 + + mShadowRight.getIntrinsicWidth() + OVERSCROLL_DISTANCE) : 0;
  544 + }
  545 +
  546 + mHelper.settleCapturedViewAt(left, top);
  547 + invalidate();
  548 + }
  549 +
  550 + @Override
  551 + public void onViewDragStateChanged(int state) {
  552 + super.onViewDragStateChanged(state);
  553 + if (mListeners != null) {
  554 + for (OnSwipeListener listener : mListeners) {
  555 + listener.onDragStateChange(state);
  556 + }
  557 + }
  558 + }
  559 +
  560 + @Override
  561 + public void onEdgeTouched(int edgeFlags, int pointerId) {
  562 + super.onEdgeTouched(edgeFlags, pointerId);
  563 + if ((mEdgeFlag & edgeFlags) != 0) {
  564 + mCurrentSwipeOrientation = edgeFlags;
  565 + }
  566 + }
  567 + }
  568 +
  569 + private void onDragFinished() {
  570 + if (mListeners != null) {
  571 + for (OnSwipeListener listener : mListeners) {
  572 + listener.onDragStateChange(STATE_FINISHED);
  573 + }
  574 + }
  575 + }
  576 +
  577 + @Override
  578 + public boolean onInterceptTouchEvent(MotionEvent ev) {
  579 + if (!mEnable) return super.onInterceptTouchEvent(ev);
  580 + try {
  581 + return mHelper.shouldInterceptTouchEvent(ev);
  582 + } catch (Exception ignored) {
  583 + ignored.printStackTrace();
  584 + }
  585 + return false;
  586 + }
  587 +
  588 + @Override
  589 + public boolean onTouchEvent(MotionEvent event) {
  590 + if (!mEnable) return super.onTouchEvent(event);
  591 + try {
  592 + mHelper.processTouchEvent(event);
  593 + return true;
  594 + } catch (Exception ignored) {
  595 + ignored.printStackTrace();
  596 + }
  597 + return false;
  598 + }
  599 +}
core/base/src/main/java/com/me/yokeyword/fragmentation/TransactionDelegate.java 0 → 100644
  1 +package com.me.yokeyword.fragmentation;
  2 +
  3 +import android.os.Bundle;
  4 +import android.os.Handler;
  5 +import android.os.Looper;
  6 +import android.util.Log;
  7 +import android.view.View;
  8 +import android.view.ViewGroup;
  9 +import android.view.animation.Animation;
  10 +import android.view.animation.AnimationUtils;
  11 +
  12 +import androidx.annotation.NonNull;
  13 +import androidx.fragment.app.Fragment;
  14 +import androidx.fragment.app.FragmentActivity;
  15 +import androidx.fragment.app.FragmentManager;
  16 +import androidx.fragment.app.FragmentTransaction;
  17 +import androidx.fragment.app.FragmentationMagician;
  18 +
  19 +import com.me.yokeyword.fragmentation.exception.AfterSaveStateTransactionWarning;
  20 +import com.me.yokeyword.fragmentation.helper.internal.ResultRecord;
  21 +import com.me.yokeyword.fragmentation.helper.internal.TransactionRecord;
  22 +import com.me.yokeyword.fragmentation.queue.Action;
  23 +import com.me.yokeyword.fragmentation.queue.ActionQueue;
  24 +
  25 +import java.util.ArrayList;
  26 +import java.util.List;
  27 +
  28 +
  29 +
  30 +/**
  31 + * Controller
  32 + * Created by YoKeyword on 16/1/22.
  33 + */
  34 +class TransactionDelegate {
  35 + static final int DEFAULT_POPTO_ANIM = Integer.MAX_VALUE;
  36 +
  37 + private static final String TAG = "Fragmentation";
  38 +
  39 + static final String FRAGMENTATION_ARG_RESULT_RECORD = "fragment_arg_result_record";
  40 + static final String FRAGMENTATION_ARG_ROOT_STATUS = "fragmentation_arg_root_status";
  41 + static final String FRAGMENTATION_ARG_IS_SHARED_ELEMENT = "fragmentation_arg_is_shared_element";
  42 + static final String FRAGMENTATION_ARG_CONTAINER = "fragmentation_arg_container";
  43 + static final String FRAGMENTATION_ARG_REPLACE = "fragmentation_arg_replace";
  44 + static final String FRAGMENTATION_ARG_CUSTOM_ENTER_ANIM = "fragmentation_arg_custom_enter_anim";
  45 + static final String FRAGMENTATION_ARG_CUSTOM_EXIT_ANIM = "fragmentation_arg_custom_exit_anim";
  46 + static final String FRAGMENTATION_ARG_CUSTOM_POP_EXIT_ANIM = "fragmentation_arg_custom_pop_exit_anim";
  47 +
  48 + static final String FRAGMENTATION_STATE_SAVE_ANIMATOR = "fragmentation_state_save_animator";
  49 + static final String FRAGMENTATION_STATE_SAVE_IS_HIDDEN = "fragmentation_state_save_status";
  50 +
  51 + private static final String FRAGMENTATION_STATE_SAVE_RESULT = "fragmentation_state_save_result";
  52 +
  53 + static final int TYPE_ADD = 0;
  54 + static final int TYPE_ADD_RESULT = 1;
  55 + static final int TYPE_ADD_WITHOUT_HIDE = 2;
  56 + static final int TYPE_ADD_RESULT_WITHOUT_HIDE = 3;
  57 + static final int TYPE_REPLACE = 10;
  58 + static final int TYPE_REPLACE_DONT_BACK = 11;
  59 +
  60 + private ISupportActivity mSupport;
  61 + private FragmentActivity mActivity;
  62 +
  63 + private Handler mHandler;
  64 +
  65 + ActionQueue mActionQueue;
  66 +
  67 + TransactionDelegate(ISupportActivity support) {
  68 + this.mSupport = support;
  69 + this.mActivity = (FragmentActivity) support;
  70 + mHandler = new Handler(Looper.getMainLooper());
  71 + mActionQueue = new ActionQueue(mHandler);
  72 + }
  73 +
  74 + void post(final Runnable runnable) {
  75 + mActionQueue.enqueue(new Action() {
  76 + @Override
  77 + public void run() {
  78 + runnable.run();
  79 + }
  80 + });
  81 + }
  82 +
  83 + void loadRootTransaction(final FragmentManager fm, final int containerId, final ISupportFragment to, final boolean addToBackStack, final boolean allowAnimation) {
  84 + enqueue(fm, new Action(Action.ACTION_LOAD) {
  85 + @Override
  86 + public void run() {
  87 + bindContainerId(containerId, to);
  88 +
  89 + String toFragmentTag = to.getClass().getName();
  90 + TransactionRecord transactionRecord = to.getSupportDelegate().mTransactionRecord;
  91 + if (transactionRecord != null) {
  92 + if (transactionRecord.tag != null) {
  93 + toFragmentTag = transactionRecord.tag;
  94 + }
  95 + }
  96 +
  97 + start(fm, null, to, toFragmentTag, !addToBackStack, null, allowAnimation, TYPE_REPLACE);
  98 + }
  99 + });
  100 + }
  101 +
  102 + void loadMultipleRootTransaction(final FragmentManager fm, final int containerId, final int showPosition, final ISupportFragment... tos) {
  103 + enqueue(fm, new Action(Action.ACTION_LOAD) {
  104 + @Override
  105 + public void run() {
  106 + FragmentTransaction ft = fm.beginTransaction();
  107 + for (int i = 0; i < tos.length; i++) {
  108 + Fragment to = (Fragment) tos[i];
  109 +
  110 + Bundle args = getArguments(to);
  111 + args.putInt(FRAGMENTATION_ARG_ROOT_STATUS, SupportFragmentDelegate.STATUS_ROOT_ANIM_DISABLE);
  112 + bindContainerId(containerId, tos[i]);
  113 +
  114 + String toName = to.getClass().getName();
  115 + ft.add(containerId, to, toName);
  116 +
  117 + if (i != showPosition) {
  118 + ft.hide(to);
  119 + }
  120 + }
  121 +
  122 + supportCommit(fm, ft);
  123 + }
  124 + });
  125 + }
  126 +
  127 + /**
  128 + * Dispatch the start transaction.
  129 + */
  130 + void dispatchStartTransaction(final FragmentManager fm, final ISupportFragment from, final ISupportFragment to, final int requestCode, final int launchMode, final int type) {
  131 + enqueue(fm, new Action(launchMode == ISupportFragment.SINGLETASK ? Action.ACTION_POP_MOCK : Action.ACTION_NORMAL) {
  132 + @Override
  133 + public void run() {
  134 + doDispatchStartTransaction(fm, from, to, requestCode, launchMode, type);
  135 + }
  136 + });
  137 + }
  138 +
  139 + /**
  140 + * Show showFragment then hide hideFragment
  141 + */
  142 + void showHideFragment(final FragmentManager fm, final ISupportFragment showFragment, final ISupportFragment hideFragment) {
  143 + enqueue(fm, new Action() {
  144 + @Override
  145 + public void run() {
  146 + doShowHideFragment(fm, showFragment, hideFragment);
  147 + }
  148 + });
  149 + }
  150 +
  151 + /**
  152 + * Start the target Fragment and pop itself
  153 + */
  154 + void startWithPop(final FragmentManager fm, final ISupportFragment from, final ISupportFragment to) {
  155 + enqueue(fm, new Action(Action.ACTION_POP_MOCK) {
  156 + @Override
  157 + public void run() {
  158 + ISupportFragment top = getTopFragmentForStart(from, fm);
  159 + if (top == null)
  160 + throw new NullPointerException("There is no Fragment in the FragmentManager, maybe you need to call loadRootFragment() first!");
  161 +
  162 + int containerId = top.getSupportDelegate().mContainerId;
  163 + bindContainerId(containerId, to);
  164 +
  165 + handleAfterSaveInStateTransactionException(fm, "popTo()");
  166 + FragmentationMagician.executePendingTransactionsAllowingStateLoss(fm);
  167 + top.getSupportDelegate().mLockAnim = true;
  168 + if (!FragmentationMagician.isStateSaved(fm)) {
  169 + mockStartWithPopAnim(SupportHelper.getTopFragment(fm), to, top.getSupportDelegate().mAnimHelper.popExitAnim);
  170 + }
  171 +
  172 + removeTopFragment(fm);
  173 + FragmentationMagician.popBackStackAllowingStateLoss(fm);
  174 + FragmentationMagician.executePendingTransactionsAllowingStateLoss(fm);
  175 + }
  176 + });
  177 +
  178 + dispatchStartTransaction(fm, from, to, 0, ISupportFragment.STANDARD, TransactionDelegate.TYPE_ADD);
  179 + }
  180 +
  181 + void startWithPopTo(final FragmentManager fm, final ISupportFragment from, final ISupportFragment to, final String fragmentTag, final boolean includeTargetFragment) {
  182 + enqueue(fm, new Action(Action.ACTION_POP_MOCK) {
  183 + @Override
  184 + public void run() {
  185 + int flag = 0;
  186 + if (includeTargetFragment) {
  187 + flag = FragmentManager.POP_BACK_STACK_INCLUSIVE;
  188 + }
  189 +
  190 + List<Fragment> willPopFragments = SupportHelper.getWillPopFragments(fm, fragmentTag, includeTargetFragment);
  191 +
  192 + final ISupportFragment top = getTopFragmentForStart(from, fm);
  193 + if (top == null)
  194 + throw new NullPointerException("There is no Fragment in the FragmentManager, maybe you need to call loadRootFragment() first!");
  195 +
  196 + int containerId = top.getSupportDelegate().mContainerId;
  197 + bindContainerId(containerId, to);
  198 +
  199 + if (willPopFragments.size() <= 0) return;
  200 +
  201 + handleAfterSaveInStateTransactionException(fm, "startWithPopTo()");
  202 + FragmentationMagician.executePendingTransactionsAllowingStateLoss(fm);
  203 + if (!FragmentationMagician.isStateSaved(fm)) {
  204 + mockStartWithPopAnim(SupportHelper.getTopFragment(fm), to, top.getSupportDelegate().mAnimHelper.popExitAnim);
  205 + }
  206 +
  207 + safePopTo(fragmentTag, fm, flag, willPopFragments);
  208 + }
  209 +
  210 + });
  211 +
  212 + dispatchStartTransaction(fm, from, to, 0, ISupportFragment.STANDARD, TransactionDelegate.TYPE_ADD);
  213 + }
  214 +
  215 +
  216 + /**
  217 + * Remove
  218 + */
  219 + void remove(final FragmentManager fm, final Fragment fragment, final boolean showPreFragment) {
  220 + enqueue(fm, new Action(Action.ACTION_POP, fm) {
  221 + @Override
  222 + public void run() {
  223 + FragmentTransaction ft = fm.beginTransaction()
  224 + .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE)
  225 + .remove(fragment);
  226 +
  227 + if (showPreFragment) {
  228 + ISupportFragment preFragment = SupportHelper.getPreFragment(fragment);
  229 + if (preFragment instanceof Fragment) {
  230 + ft.show((Fragment) preFragment);
  231 + }
  232 + }
  233 + supportCommit(fm, ft);
  234 + }
  235 + });
  236 + }
  237 +
  238 + /**
  239 + * Pop
  240 + */
  241 + void pop(final FragmentManager fm) {
  242 + enqueue(fm, new Action(Action.ACTION_POP, fm) {
  243 + @Override
  244 + public void run() {
  245 + handleAfterSaveInStateTransactionException(fm, "pop()");
  246 + FragmentationMagician.popBackStackAllowingStateLoss(fm);
  247 + removeTopFragment(fm);
  248 + }
  249 + });
  250 + }
  251 +
  252 + private void removeTopFragment(FragmentManager fm) {
  253 + try { // Safe popBackStack()
  254 + ISupportFragment top = SupportHelper.getBackStackTopFragment(fm);
  255 + if (top != null) {
  256 + fm.beginTransaction()
  257 + .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE)
  258 + .remove((Fragment) top)
  259 + .commitAllowingStateLoss();
  260 + }
  261 + } catch (Exception ignored) {
  262 +
  263 + }
  264 + }
  265 +
  266 + void popQuiet(final FragmentManager fm, final Fragment fragment) {
  267 + enqueue(fm, new Action(Action.ACTION_POP_MOCK) {
  268 + @Override
  269 + public void run() {
  270 + mSupport.getSupportDelegate().mPopMultipleNoAnim = true;
  271 + removeTopFragment(fm);
  272 + FragmentationMagician.popBackStackAllowingStateLoss(fm, fragment.getTag(), 0);
  273 + FragmentationMagician.popBackStackAllowingStateLoss(fm);
  274 + FragmentationMagician.executePendingTransactionsAllowingStateLoss(fm);
  275 + mSupport.getSupportDelegate().mPopMultipleNoAnim = false;
  276 + }
  277 + });
  278 + }
  279 +
  280 + /**
  281 + * Pop the last fragment transition from the manager's fragment pop stack.
  282 + *
  283 + * @param targetFragmentTag Tag
  284 + * @param includeTargetFragment Whether it includes targetFragment
  285 + */
  286 + void popTo(final String targetFragmentTag, final boolean includeTargetFragment, final Runnable afterPopTransactionRunnable, final FragmentManager fm, final int popAnim) {
  287 + enqueue(fm, new Action(Action.ACTION_POP_MOCK) {
  288 + @Override
  289 + public void run() {
  290 + doPopTo(targetFragmentTag, includeTargetFragment, fm, popAnim);
  291 +
  292 + if (afterPopTransactionRunnable != null) {
  293 + afterPopTransactionRunnable.run();
  294 + }
  295 + }
  296 + });
  297 + }
  298 +
  299 + /**
  300 + * Dispatch the pop-event. Priority of the top of the stack of Fragment
  301 + */
  302 + boolean dispatchBackPressedEvent(ISupportFragment activeFragment) {
  303 + if (activeFragment != null) {
  304 + boolean result = activeFragment.onBackPressedSupport();
  305 + if (result) {
  306 + return true;
  307 + }
  308 +
  309 + Fragment parentFragment = ((Fragment) activeFragment).getParentFragment();
  310 + if (dispatchBackPressedEvent((ISupportFragment) parentFragment)) {
  311 + return true;
  312 + }
  313 + }
  314 + return false;
  315 + }
  316 +
  317 + void handleResultRecord(Fragment from) {
  318 + try {
  319 + Bundle args = from.getArguments();
  320 + if (args == null) return;
  321 + final ResultRecord resultRecord = args.getParcelable(FRAGMENTATION_ARG_RESULT_RECORD);
  322 + if (resultRecord == null) return;
  323 +
  324 + ISupportFragment targetFragment = (ISupportFragment) from.getFragmentManager().getFragment(from.getArguments(), FRAGMENTATION_STATE_SAVE_RESULT);
  325 + targetFragment.onFragmentResult(resultRecord.requestCode, resultRecord.resultCode, resultRecord.resultBundle);
  326 + } catch (IllegalStateException ignored) {
  327 + // Fragment no longer exists
  328 + }
  329 + }
  330 +
  331 + private void enqueue(FragmentManager fm, Action action) {
  332 + if (fm == null) {
  333 + Log.w(TAG, "FragmentManager is null, skip the action!");
  334 + return;
  335 + }
  336 + mActionQueue.enqueue(action);
  337 + }
  338 +
  339 + private void doDispatchStartTransaction(FragmentManager fm, ISupportFragment from, ISupportFragment to, int requestCode, int launchMode, int type) {
  340 + checkNotNull(to, "toFragment == null");
  341 +
  342 + if ((type == TYPE_ADD_RESULT || type == TYPE_ADD_RESULT_WITHOUT_HIDE) && from != null) {
  343 + if (!((Fragment) from).isAdded()) {
  344 + Log.w(TAG, ((Fragment) from).getClass().getSimpleName() + " has not been attached yet! startForResult() converted to start()");
  345 + } else {
  346 + saveRequestCode(fm, (Fragment) from, (Fragment) to, requestCode);
  347 + }
  348 + }
  349 +
  350 + from = getTopFragmentForStart(from, fm);
  351 +
  352 + int containerId = getArguments((Fragment) to).getInt(FRAGMENTATION_ARG_CONTAINER, 0);
  353 + if (from == null && containerId == 0) {
  354 + Log.e(TAG, "There is no Fragment in the FragmentManager, maybe you need to call loadRootFragment()!");
  355 + return;
  356 + }
  357 +
  358 + if (from != null && containerId == 0) {
  359 + bindContainerId(from.getSupportDelegate().mContainerId, to);
  360 + }
  361 +
  362 + // process ExtraTransaction
  363 + String toFragmentTag = to.getClass().getName();
  364 + boolean dontAddToBackStack = false;
  365 + ArrayList<TransactionRecord.SharedElement> sharedElementList = null;
  366 + TransactionRecord transactionRecord = to.getSupportDelegate().mTransactionRecord;
  367 + if (transactionRecord != null) {
  368 + if (transactionRecord.tag != null) {
  369 + toFragmentTag = transactionRecord.tag;
  370 + }
  371 + dontAddToBackStack = transactionRecord.dontAddToBackStack;
  372 + if (transactionRecord.sharedElementList != null) {
  373 + sharedElementList = transactionRecord.sharedElementList;
  374 + }
  375 + }
  376 +
  377 + if (handleLaunchMode(fm, from, to, toFragmentTag, launchMode)) return;
  378 +
  379 + start(fm, from, to, toFragmentTag, dontAddToBackStack, sharedElementList, false, type);
  380 + }
  381 +
  382 + private ISupportFragment getTopFragmentForStart(ISupportFragment from, FragmentManager fm) {
  383 + ISupportFragment top;
  384 + if (from == null) {
  385 + top = SupportHelper.getTopFragment(fm);
  386 + } else {
  387 + if (from.getSupportDelegate().mContainerId == 0) {
  388 + Fragment fromF = (Fragment) from;
  389 + if (fromF.getTag() != null && !fromF.getTag().startsWith("android:switcher:")) {
  390 + throw new IllegalStateException("Can't find container, please call loadRootFragment() first!");
  391 + }
  392 + }
  393 + top = SupportHelper.getTopFragment(fm, from.getSupportDelegate().mContainerId);
  394 + }
  395 + return top;
  396 + }
  397 +
  398 + private void start(FragmentManager fm, final ISupportFragment from, ISupportFragment to, String toFragmentTag,
  399 + boolean dontAddToBackStack, ArrayList<TransactionRecord.SharedElement> sharedElementList, boolean allowRootFragmentAnim, int type) {
  400 + FragmentTransaction ft = fm.beginTransaction();
  401 + boolean addMode = (type == TYPE_ADD || type == TYPE_ADD_RESULT || type == TYPE_ADD_WITHOUT_HIDE || type == TYPE_ADD_RESULT_WITHOUT_HIDE);
  402 + Fragment fromF = (Fragment) from;
  403 + Fragment toF = (Fragment) to;
  404 + Bundle args = getArguments(toF);
  405 + args.putBoolean(FRAGMENTATION_ARG_REPLACE, !addMode);
  406 +
  407 + if (sharedElementList == null) {
  408 + if (addMode) { // Replace mode forbidden animation, the replace animations exist overlapping Bug on support-v4.
  409 + TransactionRecord record = to.getSupportDelegate().mTransactionRecord;
  410 + if (record != null && record.targetFragmentEnter != Integer.MIN_VALUE) {
  411 + ft.setCustomAnimations(record.targetFragmentEnter, record.currentFragmentPopExit,
  412 + record.currentFragmentPopEnter, record.targetFragmentExit);
  413 + args.putInt(FRAGMENTATION_ARG_CUSTOM_ENTER_ANIM, record.targetFragmentEnter);
  414 + args.putInt(FRAGMENTATION_ARG_CUSTOM_EXIT_ANIM, record.targetFragmentExit);
  415 + args.putInt(FRAGMENTATION_ARG_CUSTOM_POP_EXIT_ANIM, record.currentFragmentPopExit);
  416 + } else {
  417 + ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
  418 + }
  419 + } else {
  420 + args.putInt(FRAGMENTATION_ARG_ROOT_STATUS, SupportFragmentDelegate.STATUS_ROOT_ANIM_DISABLE);
  421 + }
  422 + } else {
  423 + args.putBoolean(FRAGMENTATION_ARG_IS_SHARED_ELEMENT, true);
  424 + for (TransactionRecord.SharedElement item : sharedElementList) {
  425 + ft.addSharedElement(item.sharedElement, item.sharedName);
  426 + }
  427 + }
  428 + if (from == null) {
  429 + ft.replace(args.getInt(FRAGMENTATION_ARG_CONTAINER), toF, toFragmentTag);
  430 + if (!addMode) {
  431 + ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
  432 + args.putInt(FRAGMENTATION_ARG_ROOT_STATUS, allowRootFragmentAnim ?
  433 + SupportFragmentDelegate.STATUS_ROOT_ANIM_ENABLE : SupportFragmentDelegate.STATUS_ROOT_ANIM_DISABLE);
  434 + }
  435 + } else {
  436 + if (addMode) {
  437 + ft.add(from.getSupportDelegate().mContainerId, toF, toFragmentTag);
  438 + if (type != TYPE_ADD_WITHOUT_HIDE && type != TYPE_ADD_RESULT_WITHOUT_HIDE) {
  439 + ft.hide(fromF);
  440 + }
  441 + } else {
  442 + ft.replace(from.getSupportDelegate().mContainerId, toF, toFragmentTag);
  443 + }
  444 + }
  445 +
  446 + if (!dontAddToBackStack && type != TYPE_REPLACE_DONT_BACK) {
  447 + ft.addToBackStack(toFragmentTag);
  448 + }
  449 + supportCommit(fm, ft);
  450 + }
  451 +
  452 + private void doShowHideFragment(FragmentManager fm, ISupportFragment showFragment, ISupportFragment hideFragment) {
  453 + if (showFragment == hideFragment) return;
  454 +
  455 + FragmentTransaction ft = fm.beginTransaction().show((Fragment) showFragment);
  456 +
  457 + if (hideFragment == null) {
  458 + List<Fragment> fragmentList = FragmentationMagician.getActiveFragments(fm);
  459 + if (fragmentList != null) {
  460 + for (Fragment fragment : fragmentList) {
  461 + if (fragment != null && fragment != showFragment) {
  462 + ft.hide(fragment);
  463 + }
  464 + }
  465 + }
  466 + } else {
  467 + ft.hide((Fragment) hideFragment);
  468 + }
  469 + supportCommit(fm, ft);
  470 + }
  471 +
  472 + private void bindContainerId(int containerId, ISupportFragment to) {
  473 + Bundle args = getArguments((Fragment) to);
  474 + args.putInt(FRAGMENTATION_ARG_CONTAINER, containerId);
  475 + }
  476 +
  477 + private Bundle getArguments(Fragment fragment) {
  478 + Bundle bundle = fragment.getArguments();
  479 + if (bundle == null) {
  480 + bundle = new Bundle();
  481 + fragment.setArguments(bundle);
  482 + }
  483 + return bundle;
  484 + }
  485 +
  486 + private void supportCommit(FragmentManager fm, FragmentTransaction transaction) {
  487 + handleAfterSaveInStateTransactionException(fm, "commit()");
  488 + transaction.commitAllowingStateLoss();
  489 + }
  490 +
  491 + private boolean handleLaunchMode(FragmentManager fm, ISupportFragment topFragment, final ISupportFragment to, String toFragmentTag, int launchMode) {
  492 + if (topFragment == null) return false;
  493 + final ISupportFragment stackToFragment = SupportHelper.findBackStackFragment(to.getClass(), toFragmentTag, fm);
  494 + if (stackToFragment == null) return false;
  495 +
  496 + if (launchMode == ISupportFragment.SINGLETOP) {
  497 + if (to == topFragment || to.getClass().getName().equals(topFragment.getClass().getName())) {
  498 + handleNewBundle(to, stackToFragment);
  499 + return true;
  500 + }
  501 + } else if (launchMode == ISupportFragment.SINGLETASK) {
  502 + doPopTo(toFragmentTag, false, fm, DEFAULT_POPTO_ANIM);
  503 + mHandler.post(new Runnable() {
  504 + @Override
  505 + public void run() {
  506 + handleNewBundle(to, stackToFragment);
  507 + }
  508 + });
  509 + return true;
  510 + }
  511 +
  512 + return false;
  513 + }
  514 +
  515 + private void handleNewBundle(ISupportFragment toFragment, ISupportFragment stackToFragment) {
  516 + Bundle argsNewBundle = toFragment.getSupportDelegate().mNewBundle;
  517 +
  518 + Bundle args = getArguments((Fragment) toFragment);
  519 + if (args.containsKey(FRAGMENTATION_ARG_CONTAINER)) {
  520 + args.remove(FRAGMENTATION_ARG_CONTAINER);
  521 + }
  522 +
  523 + if (argsNewBundle != null) {
  524 + args.putAll(argsNewBundle);
  525 + }
  526 +
  527 + stackToFragment.onNewBundle(args);
  528 + }
  529 +
  530 + /**
  531 + * save requestCode
  532 + */
  533 + private void saveRequestCode(FragmentManager fm, Fragment from, Fragment to, int requestCode) {
  534 + Bundle bundle = getArguments(to);
  535 + ResultRecord resultRecord = new ResultRecord();
  536 + resultRecord.requestCode = requestCode;
  537 + bundle.putParcelable(FRAGMENTATION_ARG_RESULT_RECORD, resultRecord);
  538 + fm.putFragment(bundle, FRAGMENTATION_STATE_SAVE_RESULT, from);
  539 + }
  540 +
  541 + private void doPopTo(final String targetFragmentTag, boolean includeTargetFragment, FragmentManager fm, int popAnim) {
  542 + handleAfterSaveInStateTransactionException(fm, "popTo()");
  543 +
  544 + Fragment targetFragment = fm.findFragmentByTag(targetFragmentTag);
  545 +
  546 + if (targetFragment == null) {
  547 + Log.e(TAG, "Pop failure! Can't find FragmentTag:" + targetFragmentTag + " in the FragmentManager's Stack.");
  548 + return;
  549 + }
  550 +
  551 + int flag = 0;
  552 + if (includeTargetFragment) {
  553 + flag = FragmentManager.POP_BACK_STACK_INCLUSIVE;
  554 + }
  555 +
  556 + List<Fragment> willPopFragments = SupportHelper.getWillPopFragments(fm, targetFragmentTag, includeTargetFragment);
  557 + if (willPopFragments.size() <= 0) return;
  558 +
  559 + Fragment top = willPopFragments.get(0);
  560 + mockPopToAnim(top, targetFragmentTag, fm, flag, willPopFragments, popAnim);
  561 + }
  562 +
  563 + private void safePopTo(String fragmentTag, final FragmentManager fm, int flag, List<Fragment> willPopFragments) {
  564 + mSupport.getSupportDelegate().mPopMultipleNoAnim = true;
  565 +
  566 + FragmentTransaction transaction = fm.beginTransaction()
  567 + .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE);
  568 + for (Fragment fragment : willPopFragments) {
  569 + transaction.remove(fragment);
  570 + }
  571 + transaction.commitAllowingStateLoss();
  572 +
  573 + FragmentationMagician.popBackStackAllowingStateLoss(fm, fragmentTag, flag);
  574 + FragmentationMagician.executePendingTransactionsAllowingStateLoss(fm);
  575 + mSupport.getSupportDelegate().mPopMultipleNoAnim = false;
  576 + }
  577 +
  578 + private void mockPopToAnim(Fragment from, String targetFragmentTag, FragmentManager fm, int flag, List<Fragment> willPopFragments, int popAnim) {
  579 + if (!(from instanceof ISupportFragment)) {
  580 + safePopTo(targetFragmentTag, fm, flag, willPopFragments);
  581 + return;
  582 + }
  583 +
  584 + final ISupportFragment fromSupport = (ISupportFragment) from;
  585 + final ViewGroup container = findContainerById(from, fromSupport.getSupportDelegate().mContainerId);
  586 + if (container == null) return;
  587 +
  588 + final View fromView = from.getView();
  589 + if (fromView == null) return;
  590 +
  591 + container.removeViewInLayout(fromView);
  592 + final ViewGroup mock = addMockView(fromView, container);
  593 +
  594 + safePopTo(targetFragmentTag, fm, flag, willPopFragments);
  595 +
  596 + Animation animation;
  597 + if (popAnim == DEFAULT_POPTO_ANIM) {
  598 + animation = fromSupport.getSupportDelegate().getExitAnim();
  599 + if (animation == null) {
  600 + animation = new Animation() {
  601 + };
  602 + }
  603 + } else if (popAnim == 0) {
  604 + animation = new Animation() {
  605 + };
  606 + } else {
  607 + animation = AnimationUtils.loadAnimation(mActivity, popAnim);
  608 + }
  609 +
  610 + fromView.startAnimation(animation);
  611 + mHandler.postDelayed(new Runnable() {
  612 + @Override
  613 + public void run() {
  614 + try {
  615 + mock.removeViewInLayout(fromView);
  616 + container.removeViewInLayout(mock);
  617 + } catch (Exception ignored) {
  618 + }
  619 + }
  620 + }, animation.getDuration());
  621 + }
  622 +
  623 +
  624 + private void mockStartWithPopAnim(final ISupportFragment from, ISupportFragment to, final Animation exitAnim) {
  625 + final Fragment fromF = (Fragment) from;
  626 + final ViewGroup container = findContainerById(fromF, from.getSupportDelegate().mContainerId);
  627 + if (container == null) return;
  628 +
  629 + final View fromView = fromF.getView();
  630 + if (fromView == null) return;
  631 +
  632 + container.removeViewInLayout(fromView);
  633 + final ViewGroup mock = addMockView(fromView, container);
  634 +
  635 + to.getSupportDelegate().mEnterAnimListener = new SupportFragmentDelegate.EnterAnimListener() {
  636 + @Override
  637 + public void onEnterAnimStart() {
  638 + fromView.startAnimation(exitAnim);
  639 +
  640 + mHandler.postDelayed(new Runnable() {
  641 + @Override
  642 + public void run() {
  643 + try {
  644 + mock.removeViewInLayout(fromView);
  645 + container.removeViewInLayout(mock);
  646 + } catch (Exception ignored) {
  647 + }
  648 + }
  649 + }, exitAnim.getDuration());
  650 + }
  651 + };
  652 + }
  653 +
  654 + @NonNull
  655 + private ViewGroup addMockView(View fromView, ViewGroup container) {
  656 + ViewGroup mock = new ViewGroup(mActivity) {
  657 + @Override
  658 + protected void onLayout(boolean changed, int l, int t, int r, int b) {
  659 + }
  660 + };
  661 +
  662 + mock.addView(fromView);
  663 + container.addView(mock);
  664 + return mock;
  665 + }
  666 +
  667 + private ViewGroup findContainerById(Fragment fragment, int containerId) {
  668 + if (fragment.getView() == null) return null;
  669 +
  670 + View container;
  671 + Fragment parentFragment = fragment.getParentFragment();
  672 + if (parentFragment != null) {
  673 + if (parentFragment.getView() != null) {
  674 + container = parentFragment.getView().findViewById(containerId);
  675 + } else {
  676 + container = findContainerById(parentFragment, containerId);
  677 + }
  678 + } else {
  679 + container = mActivity.findViewById(containerId);
  680 + }
  681 +
  682 + if (container instanceof ViewGroup) {
  683 + return (ViewGroup) container;
  684 + }
  685 +
  686 + return null;
  687 + }
  688 +
  689 + private static <T> void checkNotNull(T value, String message) {
  690 + if (value == null) {
  691 + throw new NullPointerException(message);
  692 + }
  693 + }
  694 +
  695 + private void handleAfterSaveInStateTransactionException(FragmentManager fm, String action) {
  696 + boolean stateSaved = FragmentationMagician.isStateSaved(fm);
  697 + if (stateSaved) {
  698 + AfterSaveStateTransactionWarning e = new AfterSaveStateTransactionWarning(action);
  699 + if (Fragmentation.getDefault().getHandler() != null) {
  700 + Fragmentation.getDefault().getHandler().onException(e);
  701 + }
  702 + }
  703 + }
  704 +}
core/base/src/main/java/com/me/yokeyword/fragmentation/anim/DefaultHorizontalAnimator.java 0 → 100644
  1 +package com.me.yokeyword.fragmentation.anim;
  2 +
  3 +import android.os.Parcel;
  4 +import android.os.Parcelable;
  5 +
  6 +import com.cnlive.strike.base.R;
  7 +
  8 +
  9 +/**
  10 + * Created by YoKeyword on 16/2/5.
  11 + */
  12 +public class DefaultHorizontalAnimator extends FragmentAnimator implements Parcelable {
  13 +
  14 + public DefaultHorizontalAnimator() {
  15 + enter = R.anim.h_fragment_enter;
  16 + exit = R.anim.h_fragment_exit;
  17 + popEnter = R.anim.h_fragment_pop_enter;
  18 + popExit = R.anim.h_fragment_pop_exit;
  19 + }
  20 +
  21 + protected DefaultHorizontalAnimator(Parcel in) {
  22 + super(in);
  23 + }
  24 +
  25 + @Override
  26 + public void writeToParcel(Parcel dest, int flags) {
  27 + super.writeToParcel(dest, flags);
  28 + }
  29 +
  30 + @Override
  31 + public int describeContents() {
  32 + return 0;
  33 + }
  34 +
  35 + public static final Creator<DefaultHorizontalAnimator> CREATOR = new Creator<DefaultHorizontalAnimator>() {
  36 + @Override
  37 + public DefaultHorizontalAnimator createFromParcel(Parcel in) {
  38 + return new DefaultHorizontalAnimator(in);
  39 + }
  40 +
  41 + @Override
  42 + public DefaultHorizontalAnimator[] newArray(int size) {
  43 + return new DefaultHorizontalAnimator[size];
  44 + }
  45 + };
  46 +}
core/base/src/main/java/com/me/yokeyword/fragmentation/anim/DefaultNoAnimator.java 0 → 100644
  1 +package com.me.yokeyword.fragmentation.anim;
  2 +
  3 +
  4 +import android.os.Parcel;
  5 +import android.os.Parcelable;
  6 +
  7 +/**
  8 + * Created by YoKeyword on 16/2/15.
  9 + */
  10 +public class DefaultNoAnimator extends FragmentAnimator implements Parcelable {
  11 + public DefaultNoAnimator() {
  12 + enter = 0;
  13 + exit = 0;
  14 + popEnter = 0;
  15 + popExit = 0;
  16 + }
  17 +
  18 + protected DefaultNoAnimator(Parcel in) {
  19 + super(in);
  20 + }
  21 +
  22 + @Override
  23 + public void writeToParcel(Parcel dest, int flags) {
  24 + super.writeToParcel(dest, flags);
  25 + }
  26 +
  27 + @Override
  28 + public int describeContents() {
  29 + return 0;
  30 + }
  31 +
  32 + public static final Creator<DefaultNoAnimator> CREATOR = new Creator<DefaultNoAnimator>() {
  33 + @Override
  34 + public DefaultNoAnimator createFromParcel(Parcel in) {
  35 + return new DefaultNoAnimator(in);
  36 + }
  37 +
  38 + @Override
  39 + public DefaultNoAnimator[] newArray(int size) {
  40 + return new DefaultNoAnimator[size];
  41 + }
  42 + };
  43 +}
core/base/src/main/java/com/me/yokeyword/fragmentation/anim/DefaultVerticalAnimator.java 0 → 100644
  1 +package com.me.yokeyword.fragmentation.anim;
  2 +
  3 +import android.os.Parcel;
  4 +import android.os.Parcelable;
  5 +
  6 +import com.cnlive.strike.base.R;
  7 +
  8 +
  9 +/**
  10 + * Created by YoKeyword on 16/2/5.
  11 + */
  12 +public class DefaultVerticalAnimator extends FragmentAnimator implements Parcelable {
  13 +
  14 + public DefaultVerticalAnimator() {
  15 + enter = R.anim.v_fragment_enter;
  16 + exit = R.anim.v_fragment_exit;
  17 + popEnter = R.anim.v_fragment_pop_enter;
  18 + popExit = R.anim.v_fragment_pop_exit;
  19 + }
  20 +
  21 + protected DefaultVerticalAnimator(Parcel in) {
  22 + super(in);
  23 + }
  24 +
  25 + @Override
  26 + public void writeToParcel(Parcel dest, int flags) {
  27 + super.writeToParcel(dest, flags);
  28 + }
  29 +
  30 + @Override
  31 + public int describeContents() {
  32 + return 0;
  33 + }
  34 +
  35 + public static final Creator<DefaultVerticalAnimator> CREATOR = new Creator<DefaultVerticalAnimator>() {
  36 + @Override
  37 + public DefaultVerticalAnimator createFromParcel(Parcel in) {
  38 + return new DefaultVerticalAnimator(in);
  39 + }
  40 +
  41 + @Override
  42 + public DefaultVerticalAnimator[] newArray(int size) {
  43 + return new DefaultVerticalAnimator[size];
  44 + }
  45 + };
  46 +}
core/base/src/main/java/com/me/yokeyword/fragmentation/anim/FragmentAnimator.java 0 → 100644
  1 +package com.me.yokeyword.fragmentation.anim;
  2 +
  3 +import android.os.Parcel;
  4 +import android.os.Parcelable;
  5 +
  6 +import androidx.annotation.AnimRes;
  7 +
  8 +/**
  9 + * Fragment动画实体类
  10 + * Created by YoKeyword on 16/2/4.
  11 + */
  12 +public class FragmentAnimator implements Parcelable {
  13 + @AnimRes
  14 + protected int enter;
  15 + @AnimRes
  16 + protected int exit;
  17 + @AnimRes
  18 + protected int popEnter;
  19 + @AnimRes
  20 + protected int popExit;
  21 +
  22 + public FragmentAnimator() {
  23 + }
  24 +
  25 + public FragmentAnimator(int enter, int exit) {
  26 + this.enter = enter;
  27 + this.exit = exit;
  28 + }
  29 +
  30 + public FragmentAnimator(int enter, int exit, int popEnter, int popExit) {
  31 + this.enter = enter;
  32 + this.exit = exit;
  33 + this.popEnter = popEnter;
  34 + this.popExit = popExit;
  35 + }
  36 +
  37 + public FragmentAnimator copy() {
  38 + return new FragmentAnimator(getEnter(), getExit(), getPopEnter(), getPopExit());
  39 + }
  40 +
  41 + protected FragmentAnimator(Parcel in) {
  42 + enter = in.readInt();
  43 + exit = in.readInt();
  44 + popEnter = in.readInt();
  45 + popExit = in.readInt();
  46 + }
  47 +
  48 + public static final Creator<FragmentAnimator> CREATOR = new Creator<FragmentAnimator>() {
  49 + @Override
  50 + public FragmentAnimator createFromParcel(Parcel in) {
  51 + return new FragmentAnimator(in);
  52 + }
  53 +
  54 + @Override
  55 + public FragmentAnimator[] newArray(int size) {
  56 + return new FragmentAnimator[size];
  57 + }
  58 + };
  59 +
  60 + public int getEnter() {
  61 + return enter;
  62 + }
  63 +
  64 + public FragmentAnimator setEnter(int enter) {
  65 + this.enter = enter;
  66 + return this;
  67 + }
  68 +
  69 + public int getExit() {
  70 + return exit;
  71 + }
  72 +
  73 + /**
  74 + * enter animation
  75 + */
  76 + public FragmentAnimator setExit(int exit) {
  77 + this.exit = exit;
  78 + return this;
  79 + }
  80 +
  81 + public int getPopEnter() {
  82 + return popEnter;
  83 + }
  84 +
  85 + public FragmentAnimator setPopEnter(int popEnter) {
  86 + this.popEnter = popEnter;
  87 + return this;
  88 + }
  89 +
  90 + public int getPopExit() {
  91 + return popExit;
  92 + }
  93 +
  94 + public FragmentAnimator setPopExit(int popExit) {
  95 + this.popExit = popExit;
  96 + return this;
  97 + }
  98 +
  99 + @Override
  100 + public int describeContents() {
  101 + return 0;
  102 + }
  103 +
  104 + @Override
  105 + public void writeToParcel(Parcel dest, int flags) {
  106 + dest.writeInt(enter);
  107 + dest.writeInt(exit);
  108 + dest.writeInt(popEnter);
  109 + dest.writeInt(popExit);
  110 + }
  111 +}
core/base/src/main/java/com/me/yokeyword/fragmentation/debug/DebugFragmentRecord.java 0 → 100644
  1 +package com.me.yokeyword.fragmentation.debug;
  2 +
  3 +import java.util.List;
  4 +
  5 +/**
  6 + * 为了调试时 查看栈视图
  7 + * Created by YoKeyword on 16/2/21.
  8 + */
  9 +public class DebugFragmentRecord {
  10 + public CharSequence fragmentName;
  11 + public List<DebugFragmentRecord> childFragmentRecord;
  12 +
  13 + public DebugFragmentRecord(CharSequence fragmentName, List<DebugFragmentRecord> childFragmentRecord) {
  14 + this.fragmentName = fragmentName;
  15 + this.childFragmentRecord = childFragmentRecord;
  16 + }
  17 +}
core/base/src/main/java/com/me/yokeyword/fragmentation/debug/DebugHierarchyViewContainer.java 0 → 100644
  1 +package com.me.yokeyword.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.cnlive.strike.base.R;
  20 +
  21 +import java.util.List;
  22 +
  23 +
  24 +/**
  25 + * Created by YoKeyword on 16/2/21.
  26 + */
  27 +public class DebugHierarchyViewContainer extends ScrollView {
  28 + private Context mContext;
  29 +
  30 + private LinearLayout mLinearLayout;
  31 + private LinearLayout mTitleLayout;
  32 +
  33 + private int mItemHeight;
  34 + private int mPadding;
  35 +
  36 + public DebugHierarchyViewContainer(Context context) {
  37 + super(context);
  38 + initView(context);
  39 + }
  40 +
  41 + public DebugHierarchyViewContainer(Context context, AttributeSet attrs) {
  42 + super(context, attrs);
  43 + initView(context);
  44 + }
  45 +
  46 + public DebugHierarchyViewContainer(Context context, AttributeSet attrs, int defStyleAttr) {
  47 + super(context, attrs, defStyleAttr);
  48 + initView(context);
  49 + }
  50 +
  51 + private void initView(Context context) {
  52 + mContext = context;
  53 + HorizontalScrollView hScrollView = new HorizontalScrollView(context);
  54 + mLinearLayout = new LinearLayout(context);
  55 + mLinearLayout.setOrientation(LinearLayout.VERTICAL);
  56 + hScrollView.addView(mLinearLayout);
  57 + addView(hScrollView);
  58 +
  59 + mItemHeight = dip2px(50);
  60 + mPadding = dip2px(16);
  61 + }
  62 +
  63 + private int dip2px(float dp) {
  64 + float scale = mContext.getResources().getDisplayMetrics().density;
  65 + return (int) (dp * scale + 0.5f);
  66 + }
  67 +
  68 + public void bindFragmentRecords(List<DebugFragmentRecord> fragmentRecords) {
  69 + mLinearLayout.removeAllViews();
  70 + LinearLayout ll = getTitleLayout();
  71 + mLinearLayout.addView(ll);
  72 +
  73 + if (fragmentRecords == null) return;
  74 +
  75 + DebugHierarchyViewContainer.this.setView(fragmentRecords, 0, null);
  76 + }
  77 +
  78 + @NonNull
  79 + private LinearLayout getTitleLayout() {
  80 + if (mTitleLayout != null) return mTitleLayout;
  81 +
  82 + mTitleLayout = new LinearLayout(mContext);
  83 + mTitleLayout.setPadding(dip2px(24), dip2px(24), 0, dip2px(8));
  84 + mTitleLayout.setOrientation(LinearLayout.HORIZONTAL);
  85 + ViewGroup.LayoutParams flParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
  86 + mTitleLayout.setLayoutParams(flParams);
  87 +
  88 + TextView title = new TextView(mContext);
  89 + title.setText(R.string.fragmentation_stack_view);
  90 + title.setTextSize(20);
  91 + title.setTextColor(Color.BLACK);
  92 + LinearLayout.LayoutParams p = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
  93 + p.gravity = Gravity.CENTER_VERTICAL;
  94 + title.setLayoutParams(p);
  95 + mTitleLayout.addView(title);
  96 +
  97 + ImageView img = new ImageView(mContext);
  98 + img.setImageResource(R.drawable.fragmentation_help);
  99 + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
  100 + params.leftMargin = dip2px(16);
  101 + params.gravity = Gravity.CENTER_VERTICAL;
  102 + img.setLayoutParams(params);
  103 + mTitleLayout.setOnClickListener(new OnClickListener() {
  104 + @Override
  105 + public void onClick(View v) {
  106 + Toast.makeText(mContext, R.string.fragmentation_stack_help, Toast.LENGTH_LONG).show();
  107 + }
  108 + });
  109 + mTitleLayout.addView(img);
  110 + return mTitleLayout;
  111 + }
  112 +
  113 + private void setView(final List<DebugFragmentRecord> fragmentRecordList, final int hierarchy, final TextView tvItem) {
  114 + for (int i = fragmentRecordList.size() - 1; i >= 0; i--) {
  115 + DebugFragmentRecord child = fragmentRecordList.get(i);
  116 + int tempHierarchy = hierarchy;
  117 +
  118 + final TextView childTvItem;
  119 + childTvItem = getTextView(child, tempHierarchy);
  120 + childTvItem.setTag(R.id.hierarchy, tempHierarchy);
  121 +
  122 + final List<DebugFragmentRecord> childFragmentRecord = child.childFragmentRecord;
  123 + if (childFragmentRecord != null && childFragmentRecord.size() > 0) {
  124 + tempHierarchy++;
  125 + childTvItem.setCompoundDrawablesWithIntrinsicBounds(R.drawable.fragmentation_ic_right, 0, 0, 0);
  126 + final int finalChilHierarchy = tempHierarchy;
  127 + childTvItem.setOnClickListener(new OnClickListener() {
  128 + @Override
  129 + public void onClick(View v) {
  130 + if (v.getTag(R.id.isexpand) != null) {
  131 + boolean isExpand = (boolean) v.getTag(R.id.isexpand);
  132 + if (isExpand) {
  133 + childTvItem.setCompoundDrawablesWithIntrinsicBounds(R.drawable.fragmentation_ic_right, 0, 0, 0);
  134 + DebugHierarchyViewContainer.this.removeView(finalChilHierarchy);
  135 + } else {
  136 + handleExpandView(childFragmentRecord, finalChilHierarchy, childTvItem);
  137 +
  138 + }
  139 + v.setTag(R.id.isexpand, !isExpand);
  140 + } else {
  141 + childTvItem.setTag(R.id.isexpand, true);
  142 + handleExpandView(childFragmentRecord, finalChilHierarchy, childTvItem);
  143 + }
  144 + }
  145 + });
  146 + } else {
  147 + childTvItem.setPadding(childTvItem.getPaddingLeft() + mPadding, 0, mPadding, 0);
  148 + }
  149 +
  150 + if (tvItem == null) {
  151 + mLinearLayout.addView(childTvItem);
  152 + } else {
  153 + mLinearLayout.addView(childTvItem, mLinearLayout.indexOfChild(tvItem) + 1);
  154 + }
  155 + }
  156 + }
  157 +
  158 + private void handleExpandView(List<DebugFragmentRecord> childFragmentRecord, int finalChilHierarchy, TextView childTvItem) {
  159 + DebugHierarchyViewContainer.this.setView(childFragmentRecord, finalChilHierarchy, childTvItem);
  160 + childTvItem.setCompoundDrawablesWithIntrinsicBounds(R.drawable.fragmentation_ic_expandable, 0, 0, 0);
  161 + }
  162 +
  163 + private void removeView(int hierarchy) {
  164 + int size = mLinearLayout.getChildCount();
  165 + for (int i = size - 1; i >= 0; i--) {
  166 + View view = mLinearLayout.getChildAt(i);
  167 + if (view.getTag(R.id.hierarchy) != null && (int) view.getTag(R.id.hierarchy) >= hierarchy) {
  168 + mLinearLayout.removeView(view);
  169 + }
  170 + }
  171 + }
  172 +
  173 + private TextView getTextView(DebugFragmentRecord fragmentRecord, int hierarchy) {
  174 + TextView tvItem = new TextView(mContext);
  175 +
  176 + ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, mItemHeight);
  177 + tvItem.setLayoutParams(params);
  178 + if (hierarchy == 0) {
  179 + tvItem.setTextColor(Color.parseColor("#333333"));
  180 + tvItem.setTextSize(16);
  181 + }
  182 + tvItem.setGravity(Gravity.CENTER_VERTICAL);
  183 + tvItem.setPadding((int) (mPadding + hierarchy * mPadding * 1.5), 0, mPadding, 0);
  184 + tvItem.setCompoundDrawablePadding(mPadding / 2);
  185 +
  186 + TypedArray a = mContext.obtainStyledAttributes(new int[]{android.R.attr.selectableItemBackground});
  187 + tvItem.setBackgroundDrawable(a.getDrawable(0));
  188 + a.recycle();
  189 +
  190 + tvItem.setText(fragmentRecord.fragmentName);
  191 +
  192 + return tvItem;
  193 + }
  194 +}
core/base/src/main/java/com/me/yokeyword/fragmentation/debug/DebugStackDelegate.java 0 → 100644
  1 +package com.me.yokeyword.fragmentation.debug;
  2 +
  3 +import android.content.Context;
  4 +import android.hardware.Sensor;
  5 +import android.hardware.SensorEvent;
  6 +import android.hardware.SensorEventListener;
  7 +import android.hardware.SensorManager;
  8 +import android.util.Log;
  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 +import androidx.fragment.app.FragmentManager;
  22 +import androidx.fragment.app.FragmentationMagician;
  23 +
  24 +import com.cnlive.strike.base.R;
  25 +import com.me.yokeyword.fragmentation.Fragmentation;
  26 +import com.me.yokeyword.fragmentation.ISupportFragment;
  27 +
  28 +import java.util.ArrayList;
  29 +import java.util.List;
  30 +
  31 +
  32 +/**
  33 + * Created by YoKey on 17/6/13.
  34 + */
  35 +
  36 +public class DebugStackDelegate implements SensorEventListener {
  37 + private FragmentActivity mActivity;
  38 + private SensorManager mSensorManager;
  39 + private AlertDialog mStackDialog;
  40 +
  41 + public DebugStackDelegate(FragmentActivity activity) {
  42 + this.mActivity = activity;
  43 + }
  44 +
  45 + public void onCreate(int mode) {
  46 + if (mode != Fragmentation.SHAKE) return;
  47 + mSensorManager = (SensorManager) mActivity.getSystemService(Context.SENSOR_SERVICE);
  48 + mSensorManager.registerListener(this,
  49 + mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
  50 + SensorManager.SENSOR_DELAY_NORMAL);
  51 + }
  52 +
  53 + public void onPostCreate(int mode) {
  54 + if (mode != Fragmentation.BUBBLE) return;
  55 + View root = mActivity.findViewById(android.R.id.content);
  56 + if (root instanceof FrameLayout) {
  57 + FrameLayout content = (FrameLayout) root;
  58 + final ImageView stackView = new ImageView(mActivity);
  59 + stackView.setImageResource(R.drawable.fragmentation_ic_stack);
  60 + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
  61 + params.gravity = Gravity.END;
  62 + final int dp18 = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 18, mActivity.getResources().getDisplayMetrics());
  63 + params.topMargin = dp18 * 7;
  64 + params.rightMargin = dp18;
  65 + stackView.setLayoutParams(params);
  66 + content.addView(stackView);
  67 + stackView.setOnTouchListener(new StackViewTouchListener(stackView, dp18 / 4));
  68 + stackView.setOnClickListener(new View.OnClickListener() {
  69 + @Override
  70 + public void onClick(View v) {
  71 + showFragmentStackHierarchyView();
  72 + }
  73 + });
  74 + }
  75 + }
  76 +
  77 + public void onDestroy() {
  78 + if (mSensorManager != null) {
  79 + mSensorManager.unregisterListener(this);
  80 + }
  81 + }
  82 +
  83 + @Override
  84 + public void onSensorChanged(SensorEvent event) {
  85 + int sensorType = event.sensor.getType();
  86 + float[] values = event.values;
  87 + if (sensorType == Sensor.TYPE_ACCELEROMETER) {
  88 + int value = 12;
  89 + if ((Math.abs(values[0]) >= value || Math.abs(values[1]) >= value || Math.abs(values[2]) >= value)) {
  90 + showFragmentStackHierarchyView();
  91 + }
  92 + }
  93 + }
  94 +
  95 + @Override
  96 + public void onAccuracyChanged(Sensor sensor, int accuracy) {
  97 + }
  98 +
  99 + /**
  100 + * 调试相关:以dialog形式 显示 栈视图
  101 + */
  102 + public void showFragmentStackHierarchyView() {
  103 + if (mStackDialog != null && mStackDialog.isShowing()) return;
  104 + DebugHierarchyViewContainer container = new DebugHierarchyViewContainer(mActivity);
  105 + container.bindFragmentRecords(getFragmentRecords());
  106 + container.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
  107 + mStackDialog = new AlertDialog.Builder(mActivity)
  108 + .setView(container)
  109 + .setPositiveButton(android.R.string.cancel, null)
  110 + .setCancelable(true)
  111 + .create();
  112 + mStackDialog.show();
  113 + }
  114 +
  115 + /**
  116 + * 调试相关:以log形式 打印 栈视图
  117 + */
  118 + public void logFragmentRecords(String tag) {
  119 + List<DebugFragmentRecord> fragmentRecordList = getFragmentRecords();
  120 + if (fragmentRecordList == null) return;
  121 +
  122 + StringBuilder sb = new StringBuilder();
  123 +
  124 + for (int i = fragmentRecordList.size() - 1; i >= 0; i--) {
  125 + DebugFragmentRecord fragmentRecord = fragmentRecordList.get(i);
  126 +
  127 + if (i == fragmentRecordList.size() - 1) {
  128 + sb.append("═══════════════════════════════════════════════════════════════════════════════════\n");
  129 + if (i == 0) {
  130 + sb.append("\t栈顶\t\t\t").append(fragmentRecord.fragmentName).append("\n");
  131 + sb.append("═══════════════════════════════════════════════════════════════════════════════════");
  132 + } else {
  133 + sb.append("\t栈顶\t\t\t").append(fragmentRecord.fragmentName).append("\n\n");
  134 + }
  135 + } else if (i == 0) {
  136 + sb.append("\t栈底\t\t\t").append(fragmentRecord.fragmentName).append("\n\n");
  137 + processChildLog(fragmentRecord.childFragmentRecord, sb, 1);
  138 + sb.append("═══════════════════════════════════════════════════════════════════════════════════");
  139 + Log.i(tag, sb.toString());
  140 + return;
  141 + } else {
  142 + sb.append("\t↓\t\t\t").append(fragmentRecord.fragmentName).append("\n\n");
  143 + }
  144 +
  145 + processChildLog(fragmentRecord.childFragmentRecord, sb, 1);
  146 + }
  147 + }
  148 +
  149 + private List<DebugFragmentRecord> getFragmentRecords() {
  150 + List<DebugFragmentRecord> fragmentRecordList = new ArrayList<>();
  151 +
  152 + List<Fragment> fragmentList = FragmentationMagician.getActiveFragments(mActivity.getSupportFragmentManager());
  153 +
  154 + if (fragmentList == null || fragmentList.size() < 1) return null;
  155 +
  156 + for (Fragment fragment : fragmentList) {
  157 + addDebugFragmentRecord(fragmentRecordList, fragment);
  158 + }
  159 + return fragmentRecordList;
  160 + }
  161 +
  162 + private void processChildLog(List<DebugFragmentRecord> fragmentRecordList, StringBuilder sb, int childHierarchy) {
  163 + if (fragmentRecordList == null || fragmentRecordList.size() == 0) return;
  164 +
  165 + for (int j = 0; j < fragmentRecordList.size(); j++) {
  166 + DebugFragmentRecord childFragmentRecord = fragmentRecordList.get(j);
  167 + for (int k = 0; k < childHierarchy; k++) {
  168 + sb.append("\t\t\t");
  169 + }
  170 + if (j == 0) {
  171 + sb.append("\t子栈顶\t\t").append(childFragmentRecord.fragmentName).append("\n\n");
  172 + } else if (j == fragmentRecordList.size() - 1) {
  173 + sb.append("\t子栈底\t\t").append(childFragmentRecord.fragmentName).append("\n\n");
  174 + processChildLog(childFragmentRecord.childFragmentRecord, sb, ++childHierarchy);
  175 + return;
  176 + } else {
  177 + sb.append("\t↓\t\t\t").append(childFragmentRecord.fragmentName).append("\n\n");
  178 + }
  179 +
  180 + processChildLog(childFragmentRecord.childFragmentRecord, sb, childHierarchy);
  181 + }
  182 + }
  183 +
  184 + private List<DebugFragmentRecord> getChildFragmentRecords(Fragment parentFragment) {
  185 + List<DebugFragmentRecord> fragmentRecords = new ArrayList<>();
  186 +
  187 + List<Fragment> fragmentList = FragmentationMagician.getActiveFragments(parentFragment.getChildFragmentManager());
  188 + if (fragmentList == null || fragmentList.size() < 1) return null;
  189 +
  190 + for (int i = fragmentList.size() - 1; i >= 0; i--) {
  191 + Fragment fragment = fragmentList.get(i);
  192 + addDebugFragmentRecord(fragmentRecords, fragment);
  193 + }
  194 + return fragmentRecords;
  195 + }
  196 +
  197 + private void addDebugFragmentRecord(List<DebugFragmentRecord> fragmentRecords, Fragment fragment) {
  198 + if (fragment != null) {
  199 + int backStackCount = fragment.getFragmentManager().getBackStackEntryCount();
  200 + CharSequence name = fragment.getClass().getSimpleName();
  201 + if (backStackCount == 0) {
  202 + name = span(name, " *");
  203 + } else {
  204 + for (int j = 0; j < backStackCount; j++) {
  205 + FragmentManager.BackStackEntry entry = fragment.getFragmentManager().getBackStackEntryAt(j);
  206 + if ((entry.getName() != null && entry.getName().equals(fragment.getTag()))
  207 + || (entry.getName() == null && fragment.getTag() == null)) {
  208 + break;
  209 + }
  210 + if (j == backStackCount - 1) {
  211 + name = span(name, " *");
  212 + }
  213 + }
  214 + }
  215 +
  216 + if (fragment instanceof ISupportFragment && ((ISupportFragment)fragment).isSupportVisible()) {
  217 + name = span(name, " ☀");
  218 + }
  219 +
  220 + fragmentRecords.add(new DebugFragmentRecord(name, getChildFragmentRecords(fragment)));
  221 + }
  222 + }
  223 +
  224 + @NonNull
  225 + private CharSequence span(CharSequence name, String str) {
  226 + name = name + str;
  227 + return name;
  228 + }
  229 +
  230 + private class StackViewTouchListener implements View.OnTouchListener {
  231 + private View stackView;
  232 + private float dX, dY = 0f;
  233 + private float downX, downY = 0f;
  234 + private boolean isClickState;
  235 + private int clickLimitValue;
  236 +
  237 + StackViewTouchListener(View stackView, int clickLimitValue) {
  238 + this.stackView = stackView;
  239 + this.clickLimitValue = clickLimitValue;
  240 + }
  241 +
  242 + @Override
  243 + public boolean onTouch(View v, MotionEvent event) {
  244 + float X = event.getRawX();
  245 + float Y = event.getRawY();
  246 + switch (event.getAction()) {
  247 + case MotionEvent.ACTION_DOWN:
  248 + isClickState = true;
  249 + downX = X;
  250 + downY = Y;
  251 + dX = stackView.getX() - event.getRawX();
  252 + dY = stackView.getY() - event.getRawY();
  253 + break;
  254 + case MotionEvent.ACTION_MOVE:
  255 + if (Math.abs(X - downX) < clickLimitValue && Math.abs(Y - downY) < clickLimitValue && isClickState) {
  256 + isClickState = true;
  257 + } else {
  258 + isClickState = false;
  259 + stackView.setX(event.getRawX() + dX);
  260 + stackView.setY(event.getRawY() + dY);
  261 + }
  262 + break;
  263 + case MotionEvent.ACTION_CANCEL:
  264 + case MotionEvent.ACTION_UP:
  265 + if (X - downX < clickLimitValue && isClickState) {
  266 + stackView.performClick();
  267 + }
  268 + break;
  269 + default:
  270 + return false;
  271 + }
  272 + return true;
  273 + }
  274 + }
  275 +}
core/base/src/main/java/com/me/yokeyword/fragmentation/exception/AfterSaveStateTransactionWarning.java 0 → 100644
  1 +package com.me.yokeyword.fragmentation.exception;
  2 +
  3 +import android.util.Log;
  4 +
  5 +/**
  6 + * Perform the transaction action after onSaveInstanceState.
  7 + * <p>
  8 + * This is dangerous because the action can
  9 + * be lost if the activity needs to later be restored from its state.
  10 + * <p>
  11 + * <p>
  12 + * If you don't want to lost the action:
  13 + * <p>
  14 + * // // ReceiverActivity or Fragment:
  15 + * // void start() {
  16 + * // startActivityForResult(new Intent(this, SenderActivity.class), 100);
  17 + * // }
  18 + * //
  19 + * // @Override
  20 + * // protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  21 + * // super.onActivityResult(requestCode, resultCode, data);
  22 + * // if (requestCode == 100 && resultCode == 100) {
  23 + * // // begin transaction
  24 + * // }
  25 + * // }
  26 + * //
  27 + * // // SenderActivity or Fragment:
  28 + * // void do(){ // Let ReceiverActivity(or Fragment)begin transaction
  29 + * // setResult(100);
  30 + * // finish();
  31 + * // }
  32 + * <p>
  33 + * Created by YoKey on 17/12/26.
  34 + */
  35 +public class AfterSaveStateTransactionWarning extends RuntimeException {
  36 +
  37 + public AfterSaveStateTransactionWarning(String action) {
  38 + super("Warning: Perform this " + action + " action after onSaveInstanceState!");
  39 + Log.w("Fragmentation", getMessage());
  40 + }
  41 +
  42 +}
core/base/src/main/java/com/me/yokeyword/fragmentation/helper/ExceptionHandler.java 0 → 100644
  1 +package com.me.yokeyword.fragmentation.helper;
  2 +
  3 +import androidx.annotation.NonNull;
  4 +
  5 +/**
  6 + * Created by YoKey on 17/2/5.
  7 + */
  8 +public interface ExceptionHandler {
  9 + void onException(@NonNull Exception e);
  10 +}
core/base/src/main/java/com/me/yokeyword/fragmentation/helper/internal/AnimatorHelper.java 0 → 100644
  1 +package com.me.yokeyword.fragmentation.helper.internal;
  2 +
  3 +import android.content.Context;
  4 +import android.view.animation.Animation;
  5 +import android.view.animation.AnimationUtils;
  6 +
  7 +import androidx.annotation.Nullable;
  8 +import androidx.fragment.app.Fragment;
  9 +
  10 +import com.cnlive.strike.base.R;
  11 +import com.me.yokeyword.fragmentation.anim.FragmentAnimator;
  12 +
  13 +
  14 +/**
  15 + * @Hide Created by YoKeyword on 16/7/26.
  16 + */
  17 +public final class AnimatorHelper {
  18 + private Animation noneAnim, noneAnimFixed;
  19 + public Animation enterAnim, exitAnim, popEnterAnim, popExitAnim;
  20 +
  21 + private Context context;
  22 + private FragmentAnimator fragmentAnimator;
  23 +
  24 + public AnimatorHelper(Context context, FragmentAnimator fragmentAnimator) {
  25 + this.context = context;
  26 + notifyChanged(fragmentAnimator);
  27 + }
  28 +
  29 + public void notifyChanged(FragmentAnimator fragmentAnimator) {
  30 + this.fragmentAnimator = fragmentAnimator;
  31 + initEnterAnim();
  32 + initExitAnim();
  33 + initPopEnterAnim();
  34 + initPopExitAnim();
  35 + }
  36 +
  37 + public Animation getNoneAnim() {
  38 + if (noneAnim == null) {
  39 + noneAnim = AnimationUtils.loadAnimation(context, R.anim.no_anim);
  40 + }
  41 + return noneAnim;
  42 + }
  43 +
  44 + public Animation getNoneAnimFixed() {
  45 + if (noneAnimFixed == null) {
  46 + noneAnimFixed = new Animation() {
  47 + };
  48 + }
  49 + return noneAnimFixed;
  50 + }
  51 +
  52 + @Nullable
  53 + public Animation compatChildFragmentExitAnim(Fragment fragment) {
  54 + if ((fragment.getTag() != null && fragment.getTag().startsWith("android:switcher:") && fragment.getUserVisibleHint()) ||
  55 + (fragment.getParentFragment() != null && fragment.getParentFragment().isRemoving() && !fragment.isHidden())) {
  56 + Animation animation = new Animation() {
  57 + };
  58 + animation.setDuration(exitAnim.getDuration());
  59 + return animation;
  60 + }
  61 + return null;
  62 + }
  63 +
  64 + private Animation initEnterAnim() {
  65 + if (fragmentAnimator.getEnter() == 0) {
  66 + enterAnim = AnimationUtils.loadAnimation(context, R.anim.no_anim);
  67 + } else {
  68 + enterAnim = AnimationUtils.loadAnimation(context, fragmentAnimator.getEnter());
  69 + }
  70 + return enterAnim;
  71 + }
  72 +
  73 + private Animation initExitAnim() {
  74 + if (fragmentAnimator.getExit() == 0) {
  75 + exitAnim = AnimationUtils.loadAnimation(context, R.anim.no_anim);
  76 + } else {
  77 + exitAnim = AnimationUtils.loadAnimation(context, fragmentAnimator.getExit());
  78 + }
  79 + return exitAnim;
  80 + }
  81 +
  82 + private Animation initPopEnterAnim() {
  83 + if (fragmentAnimator.getPopEnter() == 0) {
  84 + popEnterAnim = AnimationUtils.loadAnimation(context, R.anim.no_anim);
  85 + } else {
  86 + popEnterAnim = AnimationUtils.loadAnimation(context, fragmentAnimator.getPopEnter());
  87 + }
  88 + return popEnterAnim;
  89 + }
  90 +
  91 + private Animation initPopExitAnim() {
  92 + if (fragmentAnimator.getPopExit() == 0) {
  93 + popExitAnim = AnimationUtils.loadAnimation(context, R.anim.no_anim);
  94 + } else {
  95 + popExitAnim = AnimationUtils.loadAnimation(context, fragmentAnimator.getPopExit());
  96 + }
  97 + return popExitAnim;
  98 + }
  99 +}
core/base/src/main/java/com/me/yokeyword/fragmentation/helper/internal/ResultRecord.java 0 → 100644
  1 +package com.me.yokeyword.fragmentation.helper.internal;
  2 +
  3 +import android.os.Bundle;
  4 +import android.os.Parcel;
  5 +import android.os.Parcelable;
  6 +
  7 +/**
  8 + * @Hide
  9 + * Result 记录
  10 + * Created by YoKeyword on 16/6/2.
  11 + */
  12 +public final class ResultRecord implements Parcelable {
  13 + public int requestCode;
  14 + public int resultCode = 0;
  15 + public Bundle resultBundle;
  16 +
  17 + public ResultRecord() {
  18 + }
  19 +
  20 + protected ResultRecord(Parcel in) {
  21 + requestCode = in.readInt();
  22 + resultCode = in.readInt();
  23 + resultBundle = in.readBundle(getClass().getClassLoader());
  24 + }
  25 +
  26 + public static final Creator<ResultRecord> CREATOR = new Creator<ResultRecord>() {
  27 + @Override
  28 + public ResultRecord createFromParcel(Parcel in) {
  29 + return new ResultRecord(in);
  30 + }
  31 +
  32 + @Override
  33 + public ResultRecord[] newArray(int size) {
  34 + return new ResultRecord[size];
  35 + }
  36 + };
  37 +
  38 + @Override
  39 + public int describeContents() {
  40 + return 0;
  41 + }
  42 +
  43 + @Override
  44 + public void writeToParcel(Parcel dest, int flags) {
  45 + dest.writeInt(requestCode);
  46 + dest.writeInt(resultCode);
  47 + dest.writeBundle(resultBundle);
  48 + }
  49 +}
core/base/src/main/java/com/me/yokeyword/fragmentation/helper/internal/TransactionRecord.java 0 → 100644
  1 +package com.me.yokeyword.fragmentation.helper.internal;
  2 +
  3 +import android.view.View;
  4 +
  5 +import java.util.ArrayList;
  6 +
  7 +/**
  8 + * @hide Created by YoKey on 16/11/25.
  9 + */
  10 +public final class TransactionRecord {
  11 + public String tag;
  12 + public int targetFragmentEnter = Integer.MIN_VALUE;
  13 + public int currentFragmentPopExit = Integer.MIN_VALUE;
  14 + public int currentFragmentPopEnter = Integer.MIN_VALUE;
  15 + public int targetFragmentExit = Integer.MIN_VALUE;
  16 + public boolean dontAddToBackStack = false;
  17 + public ArrayList<SharedElement> sharedElementList;
  18 +
  19 + public static class SharedElement {
  20 + public View sharedElement;
  21 + public String sharedName;
  22 +
  23 + public SharedElement(View sharedElement, String sharedName) {
  24 + this.sharedElement = sharedElement;
  25 + this.sharedName = sharedName;
  26 + }
  27 + }
  28 +}
core/base/src/main/java/com/me/yokeyword/fragmentation/helper/internal/VisibleDelegate.java 0 → 100644
  1 +package com.me.yokeyword.fragmentation.helper.internal;
  2 +
  3 +import android.os.Bundle;
  4 +import android.os.Handler;
  5 +import android.os.Looper;
  6 +
  7 +import androidx.annotation.Nullable;
  8 +import androidx.fragment.app.Fragment;
  9 +import androidx.fragment.app.FragmentManager;
  10 +import androidx.fragment.app.FragmentationMagician;
  11 +
  12 +import com.me.yokeyword.fragmentation.ISupportFragment;
  13 +
  14 +import java.util.List;
  15 +
  16 +
  17 +/**
  18 + * Created by YoKey on 17/4/4.
  19 + */
  20 +
  21 +public class VisibleDelegate {
  22 + private static final String FRAGMENTATION_STATE_SAVE_IS_INVISIBLE_WHEN_LEAVE = "fragmentation_invisible_when_leave";
  23 + private static final String FRAGMENTATION_STATE_SAVE_COMPAT_REPLACE = "fragmentation_compat_replace";
  24 +
  25 + // SupportVisible相关
  26 + private boolean mIsSupportVisible;
  27 + private boolean mNeedDispatch = true;
  28 + private boolean mInvisibleWhenLeave;
  29 + private boolean mIsFirstVisible = true;
  30 + private boolean mFirstCreateViewCompatReplace = true;
  31 + private boolean mAbortInitVisible = false;
  32 + private Runnable taskDispatchSupportVisible;
  33 +
  34 + private Handler mHandler;
  35 + private Bundle mSaveInstanceState;
  36 +
  37 + private ISupportFragment mSupportF;
  38 + private Fragment mFragment;
  39 +
  40 + public VisibleDelegate(ISupportFragment fragment) {
  41 + this.mSupportF = fragment;
  42 + this.mFragment = (Fragment) fragment;
  43 + }
  44 +
  45 + public void onCreate(@Nullable Bundle savedInstanceState) {
  46 + if (savedInstanceState != null) {
  47 + mSaveInstanceState = savedInstanceState;
  48 + // setUserVisibleHint() may be called before onCreate()
  49 + mInvisibleWhenLeave = savedInstanceState.getBoolean(FRAGMENTATION_STATE_SAVE_IS_INVISIBLE_WHEN_LEAVE);
  50 + mFirstCreateViewCompatReplace = savedInstanceState.getBoolean(FRAGMENTATION_STATE_SAVE_COMPAT_REPLACE);
  51 + }
  52 + }
  53 +
  54 + public void onSaveInstanceState(Bundle outState) {
  55 + outState.putBoolean(FRAGMENTATION_STATE_SAVE_IS_INVISIBLE_WHEN_LEAVE, mInvisibleWhenLeave);
  56 + outState.putBoolean(FRAGMENTATION_STATE_SAVE_COMPAT_REPLACE, mFirstCreateViewCompatReplace);
  57 + }
  58 +
  59 + public void onActivityCreated(@Nullable Bundle savedInstanceState) {
  60 + if (!mFirstCreateViewCompatReplace && mFragment.getTag() != null && mFragment.getTag().startsWith("android:switcher:")) {
  61 + return;
  62 + }
  63 +
  64 + if (mFirstCreateViewCompatReplace) {
  65 + mFirstCreateViewCompatReplace = false;
  66 + }
  67 +
  68 + initVisible();
  69 + }
  70 +
  71 + private void initVisible() {
  72 + if (!mInvisibleWhenLeave && !mFragment.isHidden() && mFragment.getUserVisibleHint()) {
  73 + if ((mFragment.getParentFragment() != null && isFragmentVisible(mFragment.getParentFragment()))
  74 + || mFragment.getParentFragment() == null) {
  75 + mNeedDispatch = false;
  76 + safeDispatchUserVisibleHint(true);
  77 + }
  78 + }
  79 + }
  80 +
  81 + public void onResume() {
  82 + if (!mIsFirstVisible) {
  83 + if (!mIsSupportVisible && !mInvisibleWhenLeave && isFragmentVisible(mFragment)) {
  84 + mNeedDispatch = false;
  85 + dispatchSupportVisible(true);
  86 + }
  87 + } else {
  88 + if (mAbortInitVisible) {
  89 + mAbortInitVisible = false;
  90 + initVisible();
  91 + }
  92 + }
  93 + }
  94 +
  95 + public void onPause() {
  96 + if (taskDispatchSupportVisible != null) {
  97 + getHandler().removeCallbacks(taskDispatchSupportVisible);
  98 + mAbortInitVisible = true;
  99 + return;
  100 + }
  101 +
  102 + if (mIsSupportVisible && isFragmentVisible(mFragment)) {
  103 + mNeedDispatch = false;
  104 + mInvisibleWhenLeave = false;
  105 + dispatchSupportVisible(false);
  106 + } else {
  107 + mInvisibleWhenLeave = true;
  108 + }
  109 + }
  110 +
  111 + public void onHiddenChanged(boolean hidden) {
  112 + if (!hidden && !mFragment.isResumed()) {
  113 + //if fragment is shown but not resumed, ignore...
  114 + onFragmentShownWhenNotResumed();
  115 + return;
  116 + }
  117 + if (hidden) {
  118 + safeDispatchUserVisibleHint(false);
  119 + } else {
  120 + enqueueDispatchVisible();
  121 + }
  122 + }
  123 +
  124 + private void onFragmentShownWhenNotResumed() {
  125 + mInvisibleWhenLeave = false;
  126 + dispatchChildOnFragmentShownWhenNotResumed();
  127 + }
  128 +
  129 + private void dispatchChildOnFragmentShownWhenNotResumed() {
  130 + FragmentManager fragmentManager = mFragment.getChildFragmentManager();
  131 + List<Fragment> childFragments = FragmentationMagician.getActiveFragments(fragmentManager);
  132 + if (childFragments != null) {
  133 + for (Fragment child : childFragments) {
  134 + if (child instanceof ISupportFragment && !child.isHidden() && child.getUserVisibleHint()) {
  135 + ((ISupportFragment) child).getSupportDelegate().getVisibleDelegate().onFragmentShownWhenNotResumed();
  136 + }
  137 + }
  138 + }
  139 + }
  140 +
  141 + public void onDestroyView() {
  142 + mIsFirstVisible = true;
  143 + }
  144 +
  145 + public void setUserVisibleHint(boolean isVisibleToUser) {
  146 + if (mFragment.isResumed() || (!mFragment.isAdded() && isVisibleToUser)) {
  147 + if (!mIsSupportVisible && isVisibleToUser) {
  148 + safeDispatchUserVisibleHint(true);
  149 + } else if (mIsSupportVisible && !isVisibleToUser) {
  150 + dispatchSupportVisible(false);
  151 + }
  152 + }
  153 + }
  154 +
  155 + private void safeDispatchUserVisibleHint(boolean visible) {
  156 + if (mIsFirstVisible) {
  157 + if (!visible) return;
  158 + enqueueDispatchVisible();
  159 + } else {
  160 + dispatchSupportVisible(visible);
  161 + }
  162 + }
  163 +
  164 + private void enqueueDispatchVisible() {
  165 + taskDispatchSupportVisible = new Runnable() {
  166 + @Override
  167 + public void run() {
  168 + taskDispatchSupportVisible = null;
  169 + dispatchSupportVisible(true);
  170 + }
  171 + };
  172 + getHandler().post(taskDispatchSupportVisible);
  173 + }
  174 +
  175 + private void dispatchSupportVisible(boolean visible) {
  176 + if (visible && isParentInvisible()) return;
  177 +
  178 + if (mIsSupportVisible == visible) {
  179 + mNeedDispatch = true;
  180 + return;
  181 + }
  182 +
  183 + mIsSupportVisible = visible;
  184 +
  185 + if (visible) {
  186 + if (checkAddState()) return;
  187 + mSupportF.onSupportVisible();
  188 +
  189 + if (mIsFirstVisible) {
  190 + mIsFirstVisible = false;
  191 + mSupportF.onLazyInitView(mSaveInstanceState);
  192 + }
  193 + dispatchChild(true);
  194 + } else {
  195 + dispatchChild(false);
  196 + mSupportF.onSupportInvisible();
  197 + }
  198 + }
  199 +
  200 + private void dispatchChild(boolean visible) {
  201 + if (!mNeedDispatch) {
  202 + mNeedDispatch = true;
  203 + } else {
  204 + if (checkAddState()) return;
  205 + FragmentManager fragmentManager = mFragment.getChildFragmentManager();
  206 + List<Fragment> childFragments = FragmentationMagician.getActiveFragments(fragmentManager);
  207 + if (childFragments != null) {
  208 + for (Fragment child : childFragments) {
  209 + if (child instanceof ISupportFragment && !child.isHidden() && child.getUserVisibleHint()) {
  210 + ((ISupportFragment) child).getSupportDelegate().getVisibleDelegate().dispatchSupportVisible(visible);
  211 + }
  212 + }
  213 + }
  214 + }
  215 + }
  216 +
  217 + private boolean isParentInvisible() {
  218 + Fragment parentFragment = mFragment.getParentFragment();
  219 +
  220 + if (parentFragment instanceof ISupportFragment) {
  221 + return !((ISupportFragment) parentFragment).isSupportVisible();
  222 + }
  223 +
  224 + return parentFragment != null && !parentFragment.isVisible();
  225 + }
  226 +
  227 + private boolean checkAddState() {
  228 + if (!mFragment.isAdded()) {
  229 + mIsSupportVisible = !mIsSupportVisible;
  230 + return true;
  231 + }
  232 + return false;
  233 + }
  234 +
  235 + private boolean isFragmentVisible(Fragment fragment) {
  236 + return !fragment.isHidden() && fragment.getUserVisibleHint();
  237 + }
  238 +
  239 + public boolean isSupportVisible() {
  240 + return mIsSupportVisible;
  241 + }
  242 +
  243 + private Handler getHandler() {
  244 + if (mHandler == null) {
  245 + mHandler = new Handler(Looper.getMainLooper());
  246 + }
  247 + return mHandler;
  248 + }
  249 +}
core/base/src/main/java/com/me/yokeyword/fragmentation/queue/Action.java 0 → 100644
  1 +package com.me.yokeyword.fragmentation.queue;
  2 +
  3 +import androidx.fragment.app.FragmentManager;
  4 +
  5 +/**
  6 + * Created by YoKey on 17/12/28.
  7 + */
  8 +
  9 +public abstract class Action {
  10 + public static final long DEFAULT_POP_TIME = 300L;
  11 +
  12 + public static final int ACTION_NORMAL = 0;
  13 + public static final int ACTION_POP = 1;
  14 + public static final int ACTION_POP_MOCK = 2;
  15 + public static final int ACTION_BACK = 3;
  16 + public static final int ACTION_LOAD = 4;
  17 +
  18 + public FragmentManager fragmentManager;
  19 + public int action = ACTION_NORMAL;
  20 + public long duration = 0;
  21 +
  22 + public Action() {
  23 + }
  24 +
  25 + public Action(int action) {
  26 + this.action = action;
  27 + }
  28 +
  29 + public Action(int action, FragmentManager fragmentManager) {
  30 + this(action);
  31 + this.fragmentManager = fragmentManager;
  32 + }
  33 +
  34 + public abstract void run();
  35 +}
core/base/src/main/java/com/me/yokeyword/fragmentation/queue/ActionQueue.java 0 → 100644
  1 +package com.me.yokeyword.fragmentation.queue;
  2 +
  3 +import android.os.Handler;
  4 +import android.os.Looper;
  5 +
  6 +import com.me.yokeyword.fragmentation.ISupportFragment;
  7 +import com.me.yokeyword.fragmentation.SupportHelper;
  8 +
  9 +import java.util.LinkedList;
  10 +import java.util.Queue;
  11 +
  12 +
  13 +/**
  14 + * The queue of perform action.
  15 + * <p>
  16 + * Created by YoKey on 17/12/29.
  17 + */
  18 +public class ActionQueue {
  19 + private Queue<Action> mQueue = new LinkedList<>();
  20 + private Handler mMainHandler;
  21 +
  22 + public ActionQueue(Handler mainHandler) {
  23 + this.mMainHandler = mainHandler;
  24 + }
  25 +
  26 + public void enqueue(final Action action) {
  27 + if (isThrottleBACK(action)) return;
  28 +
  29 + if (action.action == Action.ACTION_LOAD && mQueue.isEmpty()
  30 + && Thread.currentThread() == Looper.getMainLooper().getThread()) {
  31 + action.run();
  32 + return;
  33 + }
  34 +
  35 + mMainHandler.post(new Runnable() {
  36 + @Override
  37 + public void run() {
  38 + enqueueAction(action);
  39 + }
  40 + });
  41 + }
  42 +
  43 + private void enqueueAction(Action action) {
  44 + mQueue.add(action);
  45 + if (mQueue.size() == 1) {
  46 + handleAction();
  47 + }
  48 + }
  49 +
  50 + private void handleAction() {
  51 + if (mQueue.isEmpty()) return;
  52 +
  53 + Action action = mQueue.peek();
  54 + action.run();
  55 +
  56 + executeNextAction(action);
  57 + }
  58 +
  59 + private void executeNextAction(Action action) {
  60 + if (action.action == Action.ACTION_POP) {
  61 + ISupportFragment top = SupportHelper.getBackStackTopFragment(action.fragmentManager);
  62 + action.duration = top == null ? Action.DEFAULT_POP_TIME : top.getSupportDelegate().getExitAnimDuration();
  63 + }
  64 +
  65 + mMainHandler.postDelayed(new Runnable() {
  66 + @Override
  67 + public void run() {
  68 + mQueue.poll();
  69 + handleAction();
  70 + }
  71 + }, action.duration);
  72 + }
  73 +
  74 + private boolean isThrottleBACK(Action action) {
  75 + if (action.action == Action.ACTION_BACK) {
  76 + Action head = mQueue.peek();
  77 + if (head != null && head.action == Action.ACTION_POP) {
  78 + return true;
  79 + }
  80 + }
  81 + return false;
  82 + }
  83 +}
core/base/src/main/java/com/me/yokeyword/fragmentation_swipeback/SwipeBackActivity.java 0 → 100644
  1 +
  2 +package com.me.yokeyword.fragmentation_swipeback;
  3 +
  4 +import android.os.Bundle;
  5 +
  6 +
  7 +import com.me.yokeyword.fragmentation.SupportActivity;
  8 +import com.me.yokeyword.fragmentation.SwipeBackLayout;
  9 +import com.me.yokeyword.fragmentation_swipeback.core.ISwipeBackActivity;
  10 +import com.me.yokeyword.fragmentation_swipeback.core.SwipeBackActivityDelegate;
  11 +
  12 +
  13 +
  14 +/**
  15 + * You can also refer to {@link me.yokeyword.fragmentation_swipeback.SwipeBackActivity} to implement YourSwipeBackActivity
  16 + * (extends Activity and impl {@link me.yokeyword.fragmentation.ISupportActivity})
  17 + * <p>
  18 + * Created by YoKey on 16/4/19.
  19 + */
  20 +public class SwipeBackActivity extends SupportActivity implements ISwipeBackActivity {
  21 + final SwipeBackActivityDelegate mDelegate = new SwipeBackActivityDelegate(this);
  22 +
  23 + @Override
  24 + protected void onCreate(Bundle savedInstanceState) {
  25 + super.onCreate(savedInstanceState);
  26 + mDelegate.onCreate(savedInstanceState);
  27 + }
  28 +
  29 + @Override
  30 + protected void onPostCreate(Bundle savedInstanceState) {
  31 + super.onPostCreate(savedInstanceState);
  32 + mDelegate.onPostCreate(savedInstanceState);
  33 + }
  34 +
  35 + @Override
  36 + public SwipeBackLayout getSwipeBackLayout() {
  37 + return mDelegate.getSwipeBackLayout();
  38 + }
  39 +
  40 + /**
  41 + * 是否可滑动
  42 + * @param enable
  43 + */
  44 + @Override
  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 + * 限制SwipeBack的条件,默认栈内Fragment数 <= 1时 , 优先滑动退出Activity , 而不是Fragment
  61 + *
  62 + * @return true: Activity优先滑动退出; false: Fragment优先滑动退出
  63 + */
  64 + @Override
  65 + public boolean swipeBackPriority() {
  66 + return mDelegate.swipeBackPriority();
  67 + }
  68 +}
core/base/src/main/java/com/me/yokeyword/fragmentation_swipeback/SwipeBackFragment.java 0 → 100644
  1 +package com.me.yokeyword.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.me.yokeyword.fragmentation.SupportFragment;
  10 +import com.me.yokeyword.fragmentation.SwipeBackLayout;
  11 +import com.me.yokeyword.fragmentation_swipeback.core.ISwipeBackFragment;
  12 +import com.me.yokeyword.fragmentation_swipeback.core.SwipeBackFragmentDelegate;
  13 +
  14 +
  15 +/**
  16 + * You can also refer to {@link me.yokeyword.fragmentation_swipeback.SwipeBackFragment} to implement YourSwipeBackFragment
  17 + * (extends Fragment and impl {@link me.yokeyword.fragmentation.ISupportFragment})
  18 + * <p>
  19 + * Created by YoKey on 16/4/19.
  20 + */
  21 +public class SwipeBackFragment extends SupportFragment implements ISwipeBackFragment {
  22 + final SwipeBackFragmentDelegate mDelegate = new SwipeBackFragmentDelegate(this);
  23 +
  24 + @Override
  25 + public void onCreate(@Nullable Bundle savedInstanceState) {
  26 + super.onCreate(savedInstanceState);
  27 + mDelegate.onCreate(savedInstanceState);
  28 + }
  29 +
  30 + @Override
  31 + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
  32 + super.onViewCreated(view, savedInstanceState);
  33 + mDelegate.onViewCreated(view, savedInstanceState);
  34 + }
  35 +
  36 + @Override
  37 + public View attachToSwipeBack(View view) {
  38 + return mDelegate.attachToSwipeBack(view);
  39 + }
  40 +
  41 + @Override
  42 + public void onHiddenChanged(boolean hidden) {
  43 + super.onHiddenChanged(hidden);
  44 + mDelegate.onHiddenChanged(hidden);
  45 + }
  46 +
  47 + public SwipeBackLayout getSwipeBackLayout() {
  48 + return mDelegate.getSwipeBackLayout();
  49 + }
  50 +
  51 + /**
  52 + * 是否可滑动
  53 + *
  54 + * @param enable
  55 + */
  56 + public void setSwipeBackEnable(boolean enable) {
  57 + mDelegate.setSwipeBackEnable(enable);
  58 + }
  59 +
  60 + @Override
  61 + public void setEdgeLevel(SwipeBackLayout.EdgeLevel edgeLevel) {
  62 + mDelegate.setEdgeLevel(edgeLevel);
  63 + }
  64 +
  65 + @Override
  66 + public void setEdgeLevel(int widthPixel) {
  67 + mDelegate.setEdgeLevel(widthPixel);
  68 + }
  69 +
  70 + /**
  71 + * Set the offset of the parallax slip.
  72 + */
  73 + public void setParallaxOffset(@FloatRange(from = 0.0f, to = 1.0f) float offset) {
  74 + mDelegate.setParallaxOffset(offset);
  75 + }
  76 +
  77 + @Override
  78 + public void onDestroyView() {
  79 + mDelegate.onDestroyView();
  80 + super.onDestroyView();
  81 + }
  82 +
  83 +
  84 +}
0 \ No newline at end of file 85 \ No newline at end of file
core/base/src/main/java/com/me/yokeyword/fragmentation_swipeback/core/ISwipeBackActivity.java 0 → 100644
  1 +package com.me.yokeyword.fragmentation_swipeback.core;
  2 +
  3 +import com.me.yokeyword.fragmentation.SwipeBackLayout;
  4 +
  5 +
  6 +/**
  7 + * Created by YoKey on 17/6/29.
  8 + */
  9 +public interface ISwipeBackActivity {
  10 +
  11 + SwipeBackLayout getSwipeBackLayout();
  12 +
  13 + void setSwipeBackEnable(boolean enable);
  14 +
  15 + void setEdgeLevel(SwipeBackLayout.EdgeLevel edgeLevel);
  16 +
  17 + void setEdgeLevel(int widthPixel);
  18 +
  19 + /**
  20 + * 限制SwipeBack的条件,默认栈内Fragment数 <= 1时 , 优先滑动退出Activity , 而不是Fragment
  21 + *
  22 + * @return true: Activity可以滑动退出, 并且总是优先; false: Fragment优先滑动退出
  23 + */
  24 + boolean swipeBackPriority();
  25 +}
core/base/src/main/java/com/me/yokeyword/fragmentation_swipeback/core/ISwipeBackFragment.java 0 → 100644
  1 +package com.me.yokeyword.fragmentation_swipeback.core;
  2 +
  3 +import android.view.View;
  4 +
  5 +import androidx.annotation.FloatRange;
  6 +
  7 +import com.me.yokeyword.fragmentation.SwipeBackLayout;
  8 +
  9 +
  10 +/**
  11 + * Created by YoKey on 17/6/29.
  12 + */
  13 +
  14 +public interface ISwipeBackFragment {
  15 +
  16 + View attachToSwipeBack(View view);
  17 +
  18 + SwipeBackLayout getSwipeBackLayout();
  19 +
  20 + void setSwipeBackEnable(boolean enable);
  21 +
  22 + void setEdgeLevel(SwipeBackLayout.EdgeLevel edgeLevel);
  23 +
  24 + void setEdgeLevel(int widthPixel);
  25 +
  26 + /**
  27 + * Set the offset of the parallax slip.
  28 + */
  29 + void setParallaxOffset(@FloatRange(from = 0.0f, to = 1.0f) float offset);
  30 +}
core/base/src/main/java/com/me/yokeyword/fragmentation_swipeback/core/SwipeBackActivityDelegate.java 0 → 100644
  1 +package com.me.yokeyword.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.FragmentActivity;
  9 +
  10 +import com.me.yokeyword.fragmentation.ISupportActivity;
  11 +import com.me.yokeyword.fragmentation.SwipeBackLayout;
  12 +
  13 +
  14 +/**
  15 + * Created by YoKey on 17/6/29.
  16 + */
  17 +
  18 +public class SwipeBackActivityDelegate {
  19 + private 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 + /**
  53 + * 限制SwipeBack的条件,默认栈内Fragment数 <= 1时 , 优先滑动退出Activity , 而不是Fragment
  54 + *
  55 + * @return true: Activity可以滑动退出, 并且总是优先; false: Fragment优先滑动退出
  56 + */
  57 + public boolean swipeBackPriority() {
  58 + return mActivity.getSupportFragmentManager().getBackStackEntryCount() <= 1;
  59 + }
  60 +
  61 + private void onActivityCreate() {
  62 + mActivity.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
  63 + mActivity.getWindow().getDecorView().setBackgroundColor(Color.TRANSPARENT);
  64 + mSwipeBackLayout = new SwipeBackLayout(mActivity);
  65 + ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
  66 + mSwipeBackLayout.setLayoutParams(params);
  67 + }
  68 +}
core/base/src/main/java/com/me/yokeyword/fragmentation_swipeback/core/SwipeBackFragmentDelegate.java 0 → 100644
  1 +package com.me.yokeyword.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.me.yokeyword.fragmentation.ISupportFragment;
  13 +import com.me.yokeyword.fragmentation.SwipeBackLayout;
  14 +
  15 +
  16 +/**
  17 + * Created by YoKey on 17/6/29.
  18 + */
  19 +
  20 +public class SwipeBackFragmentDelegate {
  21 + private Fragment mFragment;
  22 + private ISupportFragment mSupport;
  23 + private SwipeBackLayout mSwipeBackLayout;
  24 +
  25 + public SwipeBackFragmentDelegate(ISwipeBackFragment swipeBackFragment) {
  26 + if (!(swipeBackFragment instanceof Fragment) || !(swipeBackFragment instanceof ISupportFragment))
  27 + throw new RuntimeException("Must extends Fragment and implements ISupportFragment!");
  28 + mFragment = (Fragment) swipeBackFragment;
  29 + mSupport = (ISupportFragment) swipeBackFragment;
  30 + }
  31 +
  32 + public void onCreate(@Nullable Bundle savedInstanceState) {
  33 + onFragmentCreate();
  34 + }
  35 +
  36 + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
  37 + if (view instanceof SwipeBackLayout) {
  38 + View childView = ((SwipeBackLayout) view).getChildAt(0);
  39 + mSupport.getSupportDelegate().setBackground(childView);
  40 + } else {
  41 + mSupport.getSupportDelegate().setBackground(view);
  42 + }
  43 + }
  44 +
  45 + public View attachToSwipeBack(View view) {
  46 + mSwipeBackLayout.attachToFragment(mSupport, view);
  47 + return mSwipeBackLayout;
  48 + }
  49 +
  50 + public void setEdgeLevel(SwipeBackLayout.EdgeLevel edgeLevel) {
  51 + mSwipeBackLayout.setEdgeLevel(edgeLevel);
  52 + }
  53 +
  54 + public void setEdgeLevel(int widthPixel) {
  55 + mSwipeBackLayout.setEdgeLevel(widthPixel);
  56 + }
  57 +
  58 + public void onHiddenChanged(boolean hidden) {
  59 + if (hidden && mSwipeBackLayout != null) {
  60 + mSwipeBackLayout.hiddenFragment();
  61 + }
  62 + }
  63 +
  64 + public SwipeBackLayout getSwipeBackLayout() {
  65 + return mSwipeBackLayout;
  66 + }
  67 +
  68 + public void setSwipeBackEnable(boolean enable) {
  69 + mSwipeBackLayout.setEnableGesture(enable);
  70 + }
  71 +
  72 + /**
  73 + * Set the offset of the parallax slip.
  74 + */
  75 + public void setParallaxOffset(@FloatRange(from = 0.0f, to = 1.0f) float offset) {
  76 + mSwipeBackLayout.setParallaxOffset(offset);
  77 + }
  78 +
  79 + public void onDestroyView() {
  80 + mSwipeBackLayout.internalCallOnDestroyView();
  81 + }
  82 +
  83 + private void onFragmentCreate() {
  84 + if (mFragment.getContext() == null) return;
  85 +
  86 + mSwipeBackLayout = new SwipeBackLayout(mFragment.getContext());
  87 + ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
  88 + mSwipeBackLayout.setLayoutParams(params);
  89 + mSwipeBackLayout.setBackgroundColor(Color.TRANSPARENT);
  90 + }
  91 +}
core/base/src/main/res/anim/h_fragment_enter.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<set xmlns:android="http://schemas.android.com/apk/res/android">
  3 + <translate
  4 + android:duration="300"
  5 + android:fromXDelta="100%p"
  6 + android:interpolator="@android:anim/decelerate_interpolator"
  7 + android:toXDelta="0"/>
  8 +</set>
0 \ No newline at end of file 9 \ No newline at end of file
core/base/src/main/res/anim/h_fragment_exit.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<set
  3 + xmlns:android="http://schemas.android.com/apk/res/android">
  4 + <translate
  5 + android:duration="300"
  6 + android:fromXDelta="0"
  7 + android:interpolator="@android:anim/accelerate_interpolator"
  8 + android:toXDelta="100%p"/>
  9 +</set>
0 \ No newline at end of file 10 \ No newline at end of file
core/base/src/main/res/anim/h_fragment_pop_enter.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<set xmlns:android="http://schemas.android.com/apk/res/android"
  3 + android:duration="300">
  4 + <translate
  5 + android:fromXDelta="-26%p"
  6 + android:toXDelta="0"/>
  7 +</set>
0 \ No newline at end of file 8 \ No newline at end of file
core/base/src/main/res/anim/h_fragment_pop_exit.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<set
  3 + xmlns:android="http://schemas.android.com/apk/res/android"
  4 + android:duration="300">
  5 + <translate
  6 + android:fromXDelta="0%p"
  7 + android:toXDelta="-26%p"/>
  8 +</set>
0 \ No newline at end of file 9 \ No newline at end of file
core/base/src/main/res/anim/no_anim.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<set xmlns:android="http://schemas.android.com/apk/res/android"
  3 + android:duration="0">
  4 +</set>
0 \ No newline at end of file 5 \ No newline at end of file
core/base/src/main/res/anim/pop_exit_no_anim.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<set xmlns:android="http://schemas.android.com/apk/res/android"
  3 + android:duration="300">
  4 + <alpha
  5 + android:fromAlpha="1.0"
  6 + android:toAlpha="1.0"/>
  7 +</set>
0 \ No newline at end of file 8 \ No newline at end of file
core/base/src/main/res/anim/v_fragment_enter.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<!--
  3 +/*
  4 +** Copyright 2009, The Android Open Source Project
  5 +**
  6 +** Licensed under the Apache License, Version 2.0 (the "License");
  7 +** you may not use this file except in compliance with the License.
  8 +** You may obtain a copy of the License at
  9 +**
  10 +** http://www.apache.org/licenses/LICENSE-2.0
  11 +**
  12 +** Unless required by applicable law or agreed to in writing, software
  13 +** distributed under the License is distributed on an "AS IS" BASIS,
  14 +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15 +** See the License for the specific language governing permissions and
  16 +** limitations under the License.
  17 +*/
  18 +-->
  19 +
  20 +<set xmlns:android="http://schemas.android.com/apk/res/android"
  21 + android:shareInterpolator="false"
  22 + android:zAdjustment="top">
  23 + <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
  24 + android:interpolator="@android:anim/decelerate_interpolator"
  25 + android:fillEnabled="true"
  26 + android:fillBefore="false" android:fillAfter="true"
  27 + android:duration="200"/>
  28 + <translate android:fromYDelta="8%" android:toYDelta="0"
  29 + android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
  30 + android:interpolator="@android:anim/decelerate_interpolator"
  31 + android:duration="300"/>
  32 +</set>
0 \ No newline at end of file 33 \ No newline at end of file
core/base/src/main/res/anim/v_fragment_exit.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<!--
  3 +/*
  4 +** Copyright 2009, The Android Open Source Project
  5 +**
  6 +** Licensed under the Apache License, Version 2.0 (the "License");
  7 +** you may not use this file except in compliance with the License.
  8 +** You may obtain a copy of the License at
  9 +**
  10 +** http://www.apache.org/licenses/LICENSE-2.0
  11 +**
  12 +** Unless required by applicable law or agreed to in writing, software
  13 +** distributed under the License is distributed on an "AS IS" BASIS,
  14 +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15 +** See the License for the specific language governing permissions and
  16 +** limitations under the License.
  17 +*/
  18 +-->
  19 +
  20 +<set xmlns:android="http://schemas.android.com/apk/res/android"
  21 + android:shareInterpolator="false" android:zAdjustment="top">
  22 + <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
  23 + android:interpolator="@android:anim/linear_interpolator"
  24 + android:fillEnabled="true"
  25 + android:fillBefore="false" android:fillAfter="true"
  26 + android:startOffset="100"
  27 + android:duration="150"/>
  28 + <translate android:fromYDelta="0%" android:toYDelta="8%"
  29 + android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
  30 + android:interpolator="@android:anim/accelerate_interpolator"
  31 + android:duration="250"/>
  32 +</set>
0 \ No newline at end of file 33 \ No newline at end of file
core/base/src/main/res/anim/v_fragment_pop_enter.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<!--
  3 +/*
  4 +** Copyright 2009, The Android Open Source Project
  5 +**
  6 +** Licensed under the Apache License, Version 2.0 (the "License");
  7 +** you may not use this file except in compliance with the License.
  8 +** You may obtain a copy of the License at
  9 +**
  10 +** http://www.apache.org/licenses/LICENSE-2.0
  11 +**
  12 +** Unless required by applicable law or agreed to in writing, software
  13 +** distributed under the License is distributed on an "AS IS" BASIS,
  14 +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15 +** See the License for the specific language governing permissions and
  16 +** limitations under the License.
  17 +*/
  18 +-->
  19 +
  20 +<set xmlns:android="http://schemas.android.com/apk/res/android" android:zAdjustment="normal">
  21 + <alpha android:fromAlpha="0.7" android:toAlpha="1.0"
  22 + android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
  23 + android:interpolator="@android:anim/accelerate_interpolator"
  24 + android:duration="250"/>
  25 +</set>
0 \ No newline at end of file 26 \ No newline at end of file
core/base/src/main/res/anim/v_fragment_pop_exit.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<!--
  3 +/*
  4 +** Copyright 2009, The Android Open Source Project
  5 +**
  6 +** Licensed under the Apache License, Version 2.0 (the "License");
  7 +** you may not use this file except in compliance with the License.
  8 +** You may obtain a copy of the License at
  9 +**
  10 +** http://www.apache.org/licenses/LICENSE-2.0
  11 +**
  12 +** Unless required by applicable law or agreed to in writing, software
  13 +** distributed under the License is distributed on an "AS IS" BASIS,
  14 +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15 +** See the License for the specific language governing permissions and
  16 +** limitations under the License.
  17 +*/
  18 +-->
  19 +
  20 +<set xmlns:android="http://schemas.android.com/apk/res/android"
  21 + android:zAdjustment="normal">
  22 + <alpha android:fromAlpha="1.0" android:toAlpha="0.9"
  23 + android:fillEnabled="true" android:fillBefore="false" android:fillAfter="true"
  24 + android:interpolator="@android:anim/decelerate_interpolator"
  25 + android:duration="300"/>
  26 +</set>
0 \ No newline at end of file 27 \ No newline at end of file
core/base/src/main/res/drawable-xxhdpi/fragmentation_help.png 0 → 100644

742 Bytes

core/base/src/main/res/drawable-xxhdpi/fragmentation_ic_expandable.png 0 → 100644

226 Bytes

core/base/src/main/res/drawable-xxhdpi/fragmentation_ic_right.png 0 → 100644

173 Bytes

core/base/src/main/res/drawable-xxhdpi/fragmentation_ic_stack.png 0 → 100644

2.95 KB

core/base/src/main/res/layout/base_activity_main.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<FrameLayout
  3 + android:id="@+id/fl_container"
  4 + xmlns:android="http://schemas.android.com/apk/res/android"
  5 + android:layout_width="match_parent"
  6 + android:layout_height="match_parent"/>
0 \ No newline at end of file 7 \ No newline at end of file
core/base/src/main/res/values/ids.xml
@@ -2,4 +2,7 @@ @@ -2,4 +2,7 @@
2 <resources> 2 <resources>
3 <item name="statusbarutil_fake_status_bar_view" type="id" /> 3 <item name="statusbarutil_fake_status_bar_view" type="id" />
4 <item name="statusbarutil_translucent_view" type="id" /> 4 <item name="statusbarutil_translucent_view" type="id" />
  5 + <!-- -->
  6 + <item name="hierarchy" type="id"></item>
  7 + <item name="isexpand" type="id"></item>
5 </resources> 8 </resources>
6 \ No newline at end of file 9 \ No newline at end of file
core/base/src/main/res/values/strings.xml
@@ -15,7 +15,7 @@ @@ -15,7 +15,7 @@
15 15
16 <string name="msg_exit">再次点击退出网家家</string> 16 <string name="msg_exit">再次点击退出网家家</string>
17 <string name="msg_exit_login">再次点击返回登录</string> 17 <string name="msg_exit_login">再次点击返回登录</string>
18 -  
19 - <!-- TODO: Remove or change this placeholder text -->  
20 - <string name="hello_blank_fragment">Hello blank fragment</string> 18 + <!-- -->
  19 + <string name="fragmentation_stack_view">Stack</string>
  20 + <string name="fragmentation_stack_help">*: Not in backStack\n☀: Visible</string>
21 </resources> 21 </resources>