Получение текущего экземпляра Fragment в окне просмотра


210

Ниже приведен мой код, который имеет 3 Fragment classesкаждую из трех вкладок ViewPager. У меня есть пункт меню. Как показано в onOptionsItemSelected(), выбрав опцию, мне нужно обновить фрагмент, который в настоящее время виден. Чтобы обновить это, я должен вызвать метод, который находится в классе фрагмента. Может кто-нибудь подсказать, пожалуйста, как вызвать этот метод?

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

     }

    }

Предположим, что ниже приведен класс фрагмента с методом, который updateList()я хочу вызвать:

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

какой метод фрагмента вы хотите вызвать?
Бирадж Залавадия

@BirajZalavadia Мой собственный определенный метод, в котором есть параметр и который использует переменные экземпляра этого класса фрагмента, которые уже были инициализированы при создании представления.
Рик

1
Можете ли вы дать название класса ваших фрагментов, которые находятся в viewpager?
Бирадж Залавадия

какое-то решение stackoverflow.com/questions/7379165/…
An-droid

Самый простой способ получить доступ к видимым фрагментам был бы через stackoverflow.com/questions/7379165/… , посмотрите на два верхних ответа.
Лукспрог

Ответы:


205

выбрав опцию, мне нужно обновить фрагмент, который в данный момент виден.

Простой способ сделать это - использовать трюк, связанный с FragmentPagerAdapterреализацией:

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;

Пожалуйста, переосмыслите соглашение об именовании переменных, используя в качестве имени переменной имя класса, которое очень запутанно (поэтому нет ViewPager ViewPager, используйте, ViewPager mPagerнапример).


23
Является ли этот фрагмент тега перспективным, если API изменится?
Мартен

7
@ Maarten Нет, это обычный хак, который использовался с момента появления адаптера (и его исходного кода), он еще не изменился. Если вы хотите что-то более надежное, вам нужно использовать другие параметры, наиболее заметные из которых - переопределение instantiateItem()метода и получение ссылок на нужные фрагменты самостоятельно.
Лукспрог

5
После нескольких часов разочарования и расспросов о страницах прямо из mAdapter.getItem(position), офигенно ... По крайней мере, теперь я знаю, что другие 8512 испытаний не работали. Спасибо
Диолор

29
Обратите внимание, что это не работает, если вы используете FragmentStatePagerAdapter вместо FragmentPagerAdapter.
Шон Лозон

3
@ShawnLauzon FragmentStatePagerAdapter имеет другую реализацию, в этом случае вы вызываете его метод instantiateItem () для получения видимых фрагментов.
Лукспрог

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

29
Google должен предоставить FragmentPageAdapter.getCurrentPrimaryItem (), возвращающий mCurrentPrimaryItem.
Евгений

1
Я также использую эту технику. Я также определяю PagerFragment с помощью методов onPageSelected/, onPageDeselectedи все мои фрагменты пейджера расширяют его. Затем setPrimaryitemможно вызывать эти методы соответствующим образом, когда пользователь перемещается на новую страницу. Это означает, что вы можете реализовать более ленивую стратегию загрузки данных на страницах, которые даже не отображаются. Однако вы должны иметь в виду, что во время перехода страницы выглядит лучше, если следующая страница уже заполнена данными, поэтому отложенная загрузка всех данных onPageSelectedможет быть не идеальной.
JHH

3
Почему ifзаявление? Фрагмент просто вызывает equalsметод объекта, который является мелким сравнением. Так почему бы просто не всегда звонить mCurrentFragment = ((Fragment) object);?
Overclover

попробовал и все работает нормально, просто приведите getCurrentFragment () к конкретному фрагменту, который должен
PhilipJ

113

Прежде всего следите за всеми «активными» фрагментами страниц. В этом случае вы отслеживаете фрагменты страниц в FragmentStatePagerAdapter, который используется ViewPager.

@Override
public Fragment getItem(int index) {
    Fragment myFragment = MyFragment.newInstance();
    mPageReferenceMap.put(index, myFragment);
    return myFragment;
}

Чтобы избежать ссылки на «неактивные» страницы фрагмента, вам необходимо реализовать метод destroyItem (...) FragmentStatePagerAdapter:

@Override
public void destroyItem (ViewGroup container, int position, Object object) {
    super.destroyItem(container, position, object);
    mPageReferenceMap.remove(position);
}

и когда вам нужно получить доступ к видимой в данный момент странице, вы затем звоните:

int index = mViewPager.getCurrentItem();
MyAdapter adapter = ((MyAdapter)mViewPager.getAdapter());
MyFragment fragment = adapter.getFragment(index);

Где метод getFragment (int) в MyAdapter выглядит следующим образом:

public MyFragment getFragment(int key) {
    return mPageReferenceMap.get(key);
}

Надеюсь, что это может помочь!


Можете ли вы объяснить, ясно? Где мне нужно сохранить этот класс FragmentStatePagerAdapter в моем коде? Кстати, у меня есть 3 класса фрагментов, а не один MyFragmentClass.
Рик,

7
Еще лучше, если вы обновите mPageReferenceMap в instantiateItem вместо getItem, потому что он также работает после изменения ориентации. '@Override public Object instantiateItem (контейнер ViewGroup, int position) {Фрагмент фрагмента = (Fragment) Super.instantiateItem (контейнер, позиция); mPageReferenceMap.put (позиция, фрагмент); возвратный фрагмент; } '
pmellaaho

Какой тип mPageReferenceMap?
ДоруАдрян

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

3
Я попробовал этот подход, но, к сожалению, он не работает, когда деятельность воссоздается. В Android N и более поздних версиях это можно увидеть при использовании многооконной функции. Когда ваше приложение открыто, долго удерживайте кнопку «последние» (квадратная). Действие и фрагмент воссоздаются из saveInstanceState, адаптер воссоздается (поэтому mPageReferenceMap теперь пуст), но getItem больше не вызывается. Карта остается пустой, поэтому адаптер.getFragment (index) будет аварийно завершать работу.
Мартин Коничек

102

Это единственный способ получить NullPointerException для переменных экземпляра определенных классов фрагментов. Это может быть полезно для тех, кто придерживается того же. В onOptionsItemSelected () я кодировал следующий способ:

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

3
Я думаю, что это самый правильный ответ - согласовать с дизайном, FragmentStatePagerAdapterне переопределяя любой код. На самом деле, это должно быть так же просто, как функция просто вернуть viewPager.getAdapter().instantiateItem(viewPager, viewPager.getCurrentItem()).
Джон Пан

39

FragmentStatePagerAdapter имеет открытый метод с именем instantiateItem, который возвращает ваш фрагмент на основе указанных значений параметров, этот метод имеет два параметра ViewGroup (ViewPager) и position.

public Object instantiateItem(ViewGroup container, int position);

Использовал этот метод для получения фрагмента указанной позиции,

Fragment fragment = (Fragment) adaper.instantiateItem(mViewPager, position);

5
Но это не возвращает текущий уже созданный фрагмент, а новый вместо этого, нет? Таким образом, имя "экземпляр" ...
Ixx

1
@ Ixx Нет, это не создает новый фрагмент. Я думаю, что имя метода здесь неверно.
Ошибки происходят

15

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

// для фрагмента при 0 возможности

((mFragment) viewPager.getAdapter().instantiateItem(viewPager, 0)).yourMethod();

10

Здесь есть много ответов, которые на самом деле не касаются основного факта, что на самом деле НЕТ СПОСОБА сделать это предсказуемо, и таким образом, что в какой-то момент в будущем вы не выстрелите себе в ногу.

FragmentStatePagerAdapterэто единственный класс, который знает, как надежно получить доступ к фрагментам, которые отслеживаются ... FragmentManagerлюбая попытка угадать идентификатор или тег фрагмента не является надежной, долгосрочной. И попытки отследить экземпляры вручную, вероятно, не будут работать хорошо, когда состояние будет сохранено / восстановлено, потому что FragmentStatePagerAdapterвполне может не вызывать обратные вызовы, когда оно восстанавливает состояние.

Единственное, что мне удалось сделать - это скопировать код FragmentStatePagerAdapterи добавить метод, который возвращает фрагмент с учетом позиции ( mFragments.get(pos)). Обратите внимание, что этот метод предполагает, что фрагмент действительно доступен (т.е. он был виден в какой-то момент).

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


1
чтобы иметь дело с «не работает хорошо, когда состояние сохраняется / восстанавливается», я переопределяю метод saveState (). Чтобы пейджер не сохранял ни одного фрагмента при приостановке активности. оно работает.
AntoineP

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

8
getSupportFragmentManager().getFragments().get(viewPager.getCurrentItem());

Приведите экземпляр полученной сверху строки к фрагменту, с которым вы хотите работать. Работает отлично.

viewPager

это экземпляр пейджера, управляющий фрагментами.


Это работает, только если все страницы загружены как фрагмент. Например, при наличии табуляции с множеством вкладок / страниц загружаются не все, что может вызвать исключение indexout ofbounce.
progNewbie

@progNewbie да, для этого потребуется дополнительный обходной код.
Гаурав Пангам

@progNewbie Ответ Евгения, приведенный ниже, справится с этой ситуацией, я думаю
Гаурав Пангам

7

выбрав опцию, мне нужно обновить фрагмент, который в данный момент виден.

Чтобы получить ссылку на видимый в данный момент фрагмент, предположим, что у вас есть ссылка на ViewPageras mPager. Затем следующие шаги получат ссылку на currentFragment:

  1. PageAdapter adapter = mPager.getAdapter();
  2. int fragmentIndex = mPager.getCurrentItem();
  3. FragmentStatePagerAdapter fspa = (FragmentStatePagerAdapter)adapter;
  4. Fragment currentFragment = fspa.getItem(fragmentIndex);

Единственная используемая линия 3 броска действительна обычно. FragmentStatePagerAdapterполезный адаптер для ViewPager


7

Лучший способ сделать это, просто вызвать CallingFragmentName фрагмент = (CallingFragmentName) viewPager .getAdapter () .instantiateItem (viewPager, viewPager.getCurrentItem ()); Он будет повторно создавать экземпляр вызывающего фрагмента, чтобы не вызывать исключение нулевого указателя и вызывать любой метод этого фрагмента.


6

Текущий фрагмент:

Это работает, если вы создали проект с шаблоном панели вкладок фрагментов.

Fragment f = mSectionsPagerAdapter.getItem(mViewPager.getCurrentItem());

Обратите внимание, что это работает с реализацией шаблона активности с вкладками по умолчанию.


30
Это зависит от вашей реализации getItem () - он может вернуть новый экземпляр фрагмента, что, вероятно, не то, что вы хотите.
Том

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

3

Я использовал следующее:

 int index = vpPager.getCurrentItem();
 MyPagerAdapter adapter = ((MyPagerAdapter)vpPager.getAdapter());
 MyFragment suraVersesFragment = (MyFragment)adapter.getRegisteredFragment(index);

1
Это зависит от реализации пользовательского пейджера из ответа, найденного здесь: stackoverflow.com/questions/8785221/…
Том Редман

1
Это именно то, что я пытался сделать, но не зная, какие методы переопределить, потратил бы впустую часы - спасибо!
Брон Дэвис

2

FragmentStatePagerAdapterимеет частную переменную экземпляра с именем mCurrentPrimaryItemтипа Fragment. Можно только удивляться, почему разработчики Android не снабжали его геттером. Эта переменная создается в setPrimaryItem()методе. Итак, переопределите этот метод таким образом, чтобы получить ссылку на эту переменную. Я просто закончил тем, что объявил свое собственное mCurrentPrimaryItemи скопировал содержимое setPrimaryItem()моего переопределения.

В вашей реализации 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;
}

2

Вы можете определить PagerAdapterкак это, тогда вы сможете получить любой Fragmentв ViewPager.

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

Чтобы получить текущий Fragment

Fragment currentFragment = mPagerAdapter.getItem(mViewPager.getCurrentItem());

2

Когда мы используем viewPager, хорошим способом доступа к экземпляру фрагмента в деятельности является instantiateItem (viewpager, index). // index - индекс фрагмента, экземпляр которого вы хотите.

например, я обращаюсь к экземпляру фрагмента 1 index-

Fragment fragment = (Fragment) viewPageradapter.instantiateItem(viewPager, 1);

if (fragment != null && fragment instanceof MyFragment) {      
 ((MyFragment) fragment).callYourFunction();

}

2

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

Я в конечном итоге с помощью instantiateItem(...)метода, чтобы получить текущий фрагмент:

val currentFragment = adapter?.instantiateItem(viewPager, viewPager.currentItem)

Или получить любой другой фрагмент на позиции:

val position = 0
val myFirstFragment: MyFragment? = (adapter?.instantiateItem(viewPager, position) as? MyFragment)

Из документации :

Создайте страницу для данной позиции. Адаптер отвечает за добавление представления к указанному здесь контейнеру, хотя он должен только гарантировать, что это будет сделано к тому времени, как он вернется из finishUpdate (ViewGroup).


Коротко и чисто, спасибо
JimmyFlash

1

У меня была та же проблема, и я решил ее с помощью этого кода.

MyFragment fragment = (MyFragment) thisActivity.getFragmentManager().findFragmentById(R.id.container);

Просто замените имя MyFragment именем вашего фрагмента и добавьте id вашего контейнера фрагментов.


1

Это более перспективно, чем принятый ответ:

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
    /* ------------------------------------------------------------------------------------------ */
}

Вместо этого вы должны использовать WeakHashMap.
Пракаш Надар

1

Рассматриваемый сценарий лучше обслуживается каждым фрагментом, добавляющим свои собственные пункты меню и непосредственно обрабатывающим onOptionsItemSelected (), как описано в официальной документации . Лучше избегать недокументированных уловок.


Этот ответ может использовать более подробную информацию о том, как на самом деле это сделать. Как добавление пункта меню решает ViewPagerпроблему?
Сурагч

@Suragch ViewPager проблема существует, если события меню обрабатываются в Activity, которая содержит фрагменты, и не существует, если события обрабатываются внутри самого фрагмента. Ссылка показывает, как фрагмент может добавлять свои собственные пункты меню.
Y2i

1

После прочтения всех комментариев и ответов я собираюсь объяснить оптимальное решение этой проблемы. Лучший вариант - решение @ rik, поэтому мое улучшение основано на его.

Вместо того, чтобы спрашивать каждый FragmentClass как

if(FragmentClass1){
   ...
if(FragmentClass2){
   ...
}

Создайте свой собственный интерфейс и сделайте так, чтобы ваши дочерние фрагменты реализовали его, что-то вроде

public interface MyChildFragment {
    void updateView(int position);
}

Затем вы можете сделать что-то подобное, чтобы инициировать и обновить свои внутренние фрагменты.

Fragment childFragment = (Fragment) mViewPagerDetailsAdapter.instantiateItem(mViewPager,mViewPager.getCurrentItem());

if (childFragment != null) {
   ((MyChildFragment) childFragment).updateView();
}

PS Будьте осторожны с тем, куда вы помещаете этот код, если вы вызываете insatiateItem до того, как система фактически его создаст, savedInstanceStateваш дочерний фрагмент для этого будет нулевым

public void onCreate(@Nullable Bundle savedInstanceState){
      super(savedInstanceState)
}

Вылетит ваше приложение.

Удачи


1

На основании того, что он ответил @chahat jain:

«Когда мы используем viewPager, хорошим способом доступа к экземпляру фрагмента в действии является instantiateItem (viewpager, index). // index - индекс фрагмента, экземпляр которого вы хотите.»

Если вы хотите сделать это в kotlin

val fragment =  mv_viewpager.adapter!!.instantiateItem(mv_viewpager, 0) as Fragment
                if ( fragment is YourFragmentFragment)
                 {
                    //DO somthign 
                 }

0 к экземпляру фрагмента 0

// ================================================ ========================= // // ##################### ######## Пример использования ################################# // // == ================================================== ===================== //

Вот полный пример, чтобы получить потерянное представление о

вот мой veiewPager в .xml файле

   ...
    <android.support.v4.view.ViewPager
                android:id="@+id/mv_viewpager"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_margin="5dp"/>
    ...

И домашняя активность, где я вставляю вкладку

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

}

0

В моей деятельности я имею:

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

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

Иногда фрагмент может отправить пустой объект, поэтому вы можете запустить новый Runnable, чтобы решить проблему при первой загрузке.

Спасибо, Рик


Пожалуйста, добавьте текст, объясняющий, почему этот код решит проблему ОП. Кроме того, учитывая, сколько существует других ответов, объясните, почему этот ответ лучше тех, которые уже были даны. Помогите другим понять.
APC

0

Переопределите setPrimaryItem из вашего FragmentPagerAdapter: объект является видимым фрагментом:

 @Override
        public void setPrimaryItem(ViewGroup container, int position, Object object) {
            if (mCurrentFragment != object) {
                mCurrentFragment = (LeggiCapitoloFragment) object;
            }
            super.setPrimaryItem(container, position, object);
        }

0

Просто возьмите текущий элемент из пейджера, а затем попросите у вашего адаптера фрагмент этой позиции.

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

3
Что, если getItemсоздать новый экземпляр
Пракаш Надар

0

Чтобы получить текущий фрагмент - получите позицию в ViewPager в публичном void onPageSelected (final int position) , а затем

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 - аргумент позиции, назначенный в публичном статическом PlaceholderFragment newInstance (int sectionNumber);фрагмента

getChildFragmentManager () или getFragmentManager () - зависит от того, как создан SectionsPagerAdapter


0

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

Одно предостережение заключается в том, что компонент View уже создан и (и для некоторых операций, таких как прокрутка списка, ListView уже должен отображаться).


0

Это самый простой взлом:

fun getCurrentFragment(): Fragment? {
    return if (count == 0) null
    else instantiateItem(view_pager, view_pager.currentItem) as? Fragment
}

(код Котлина)

Просто позвони instantiateItem(viewPager, viewPager.getCurrentItem()и брось Fragment. Ваш предмет уже будет создан. Чтобы быть уверенным, вы можете добавить чек для getCount.

Работает с обоими FragmentPagerAdapterи FragmentStatePagerAdapter!


0

Если ваш пейджер находится внутри фрагмента, используйте это:

private fun getPagerCurrentFragment(): Fragment? {
    return childFragmentManager.findFragmentByTag("android:switcher:${R.id.myViewPagerId}:${myViewPager.currentItem}")
}

Где R.id.myViewPagerIdнаходится идентификатор вашего ViewPager внутри XML-макета.


Это работает только с обычным FragmentPageAdapter, а не с FragmentStatePageAdapter.
progNewbie

0

Вы можете объявить массив фрагментов как фрагменты регистра

class DashboardPagerAdapter(fm: FragmentManager?) : FragmentStatePagerAdapter(fm!!) {
    // CURRENT FRAGMENT
    val registeredFragments = SparseArray<Fragment>()

    override fun instantiateItem(container: ViewGroup, position: Int): Any {
        val fragment = super.instantiateItem(container, position) as Fragment
        registeredFragments.put(position, fragment)
        return fragment
    }

    override fun getItem(position: Int): Fragment {
        return when (position) {
            0 -> HomeFragment.newInstance()
            1 -> ConverterDashboardFragment.newInstance()
            2 -> CartFragment.newInstance()
            3 -> CustomerSupportFragment.newInstance()
            4 -> ProfileFragment.newInstance()
            else -> ProfileFragment.newInstance()
        }
    }

    override fun getCount(): Int {
        return 5
    }

}

Тогда вы можете использовать его как

adapter?.let {
    val cartFragment = it.registeredFragments[2] as CartFragment?
    cartFragment?.myCartApi(true)
}

Если вы решите пойти по этому пути, вы должны также реализовать destroyItem () и удалить уничтоженный экземпляр из зарегистрированных фрагментов, в противном случае у вас будет утечка памяти.
Dephinera

Это хороший совет. Вы можете внести изменения в ответ.
Хамза Хан

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.