[英]setRetainInstance(true) + setCustomAnimations(…) = animation for each orientation change?
I have an activity with a fragment that needs to be animated when being created, but not when the orientation changes . 我有一个活动,片段需要在创建时动画,但不是在方向改变时。
The fragment is being inserted into a layout dynamically, as it's a part of a navigation-drawer-style activity. 片段被动态插入到布局中,因为它是导航抽屉式活动的一部分。
I wanted to avoid re-creating the fragment for configuration changes, so I used setRetainInstance in the fragment. 我想避免为配置更改重新创建片段,所以我在片段中使用了setRetainInstance。 It works, but for some reason the animation also restarts each time I rotate the device. 它可以工作,但由于某些原因,每次旋转设备时动画也会重新启动。
I've added this to the fragment: 我已将此添加到片段中:
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
and this to the activity: 这对活动:
final FragmentManager fragmentManager = getSupportFragmentManager();
final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
MyFragment fragment= (MyFragment) fragmentManager.findFragmentByTag(MyFragment.TAG);
if (fragment== null) {
fragmentTransaction.setCustomAnimations(R.anim.slide_in_from_left, R.anim.slide_out_to_right);
fragment= new MyFragment();
fragmentTransaction
.add(R.id.fragmentContainer, fragment, MyFragment.TAG).commit();
}
fragment_container.xml fragment_container.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/fragmentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent" />
This solution works in general, but it causes bad things to the lifecycle you've tried to achieve : 这个解决方案通常起作用,但它会给你试图实现的生命周期带来不好的结果:
MyFragment fragment= (MyFragment) fragmentManager.findFragmentByTag(MyFragment.TAG);
if (MyFragment== null) {
MyFragment= new MyFragment();
fragmentManager.beginTransaction().setCustomAnimations(R.anim.slide_in_from_left, R.anim.slide_out_to_right)
.replace(R.id.fragmentContainer, fragment, MyFragment.TAG).commit();
} else {
//workaround: fragment already exists, so avoid re-animating it by quickly removing and re-adding it:
fragmentManager.beginTransaction().remove(fragment).commit();
final Fragment finalFragment = fragment;
new Handler().post(new Runnable() {
@Override
public void run() {
fragmentManager.beginTransaction().replace(R.id.fragmentContainer, fragment, finalFragment .TAG).commit();
}
});
}
I would still want to see what can be done, because this can cause things you didn't want to occur(onDetach for the fragment, for example). 我仍然希望看到可以做什么,因为这可能导致你不想发生的事情(例如onDetach片段)。
One way to solve this is to avoid adding the animation via the fragmentManager, and just do it for the view itself within the fragment lifecycle. 解决此问题的一种方法是避免通过fragmentManager添加动画,并在片段生命周期内为视图本身执行此操作。 This is how it looks like: 这是它的样子:
BaseFragment BaseFragment
@Override
public void onViewCreated(final View rootView, final Bundle savedInstanceState) {
super.onViewCreated(rootView, savedInstanceState);
if (savedInstanceState == null)
rootView.startAnimation(AnimationUtils.loadAnimation(getActivity(), R.anim.slide_in_from_left));
}
@Override
public void onDestroyView() {
super.onDestroyView();
if (!getActivity().isChangingConfigurations())
getView().startAnimation(AnimationUtils.loadAnimation(getActivity(), R.anim.fade_out));
}
How about you override the onCreateAnimation()
method and prevent the animation from happening if the fragment is being recreated after a rotation? 你如何覆盖onCreateAnimation()
方法并防止在旋转后重新创建片段时发生动画?
As shown here: How to disable/avoid Fragment custom animations after screen rotation 如下所示: 如何在屏幕旋转后禁用/避免片段自定义动画
EDIT: Here's a sample code: 编辑:这是一个示例代码:
BaseFragment.java BaseFragment.java
...
private boolean mNeedToAvoidAnimation;
@Override
public void onDestroyView() {
super.onDestroyView();
mNeedToAvoidAnimation = true;
}
@Override
public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
// This avoids the transaction animation when the orienatation changes
boolean needToAvoidAnimation = mNeedToAvoidAnimation;
mNeedToAvoidAnimation = false;
return needToAvoidAnimation ? new Animation() {
} : super.onCreateAnimation(transit, enter, nextAnim);
}
This fragment should be the base one that all fragments in this activity will extend. 此片段应该是此活动中所有片段将扩展的基础片段。
take a look at your code again: 再看看你的代码:
final FragmentManager fragmentManager = getSupportFragmentManager();
final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
MyFragment fragment= (MyFragment)
fragmentManager
.findFragmentByTag(MyFragment.TAG);
if (fragment== null) {
fragmentTransaction.setCustomAnimations(R.anim.slide_in_from_left, R.anim.slide_out_to_right);
fragment= new MyFragment();
fragmentTransaction
.add(R.id.fragmentContainer, fragment,
PhoneInsertionFragment.TAG).commit();
}
you're using MyFragment.TAG
to find the fragment, but you're adding to transaction with PhoneInsertionFragment.TAG
. 您正在使用MyFragment.TAG
找到片段,但你增加交易与PhoneInsertionFragment.TAG
。
That's why you're getting the animation and the fragment re-creating every time. 这就是为什么你每次都要重新创建动画和片段的原因。 Just use the same tag for find
and add
and it should be fine. 只需使用相同的标签进行find
和add
。
Why it is occurring because when fragment manager tries to re-attach the fragment on orientation, it applies the animations which already stored in the transaction. 为什么会发生这种情况,因为当片段管理器尝试在方向上重新附加片段时,它会应用已存储在事务中的动画。 (ie which you set when the fragment was added). (即添加片段时设置的)。
We solved this by handling orientation change in activity itself. 我们通过处理活动本身的方向变化来解决这个问题 If you want to change the UI design, attach and detach the fragment in onConfigChanges method. 如果要更改UI设计,请在onConfigChanges方法中附加和分离片段。
I studied the code, looks like the animation information is saved in Fragment.animationInfo, this value is set by 我研究了代码,看起来动画信息保存在Fragment.animationInfo中,这个值是由设置的
BackStackState.executeOps() -> Fragment.setNextAnim(int animResourceId)
By default, re-creating the fragment will discard the animation information, but if you set fragment retainInstance, the animation information will also is retained 默认情况下,重新创建片段将丢弃动画信息,但如果设置片段retainInstance,则动画信息也将保留
My solution: 我的解决方案
class TestFragment : Fragment() {
override fun onDetach() {
super.onDetach()
if (retainInstance) {
// use reflect clear retain Animation
reflectField<Fragment>("mAnimationInfo").set(this, null)
}
}
@Throws(NoSuchFieldException::class, SecurityException::class)
inline fun <reified T : Any> reflectField(name: String): Field {
val field = T::class.java.getDeclaredField(name)
field.isAccessible = true
return field
}
}
I only tested support.v4.app.Fragment, but I think this solution also applies to android.app.Fragment 我只测试了support.v4.app.Fragment,但我认为这个解决方案也适用于android.app.Fragment
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.