在使用FragmentTransaction的时候,它提供了两种方法,add和replace
add和replace影响的只是界面,而控制回退的,是事务
add是把一个fragment添加到一个容器container里
replace是先remove掉相同的id的所有的fragment,然后在add当前的fragment
在大部分情况下,这两个的表现基本相同。因为,一般会使用一个FrameLayout来当容器,而每个Fragment被add或者replace到这个FrameLayout的时候,都是显示在最上层,所以看到的界面都一样。但是在add的时候,这个FrameLayout其实是两层/多层。
每次replace会把声明周期重新走一遍,如果在这些生命周期里拉取数据的话,就会不断重复的加载刷新数据,可以用add的方法解决.
eg:
private void initView() {
one = findViewById(R.id.one);
two = findViewById(R.id.two);
three = findViewById(R.id.three);
change("one");
one.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
change("one");
}
});
two.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
change("two");
}
});
three.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
change("three");
}
});
}
private void change(String tag) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction f = fragmentManager.beginTransaction();
FragmentOne fragmentone = (FragmentOne) fragmentManager.findFragmentByTag("one");
FragmentTwo fragmenttwo = (FragmentTwo) fragmentManager.findFragmentByTag("two");
FragmentThree fragmentthree = (FragmentThree) fragmentManager.findFragmentByTag("three");
if ("one".equals(tag)) {
if (null != fragmenttwo) {
f.hide(fragmenttwo);
}
if (null != fragmentthree) {
f.hide(fragmentthree);
}
if (fragmentone == null) {
fragmentone = new FragmentOne();
f.add(R.id.content, fragmentone, tag);
}else{
f.show(fragmentone);
}
} else if ("two".equals(tag)) {
if (null != fragmentone) {
f.hide(fragmentone);
}
if (null != fragmentthree) {
f.hide(fragmentthree);
}
if (fragmenttwo == null) {
fragmenttwo = new FragmentTwo();
f.add(R.id.content, fragmenttwo, tag);
}else{
f.show(fragmenttwo);
}
//
} else if ("three".equals(tag)) {
if (null != fragmentone) {
f.hide(fragmentone);
}
if (null != fragmenttwo) {
f.hide(fragmenttwo);
}
if (fragmentthree == null) {
fragmentthree = new FragmentThree();
f.add(R.id.content, fragmentthree, tag);
} else {
f.show(fragmentthree);
}
}
f.commit();
}
关于Fragment回退问题,在事务调用commit之前,为了把事务添加到Fragment事务的回退堆栈,你可能要调用addToBackStack()方法。这个回退堆栈被Activity管理,并且允许用户通过返回按钮回到之前的状态。
eg:
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
transaction.commit();
如果给事务添加多个改变(如用add()或remove()方法),并且调用了addToBackStack()方法,那么所有这些改变在调用commit()方法之前,都会作为一个单一的事务被添加到回退堆栈中,并且案返回按钮时,所有这些改变将会被恢复.
在你执行删除Fragment的事务时,如果没有调用addToBackStack()方法,那么Fragment将会在事务被提交时销毁,并且用户不能再向后导航。因此,在删除Fragment时,如果调用了addToBackStack()方法,那么这个Fragment就会被终止,并且用户向后导航时将会被恢复。
调用commit()方法并不立即执行这个事务,而是在Activity的UI线程之上(”main”线程)调度运行,以便这个线程能够尽快执行这个事务。但是,如果需要,可以调用来自UI线程的executePendingTransactions()方法,直接执行被commit()方法提交的事务。通常直到事务依赖其他线程的工作时才需要这样做。
警告:你能够使用commit()方法提交一个只保存之前Activity状态的事务(在用户离开Activity时)。如果试图在用户离开Activity之后提交,将会发生一个异常。这是因为如果Activity需要被恢复,而提交之后的状态却丢失了。这种情况下,使用commitAllowingStateLoss()方法,你丢失的提交就没问题了。
提示:对于每个Fragment事务,你能够在提交之前通过调用setTransition()方法,申请一个过渡动画
标准转场动画:
可以给Fragment指定标准的转场动画,通过setTransition(int transit)方法。
该方法可传入的三个参数是:
TRANSIT_NONE,
TRANSIT_FRAGMENT_OPEN,
TRANSIT_FRAGMENT_CLOSE
分别对应无动画、打开形式的动画和关闭形式的动画。
标准动画设置好后,在Fragment添加和移除的时候都会有。
自定义转场动画
自定义转场动画是通过setCustomAnimations()方法,因为Fragment添加时可以指定加入到Back Stack中,所以转场动画有添加、移除、从Back stack中pop出来,还有进入四种情况。
注意setCustomAnimations()方法必须在add、remove、replace调用之前被设置,否则不起作用。
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
//自带的动画
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
//自定义动画
//注意setCustomAnimations()方法必须在add、remove、replace调用之//前被设置,否则不起作用
ft.setCustomAnimations(R.anim.slide_left_in, R.anim.slide_right_in);