2012-02-08 2 views
43

Я толкаю фрагмент в стеке фрагмента, используя следующий код:Поп фрагмент backstack без воспроизведения поп-анимации

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(); 

Таким образом, когда стек фрагмент извлекается, например нажатием кнопки «Назад» воспроизводится анимация поп-фрагмента. Тем не менее, есть ситуации, в которых я хотел бы поместить фрагмент backstack, не показывая эту анимацию, например. потому что я только что вернулся из другого действия и хочу отобразить предыдущий фрагмент сразу, без анимации.

Пример навигация может выглядеть следующим образом:

  • Пользователь находится на начальном экране с корнем фрагментом
  • Он выбирает элемент на фрагменте корня, который затем отображает новый фрагмент, чтобы показать детали это item. Он делает это, используя транзакцию фрагмента, которая устанавливает анимацию как для нажатия, так и для поп-кейса (поэтому, когда пользователь нажимает кнопку «Назад», переход анимируется)
  • Из этого фрагмента начинается действие, которое (по какой-либо причине) удаляет элемент, который был только что показал
  • После завершения этой деятельности, я хотел бы вернуться к корневому фрагменту, не показывая «поп-анимацию» из «фрагмента детали»

есть ли способ, чтобы совать фрагмент backstack без воспроизведения указанной поп-анимации?

+0

Что вы имеете в виду, я только что вернулся из другой деятельности? Можете ли вы рассказать о шагах перехода, то есть о том, как вы пытаетесь перемещаться. – 500865

+0

Привет, 500865, я добавил пример навигации по вопросу. – ChristophK

+0

не устанавливает 0 как 3-й и 4-й аргументы в setCustomAnimations делать это? – Boy

ответ

72

Так Warpzit был на правильном пути, он просто не рассматривал конкретный вопрос слишком хорошо. Я столкнулся с одной и той же проблемой, и вот как я ее решил.

Сначала я создал статическую логическую переменную (для простоты, позволяет поместить его в классе 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); 
} 

Затем, когда вам нужно очистить backstack от вашей деятельности просто сделайте следующее ...

public void clearBackStack() { 
    FragmentUtils.sDisableFragmentAnimations = true; 
    getSupportFragmentManager().popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); 
    FragmentUtils.sDisableFragmentAnimations = false; 
} 

И voila, вызов clearBackStack() вернет вас обратно в корневой фрагмент без каких-либо переходных анимаций.

Надеюсь, большой G добавит менее глупый способ сделать это в будущем.

+6

Это работает, но фрагмент по-прежнему будет отображаться для краткого Рамка. Есть ли способ, чтобы он вообще не появлялся? – plackemacher

+1

+1, кажется, единственное, что работает для меня на 2.3 и 4.3 :) – Dori

+7

+1 Нужно иметь в виду, что это работает только с popBackStackImmediate (он не работает с popBackStack). – Tiago

0

Просто используйте другой перегруженный метод из setCustomAnimation() и в котором не устанавливает R.anim.slide_out и что будет решить вашу проблему

Приветствие :)

+0

однако это предотвратит любую анимацию из игры, когда пользователь нажимает кнопка назад, не так ли? Я хочу, чтобы анимация в случае по умолчанию (пользователь нажимает кнопку «Назад»), однако есть случай, когда стек фрагментов вызывается в ответ на нажатие кнопки, и в этом случае я не хочу анимации. – ChristophK

4

Пользователь находится на начальный экран с корневым фрагментом

Скажем, фрагмент корня содержится в действии A.

Он выбирает элемент корневого фрагмента, который затем отображает новый фрагмент, чтобы отобразить детали этого элемента. Он делает это, используя транзакцию фрагмента, которая устанавливает анимацию как для нажатия, так и для поп-кейса (поэтому, когда пользователь нажимает кнопку «Назад», переход анимируется)

Сделка добавляется в задний стек. Это означает, что при нажатии кнопки «Назад» из фрагмента детали процесс popping анимируется.

Из этого фрагмента начинается действие, которое (по какой-либо причине) удаляет только что показанный объект.

Позволяет сказать, что активность B

После завершения этой деятельности, я хотел бы вернуться к корневому фрагмента, не показывая «поп-анимации» из «фрагмента деталь»

Одним из способов получения такого поведения, делая это в активность 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(); 

Это начнется тыс e Activity A, сбросив его в его корневое состояние в соответствии с documentation (проверьте последний абзац в разделе, в котором говорится: «Этот режим запуска также может быть использован для хорошего эффекта в сочетании с FLAG_ACTIVITY_NEW_TASK: ......»)

при такой конфигурации, анимация будет присутствовать в случае, если по умолчанию в то время как в частном случае, вы можете управлять анимацией с помощью:

intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); 

который начинает новую деятельность без какой-либо анимации. Если вам нужна анимация, вы можете сделать это, используя метод overridePendingTransition.

+0

Спасибо за ваш ответ! Для моего конкретного приложения есть только одна проблема: активность A содержится внутри TabHost, которая создается моей «основной деятельностью» (назовем ее C). Есть ли способ сбросить A без сброса C? – ChristophK

+0

Если вы проверите первый абзац в ссылке, опубликованной в ответе, вы увидите, что «все остальные действия поверх нее будут закрыты». Поскольку C находится ниже A в стеке (Tabhost Activity будет находиться в нижней части стека), он не будет перезагружен C. – 500865

+0

К сожалению, это не работает: когда я запускаю ваш код в активности B, активность A не отображается на его вкладке больше, вместо этого отображается «полноэкранный» – ChristophK

6

Так что для библиотеки поддержки следующих работ:

В фрагменте, который должен иметь собственный поп-анимацию вы переопределение 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 { 

} 
+0

Ответ на Warpzit на самом деле правильный, просто не объясняется супер хорошо ... Так как я не могу опубликовать код в комментарии, я отправлю еще один ответ ... – Geoff

0

Прежде чем ответить на ваш вопрос, мне нужно задать вопрос сам.

В методе onBackPressed() второго действия вы можете получить доступ к стопке первой операции?

Если да, то вы можете вызвать popBackStackImmediate (String trnaisiotnName, int inclusive), и он удалит переход фрагмента из backstack, и вам не нужно беспокоиться о анимации.

Я предполагаю, что вы можете получить доступ к backstack предыдущей деятельности, в противном случае это не будет работать

-1

Ответить на Джефф и plackemacher комментария.

Вы можете удалить все мнения из этого фрагмента. Тогда фрагмент покажет, но он должен быть прозрачным.

Удалить все-1 (я использую NAVIGATE ящик так осколок ящик должен остаться) фрагмент:

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); 
    } 

Извините за мой английский

0

Это довольно легко достичь с помощью overridePendingTransition(int enterAnim, int exitAnim) как с 0 без всякой анимации ,

FragmentManager fm = getSupportFragmentManager(); 
if (fm.getBackStackEntryCount() > 0) { 
    fm.popBackStack(); 
    overridePendingTransition(0, 0); 
} 
+1

Это работает только в том случае, если вы работаете с действиями. Вопрос касается фрагментов. – LightMan

1

Итак, я хотел бы предложить небольшое изменение для ответа Джеффа.

Вместо того, чтобы иметь глобальное статическое булево значение, я бы предпочел иметь локальный нестатический. Это то, что я придумал.

Создать интерфейс

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; 
    } 

И тогда, когда вы хотите, чтобы отключить анимацию перехода для фрагмента, просто сделать

if (fragment instanceof TransitionAnimator) { 
    ((TransitionAnimator) fragment).disableTransitionAnimation(); 
} 

, чтобы включить их, просто сделать

if (fragment instanceof TransitionAnimator) { 
    ((TransitionAnimator) fragment).enableTransitionAnimation(); 
} 

Если вы хотите сделать то же самое для всех фрагментов в менеджере фрагментов, просто сделайте

List<Fragment> fragments = getSupportFragmentManager().getFragments(); 
for (Fragment fragment : fragments) { 
    if (fragment instanceof TransitionAnimator) { 
     // disable animations 
     ((TransitionAnimator) fragment).disableTransitionAnimation(); 
    } 
} 

Очень похоже, но без статических полей.

0

Это продолжение замечательного ответа Джеффа, но для более динамичного и реального сценария.

Я подумал, что это хорошая записка, но теперь я понимаю, что она немного вышла из-под контроля. Тем не менее, код все там, и я нахожу его действительно полезным, хотя он охватывает гораздо больше, чем просто отключить переходные анимации.

Обычно, когда я работаю с фрагментами, мне нравится иметь BaseFragment, который прикрепляется к BaseActivityCallback.Это BaseActivityCallback может быть использован в моих фрагментов, чтобы добавить новый фрагмент поверх себя, или даже поп-фрагменты под ним, следовательно, желание отключить всплывающие анимации - или поп молча:

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 
    } 
} 

сейчас вы можете создать свой MainActivity и есть что показать Fragment1, который может добавить еще один Fragment2, который в свою очередь может поп Fragment1молча:

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); 
       } 
      }); 
    } 
} 
0

Override этом во фрагменте, который вам хотите поп без анимации и продолжайте анимацию при вводе

@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); 
} 
Смежные вопросы