Android - проблемы с анимацией значка ActionBar из фрагментов

У меня возникли проблемы с последовательной анимацией значка "обновить" в ActionBar моего приложения.

У меня есть контейнер FragmentActivity, который меняет местами фрагменты, когда пользователь перемещается через приложение (либо из самого фрагмента, либо из опции SlidingMenu). Поэтому, когда приложение загружается первым, мой FragmentContainer добавляет FragA. Из FragA пользователь может перейти к FragB, который затем заменяется.

На панели действий отображается статический значок "Обновить". Когда каждый фрагмент загружается, я заменяю его анимированным символом "spinner". Когда загрузка завершится, я вернусь к исходному значку обновления.

Проблема в том, что эта анимация работает только для исходного фрагмента (в данном случае FragA). Когда пользователь переходит к FragB и выбирает значок обновления, активируется обновление, но анимация никогда не происходит. Аналогично, если для возврата к FragA нажата кнопка "Назад", это теперь следует за тем же шаблоном, то есть кнопка обновления не изменяется при нажатии.

Что нужно отметить...

  • Я использую ActionBarSherlock и реализацию SlidingMenu в https://github.com/jfeinstein10/SlidingMenu. Таким образом, вышеуказанная активность фактически равна SlidingFragmentActivity.
  • Оба фрагмента вызова setHasOptionsMenu(true) - я отлаживал это, и onCreateOptionsMenu правильно вызывается для каждого.
  • Значки отображаются правильно для обоих фрагментов - анимация просто не происходит, когда я перемещаюсь от фрагмента по умолчанию.
  • Я вижу такое же поведение при использовании SlidingMenu для навигации - загрузки FragA, работы анимации → SlidingMenu используется для перехода к другому фрагменту... анимация не работает → кнопка "Назад" для FragA... анимация doesn Здесь тоже.
  • Я использую FragmentTransaction.remove() и add(), а не replace(), поскольку ранее у меня были проблемы с кнопками replace() - я использую lib совместимости, и здесь я читаю, что реализация replace немного багги - и не использовать его, конечно, исправил проблемы, которые я видел.

Ниже приведены фрагменты кода:

Мой код для загрузки исходного фрагмента - это....

FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.content_frame, new FragA());
ft.addToBackStack(null);
ft.commit();

Чтобы "обменять" FragB на FragA....

public void switchContent(PysoBaseFragment fragment) {
    FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
    ft.remove(existingFragment);
    ft.add(R.id.content_frame, fragment);
    ft.addToBackStack(null);
    ft.commit();
}

Этот метод объявляется в активности контейнера и вызывается из FragA i.e....

getFragmentContainer().switchContent(new FragB());

Код для вращения значка вызывается из нового фрагмента, когда он начинает загружаться. Его что-то вроде...

    ImageView spinnerActionView = (ImageView) inflater.inflate(R.layout.refresh_action_view, null);
    Animation rotation = AnimationUtils.loadAnimation(this, R.anim.rotate_animation);
    rotation.setRepeatCount(Animation.INFINITE);
    spinnerActionView.startAnimation(rotation);
    menuItemRefresh = menu.findItem(R.id.menu_refresh);
    menuItemRefresh.setActionView(spinnerActionView);

Где menu назначается переменной экземпляра контейнера при вызове onCreateOptionsMenu.

Обновление:

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

Когда я впервые загружаю фрагмент, у меня появляется 1 статический значок обновления. Если я поворачиваю экран... появляется другой значок обновления... когда я поворачиваю экран назад, появляется третий значок обновления!

Незнакомец, нажав кнопку "назад", поочередно удаляет каждый дополнительный значок, прежде чем, наконец, (на четвертом щелчке) вернется к предыдущему экрану.

Ответ 1

Никогда не меняйте пункты меню, кроме

onPrepareOtionsMenu(){
}

вам нужно что-то вроде этого.

в вашей деятельности:

boolean mIsRefreshing =false;

public boolean onPrepareOptionsMenu(Menu menu) {
if(mIsRefreshing){
        final MenuItem menuItemRefresh = menu.findItem(R.id.menu_refresh);
    menuItemRefresh.setActionView(spinnerActionView);
}
        return true;
    }

public void setRefreshing(boolean refreshing){
mIsRefreshing = refreshing;
invalidateOptionsMenu();  //supportInvelidateOptionsMenu()
}

Итак, теперь вы можете позвонить со своего frament

((YourActivity)getActivity()).setRefreshing(true);
((YourActivity)getActivity()).setRefreshing(false);

Ответ 2

Если вы используете один и тот же объект Animation каждый раз, вам может понадобиться reset анимация, прежде чем пытаться запустить его снова.

Попробуйте добавить rotation.reset() над вашим вызовом startAnimation().

Ответ 3

    "I've noticed another weird bug in this area (I'm happy to add this as a separate question, but I'm updating it here in the hope that it will shed some light on my original problem - I believe both are caused by how I have configured my action-bar from my Fragments).   
    When I first load a fragment I have 1 static refresh icon displayed. If I rotate the screen... another refresh icon appears... when I rotate the screen back, a 3rd refresh icon appears! 
    Stranger still, clicking the back-button removes each additional icon in turn, before finally (on the 4th click) returning to the previous screen."

Я могу дать пояснение этому, когда когда-либо вы меняете ориентацию (Potrait ↔ пейзаж).

Активность меняется при изменении ориентации. Я предполагаю, что ваш код не сохраняет необходимую информацию до этого перезапуска. Вы можете остановить это поведение по умолчанию, самостоятельно отрегулировав определенные изменения конфигурации (т.е. Изменение ориентации). Хороший учебник по этому вопросу находится здесь: Обработка изменений времени выполнения

Ответ 4

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

Ответ 5

Только вызов onCreateOptionsMenu() в основном действии (я имею в виду активность раздвижного фрагмента). Нет необходимости вызывать onCreateOptionsMenu() из каждого фрагмента. Я даю образец фрагмента ниже.

Call from fragment (whenerver loading starts and end)

    yourSlidingFragmnetActivity.refresh = true/false; (u can have this logic of your own)
    getActivity().supportInvalidateOptionsMenu();


    @Override
        public boolean onCreateOptionsMenu(Menu menu) {


            menu.add(BaseListActivity.DEFAULT_GROUP_ID, BaseListActivity.MENU_ITEM_RELOAD_LIST, BaseListActivity.DEFAULT_ORDER,
                    "Refresh").setIcon(R.drawable.ic_menu_refresh_new)
                    .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
            return true;
        }

        @Override
        public boolean onOptionsItemSelected(MenuItem item) {

            if (item.getItemId() == BaseListActivity.MENU_ITEM_RELOAD_LIST) {
                item.setActionView(R.layout.progressbar_layout);
                item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
                return true;
            }
            return true;
        }

        public static boolean refresh = false;

        @Override
        public boolean onPrepareOptionsMenu(Menu menu) {
            MenuItem item = menu.getItem(0);
            if (refresh) {
                item.setActionView(R.layout.progressbar_layout);
            } else {
                item.setIcon(R.drawable.ic_menu_refresh_new);
            }
            return true;
        }

        R.layout.progressbar_layout:
        <?xml version="1.0" encoding="utf-8"?>
        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                      android:layout_width="wrap_content"
                      android:layout_height="wrap_content"
                      android:addStatesFromChildren="true"
                      android:focusable="true"
                      android:paddingLeft="4dp"
                      android:paddingRight="4dp"
                      android:gravity="center"
                      style="?attr/actionButtonStyle">
        <ProgressBar
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:focusable="true"
                    style="@android:style/Widget.ProgressBar.Small"/>
        </LinearLayout>

Я также использую jfeinstein10 slidemenu lib, я не добавляю или не удаляю фрагменты, я всегда их заменяю и в oncreate menthod iam, используя это

private Fragment mContent;
if(mContent == null){
mContent = new SampleFragment();
}
// set the Above View
    setContentView(R.layout.content_frame);
                getSupportFragmentManager()
                .beginTransaction()
                .replace(R.id.content_frame,mContent)
                .commit();