Unten ist mein Code, der 3 Fragment classes
mit jeweils drei Registerkarten in ViewPager
enthält. Ich habe eine Menüoption. Wie in onOptionsItemSelected()
gezeigt, muss ich durch Auswählen einer Option das aktuell sichtbare Fragment aktualisieren. Um das zu aktualisieren, muss ich eine Methode aufrufen, die in der Fragment-Klasse enthalten ist. Kann jemand bitte vorschlagen, wie man diese Methode aufruft?
public class MainActivity extends ActionBarActivity {
ViewPager ViewPager;
TabsAdapter TabsAdapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ViewPager = new ViewPager(this);
ViewPager.setId(R.id.pager);
setContentView(ViewPager);
final ActionBar bar = getSupportActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
//Attaching the Tabs to the fragment classes and setting the tab title.
TabsAdapter = new TabsAdapter(this, ViewPager);
TabsAdapter.addTab(bar.newTab().setText("FragmentClass1"),
FragmentClass1.class, null);
TabsAdapter.addTab(bar.newTab().setText("FragmentClass2"),
FragmentClass2.class, null);
TabsAdapter.addTab(bar.newTab().setText("FragmentClass3"),
FragmentClass3.class, null);
if (savedInstanceState != null) {
bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.addText:
**// Here I need to call the method which exists in the currently visible Fragment class**
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("tab", getSupportActionBar().getSelectedNavigationIndex());
}
public static class TabsAdapter extends FragmentPagerAdapter
implements ActionBar.TabListener, ViewPager.OnPageChangeListener {
private final Context mContext;
private final ActionBar mActionBar;
private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
static final class TabInfo {
private final Class<?> clss;
private final Bundle args;
TabInfo(Class<?> _class, Bundle _args) {
clss = _class;
args = _args;
}
}
public TabsAdapter(ActionBarActivity activity, ViewPager pager) {
super(activity.getSupportFragmentManager());
mContext = activity;
mActionBar = activity.getSupportActionBar();
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}
public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
TabInfo info = new TabInfo(clss, args);
tab.setTag(info);
tab.setTabListener(this);
mTabs.add(info);
mActionBar.addTab(tab);
notifyDataSetChanged();
}
@Override
public void onPageScrollStateChanged(int state) {
// TODO Auto-generated method stub
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// TODO Auto-generated method stub
}
@Override
public void onPageSelected(int position) {
// TODO Auto-generated method stub
mActionBar.setSelectedNavigationItem(position);
}
@Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
Object tag = tab.getTag();
for (int i=0; i<mTabs.size(); i++) {
if (mTabs.get(i) == tag) {
mViewPager.setCurrentItem(i);
}
}
tabPosition = tab.getPosition();
}
@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
@Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
return Fragment.instantiate(mContext, info.clss.getName(), info.args);
}
@Override
public int getCount() {
return mTabs.size();
}
}
}
Angenommen, unten ist die Fragmentklasse mit der Methode updateList()
, die ich aufrufen möchte:
public class FragmentClass1{
ArrayList<String> originalData;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View fragmentView = inflater.inflate(R.layout.frag1, container, false);
originalData = getOriginalDataFromDB();
return fragmentView;
}
public void updateList(String text)
{
originalData.add(text);
//Here I could do other UI part that need to added
}
}
durch die Auswahl einer Option muss das Fragment aktualisiert werden derzeit sichtbar.
Ein einfacher Weg, dies zu tun, besteht darin, einen Trick zu verwenden, der sich auf die Implementierung von FragmentPagerAdapter
bezieht:
case R.id.addText:
Fragment page = getSupportFragmentManager().findFragmentByTag("Android:switcher:" + R.id.pager + ":" + ViewPager.getCurrentItem());
// based on the current position you can then cast the page to the correct
// class and call the method:
if (ViewPager.getCurrentItem() == 0 && page != null) {
((FragmentClass1)page).updateList("new item");
}
return true;
Bitte überdenken Sie Ihre Namenskonvention für Variablen. Als Variablenname ist der Name der Klasse sehr verwirrend (also kein ViewPager ViewPager
, beispielsweise ViewPager mPager
).
public class MyPagerAdapter extends FragmentPagerAdapter {
private Fragment mCurrentFragment;
public Fragment getCurrentFragment() {
return mCurrentFragment;
}
//...
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
if (getCurrentFragment() != object) {
mCurrentFragment = ((Fragment) object);
}
super.setPrimaryItem(container, position, object);
}
}
Behalten Sie zunächst alle "aktiven" Fragmentseiten im Auge. In diesem Fall verfolgen Sie die Fragmentseiten im FragmentStatePagerAdapter, der vom ViewPager verwendet wird.
@Override
public Fragment getItem(int index) {
Fragment myFragment = MyFragment.newInstance();
mPageReferenceMap.put(index, myFragment);
return myFragment;
}
Um zu vermeiden, dass ein Verweis auf "inaktive" Fragmentseiten beibehalten wird, müssen Sie die destroyItem (...) - Methode des FragmentStatePagerAdapter implementieren:
@Override
public void destroyItem (ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
mPageReferenceMap.remove(position);
}
und wenn Sie auf die aktuell sichtbare Seite zugreifen müssen, rufen Sie an:
int index = mViewPager.getCurrentItem();
MyAdapter adapter = ((MyAdapter)mViewPager.getAdapter());
MyFragment fragment = adapter.getFragment(index);
Die getFragment (int) -Methode von MyAdapter sieht folgendermaßen aus:
public MyFragment getFragment(int key) {
return mPageReferenceMap.get(key);
}
Hoffe es kann helfen!
Nur so bekomme ich keine NullPointerException für die Instanzvariablen dieser bestimmten Fragmentklassen. Dies kann für andere hilfreich sein, die das Gleiche tun. In onOptionsItemSelected () habe ich den folgenden Weg codiert:
if(viewPager.getCurrentItem() == 0) {
FragmentClass1 frag1 = (FragmentClass1)viewPager
.getAdapter()
.instantiateItem(viewPager, viewPager.getCurrentItem());
frag1.updateList(text);
} else if(viewPager.getCurrentItem() == 1) {
FragmentClass2 frag2 = (FragRecentApps)viewPager
.getAdapter()
.instantiateItem(viewPager, viewPager.getCurrentItem());
frag2.updateList(text);
}
FragmentStatePagerAdapter hat eine öffentliche Methode mit dem Namen instantiateItem, die Ihr Fragment basierend auf den angegebenen Parameterwerten zurückgibt. Diese Methode verfügt über die beiden Parameter ViewGroup (ViewPager) und position.
public Object instantiateItem(ViewGroup container, int position);
Verwenden Sie diese Methode, um das Fragment der angegebenen Position abzurufen.
Fragment fragment = (Fragment) adaper.instantiateItem(mViewPager, position);
Ich weiß, es ist zu spät, aber ich habe wirklich einfache Wege,
// für Fragment bei 0 Possition
((mFragment) viewPager.getAdapter().instantiateItem(viewPager, 0)).yourMethod();
Es gibt viele Antworten, die sich nicht wirklich mit der grundlegenden Tatsache auseinandersetzen, dass es wirklich keinen Weg gibt, dies vorhersehbar zu tun, und auf eine Weise, die nicht dazu führt, dass Sie sich irgendwann in der Zukunft in den Fuß schießen.
FragmentStatePagerAdapter
ist die einzige Klasse, die zuverlässig auf die Fragmente zugreifen kann, die von der FragmentManager
verfolgt werden. Jeder Versuch, die ID oder das Tag des Fragments zu erraten, ist langfristig und langfristig nicht zuverlässig. Versuche, die Instanzen manuell zu verfolgen, funktionieren wahrscheinlich nicht gut, wenn der Status gespeichert/wiederhergestellt wird, da FragmentStatePagerAdapter
die Rückrufe möglicherweise nicht aufrufen kann, wenn der Status wiederhergestellt wird.
Die einzige Sache, die ich machen konnte, ist das Kopieren des Codes für FragmentStatePagerAdapter
und das Hinzufügen einer Methode, die das Fragment bei einer gegebenen Position (mFragments.get(pos)
) zurückgibt. Beachten Sie, dass diese Methode davon ausgeht, dass das Fragment tatsächlich verfügbar ist (d. H. Es war irgendwann sichtbar).
Wenn Sie besonders abenteuerlustig sind, können Sie Reflection verwenden, um auf die Elemente der privaten mFragments
-Liste zuzugreifen, aber dann sind wir wieder bei Platz eins (der Name der Liste wird nicht garantiert gleich bleiben).
wenn Sie eine Option auswählen, muss das derzeit sichtbare Fragment aktualisiert werden.
Angenommen, Sie haben einen Verweis auf ViewPager
als mPager
, um einen Verweis auf das derzeit sichtbare Fragment zu erhalten. Die folgenden Schritte erhalten dann einen Verweis auf currentFragment
:
PageAdapter adapter = mPager.getAdapter();
int fragmentIndex = mPager.getCurrentItem();
FragmentStatePagerAdapter fspa = (FragmentStatePagerAdapter)adapter;
Fragment currentFragment = fspa.getItem(fragmentIndex);
Die einzige verwendete Besetzung der Linie 3 ist normalerweise gültig. FragmentStatePagerAdapter
ist ein nützlicher Adapter für einen ViewPager.
Aktuelles Fragment:
Dies funktioniert, wenn Sie ein Projekt mit der Vorlagenvorlage "Fragmente" erstellt haben.
Fragment f = mSectionsPagerAdapter.getItem(mViewPager.getCurrentItem());
Beachten Sie, dass dies mit der standardmäßigen Implementierung der Aktivitätsvorlage mit Registerkarten funktioniert.
getSupportFragmentManager().getFragments().get(viewPager.getCurrentItem());
Konvertieren Sie die von der obigen Zeile abgerufene Instanz in das Fragment, mit dem Sie arbeiten möchten. Funktioniert einwandfrei.
viewPager
ist die Pager-Instanz, die die Fragmente verwaltet.
Am besten rufen Sie einfach CallingFragmentName fragment = (CallingFragmentName) auf. ViewPager .getAdapter () .instantiateItem (viewPager, viewPager.getCurrentItem ()); Dadurch wird Ihr aufrufendes Fragment erneut instanziiert, sodass keine Nullzeigerausnahme ausgelöst wird und keine Methode dieses Fragments aufgerufen wird.
Ich habe folgendes verwendet:
int index = vpPager.getCurrentItem();
MyPagerAdapter adapter = ((MyPagerAdapter)vpPager.getAdapter());
MyFragment suraVersesFragment = (MyFragment)adapter.getRegisteredFragment(index);
FragmentStatePagerAdapter
hat eine private Instanzvariable namens mCurrentPrimaryItem
vom Typ Fragment
. Man kann sich nur wundern, warum Android-Entwickler es nicht mit einem Getter versorgt haben. Diese Variable wird in der setPrimaryItem()
-Methode instanziiert. Überschreiben Sie diese Methode also so, dass Sie den Verweis auf diese Variable erhalten. Am Ende habe ich einfach meine eigene mCurrentPrimaryItem
deklariert und den Inhalt von setPrimaryItem()
in meine Überschreibung kopiert.
In Ihrer Implementierung von FragmentStatePagerAdapter
:
private Fragment mCurrentPrimaryItem = null;
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
Fragment fragment = (Fragment)object;
if (fragment != mCurrentPrimaryItem) {
if (mCurrentPrimaryItem != null) {
mCurrentPrimaryItem.setMenuVisibility(false);
mCurrentPrimaryItem.setUserVisibleHint(false);
}
if (fragment != null) {
fragment.setMenuVisibility(true);
fragment.setUserVisibleHint(true);
}
mCurrentPrimaryItem = fragment;
}
}
public TasksListFragment getCurrentFragment() {
return (YourFragment) mCurrentPrimaryItem;
}
Wenn Sie viewPager verwenden, ist InstantiateItem (viewpager, index) eine gute Möglichkeit, auf die Fragmentinstanz in activity zuzugreifen. // Indexindex des Fragments, dessen Instanz Sie erstellen möchten.
zum Beispiel greife ich auf die Fragment-Instanz von 1 Index-
Fragment fragment = (Fragment) viewPageradapter.instantiateItem(viewPager, 1);
if (fragment != null && fragment instanceof MyFragment) {
((MyFragment) fragment).callYourFunction();
}
Ich hatte das gleiche Problem und löste es mit diesem Code.
MyFragment fragment = (MyFragment) thisActivity.getFragmentManager().findFragmentById(R.id.container);
Ersetzen Sie einfach den Namen MyFragment durch den Namen Ihres Fragments und fügen Sie die ID Ihres Fragment-Containers hinzu.
Sie können PagerAdapter
so definieren, dann können Sie Fragment
in ViewPager
erhalten.
private class PagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
public PagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
@Override
public int getCount() {
return mFragmentList.size();
}
public void addFragment(Fragment fragment) {
mFragmentList.add(fragment);
}
}
Um die aktuelle Fragment
zu erhalten
Fragment currentFragment = mPagerAdapter.getItem(mViewPager.getCurrentItem());
Das betreffende Szenario ist besser geeignet, wenn jedes Fragment seine eigenen Menüelemente hinzufügt und onOptionsItemSelected () direkt behandelt, wie in offizielle Dokumentation beschrieben. Es ist besser, undokumentierte Tricks zu vermeiden.
Basierend auf dem, was er @chahat jain antwortete:
"Wenn wir den viewPager verwenden, ist InstantiateItem (viewpager, index) der beste Weg, um auf die Fragmentinstanz in activity zuzugreifen. // Indexindex des Fragments, dessen Instanz Sie möchten."
Wenn Sie das in kotlin machen wollen
val fragment = mv_viewpager.adapter!!.instantiateItem(mv_viewpager, 0) as Fragment
if ( fragment is YourFragmentFragment)
{
//DO somthign
}
0 zur Fragmentinstanz von 0
// ================================================= ========================== // // ################### ########### Anwendungsbeispiele ################################ ////============================================= ============================= //
Hier ist ein vollständiges Beispiel, um eine Vision zu erhalten, von der man am wenigsten erfahren kann
hier ist mein veiewPager in der .xml-Datei
...
<Android.support.v4.view.ViewPager
Android:id="@+id/mv_viewpager"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:layout_margin="5dp"/>
...
Und die Heimaktivität, bei der ich die Registerkarte einsetze
...
import kotlinx.Android.synthetic.main.movie_tab.*
class HomeActivity : AppCompatActivity() {
lateinit var adapter:HomeTabPagerAdapter
override fun onCreate(savedInstanceState: Bundle?) {
...
}
override fun onCreateOptionsMenu(menu: Menu) :Boolean{
...
mSearchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
...
override fun onQueryTextChange(newText: String): Boolean {
if (mv_viewpager.currentItem ==0)
{
val fragment = mv_viewpager.adapter!!.instantiateItem(mv_viewpager, 0) as Fragment
if ( fragment is ListMoviesFragment)
fragment.onQueryTextChange(newText)
}
else
{
val fragment = mv_viewpager.adapter!!.instantiateItem(mv_viewpager, 1) as Fragment
if ( fragment is ListShowFragment)
fragment.onQueryTextChange(newText)
}
return true
}
})
return super.onCreateOptionsMenu(menu)
}
...
}
Nachdem ich alle Kommentare und Antworten gelesen habe, werde ich eine optimale Lösung für dieses Problem erläutern. Die beste Option ist die Lösung von @ rik, daher basiert meine Verbesserung auf seiner.
Anstatt jede FragmentClass gerne fragen zu müssen
if(FragmentClass1){
...
if(FragmentClass2){
...
}
Erstellen Sie Ihre eigene Benutzeroberfläche, und erstellen Sie die Implementierung Ihrer untergeordneten Fragmente
public interface MyChildFragment {
void updateView(int position);
}
Dann können Sie so etwas tun, um Ihre inneren Fragmente zu initiieren und zu aktualisieren.
Fragment childFragment = (Fragment) mViewPagerDetailsAdapter.instantiateItem(mViewPager,mViewPager.getCurrentItem());
if (childFragment != null) {
((MyChildFragment) childFragment).updateView();
}
P.S. Seien Sie vorsichtig, wo Sie diesen Code einfügen. Wenn Sie insatiateItem aufrufen, bevor das System es tatsächlich erstellt, ist die savedInstanceState
Ihres untergeordneten Fragments null
public void onCreate(@Nullable Bundle savedInstanceState){
super(savedInstanceState)
}
Stürzt Ihre App ab.
Viel Glück
Dies ist zukunftssicherer als die akzeptierte Antwort:
public class MyFragmentPagerAdapter extends FragmentPagerAdapter {
/* ------------------------------------------------------------------------------------------ */
// region Private attributes :
private Context _context;
private FragmentManager _fragmentManager;
private Map<Integer, String> _fragmentsTags = new HashMap<>();
// endregion
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
// region Constructor :
public MyFragmentPagerAdapter(Context context, FragmentManager fragmentManager) {
super(fragmentManager);
_context = context;
_fragmentManager = fragmentManager;
}
// endregion
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
// region FragmentPagerAdapter methods :
@Override
public int getCount() { return 2; }
@Override
public Fragment getItem(int position) {
if(_fragmentsTags.containsKey(position)) {
return _fragmentManager.findFragmentByTag(_fragmentsTags.get(position));
}
else {
switch (position) {
case 0 : { return Fragment.instantiate(_context, Tab1Fragment.class.getName()); }
case 1 : { return Fragment.instantiate(_context, Tab2Fragment.class.getName()); }
}
}
return null;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
// Instantiate the fragment and get its tag :
Fragment result = (Fragment) super.instantiateItem(container, position);
_fragmentsTags.put(position, result.getTag());
return result;
}
// endregion
/* ------------------------------------------------------------------------------------------ */
}
Sie können einen BroadcastReceiver im Fragment implementieren und von überall aus sendan Intent senden. Der Empfänger des Fragments kann .__ auf die spezifische Aktion lauschen und die Methode der Instanz aufrufen.
Eine Einschränkung stellt jedoch sicher, dass die View-Komponente bereits instanziiert ist (Bei einigen Operationen, z. B. beim Scrollen einer Liste, muss ListView Bereits gerendert sein).
Überschreiben Sie setPrimaryItem aus Ihrem FragmentPagerAdapter: Das Objekt ist das sichtbare Fragment:
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
if (mCurrentFragment != object) {
mCurrentFragment = (LeggiCapitoloFragment) object;
}
super.setPrimaryItem(container, position, object);
}
In meiner Tätigkeit habe ich:
int currentPage = 0;//start at the first tab
private SparseArray<Fragment> fragments;//list off fragments
viewPager.setOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageSelected(int pos) {
currentPage = pos;//update current page
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {}
@Override
public void onPageScrollStateChanged(int arg0) {}
});
@Override
public void onAttachFragment(Fragment fragment) {
super.onAttachFragment(fragment);
if(fragment instanceof Fragment1)
fragments.put(0, fragment);
if(fragment instanceof Fragment2)
fragments.put(2, fragment);
if(fragment instanceof Fragment3)
fragments.put(3, fragment);
if(fragment instanceof Fragment4)
fragments.put(4, fragment);
}
Then I have the following method for getting the current fragment
public Fragment getCurrentFragment() {
return fragments.get(currentPage);
}
Um das aktuelle Fragment abzurufen, erhalten Sie die Position in ViewPager unter public void onPageSelected (letzte int-Position) und dann
public PlaceholderFragment getFragmentByPosition(Integer pos){
for(Fragment f:getChildFragmentManager().getFragments()){
if(f.getId()==R.viewpager && f.getArguments().getInt("SECTNUM") - 1 == pos) {
return (PlaceholderFragment) f;
}
}
return null;
}
SECTNUM - Positionsargument zugewiesen in public static PlaceholderFragment newInstance (int sectionNumber); des Fragments
getChildFragmentManager () oder getFragmentManager () - hängt davon ab, wie SectionsPagerAdapter erstellt wurde
final ViewPager.OnPageChangeListener onPageChangeListener =
new ViewPager.OnPageChangeListener() {
@Override public void onPageSelected(int position) {
switch (position) {
case 0:
FragmentClass1 frag1 =
(FragmentClass1) viewPager.getAdapter()
.instantiateItem(viewPager, viewPager.getCurrentItem());
frag1.updateList("Custom text");
break;
case 1:
break;
case 2:
break;
}
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override public void onPageScrollStateChanged(int state) {
}
};
viewPager.addOnPageChangeListener(onPageChangeListener);
viewPager.setAdapter(adapter);
viewPager.post(new Runnable() {
@Override public void run() {
onPageChangeListener.onPageSelected(viewPager.getCurrentItem());
}
});
Manchmal kann das Fragment ein Nullobjekt auslösen, sodass Sie ein neues Runable ausführen können, um das Problem beim ersten Laden zu lösen.
Danke, Rick
Wenn sich Ihr Pager in einem Fragment befindet, verwenden Sie Folgendes:
private fun getPagerCurrentFragment(): Fragment? {
return childFragmentManager.findFragmentByTag("Android:switcher:${R.id.myViewPagerId}:${myViewPager.currentItem}")
}
Dabei ist R.id.myViewPagerId
die ID Ihres ViewPagers im XML-Layout.
Rufen Sie einfach das aktuelle Element aus dem Pager ab und fragen Sie dann Ihren Adapter nach dem Fragment dieser Position.
int currentItem = viewPager.getCurrentItem();
Fragment item = mPagerAdapter.getItem(currentItem);
if (null != item && item.isVisible()) {
//do whatever want to do with fragment after doing type checking
return;
}
Dies ist der einfachste Hack:
fun getCurrentFragment(): Fragment? {
return if (count == 0) null
else instantiateItem(view_pager, view_pager.currentItem) as? Fragment
}
(Kotlin-Code)
Rufe einfach instantiateItem(viewPager, viewPager.getCurrentItem()
auf und wandle es in Fragment
Ihr Artikel wäre bereits instanziiert. Um sicherzugehen, können Sie einen Check für getCount
hinzufügen.
Funktioniert mit FragmentPagerAdapter
und FragmentStatePagerAdapter
!