在我正在开发的应用程序中,我正在使用带有片段的 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>
正在填充的操作菜单:https://i.stack.imgur.com/QFMDd.png
未填充操作菜单:https://i.stack.imgur.com/sH5Pp.png
你应该读这个(xcolw...(
通过实验,似乎根本原因是 invalidateOptionsMenu 被调用多个,主线程上没有中断来处理排队的作业。一个猜测 - 如果菜单创建的某些关键部分通过帖子延迟,使操作栏处于错误状态直到运行,这将很重要。
有一些地方可能会发生
,但并不明显:多次调用视图Pager.setCurrentItem 对于同一项目
在创建活动时调用 viewPager.setCurrentCurrentItem。setCurrentItem 会导致选项菜单失效,紧接着是活动的选项菜单无效
我为每个找到的解决方法
保护对 viewPager.setCurrentItem 的调用
if (viewPager.getCurrentItem() != position) viewPager.setCurrentItem(position);
推迟对 viewPager.setCurrentItem 的调用 onCreate
public void onCreate(...) { ... view.post(new Runnable() { public void run() { // guarded viewPager.setCurrentItem } } }
在这些更改之后,视图寻呼机中的选项菜单似乎按预期工作。我希望有人能对此有更多的了解。
来源 http://code.google.com/p/android/issues/detail?id=29472
简单的答案是不要在 ViewPager 的片段中使用菜单。如果您确实需要在片段中使用菜单,我建议通过父活动中的onCreateOptionsMenu方法加载菜单。显然,您需要能够确定要显示的菜单。
我能够通过使用课堂反思来实现这一点。您还需要在每次切换页面时使用 invalidateOptionsMenu 方法。您将需要一个 OnPageChangeListener 来在 ViewPager 更改页面时调用它。
我也有同样的问题。就我而言,我有一个带有 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中触发自己的任务,获取数据并根据获得的数据绘制其布局。此外,每个片段都有创建选项菜单
@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);
}
});
就我而言,我将问题的根本原因追溯到我认为是 FragmentStatePagerAdapter 中的一个错误,该错误将 Fragment#setMenuVisibility 调用为 false,并且在恢复其状态时未能正确将其设置回 true。
解决方法:
-
使用 FragmentPagerAdapter 而不是 FragmentStatePagerAdapter
-
如果必须使用 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); } }
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;
}
现在在主活动中覆盖以下方法
@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 from Activity to fragment
@Override
public boolean onOptionsItemSelected(MenuItem item) {
mTabsAdapter.getFragment().onOptionsItemSelected(item);
return super.onOptionsItemSelected(item);
}
我解决了一个非常相似的问题,其中由ViewPager内部片段分配的操作栏图标在Pause((上消失了。当片段重新出现在视野中并且用户向左或向右滑动时,它们会重新出现,但不会立即出现。 解决方案是在片段的 onResume(( 方法中调用 PagerAdapter 上的 notifyDataSetChanged((。
@Override
public void onResume() {
mPagerAdapter.notifyDataSetChanged();
}
当我使用水平滚动视图显示选项卡时,我在操作栏项目上遇到了这个问题,但我更改为 PagerTitleStrip 并且问题解决了。
也许这些信息可以帮助其他人。
我对这个问题的解决方案是仅在片段当前可见时才膨胀片段菜单。此解决方案对于您的目的来说可能过于具体,但它可能会帮助某人。
在主要活动中:
boolean isFragmentVisible(int fragmentIndex) { ... }
在您的片段中onCreateOptionsMenu()
:
if ( getActivity().isFragmentVisible(HOME_FRAGMENT_POS) ) {
inflater.inflate(R.menu.menu_home_fragment, menu);
}