- 效果
add方式添加Fragment
- 使用方式
// 加载第一个Fragment V4包 兼容11以下的版本
FragmentManager fragmentManager = getSupportFragmentManager();
// 开启事物
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
// 把第一个Fragment HomeFragment加载进来
mHomeFragment = new HomeFragment();
// 第一个参数是Fragment的容器id,需要添加的Fragment
fragmentTransaction.add(R.id.main_tab_fl, mHomeFragment);
// 一定要commit
fragmentTransaction.commit();
- add(int contianerId,Fragment); 方式
private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
final Class fragmentClass = fragment.getClass();
final int modifiers = fragmentClass.getModifiers();
if (fragmentClass.isAnonymousClass() || !Modifier.isPublic(modifiers)
|| (fragmentClass.isMemberClass() && !Modifier.isStatic(modifiers))) {
throw new IllegalStateException("Fragment " + fragmentClass.getCanonicalName()
+ " must be a public static class to be properly recreated from"
+ " instance state.");
}
fragment.mFragmentManager = mManager;
if (tag != null) {
if (fragment.mTag != null && !tag.equals(fragment.mTag)) {
throw new IllegalStateException("Can't change tag of fragment "
+ fragment + ": was " + fragment.mTag
+ " now " + tag);
}
fragment.mTag = tag;
}
if (containerViewId != 0) {
if (containerViewId == View.NO_ID) {
throw new IllegalArgumentException("Can't add fragment "
+ fragment + " with tag " + tag + " to container view with no id");
}
if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) {
throw new IllegalStateException("Can't change container ID of fragment "
+ fragment + ": was " + fragment.mFragmentId
+ " now " + containerViewId);
}
fragment.mContainerId = fragment.mFragmentId = containerViewId;
}
addOp(new Op(opcmd, fragment));
}
add()方法实际上就是对设置进行封装,真正的添加是在commit()方法时执行
- commit()提交流程
replace()方式添加Fragment
// 加载第一个Fragment V4包 兼容11以下的版本
FragmentManager fragmentManager = getSupportFragmentManager();
// 开启事物
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
// 把第一个Fragment HomeFragment加载进来
mHomeFragment = new HomeFragment();
// 第一个参数是Fragment的容器id,需要添加的Fragment
fragmentTransaction.replace(R.id.main_tab_fl, mHomeFragment);
// 一定要commit
fragmentTransaction.commit();
replace()和add()同样调用的是doAddOp()方法,只是opcmd不一样
@Override
public FragmentTransaction add(int containerViewId, Fragment fragment, String tag) {
doAddOp(containerViewId, fragment, tag, OP_ADD);
return this;
}
@Override
public FragmentTransaction replace(int containerViewId, Fragment fragment, String tag) {
if (containerViewId == 0) {
throw new IllegalArgumentException("Must use non-zero containerViewId");
}
doAddOp(containerViewId, fragment, tag, OP_REPLACE);
return this;
}
- OP_ADD
switch (op.cmd) {
case OP_ADD:
case OP_ATTACH:
added.add(op.fragment);
break;
case OP_REMOVE:
case OP_DETACH: {
added.remove(op.fragment);
if (op.fragment == oldPrimaryNav) {
mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, op.fragment));
opNum++;
oldPrimaryNav = null;
}
}
可以看到OP_ADD直接执行的是added.add(op.fragment);添加操作
- OP_REPLACE
case OP_REPLACE: {
final Fragment f = op.fragment;
final int containerId = f.mContainerId;
boolean alreadyAdded = false;
for (int i = added.size() - 1; i >= 0; i--) {
final Fragment old = added.get(i);
if (old.mContainerId == containerId) {
if (old == f) {
alreadyAdded = true;
} else {
// This is duplicated from above since we only make
// a single pass for expanding ops. Unset any outgoing primary nav.
if (old == oldPrimaryNav) {
mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, old));
opNum++;
oldPrimaryNav = null;
}
final Op removeOp = new Op(OP_REMOVE, old);
removeOp.enterAnim = op.enterAnim;
removeOp.popEnterAnim = op.popEnterAnim;
removeOp.exitAnim = op.exitAnim;
removeOp.popExitAnim = op.popExitAnim;
mOps.add(opNum, removeOp);
added.remove(old);
opNum++;
}
}
}
if (alreadyAdded) {
mOps.remove(opNum);
opNum--;
} else {
op.cmd = OP_ADD;
added.add(f);
}
OP_REPLACE首先吧cmd变成OP_REMOVE,然后执行的是added.remove(old);操作,然后执行 added.add(f);CMD变为OP_ADD
void executeOps() {
final int numOps = mOps.size();
for (int opNum = 0; opNum < numOps; opNum++) {
final Op op = mOps.get(opNum);
final Fragment f = op.fragment;
if (f != null) {
f.setNextTransition(mTransition, mTransitionStyle);
}
switch (op.cmd) {
case OP_ADD:
f.setNextAnim(op.enterAnim);
mManager.addFragment(f, false);
break;
case OP_REMOVE:
f.setNextAnim(op.exitAnim);
mManager.removeFragment(f);
break;
case OP_HIDE:
f.setNextAnim(op.exitAnim);
mManager.hideFragment(f);
break;
case OP_SHOW:
f.setNextAnim(op.enterAnim);
mManager.showFragment(f);
break;
case OP_DETACH:
f.setNextAnim(op.exitAnim);
mManager.detachFragment(f);
break;
case OP_ATTACH:
f.setNextAnim(op.enterAnim);
mManager.attachFragment(f);
break;
case OP_SET_PRIMARY_NAV:
mManager.setPrimaryNavigationFragment(f);
break;
case OP_UNSET_PRIMARY_NAV:
mManager.setPrimaryNavigationFragment(null);
break;
default:
throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
}
if (!mReorderingAllowed && op.cmd != OP_ADD && f != null) {
mManager.moveFragmentToExpectedState(f);
}
}
if (!mReorderingAllowed) {
// Added fragments are added at the end to comply with prior behavior.
mManager.moveToState(mManager.mCurState, true);
}
}
执行的是 mManager.removeFragment(f);
removeFragment()会把上一个Fragment移除
mManager.addFragment(f, false);
addFragment() 会把新的Fragment添加到容器中
replace()的源码就是把之前的移除,会重新执行Fragment生命周期, 会重新绘制界面
封装工具类
package com.qufu.fragmentdemo.helper;
import android.support.annotation.IdRes;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import java.util.List;
public class FragmentManagerHelper {
private FragmentManager mFragmentManager;
private int mContainerViewId;
/**
* 构造函数
*
* @param fragmentManager 管理类FragmentManager
* @param containerViewId 容器布局id containerViewId
*/
public FragmentManagerHelper(@Nullable FragmentManager fragmentManager, @IdRes int containerViewId) {
this.mFragmentManager = fragmentManager;
this.mContainerViewId = containerViewId;
}
/**
* 添加Fragment
*/
public void add(Fragment fragment) {
// 开启事物
FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
// 第一个参数是Fragment的容器id,需要添加的Fragment
fragmentTransaction.add(mContainerViewId, fragment);
// 一定要commit
fragmentTransaction.commit();
}
/**
* 切换显示Fragment
*/
public void switchFragment(Fragment fragment) {
// 开启事物
FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
// 1.先隐藏当前所有的Fragment
List<Fragment> childFragments = mFragmentManager.getFragments();
for (Fragment childFragment : childFragments) {
fragmentTransaction.hide(childFragment);
}
// 2.如果容器里面没有我们就添加,否则显示
if (!childFragments.contains(fragment)) {
fragmentTransaction.add(mContainerViewId, fragment);
} else {
fragmentTransaction.show(fragment);
}
// 一定要commit
fragmentTransaction.commit();
}
}
- 使用案例
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.BottomNavigationView;
import android.support.v4.app.Fragment;
import android.support.v7.app.AppCompatActivity;
import android.view.MenuItem;
import com.qufu.fragmentdemo.helper.FragmentManagerHelper;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
private BottomNavigationView mNavigation;
private FragmentManagerHelper mFragmentManagerHelper;
private ArrayList<Fragment> fragments = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mFragmentManagerHelper = new FragmentManagerHelper(getSupportFragmentManager(), R.id.fl_main);
fragments.add(OneFragment.newInstance());
fragments.add(TwoFragment.newInstance());
fragments.add(ThreeFragment.newInstance());
fragments.add(FourFragment.newInstance());
mFragmentManagerHelper.add(fragments.get(0));
initView();
initListener();
}
@SuppressLint("NewApi")
private void initView() {
mNavigation = (BottomNavigationView) findViewById(R.id.navigation);
}
private void initListener() {
mNavigation.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_home:
mFragmentManagerHelper.switchFragment(fragments.get(0));
return true;
case R.id.navigation_fun:
mFragmentManagerHelper.switchFragment(fragments.get(1));
return true;
case R.id.navigation_income:
mFragmentManagerHelper.switchFragment(fragments.get(2));
return true;
case R.id.navigation_notifications:
mFragmentManagerHelper.switchFragment(fragments.get(3));
return true;
}
return false;
}
});
}
}