Commit 556ee8b2a75d0fb8c69c32c6da8f3325e509b8b2
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 | 24 | protected void onCreate(@Nullable Bundle savedInstanceState) { |
| 25 | 25 | super.onCreate(savedInstanceState); |
| 26 | 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 | 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 | 13 | |
| 14 | 14 | @Override |
| 15 | 15 | protected void initView() { |
| 16 | - setOpenSwipBack(true); | |
| 17 | 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 | 19 | import com.cnlive.strike.network.api.ApiService; |
| 20 | 20 | import com.cnlive.strike.network.bean.LetHimNoSeeBean; |
| 21 | 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 | 25 | import androidx.annotation.NonNull; |
| 24 | 26 | import androidx.annotation.Nullable; |
| ... | ... | @@ -31,23 +33,21 @@ import io.reactivex.functions.Function; |
| 31 | 33 | |
| 32 | 34 | |
| 33 | 35 | public class MyFragment extends BaseFragment<MyFragmentView, MyPresenter> { |
| 34 | - private View view; | |
| 35 | 36 | public TextView textView; |
| 36 | 37 | |
| 37 | - @Nullable | |
| 38 | 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 | 43 | @Override |
| 46 | 44 | protected void initView() { |
| 47 | 45 | super.initView(); |
| 46 | + setSwipeBackEnable(true); | |
| 48 | 47 | setStatusBarColor(R.color.green, 0); |
| 49 | 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 | 51 | @Override |
| 52 | 52 | public void onClick(View v) { |
| 53 | 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<MyFragmentView, MyPresenter> { |
| 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 | 67 | @Override |
| 68 | 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 | 84 | @Override |
| 84 | 85 | public void onClick(View v) { |
| 85 | 86 | //单个请求 |
| ... | ... | @@ -144,4 +145,17 @@ public class MyFragment extends BaseFragment<MyFragmentView, MyPresenter> { |
| 144 | 145 | getPresenter().setData("hha"); |
| 145 | 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 | 14 | |
| 15 | 15 | |
| 16 | 16 | public class MyFragment1 extends BaseFragment { |
| 17 | - private View view; | |
| 18 | 17 | |
| 19 | - @Nullable | |
| 18 | + | |
| 20 | 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 | 24 | @Override |
| ... | ... | @@ -28,5 +26,6 @@ public class MyFragment1 extends BaseFragment { |
| 28 | 26 | super.initView(); |
| 29 | 27 | setStatusBarColor(R.color.qmui_config_color_red, 0); |
| 30 | 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 | import com.cnlive.core.libs.base.frame.activity.BaseActivity; |
| 8 | 8 | import com.cnlive.core.libs.base.interfaces.OnPermissionResponseListener; |
| 9 | 9 | import com.cnlive.core.libs.base.util.StatusBarConfig; |
| 10 | +import com.cnlive.strike.MyFragment; | |
| 10 | 11 | import com.cnlive.strike.R; |
| 12 | +import com.cnlive.strike.base.BuildConfig; | |
| 11 | 13 | |
| 12 | 14 | /** |
| 13 | 15 | * 继承BaseActivity |
| ... | ... | @@ -19,10 +21,10 @@ public class DemoActivity extends BaseActivity { |
| 19 | 21 | * |
| 20 | 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 | 30 | * 设置binding布局 |
| ... | ... | @@ -30,16 +32,16 @@ public class DemoActivity extends BaseActivity { |
| 30 | 32 | * |
| 31 | 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 | 47 | * 初始化intent传递参数 |
| ... | ... | @@ -55,8 +57,8 @@ public class DemoActivity extends BaseActivity { |
| 55 | 57 | @Override |
| 56 | 58 | protected void initView() { |
| 57 | 59 | super.initView(); |
| 58 | - //是指是否可以侧滑返回,默认禁用 | |
| 59 | - setOpenSwipBack(true); | |
| 60 | + //是指是否可以侧滑返回,默认禁用d | |
| 61 | +// setSwipeBackEnable(true); | |
| 60 | 62 | //设置状态栏字体颜色 |
| 61 | 63 | setStatusBarTextColor(StatusBarConfig.WHITE); |
| 62 | 64 | //设置状态栏颜色 |
| ... | ... | @@ -75,6 +77,8 @@ public class DemoActivity extends BaseActivity { |
| 75 | 77 | //px2dp |
| 76 | 78 | px2dp(10); |
| 77 | 79 | |
| 80 | + loadRootFragment(R.id.fl_container, new MyFragment()); | |
| 81 | + | |
| 78 | 82 | // String[] permissions = new String[]{Manifest.permission.ACCESS_FINE_LOCATION, |
| 79 | 83 | // Manifest.permission.ACCESS_COARSE_LOCATION}; |
| 80 | 84 | // //请求权限(默认提示语的) |
| ... | ... | @@ -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 | 152 | super.initData(); |
| 158 | 153 | } |
| 159 | 154 | |
| 160 | - | |
| 161 | 155 | } | ... | ... |
app/strike/src/main/res/values/styles.xml
| ... | ... | @@ -2,6 +2,7 @@ |
| 2 | 2 | |
| 3 | 3 | <!-- Base application theme. --> |
| 4 | 4 | <style name="AppTheme" parent="QMUI.Compat.NoActionBar"> |
| 5 | + <item name="android:windowIsTranslucent">true</item> | |
| 5 | 6 | <!-- Customize your theme here. --> |
| 6 | 7 | <item name="colorPrimary">@color/colorPrimary</item> |
| 7 | 8 | <item name="colorPrimaryDark">@color/colorPrimaryDark</item> | ... | ... |
config.gradle
| ... | ... | @@ -25,7 +25,7 @@ ext { |
| 25 | 25 | ] |
| 26 | 26 | |
| 27 | 27 | androidx = [ |
| 28 | - appcompat : "androidx.appcompat:appcompat:1.1.0+", | |
| 28 | + appcompat : "androidx.appcompat:appcompat:1.1.0", | |
| 29 | 29 | constraintlayout: "androidx.constraintlayout:constraintlayout:1.1.3", |
| 30 | 30 | multidex : "androidx.multidex:multidex:2.0.1" |
| 31 | 31 | ] |
| ... | ... | @@ -47,6 +47,12 @@ ext { |
| 47 | 47 | ] |
| 48 | 48 | |
| 49 | 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 | 56 | logger : 'com.orhanobut:logger:2.2.0', |
| 51 | 57 | // //空祖对话框 https://github.com/kongzue/DialogV3 |
| 52 | 58 | // kongzueDailog : 'com.kongzue.dialog_v3x:dialog:3.1.6', |
| ... | ... | @@ -101,31 +107,33 @@ ext { |
| 101 | 107 | // ] |
| 102 | 108 | //基础三方库 |
| 103 | 109 | base_librarys = [ |
| 104 | - library.logger, | |
| 105 | - //对话框 | |
| 110 | +// library.fragmentation_swipeback, | |
| 111 | +// library.fragmentationx, | |
| 112 | +library.logger, | |
| 113 | +//对话框 | |
| 106 | 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 | 129 | // library.mvp, |
| 122 | 130 | // library.mvp_lce, |
| 123 | 131 | // library.mvp_nullobject_presenter, |
| 124 | 132 | // library.mvp_viewstate, |
| 125 | - //图片加载Glide | |
| 126 | - glide.api, | |
| 127 | - glide.transformations, | |
| 128 | - //兼容旧版 | |
| 133 | +//图片加载Glide | |
| 134 | +glide.api, | |
| 135 | +glide.transformations, | |
| 136 | +//兼容旧版 | |
| 129 | 137 | // library.supportV4, |
| 130 | 138 | // library.appcompatV7, |
| 131 | 139 | // library.design, |
| ... | ... | @@ -133,26 +141,26 @@ ext { |
| 133 | 141 | // library.recyclerviewV7, |
| 134 | 142 | // library.cardviewV7, |
| 135 | 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 | 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 | 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 | 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 | 14 | import android.text.TextUtils; |
| 15 | 15 | import android.util.DisplayMetrics; |
| 16 | 16 | import android.view.Display; |
| 17 | +import android.view.MotionEvent; | |
| 17 | 18 | import android.view.View; |
| 18 | 19 | import android.view.Window; |
| 19 | 20 | import android.view.WindowManager; |
| 20 | 21 | import android.view.inputmethod.InputMethodManager; |
| 21 | 22 | |
| 22 | 23 | import androidx.annotation.ColorRes; |
| 24 | +import androidx.annotation.DrawableRes; | |
| 23 | 25 | import androidx.annotation.IntRange; |
| 24 | 26 | import androidx.annotation.NonNull; |
| 25 | 27 | import androidx.annotation.Nullable; |
| ... | ... | @@ -31,6 +33,7 @@ import androidx.databinding.DataBindingUtil; |
| 31 | 33 | import androidx.databinding.ViewDataBinding; |
| 32 | 34 | |
| 33 | 35 | import com.alibaba.android.arouter.launcher.ARouter; |
| 36 | +import com.cnlive.core.libs.base.application.AppConfig; | |
| 34 | 37 | import com.cnlive.core.libs.base.frame.presenter.BasePresenter; |
| 35 | 38 | import com.cnlive.core.libs.base.frame.view.BaseView; |
| 36 | 39 | import com.cnlive.core.libs.base.interfaces.OnPermissionResponseListener; |
| ... | ... | @@ -39,27 +42,36 @@ import com.cnlive.core.libs.base.util.AppManager; |
| 39 | 42 | import com.cnlive.core.libs.base.util.ReflectUtil; |
| 40 | 43 | import com.cnlive.core.libs.base.util.StatusBarConfig; |
| 41 | 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 | 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 | 57 | import com.orhanobut.logger.Logger; |
| 48 | 58 | |
| 49 | 59 | import java.lang.reflect.Field; |
| 50 | 60 | import java.util.ArrayList; |
| 51 | 61 | import java.util.List; |
| 52 | 62 | |
| 63 | + | |
| 53 | 64 | /** |
| 54 | 65 | * @author ys |
| 55 | 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 | 70 | private V view; |
| 59 | 71 | private P presenter; |
| 60 | 72 | public ViewDataBinding baseBinding; |
| 61 | 73 | //获取TAG的activity名称 |
| 62 | - protected final String TAG = this.getClass().getSimpleName(); | |
| 74 | + public final String TAG = this.getClass().getSimpleName(); | |
| 63 | 75 | //是否显示标题栏 |
| 64 | 76 | private boolean isShowTitle = true; |
| 65 | 77 | //是否显示状态栏 |
| ... | ... | @@ -76,9 +88,12 @@ public abstract class BaseActivity<V extends BaseView, P extends BasePresenter<V |
| 76 | 88 | private int USER_SET_REQUEST_CODE_PERMISSION = -0x00099;//用户设置的权限请求码 |
| 77 | 89 | private String defaultDefinePermissionTip = "需要必要的权限才可以正常使用该功能,您已拒绝获得该权限。\n如果需要重新授权,您可以点击“允许”按钮进入系统设置进行授权";//默认拒绝的权限提示语 |
| 78 | 90 | private String userSetDefinePermissionTip = "";//用户设置的权限提示语 |
| 79 | - private SwipeBackActivityHelper mHelper;//侧滑返回 | |
| 91 | + // private SwipeBackActivityHelper mHelper;//侧滑返回 | |
| 80 | 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 | 98 | @Override |
| 84 | 99 | protected void onCreate(@Nullable Bundle savedInstanceState) { |
| ... | ... | @@ -88,8 +103,17 @@ public abstract class BaseActivity<V extends BaseView, P extends BasePresenter<V |
| 88 | 103 | } else if (0 != getViewLayoutId()) { |
| 89 | 104 | setContentView(getViewLayoutId()); |
| 90 | 105 | } |
| 106 | + //两种视图都没有设置,就加载默认跟视图,用于fragment切换 | |
| 107 | + if (0 == getBindLayoutId() && 0 == getViewLayoutId()) { | |
| 108 | + setContentView(R.layout.base_activity_main); | |
| 109 | + } | |
| 91 | 110 | context = this; |
| 92 | 111 | me = this; |
| 112 | + //fragment管理 | |
| 113 | + mDelegate.onCreate(savedInstanceState); | |
| 114 | + mSwipeDelegate.onCreate(savedInstanceState); | |
| 115 | + //是否开启滑动返回 | |
| 116 | + setSwipeBackEnable(isOpenSwipBack); | |
| 93 | 117 | this.savedInstanceState = savedInstanceState; |
| 94 | 118 | //路由参数初始化 |
| 95 | 119 | ARouter.getInstance().inject(this); |
| ... | ... | @@ -118,16 +142,11 @@ public abstract class BaseActivity<V extends BaseView, P extends BasePresenter<V |
| 118 | 142 | initView(); |
| 119 | 143 | //设置数据 |
| 120 | 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<V extends BaseView, P extends BasePresenter<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<V extends BaseView, P extends BasePresenter<V |
| 242 | 265 | |
| 243 | 266 | @Override |
| 244 | 267 | protected void onDestroy() { |
| 268 | + mDelegate.onDestroy(); | |
| 245 | 269 | super.onDestroy(); |
| 246 | - if (null != alertDialog) { | |
| 247 | - alertDialog.dismiss(); | |
| 270 | + if (null != baseBinding) { | |
| 271 | + baseBinding.unbind(); | |
| 248 | 272 | } |
| 249 | 273 | //activity管理 |
| 250 | 274 | AppManager.getInstance().deleteActivity(me); |
| ... | ... | @@ -258,15 +282,15 @@ public abstract class BaseActivity<V extends BaseView, P extends BasePresenter<V |
| 258 | 282 | * @param color |
| 259 | 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 | 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 | 294 | if (type == StatusBarConfig.BLACK) { |
| 271 | 295 | StatusBarUtil.setStatusBarWrite(this); |
| 272 | 296 | } else if (type == StatusBarConfig.WHITE) { |
| ... | ... | @@ -615,33 +639,36 @@ public abstract class BaseActivity<V extends BaseView, P extends BasePresenter<V |
| 615 | 639 | @Override |
| 616 | 640 | protected void onPostCreate(Bundle savedInstanceState) { |
| 617 | 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 | 674 | public void logError(Object info) { |
| ... | ... | @@ -671,4 +698,278 @@ public abstract class BaseActivity<V extends BaseView, P extends BasePresenter<V |
| 671 | 698 | public void logXml(String xml) { |
| 672 | 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 | 976 | \ No newline at end of file | ... | ... |
core/base/src/main/java/com/cnlive/core/libs/base/frame/fragment/BaseFragment.java
| 1 | 1 | package com.cnlive.core.libs.base.frame.fragment; |
| 2 | 2 | |
| 3 | +import android.app.Activity; | |
| 4 | +import android.content.Intent; | |
| 3 | 5 | import android.os.Bundle; |
| 4 | 6 | import android.view.LayoutInflater; |
| 5 | 7 | import android.view.View; |
| 6 | 8 | import android.view.ViewGroup; |
| 9 | +import android.view.animation.Animation; | |
| 7 | 10 | import android.view.inputmethod.InputMethodManager; |
| 8 | 11 | |
| 9 | 12 | import androidx.annotation.ColorRes; |
| 13 | +import androidx.annotation.FloatRange; | |
| 10 | 14 | import androidx.annotation.IntRange; |
| 11 | 15 | import androidx.annotation.NonNull; |
| 12 | 16 | import androidx.annotation.Nullable; |
| ... | ... | @@ -24,6 +28,16 @@ import com.cnlive.core.libs.base.util.ReflectUtil; |
| 24 | 28 | import com.cnlive.core.libs.base.frame.view.BaseView; |
| 25 | 29 | import com.cnlive.core.libs.base.util.StatusBarConfig; |
| 26 | 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 | 42 | import static android.content.Context.INPUT_METHOD_SERVICE; |
| 29 | 43 | |
| ... | ... | @@ -34,19 +48,26 @@ import static android.content.Context.INPUT_METHOD_SERVICE; |
| 34 | 48 | * @param <P> |
| 35 | 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 | 52 | private V view; |
| 39 | 53 | private P presenter; |
| 40 | - protected final String TAG = this.getClass().getSimpleName(); | |
| 54 | + public final String TAG = this.getClass().getSimpleName(); | |
| 41 | 55 | public ViewDataBinding baseBinding; |
| 42 | 56 | public View baseView; |
| 43 | 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 | 63 | @Override |
| 46 | 64 | public void onCreate(Bundle savedInstanceState) { |
| 47 | 65 | super.onCreate(savedInstanceState); |
| 48 | 66 | if (getActivity() == null) return; |
| 49 | 67 | me = (BaseActivity) getActivity(); |
| 68 | + mDelegate.onCreate(savedInstanceState); | |
| 69 | + mSwipeDelegate.onCreate(savedInstanceState); | |
| 70 | + setSwipeBackEnable(me.isOpenSwipBack()); | |
| 50 | 71 | ARouter.getInstance().inject(this); |
| 51 | 72 | initFragmentStyle(); |
| 52 | 73 | initParams(); |
| ... | ... | @@ -57,10 +78,18 @@ public abstract class BaseFragment<V extends BaseView, P extends BasePresenter<V |
| 57 | 78 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { |
| 58 | 79 | if (0 != getBindLayoutId()) { |
| 59 | 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 | 86 | } else if (0 != getViewLayoutId()) { |
| 62 | 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 | 94 | return super.onCreateView(inflater, container, savedInstanceState); |
| 66 | 95 | } |
| ... | ... | @@ -68,6 +97,7 @@ public abstract class BaseFragment<V extends BaseView, P extends BasePresenter<V |
| 68 | 97 | @Override |
| 69 | 98 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { |
| 70 | 99 | super.onViewCreated(view, savedInstanceState); |
| 100 | + mSwipeDelegate.onViewCreated(view, savedInstanceState); | |
| 71 | 101 | if (null != getMvpView() && null != getPresenter()) { |
| 72 | 102 | initBindingData(); |
| 73 | 103 | initView(); |
| ... | ... | @@ -153,48 +183,40 @@ public abstract class BaseFragment<V extends BaseView, P extends BasePresenter<V |
| 153 | 183 | */ |
| 154 | 184 | protected void setStatusBarColor(@ColorRes int color, |
| 155 | 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 | 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<V extends BaseView, P extends BasePresenter<V |
| 238 | 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 | 2 | |
| 3 | 3 | import com.cnlive.core.libs.base.frame.view.BaseView; |
| 4 | 4 | import com.hannesdorfmann.mosby3.mvp.MvpBasePresenter; |
| 5 | +import com.orhanobut.logger.Logger; | |
| 5 | 6 | |
| 6 | 7 | public class BasePresenter<V extends BaseView> extends MvpBasePresenter<V> { |
| 7 | 8 | protected final String TAG = this.getClass().getSimpleName(); |
| ... | ... | @@ -17,4 +18,32 @@ public class BasePresenter<V extends BaseView> extends MvpBasePresenter<V> { |
| 17 | 18 | // public V getView() { |
| 18 | 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 | 1 | package com.cnlive.core.libs.base.frame.view; |
| 2 | 2 | |
| 3 | 3 | import com.hannesdorfmann.mosby3.mvp.MvpView; |
| 4 | +import com.orhanobut.logger.Logger; | |
| 4 | 5 | |
| 5 | 6 | /** |
| 6 | 7 | * @author ys |
| ... | ... | @@ -22,4 +23,32 @@ public class BaseView implements MvpView { |
| 22 | 23 | } |
| 23 | 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 | 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
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 | 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 | 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 | 10 | \ No newline at end of file | ... | ... |
core/base/src/main/res/anim/h_fragment_pop_enter.xml
0 → 100644
core/base/src/main/res/anim/h_fragment_pop_exit.xml
0 → 100644
core/base/src/main/res/anim/no_anim.xml
0 → 100644
core/base/src/main/res/anim/pop_exit_no_anim.xml
0 → 100644
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 | 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 | 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 | 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 | 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
core/base/src/main/res/values/ids.xml
| ... | ... | @@ -2,4 +2,7 @@ |
| 2 | 2 | <resources> |
| 3 | 3 | <item name="statusbarutil_fake_status_bar_view" type="id" /> |
| 4 | 4 | <item name="statusbarutil_translucent_view" type="id" /> |
| 5 | + <!-- --> | |
| 6 | + <item name="hierarchy" type="id"></item> | |
| 7 | + <item name="isexpand" type="id"></item> | |
| 5 | 8 | </resources> |
| 6 | 9 | \ No newline at end of file | ... | ... |
core/base/src/main/res/values/strings.xml
| ... | ... | @@ -15,7 +15,7 @@ |
| 15 | 15 | |
| 16 | 16 | <string name="msg_exit">再次点击退出网家家</string> |
| 17 | 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 | 21 | </resources> | ... | ... |