popup片段叠加而不popupPop-Animation
我使用以下代码在片段堆栈上推送一个片段:
FragmentManager fragmentManager = getActivity().getSupportFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); fragmentTransaction.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_right, R.anim.slide_in_left, R.anim.slide_out_left); fragmentTransaction.replace(getId(), newFragment); fragmentTransaction.addToBackStack(null); fragmentTransaction.commit();
这样,当片段堆栈popup时,例如通过按下后退button,播放片段popupanimation。 但是,在某些情况下,我想popup片段叠加而不显示该animation,例如,因为我刚刚从另一个活动返回,并希望一次显示前一个片段,而没有animation。
示例导航可能如下所示:
- 用户在开始屏幕上的根片段
- 他在根片段上select一个项目,然后显示一个新的片段来显示该项目的细节。 它使用一个片段事务来为推送和stream行案例设置animation(所以当用户按下后退button时,过渡是animation的)
- 从这个片段他开始了一个活动(不pipe什么原因)删除刚才显示的项目
- 当这个活动结束时,我想返回到根片段而不显示“细节片段”的“stream行animation”
有没有方法来popup片段的堆栈,而不玩指定的stream行animation?
所以Warpzit是在正确的轨道上,他只是没有解决你的具体问题。 我遇到了完全相同的问题,这是我如何解决它。
首先我创build了一个静态布尔variables(为了简单起见,我们把它放在FragmentUtils类中)…
public class FragmentUtils { public static boolean sDisableFragmentAnimations = false; }
然后,在每个片段中,您都需要重写onCreateAnimation方法…
@Override public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) { if (FragmentUtils.sDisableFragmentAnimations) { Animation a = new Animation() {}; a.setDuration(0); return a; } return super.onCreateAnimation(transit, enter, nextAnim); }
然后,当您需要清除您的活动中的后台时,只需执行以下操作…
public void clearBackStack() { FragmentUtils.sDisableFragmentAnimations = true; getSupportFragmentManager().popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); FragmentUtils.sDisableFragmentAnimations = false; }
而且,对clearBackStack()的调用将会让你回到没有任何转换animation的根片段中。
希望大G能够在未来增加一个不那么愚蠢的做法。
所以对于支持库下面的工作:
在应该有自定义stream行animation的片段中,您可以用自己的自定义属性覆盖onCreateAnimation。 你可以得到它,并根据你想要的设置某种参数。 可能需要做一些额外的工作才能使它与常规片段一起工作。
这里是我重写它并更改设置持续时间的示例:
@Override public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) { Animation anim = (Animation) super.onCreateAnimation(transit, enter, nextAnim); if(!enter) { if(anim != null) { anim.setDuration(0); // This doesn't seem to be called. return anim; } else { Animation test = new TestAnimation(); test.setDuration(0); return test; } } return anim; } private class TestAnimation extends Animation { }
用户在开始屏幕上的根片段
可以说,根分片包含在Activity A中
他在根片段上select一个项目,然后显示一个新的片段来显示该项目的细节。 它使用一个片段事务来为推送和stream行案例设置animation(所以当用户按下后退button时,过渡是animation的)
该事务被添加到后退堆栈。 这意味着当从详细片段按下后退button时,popup过程被激活。
从这个片段他开始了一个活动(不pipe什么原因)删除刚才显示的项目。
让我们说这是活动乙
当这个活动结束时,我想返回到根片段而不显示“细节片段”的“stream行animation”
获取此行为的一种方法是在活动B中执行此操作:
Intent intent = new Intent(this, A.class); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); finish();
这将启动活动A,根据文档将其重置为根状态(查看“这个启动模式也可以与FLAG_ACTIVITY_NEW_TASK一起使用效果良好:……”一节中的最后一段) )
使用此configuration,animation将以默认情况下呈现,而在特殊情况下,您可以使用以下方式控制animation:
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
没有任何animation就开始新的活动。 如果你想要任何animation,你可以使用overridePendingTransition
方法。
所以,我想build议对@Geoff的答案做个小小的改动。
而不是有一个全局的静态布尔,我宁愿有一个本地非静态的。 这是我想出来的。
创build一个界面
public interface TransitionAnimator { void disableTransitionAnimation(); void enableTransitionAnimation(); }
制作界面的片段工具。
public class MyFragment extends Fragment implements TransitionAnimator { private boolean mTransitionAnimation; @Override public void disableTransitionAnimation() { mTransitionAnimation = false; } @Override public void enableTransitionAnimation() { mTransitionAnimation = true; } @Override public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) { Animation result; if (!mTransitionAnimation) { Animation dummyAnimation = new Animation() { }; dummyAnimation.setDuration(0); result = dummyAnimation; } else { result = super.onCreateAnimation(transit, enter, nextAnim); } return result; }
然后,当你想禁用一个片段的过渡animation,就这样做
if (fragment instanceof TransitionAnimator) { ((TransitionAnimator) fragment).disableTransitionAnimation(); }
为了使他们,只是做
if (fragment instanceof TransitionAnimator) { ((TransitionAnimator) fragment).enableTransitionAnimation(); }
如果你想对片段pipe理器中的所有片段做同样的事情,那就做吧
List<Fragment> fragments = getSupportFragmentManager().getFragments(); for (Fragment fragment : fragments) { if (fragment instanceof TransitionAnimator) { // disable animations ((TransitionAnimator) fragment).disableTransitionAnimation(); } }
非常相似,但没有静态字段。
只需使用setCustomAnimation()
另一个重载方法,并在其中不设置R.anim.slide_out ,这将解决您的问题
干杯:)
在回答你的问题之前,我需要自己提出一个问题。
在第二个activity的onBackPressed()方法中,你可以访问第一个activity的backstack吗?
如果是的话,那么你可以调用popBackStackImmediate(String trnaisiotnName,int inclusive),它将从堆栈中删除片段的过渡,你不需要担心animation。
我假设你可以访问以前的活动的后台,否则这将无法正常工作
这通过overridePendingTransition(int enterAnim, int exitAnim)
可以非常容易的实现overridePendingTransition(int enterAnim, int exitAnim)
对于没有animation的情况都是0
。
FragmentManager fm = getSupportFragmentManager(); if (fm.getBackStackEntryCount() > 0) { fm.popBackStack(); overridePendingTransition(0, 0); }
这是@ Geoff的出色答案的后续,但适合更具活力和真实生活的情况。
我想这是一个不错的小贴子,但是现在我意识到它有点失控了。 然而,代码是在那里,我觉得它真的很有用,但它不仅涵盖了如何禁用过渡animation。
通常,当我使用片段时,我喜欢将BaseFragment连接到BaseActivityCallback。 这个BaseActivityCallback可以被我的Fragments用来在它自己之上添加一个新的Fragment,或者甚至popup它下面的Fragment,因此可以禁用popanimation – 或者默默地popup:
interface BaseActivityCallback { void addFragment ( BaseFragment f, int containerResId ); void popFragment ( boolean silently ); } class BaseActivity extends android.support.v4.app.FragmentActivity implements BaseActivityCallback { public void addFragment ( BaseFragment f, int containerResId ) { FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); ft.setCustomAnimations(R.anim.enter, R.anim.exit, R.anim.enter, R.anim.pop_exit); // http://stackoverflow.com/a/17488542/2412477 ft.addToBackStack(DEFAULT_FRAGMENT_STACK_NAME); ft.replace(containerResId, fragment); ft.commitAllowingStateLoss(); } public void popFragment ( boolean silently ) { FragmentManager fm = getSupportFragmentManager(); if ( silently ) { int count = fm.getFragments().size(); BaseFragment f = (BaseFragment)fm.getFragments().get(count-1); f.setDisableTransitionAnimations(true); } fm.popBackStackImmediate(); } } public abstract class BaseFragment extends android.support.v4.app.Fragment { private static final String TAG = "BaseFragment"; private final String STATE_DISABLE_TRANSITION_ANIMATIONS = TAG+".stateDisableTransitionAnimations"; protected BaseActivityCallback baseActivityCallback; private boolean disableTransitionAnimations; @Override public void onCreate ( @Nullable Bundle savedInstanceState ) { super.onCreate(savedInstanceState); disableTransitionAnimations = (savedInstanceState==null ? false : savedInstanceState.getBoolean(STATE_DISABLE_TRANSITION_ANIMATIONS, false)); } @Override public void onAttach ( Context context ) { super.onAttach(context); baseActivityCallback = (BaseActivityCallback)context; } @Override public void onSaveInstanceState ( Bundle outState ) { super.onSaveInstanceState(outState); outState.putBoolean(STATE_DISABLE_TRANSITION_ANIMATIONS, disableTransitionAnimations); } @Override public Animation onCreateAnimation ( int transit, boolean enter, int nextAnim ) { if ( disableTransitionAnimations ) { Animation nop = new Animation(){}; nop.setDuration(0); return nop; } return super.onCreateAnimation(transit, enter, nextAnim); } public void setDisableTransitionAnimations ( boolean disableTransitionAnimations ) { this.disableTransitionAnimations = disableTransitionAnimations; // http://stackoverflow.com/a/11253987/2412477 } }
现在你可以创build你的MainActivity
,并显示一个Fragment1
,它可以添加另一个Fragment2
,然后默认popupFragment1
:
public class MainActivity extends BaseActivity { protected void onCreate ( Bundle savedInstanceState ) { setContentView(R.layout.main_activity); ... if ( getSupportFragmentManager().getFragments() != null && !getSupportFragmentManager().getFragments().isEmpty() ) { addFragment( FragmentA.newInstance(), R.id.main_activity_fragment_container ); } } ... } public class FragmentA extends BaseFragment { public View onCreateView ( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState ) { ViewGroup root = (ViewGroup)inflater.inflate(R.layout.fragment_a, container, false); ... root.findViewById(R.id.fragment_a_next_button) .setOnClickListener( new View.OnClickListener() { public void onClick ( View v ) { baseActivityCallback.addFragment( FragmentB.newInstance(), R.id.main_activity_fragment_container ); } }); } } public class FragmentB extends BaseFragment { public View onCreateView ( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState ) { ViewGroup root = (ViewGroup)inflater.inflate(R.layout.fragment_b, container, false); ... root.findViewById(R.id.fragment_b_pop_silently_button) .setOnClickListener( new View.OnClickListener() { public void onClick ( View v ) { baseActivityCallback.popFragment( true ); } }); } }
在您想要popup的片段中覆盖此选项,而不inputanimation,并在input时仍保留animation
@Override public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) { if(!enter){ Animation a = new Animation() {}; a.setDuration(0); return a; } return super.onCreateAnimation(transit, enter, nextAnim); }
回复杰夫和普莱克马赫的评论。
你可以尝试删除这个片段的所有视图。 然后片段将显示,但它应该是透明的。
删除所有-1(我使用导航抽屉,所以抽屉碎片应停留)片段:
int size = fragmentsList.size ()-1; FragmentTransaction transaction = fragmentManager.beginTransaction (); transaction.setTransition (FragmentTransaction.TRANSIT_NONE); Fragment fragment; for (int i = size ; i > 0 ; i--) { fragment = fragmentsList.get (i); if(fragment != null) { View viewContainer = fragment.getView (); if (viewContainer != null) { ((ViewGroup) viewContainer).removeAllViews (); } transaction.remove (fragment); } } size = fragmentManager.getBackStackEntryCount (); for (int i = 0; i < size ; i++) { fragmentManager.popBackStack (null, FragmentManager.POP_BACK_STACK_INCLUSIVE); }
对不起我的英语不好