单个Activity+多个fragment的架构可以让应用更加轻便灵活,跳转的UI响应速度更快,但是fragment的坑还是比较多的,这里推荐一个第三方框架Fragmentation,使用起来还是很方便的。
一、导入
api 'me.yokeyword:fragmentation:1.3.8'
二、初始化
publicclassAppextendsApplication{
@Override
public void onCreate() {
super.onCreate();
Fragmentation.builder()
// 设置 栈视图 模式为 (默认)悬浮球模式 SHAKE: 摇一摇唤出 NONE:隐藏, 仅在Debug环境生效
.stackViewMode(Fragmentation.BUBBLE)
.debug(BuildConfig.DEBUG)// 实际场景建议.debug(BuildConfig.DEBUG)
/**
* 可以获取到{@link me.yokeyword.fragmentation.exception.AfterSaveStateTransactionWarning}
* 在遇到After onSaveInstanceState时,不会抛出异常,会回调到下面的ExceptionHandler
*/
.handleException(newExceptionHandler() {
@Override
public void onException(Exceptione) {
// 以Bugtags为例子: 把捕获到的 Exception 传到 Bugtags 后台。
// Bugtags.sendException(e);
}
})
.install();
}
三、Activity继承SupportActivity并加载首页fragment
@Override
protectedvoidonCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loadRootFragment(R.id.fl_container, MainFragment.newInstance());
//全局改变Fragment的动画
setFragmentAnimator(newDefaultNoAnimator());
}
提示下,fragment切换动画共有3种,无动画、横向和纵向切换,分别是DefaultNoAnimator、DefaultHorizontalAnimator和DefaultVerticalAnimator
返回键监听可以这么写:
@Override
publicvoidonBackPressedSupport(){
if(getSupportFragmentManager().getBackStackEntryCount() >1) {
pop();
}else{
ActivityCompat.finishAfterTransition(this);
}
}
四、Fragment继承SupportFragment
publicclassMainFragmentextendsSupportFragment{
privateUnbinder unbinder;
publicstaticMainFragmentnewInstance(){
returnnewMainFragment();
}
@Override
publicViewonCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState){
View view = inflater.inflate(R.layout.fragment_main, container,false);
unbinder = ButterKnife.bind(this, view);
// 动态改动 当前Fragment的动画
// setFragmentAnimator(fragmentAnimator);
returnview;
}
@Override
publicvoidonDestroyView(){
super.onDestroyView();
if(unbinder !=null) {
unbinder.unbind();
}
}
}
Butterknife的内容可以无视
五、Fragment跳转到另一个Fragment并传递参数
Bundle bundle =newBundle();
bundle.putInt(Constants.PRODUCT_ID, productId);
start(ProductDetailFragment.newInstance(bundle));
ProductDetailFragment接收参数:
publicstaticProductDetailFragmentnewInstance(Bundle args){
ProductDetailFragment fragment =newProductDetailFragment();
fragment.setArguments(args);
returnfragment;
}
@Override
publicvoidonCreate(@NullableBundle savedInstanceState){
super.onCreate(savedInstanceState);
Bundle args = getArguments();
if(args !=null) {
productId = args.getInt(Constants.PRODUCT_ID,0);
}
}
@Override
publicViewonCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View view = inflater.inflate(R.layout.fragment_product_detail, container,false);
getProductList();
returnview;
}
六、在Activity跳转到另一个Fragment以及跳转到单例Fragment(类似Activity设置了singletask)
Bundleargs = new Bundle();
args.putString(Constants.KEY_WORD,event.getContent());
SearchResultFragmentfragment = findFragment(SearchResultFragment.class);
if(fragment == null) {
fragment=SearchResultFragment.newInstance(args);
}else {
fragment.putNewBundle(args);
}
finalISupportFragment topFragment = getTopFragment();
MyBaseFragmentbaseFragment = (MyBaseFragment) topFragment;
baseFragment.start(fragment,SupportFragment.SINGLETASK);
SearchResultFragment如果已经存在,则会调用如下方法:
/**
* 类似于 Activity的 onNewIntent()
*/
@Override
publicvoidonNewBundle(Bundle args) {
super.onNewBundle(args);
Stringkeyword = args.getString(Constants.KEY_WORD);
}
七、跳转到另一个Fragment之后返回获取到数据
FragmentA:
startForResult(ModifyDetailFragment.newInstance(mTitle), REQ_MODIFY_FRAGMENT);
@Override
publicvoidonFragmentResult(intrequestCode,intresultCode, Bundle data){
super.onFragmentResult(requestCode, resultCode, data);
if(requestCode == REQ_MODIFY_FRAGMENT && resultCode == RESULT_OK && data !=null) {
mTitle = data.getString(KEY_RESULT_TITLE);
mToolbar.setTitle(mTitle);
// 保存被改变的 title
getArguments().putString(ARG_TITLE, mTitle);
Toast.makeText(_mActivity, R.string.modify_title, Toast.LENGTH_SHORT).show();
}
}
ModifyDetailFragment:
Bundle bundle =newBundle();
bundle.putString(DetailFragment.KEY_RESULT_TITLE, mEtModiyTitle.getText().toString());
setFragmentResult(RESULT_OK, bundle);
八、跳转到另一个Fragment并销毁当前Fragment
startWithPop(CycleFragment.newInstance(mNumber +1));
九、如果跳转Fragment时不想隐藏上一个Fragment,使用场景:比如半透明界面,可以这么写
extraTransaction().startDontHideSelf(DetailFragment.newInstance());
十、Fragment当中的返回监听
前面写的是Activity的返回监听,这里还要特别注意下Fragment的,将一个Activity改造成Fragment时很有可能漏掉这一点。在Activity当中,对控件设置的onKeyListener之类的是可以响应的,但在Fragment当中就有可能没响应了,比如我写的这一段:
mAgentWeb.getWebCreator().getWebView().setOnKeyListener(newView.OnKeyListener() {
@Override
publicbooleanonKey(View v,intkeyCode, KeyEvent event){
if(event.getAction() == KeyEvent.ACTION_DOWN) {
if(keyCode == KeyEvent.KEYCODE_BACK && mAgentWeb.getWebCreator().getWebView().canGoBack()) {// 表示按返回键时的操作
mAgentWeb.getWebCreator().getWebView().goBack();// 后退
// webview.goForward();//前进
returntrue;// 已处理
}elseif(keyCode == KeyEvent.KEYCODE_BACK) {
pop();
}
}
returnfalse;
}
});
这里我引用了WebView的第三方框架AgentWeb,对其做返回键监听,结果改造成Fragment之后就没响应了。解决方法是重写onBackPressedSupport()方法:
@Override
publicbooleanonBackPressedSupport(){
String originalUrl = mAgentWeb.getWebCreator().getWebView().copyBackForwardList().getCurrentItem().getOriginalUrl();
if(mAgentWeb.getWebCreator().getWebView().canGoBack() && !(originalUrl.equals(url))) {
mAgentWeb.getWebCreator().getWebView().goBack();// 后退
}else{
pop();
}
returntrue;
}
十一、其他:fragment当中添加viewpager+fragment时,viewpager的adapter有一个参数需要填入FragmentManager,这个manager一定要填入getChildFragmentManager(),而不是getFragmentManager(),否则会造成fragment重复生成无法被销毁
publicclassAppextendsApplication{
@Override
public void onCreate() {
super.onCreate();
Fragmentation.builder()
// 设置 栈视图 模式为 (默认)悬浮球模式 SHAKE: 摇一摇唤出 NONE:隐藏, 仅在Debug环境生效
.stackViewMode(Fragmentation.BUBBLE)
.debug(BuildConfig.DEBUG)// 实际场景建议.debug(BuildConfig.DEBUG)
/**
* 可以获取到{@link me.yokeyword.fragmentation.exception.AfterSaveStateTransactionWarning}
* 在遇到After onSaveInstanceState时,不会抛出异常,会回调到下面的ExceptionHandler
*/
.handleException(newExceptionHandler() {
@Override
public void onException(Exceptione) {
// 以Bugtags为例子: 把捕获到的 Exception 传到 Bugtags 后台。
// Bugtags.sendException(e);
}
})
.install();
}