Viewpager の最初のフラグメントのアクション アイテムが表示されない
-
27-10-2019 - |
質問
私が開発しているアプリケーションでは、フラグメントを持つ 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
解決
あなたはこれを読むべきです(xcolwによって...)
実験を通じて、根本的な原因は、メインスレッドで休憩なしでジョブを処理することなく複数と呼ばれるようになっているように思われます。推測 - これは、メニュー作成の重要な部分が投稿を介して延期され、アクションバーが実行されるまで悪い状態になった場合に重要です。
明らかではないこれが起こる可能性のあるいくつかのスポットがあります:
同じアイテムに対してviewpager.setCurrentitemを複数回呼び出します
アクティビティの作成中のviewpager.setCurrentitemを呼び出します。 setCurrentITemはオプションメニューを原因で発生し、すぐにアクティビティのオプションメニューが無効になります。
それぞれに見つけた回避策
viewpager.setCurrentitemへの呼び出しをガードします
if (viewPager.getCurrentItem() != position) viewPager.setCurrentItem(position);
oncreateのviewpager.setCurrentitemへの呼び出しを延期します
public void onCreate(...) { ... view.post(new Runnable() { public void run() { // guarded viewPager.setCurrentItem } } }
これらの変更後、ビュー内のオプションメニューは、予想どおりに機能するようです。誰かがこれにもっと光を当てることができることを願っています。
他のヒント
簡単な答えは、ViewPagerのフラグメント内でメニューを使用しないことです。フラグメント内でメニューを使用する必要がある場合、私が提案するのは、親アクティビティのOnCreateOptionsmenuメソッドを使用してメニューをロードすることです。明らかに、表示するメニューを決定できる必要があります。
クラスリフレクションを使用してこれを達成することができました。また、ページを切り替えるたびにInvalidateoptionsmenuメソッドを使用する必要があります。 ViewPagerがページを変更したときにこれを呼び出すには、OnPageChangElistenerが必要です。
私も同じ問題を抱えていました。私の場合、2つのフラグメントを含むViewPagerを使用して1つのアクティビティがあります。すべてのフラグメントは独自のアクションメニューを膨らませますが、フラグメントアクションメニューは表示されません。
ページャーアダプターコードを表示します
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には2つのフラグメントがあり、すべてのフラグメントがonactivityで作成された独自のタスクを発射し、データを取得し、取得したデータに基づいてレイアウトを描画します。また、すべてのフラグメントには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);
}
});
最初に、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);
}
次に、アクティビティからフラグメントに選択されたOnoPtionItemを呼び出します
@Override
public boolean onOptionsItemSelected(MenuItem item) {
mTabsAdapter.getFragment().onOptionsItemSelected(item);
return super.onOptionsItemSelected(item);
}
私は非常によく似た問題を解決しました。この問題では、ビューページの内側のフラグメントによって割り当てられたアクションバーアイコンがonPause()が消えていました。フラグメントが戻ってきて、ユーザーが左または右にスワイプされたときに再び現れますが、すぐには登場しませんでした。解決策は、フラグメントのonResume()メソッドのpageradapterでnotifydatasetchanged()を呼び出すことでした。
@Override
public void onResume() {
mPagerAdapter.notifyDataSetChanged();
}
を使用しているときにアクションバーアイテムでこの問題が発生しました 水平スクロールビュー タブを表示するために変更しましたが、 ポケベルタイトルストリップ そして問題は解決されました。
おそらくこの情報は他の人の役に立つかもしれません。
私の場合、私は問題の根本原因を、私が信じているものに、fragmentStatePagerAdapterのバグだと思いました。 フラグメント#setMenuvisibility 虚偽に合わせて、それが状態を復元するときにそれを真のものに適切に設定することに失敗します。
回避策:
FragmentStatePagerAdapterの代わりにFragmentPagerAdapterを使用します
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); } }