当我从replace
拨打FragmentManager
以打开新片段时,是否可以保持片段运行?
基本上我不希望在导航(通过replace
方法)到另一个片段时暂停片段。
有可能吗? 或者正确的方法是,每当我需要打开它并恢复其先前的状态时,总是会实例化一个新的片段吗?
谢谢!
答案 0 :(得分:9)
FragmentManger replace方法将完全破坏前一个片段,因此在每个事务onDestroyView()中,onDestroy()和onDetach()将在前一个片段上被调用。如果你想保持你的片段运行,你可以使用FragmentManger hide()和show()方法!它隐藏并显示碎片而不破坏它们。
所以首先将两个片段添加到片段管理器中,并隐藏第二个片段。
fragmentManager.beginTransaction()
.add(R.id.new_card_container, FragmentA)
.add(R.id.new_card_container,FragmentB)
.hide(FragmentB)
.commit();
请注意,您只能在隐藏片段上调用show()。所以在这里你不能在FragmentA上调用show(),但这不是问题,因为通过隐藏和显示FragmentB你可以获得你想要的替换效果。
这是一种在片段之间来回切换的方法。
public void showOtherFragment() {
if(FragmentB.isHidden()){
fragmentManager.beginTransaction()
.show(FragmentB).commit();
} else {
fragmentManager.beginTransaction()
.hide(FragmentB).commit();
}
}
现在,如果你把日志消息放在片段回调方法中,你会看到没有破坏(除了屏幕方向改变!),甚至视图也不会被破坏,因为onDistroyView没有被调用。
只有一个问题就是,第一次应用程序启动onCreateView()方法时会为每个片段调用一次(它应该是!)但是当方向更改onCreateView()时会为每个片段调用两次,这是因为片段一旦像往常一样创建,一次因为FragmentManger的附件(保存在bundle对象上)为了避免你有两个选项1)在onSaveInstaneState()回调中分离片段。
@Override
protected void onSaveInstanceState(Bundle outState) {
fragmentManager.beginTransaction()
.detach(FragmentA)
.detach(FragmentB)
.commit();
super.onSaveInstanceState(outState);
}
它正在工作,但视图状态不会自动更新,例如,如果您有一个EditText,其文本将在每次方向更改发生时擦除。当然,您可以通过在片段中保存状态来解决这个问题,但如果使用第二个选项则不需要!
首先,我在onSaveInstaneState()方法中保存一个布尔值,以记住巫婆片段。
@Override
protected void onSaveInstanceState(Bundle outState) {
boolean isFragAVisible = true;
if(!FragmentB.isHidden())
isFragAVisible = false;
outState.putBoolean("isFragAVisible",isFragAVisible);
super.onSaveInstanceState(outState);
}
现在在活动onCreate方法中我检查以查看savedInstanceState == null。如果是,那么如果没有活动是第二次创建的话。所以片段管理器已经包含了片段。所以我得到了片段管理器中我的片段的引用。我也确保显示正确的片段,因为它没有自动恢复。
fragmentManager = getFragmentManager();
if(savedInstanceState == null){
FragmentA = new FragmentA();
FragmentB = new FragmentB();
fragmentManager.beginTransaction()
.add(R.id.new_card_container, FragmentA, "fragA")
.add(R.id.new_card_container, FragmentB, "fragB")
.hide(FragmentB)
.commit();
} else {
FragmentA = (FragmentA) fragmentManager.findFragmentByTag("fragA");
FragmentB = (FragmentB) fragmentManager.findFragmentByTag("fragB");
boolean isFragAVisible = savedInstanceState.getBoolean("isFragAVisible");
if(isFragAVisible)
fragmentManager.beginTransaction()
.hide(FragmentB)
.commit();
else
fragmentManager.beginTransaction()
.hide(FragmetA) //only if using transaction animation
.commit();
}
到目前为止,如果不使用事务动画,您的片段将完美运行。如果这样做,您还需要显示和隐藏FragmentA。因此,当你想显示FragmentB时,首先隐藏FragmentA然后显示FragmentB(在同一个事务中),当你想要隐藏FragmentB时首先隐藏它并同时显示FragmentA(再次在同一个事务中)。这是我的卡片翻转动画代码(从developer.goodle.com下载)
public void flipCard(String direction) {
int animationEnter, animationLeave;
if(direction == "left"){
animationEnter = R.animator.card_flip_right_in;
animationLeave = R.animator.card_flip_right_out;
} else {
animationEnter = R.animator.card_flip_left_in;
animationLeave = R.animator.card_flip_left_out;
}
if(cardBack.isHidden()){
fragmentManager.beginTransaction()
.setCustomAnimations(animationEnter, animationLeave)
.hide(cardFront)
.show(cardBack)
.commit();
} else {
fragmentManager.beginTransaction()
.setCustomAnimations(animationEnter,animationLeave)
.hide(cardBack)
.show(cardFront)
.commit();
}
}