Элементы действий из исходного фрагмента Viewpager не отображаются - PullRequest
30 голосов
/ 18 февраля 2012

В разрабатываемом приложении я использую ViewPager с фрагментами, и каждый фрагмент создает свое собственное меню независимо от всех других фрагментов в ViewPager.

Проблема в том, что иногда инициализируются фрагментыпо умолчанию ViewPager (то есть в его начальном состоянии) не имеют своих элементов, заполненных в меню элементов действий.Что еще хуже, эта проблема возникает только с перерывами.Если я проведу пальцем по ViewPager достаточно, чтобы фрагменты были вынуждены повторно инициализировать себя, когда я проведу назад, меню заполнится правильно.

Код активности:

package net.solarnz.apps.fragmentsample;

import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.os.Bundle;
import android.support.v13.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;

public class FragmentSampleActivity extends Activity {
    private ViewPagerAdapter mViewPagerAdapter;
    private ViewPager mViewPager;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        if (mViewPagerAdapter == null) {
            mViewPagerAdapter = new ViewPagerAdapter(getFragmentManager());
        }

        mViewPager = (ViewPager) findViewById(R.id.log_pager);
        mViewPager.setAdapter(mViewPagerAdapter);
        mViewPager.setCurrentItem(0);
    }


    private class ViewPagerAdapter extends FragmentStatePagerAdapter {
        public ViewPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public int getCount() {
            return 8;
        }

        @Override
        public Fragment getItem(int position) {
            Fragment f = Fragment1.newInstance(position);
            // f.setRetainInstance(true);
            f.setHasOptionsMenu(true);
            return f;
        }
    }
}

Код фрагмента:

package net.solarnz.apps.fragmentsample;

import android.app.Fragment;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;

public class Fragment1 extends Fragment {
    int mNum;

    static Fragment newInstance(int num) {
        Fragment1 f = new Fragment1();

        // Supply num input as an argument.
        Bundle args = new Bundle();
        args.putInt("num", num);
        f.setArguments(args);

        return f;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
        mNum = getArguments() != null ? getArguments().getInt("num") : 0;
    }

    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        inflater.inflate(R.menu.menu_list, menu);
    }

}

Расположение:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

            <android.support.v4.view.ViewPager
                android:id="@+id/log_pager"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
</LinearLayout>

Меню:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/menu_refresh"
          android:title="Refresh"
          android:icon="@android:drawable/ic_delete"
          android:showAsAction="ifRoom|withText" />
</menu>

Заполняется меню действий: http://i.stack.imgur.com/QFMDd.png

Меню действий не выполняетсязаселено: http://i.stack.imgur.com/sH5Pp.png

Ответы [ 7 ]

22 голосов
/ 21 августа 2012

Вы должны прочитать это (по xcolw ...)

В результате экспериментов кажется, что первопричиной является invalidateOptionsMenu, вызываемый более чем один без перерыва в главном потоке для обработкив очереди на работу.Предположение - это будет иметь значение, если некоторая критическая часть создания меню будет отложена через сообщение, оставляя панель действий в плохом состоянии, пока она не запустится.

Может произойти несколько не очевидных моментов:

  1. многократный вызов viewPager.setCurrentItem для одного и того же элемента

  2. вызов viewPager.setCurrentItem в onCreate действия.setCurrentItem приводит к тому, что меню параметров становится недействительным, за которым сразу следует меню действий действия, которое делает недействительным

Обходные пути, которые я нашел для каждого

  1. Защитавызов viewPager.setCurrentItem

    if (viewPager.getCurrentItem() != position)
        viewPager.setCurrentItem(position);
    
  2. Отложить вызов viewPager.setCurrentItem в onCreate

    public void onCreate(...) {
        ...
        view.post(new Runnable() {
            public void run() {
                // guarded viewPager.setCurrentItem
            }
        }
    }
    

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

source http://code.google.com/p/android/issues/detail?id=29472

8 голосов
/ 23 марта 2012

Простой ответ - не использовать меню внутри фрагментов в ViewPager. Если вам нужно использовать меню во фрагментах, я предлагаю загрузить меню с помощью метода onCreateOptionsMenu в родительском Activity. Очевидно, вам нужно будет определить, какое меню отображать.

Мне удалось достичь этого с помощью отражения классов. Вам также нужно будет использовать метод invalidateOptionsMenu при каждом переключении страниц. Вам потребуется OnPageChangeListener для вызова этого, когда ViewPager изменяет страницы.

3 голосов
/ 20 августа 2013

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

Просмотр кода адаптера пейджера

 public class ScreensAdapter extends FragmentPagerAdapter {

    public TrackerScreensAdapter(Context context, FragmentManager fm) {
        super(fm);
    }

    @Override
    public int getCount() {
        return 2;
    }

    public Fragment getItem(int position) {
        Fragment fragment = null;
        switch (position){
            case 0:
                fragment = new Fragment1();
                break;
            case 1:
                fragment = new Fragment2();
                break;
        }
        return fragment;
    }

}

Деятельность при создании

    screensAdapter = new ScreensAdapter(this, getFragmentManager());
    viewPager.setAdapter(screensAdapter);

Таким образом, мой viewPager имеет два фрагмента, каждый фрагмент запускает свою собственную задачу в onActivityCreated, получает данные и рисует свой макет на основе полученных данных.Также каждый фрагмент имеет onCreateOptionsMenu

  @Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    setHasOptionsMenu(true);
    MyTask task = new MyTask();
    task.setTaskListener(this);
    task.execute();


}

 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.fragment_menu, menu);
}

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

    screenAdapter = new ScreenAdapter(this, getFragmentManager());
    viewPager.post(new Runnable() {
        public void run() {
            viewPager.setAdapter(screenAdapter);
        }
    });
0 голосов
/ 06 января 2015

В моем случае я отследил основную причину проблемы, которая, по моему мнению, является ошибкой в ​​FragmentStatePagerAdapter, которая вызывает Fragment # setMenuVisibility в значение false и не удается правильно установить его в значение true, когда он восстанавливает егоstate.

Обходные пути:

  1. Использование FragmentPagerAdapter вместо FragmentStatePagerAdapter

  2. Если необходимо использовать FragmentStatePagerAdapter в переопределении подкласса адаптераsetPrimaryItem примерно так:

    @Override
    public void setPrimaryItem(ViewGroup container, int position, Object object) {
        super.setPrimaryItem(container, position, object);
    
        //This is a workaround for a bug in FragmentStatePagerAdapter
        Fragment currentItem = getItem(position);
        if (currentItem != null) {
            currentItem.setMenuVisibility(true);
            currentItem.setUserVisibleHint(true);
        }
    }
    
0 голосов
/ 17 марта 2014

У меня была эта проблема с элементами панели действий, когда я использовал HorizontalScrollView для отображения вкладок, но я изменил на PagerTitleStrip , и проблема была решена.

Возможно, эта информация может помочь кому-то еще.

0 голосов
/ 27 февраля 2014

Я решил очень похожую проблему, в которой значки панели действий, назначенные фрагментом внутри ViewPager, исчезали в OnPause (). Они появятся снова, когда фрагмент снова появится в поле зрения, и пользователь проведет пальцем влево или вправо, но не сразу. Решение вызывало notifyDataSetChanged () для PagerAdapter в методе onResume () фрагмента.

@Override
public void onResume() {
    mPagerAdapter.notifyDataSetChanged();
}
0 голосов
/ 25 марта 2013

Сначала создайте метод в подклассе FragmentPagerAdapter, чтобы получить текущий фрагмент

    public SherlockFragment getFragment() {
    return currentFragment;
}

        @Override
public void onTabSelected(final Tab tab, FragmentTransaction ft) {

    ((SherlockFragmentActivity) mContext).invalidateOptionsMenu();
    Fragment f = ((SherlockFragmentActivity) mContext)
            .getSupportFragmentManager().findFragmentByTag(
                    makeFragmentName(tab.getPosition()));

    currentFragment=(SherlockFragment) f;
 }

Теперь переопределите методы ниже в Main Actvity

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    if (mTabsAdapter.getPositionOfTabSelected() != 0) {
        menu.add("Read").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
        menu.add("Write").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
        menu.add("Clear").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
        menu.add("Factory data reset").setShowAsAction(
                MenuItem.SHOW_AS_ACTION_IF_ROOM);
    }

    return super.onCreateOptionsMenu(menu);
}

Теперь вызовите onOptionItemSelected от действия кфрагмент

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    mTabsAdapter.getFragment().onOptionsItemSelected(item);
    return super.onOptionsItemSelected(item);
}
...