web-dev-qa-db-ger.com

Aktionselemente aus dem ursprünglichen Viewpager-Fragment werden nicht angezeigt

In der von mir entwickelten Anwendung verwende ich einen ViewPager mit Fragmenten, und jedes Fragment erstellt unabhängig von allen anderen Fragmenten im ViewPager ein eigenes Menü.

Das Problem ist, dass die Elemente der Fragmente, die vom ViewPager standardmäßig initialisiert werden (d. H. In ihrem ursprünglichen Zustand), manchmal nicht im Menü für Aktionselemente angezeigt werden. Schlimmer ist, dass dieses Problem nur zeitweise auftritt. Wenn ich durch den ViewPager wische, sodass die Fragmente gezwungen sind, sich selbst neu zu initialisieren, wird das Menü beim Zurückwischen korrekt ausgefüllt.

Aktivitätscode:

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

Fragmentcode:

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

}

Layout:

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

Speisekarte:

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

Aktionsmenü wird gefüllt: http://i.stack.imgur.com/QFMDd.png

Aktionsmenü wird nicht gefüllt: http://i.stack.imgur.com/sH5Pp.png

29
solarnz

Das solltest du lesen (von xcolw ...)

Durch Experimente scheint es, als ob die Hauptursache darin besteht, dass invalidateOptionsMenu mehr als eins aufgerufen wird, ohne dass der Hauptthread unterbrochen wird, um Jobs in der Warteschlange zu verarbeiten. Eine Vermutung - dies ist wichtig, wenn ein kritischer Teil der Menüerstellung über einen Beitrag zurückgestellt wird und die Aktionsleiste in einem fehlerhaften Zustand bleibt, bis sie ausgeführt wird.

Es gibt einige Stellen, an denen dies passieren kann und die nicht offensichtlich sind:

  1. viewPager.setCurrentItem wird für dasselbe Element mehrmals aufgerufen

  2. aufruf von viewPager.setCurrentItem in onCreate der Aktivität. setCurrentItem bewirkt, dass das Optionsmenü ungültig wird, unmittelbar gefolgt vom ungültigen Optionsmenü der Aktivität

Problemumgehungen habe ich für jeden gefunden

  1. Schützen Sie den Aufruf von viewPager.setCurrentItem

    if (viewPager.getCurrentItem() != position)
        viewPager.setCurrentItem(position);
    
  2. Verzögern Sie den Aufruf von viewPager.setCurrentItem in onCreate

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

Nach diesen Änderungen scheint das Optionsmenü im Ansichts-Pager wie erwartet zu funktionieren. Ich hoffe, jemand kann mehr Licht ins Dunkel bringen.

Quellehttp://code.google.com/p/Android/issues/detail?id=29472

21
Wayne

Die einfache Antwort ist, keine Menüs innerhalb von Fragmenten im ViewPager zu verwenden. Wenn Sie Menüs in den Fragmenten verwenden müssen, sollten Sie die Menüs über die onCreateOptionsMenu-Methode in der übergeordneten Activity laden. Natürlich müssen Sie in der Lage sein, das anzuzeigende Menü zu bestimmen.

Dies konnte ich durch Klassenreflexion erreichen. Sie müssen außerdem bei jedem Seitenwechsel die Methode invalidateOptionsMenu verwenden. Sie benötigen einen OnPageChangeListener, um dies aufzurufen, wenn der ViewPager die Seite wechselt.

8
solarnz

Ich hatte auch das gleiche Problem. In meinem Fall habe ich eine Aktivität mit Viewpager, die zwei Fragmente enthält. Jedes Fragment bläst sein eigenes Aktionsmenü auf, aber das Menü für Fragmentaktionen wird nicht angezeigt.

Pager-Adaptercode anzeigen

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

}

Aktivität beim Erstellen

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

Auf diese Weise verfügt mein viewPager über zwei Fragmente, von denen jedes in onActivityCreated eine eigene Aufgabe auslöst, Daten abruft und das Layout anhand der erhaltenen Daten erstellt. Jedes Fragment hat auch 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);
}

Verbrachte viele Male, um dieses Problem zu lösen und herauszufinden, warum das Fragment-Menü nicht angezeigt wird. Alles was ich brauchte ist

    screenAdapter = new ScreenAdapter(this, getFragmentManager());
    viewPager.post(new Runnable() {
        public void run() {
            viewPager.setAdapter(screenAdapter);
        }
    });
3
Georgy Gobozov

Erstellen Sie zunächst eine Methode in der Unterklasse von FragmentPagerAdapter, um das aktuelle Fragment abzurufen

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

Überschreiben Sie nun die folgenden Methoden in 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);
}

Rufen Sie jetzt das onOptionItemSelected von Aktivität zu Fragment auf

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

Ich hatte dieses Problem mit den Aktionsleistenelementen, als ich HorizontalScrollView zum Anzeigen der Registerkarten verwendete, aber ich habe zu PagerTitleStrip gewechselt und das Problem wurde behoben.

Vielleicht können diese Informationen jemand anderem helfen.

0
Jose M Lechon

In meinem Fall habe ich die Ursache des Problems auf einen Fehler in FragmentStatePagerAdapter zurückgeführt, der meines Erachtens Fragment # setMenuVisibility auf false ruft und den Fehler nicht richtig auf true zurücksetzt, wenn der Status wiederhergestellt wird.

Problemumgehungen:

  1. Verwenden Sie FragmentPagerAdapter anstelle von FragmentStatePagerAdapter

  2. Wenn Sie FragmentStatePagerAdapter verwenden müssen, überschreiben Sie setPrimaryItem in Ihrer Adapter-Unterklasse folgendermaßen:

    @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
Ilan Klinghofer

Ich habe ein sehr ähnliches Problem behoben, bei dem die vom Fragment in einem ViewPager zugewiesenen Aktionsleistensymbole bei Pause () ausgeblendet wurden. Sie würden wieder erscheinen, wenn das Fragment wieder in Sicht kam und der Benutzer nach links oder rechts wischte, aber nicht sofort. Die Lösung rief notifyDataSetChanged () für den PagerAdapter in der onResume () -Methode des Fragments auf.

@Override
public void onResume() {
    mPagerAdapter.notifyDataSetChanged();
}
0
Matt W