Отримання поточного екземпляра фрагмента у вікні перегляду


210

Нижче наведено мій код, який має 3 Fragment classesвбудовану кожну з 3 вкладок 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
чи можете ви вказати назву класу ваших фрагментів, які перебувають у вікні перегляду?
Бірай Залавадія


Найпростіший спосіб отримати доступ до видимих ​​фрагментів був би через stackoverflow.com/questions/7379165/… , подивіться на дві найкращі відповіді.
Luksprog

Відповіді:


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 змінюється?
Maarten

7
@Maarten Ні, це просто звичайний хак, який використовується з моменту появи адаптера (і його вихідний код був доступний), він ще не змінився. Якщо ви хочете чогось більш надійного, вам потрібно буде скористатись іншими параметрами, найбільш помітними способами перегляду instantiateItem()способу та самостійно отримувати посилання на належні фрагменти.
Luksprog

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

29
Зверніть увагу, це не працює, якщо ви використовуєте FragmentStatePagerAdapter, а не FragmentPagerAdapter.
Шон Лаусон

3
@ShawnLauzon FragmentStatePagerAdapter має іншу реалізацію, і в цьому випадку ви викликаєте його метод instantiateItem (), щоб отримати видимі фрагменти.
Luksprog

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

28
Google повинен надати FragmentPageAdapter.getCurrentPrimaryItem (), що повертається mCurrentPrimaryItem.
eugene

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

3
Чому ifзаява? Фрагмент просто викликає equalsметод об'єкта, який є неглибоким порівнянням. То чому б не просто завжди телефонувати mCurrentFragment = ((Fragment) object);?
Оверкловер

спробував, і це працює чудово, просто киньте getCurrentFragment () на конкретний фрагмент, який він повинен
PhilipJ

113

Насамперед слідкуйте за всіма "активними" фрагментами сторінок. У цьому випадку ви відслідковуєте сторінки фрагментів у FragmentStatePagerAdapter, який використовується ViewPager.

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

Щоб уникнути посилання на "неактивні" сторінки фрагментів, вам потрібно застосувати метод killItem (...) 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) {фрагмент фрагмента = (фрагмент) Super.instantiateItem (контейнер, позиція); mPageReferenceMap.put (позиція, фрагмент); повернутий фрагмент; } '
pmellaaho

Який тип - це mPageReferenceMap?
ДоруАдріан

10
Ця відповідь справді погана! Ви не повинні тримати кеш ViewPager вручну, оскільки він обробляє його сам. ViewPager вирішує, коли фрагмент слід виділити чи ні, що робити паузу та коли, зберігаючи посилання на кожен фрагмент, додасть непотрібні накладні витрати та не оптимізовано для пам'яті.
Лівіо

3
Я спробував такий підхід, але, на жаль, він не працює, коли відтворюється діяльність. На Android N і пізніших версіях ви можете бачити це під час використання функції багатовікон. Коли ваш додаток відкрито, довго тримайте кнопку "вступ" (квадратну). Активність та фрагмент відтворені з збереженогоInstanceState, адаптер відтворений (тому mPageReferenceMap тепер порожній), але getItem не викликається знову. Карта залишається порожньою, тому адаптер.getFragment (індекс) вийде з ладу.
Мартін Конічек

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) та положення.

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

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


Це працює лише в тому випадку, якщо всі сторінки завантажені як фрагмент. Якщо є, наприклад, табличний розклад з багатьма вкладками / сторінками, вони завантажуються не всі, тому це може призвести до виключення indexoutofbounce.
progNewbie

@progNewbie так, знадобиться додатковий обхідний код.
Гаурав Пангам

@progNewbie Відповідь Євгена нижче вирішує таку ситуацію, я думаю
Гаурав Пангам

7

вибравши варіант, мені потрібно оновити фрагмент, який зараз видно.

Для того, щоб отримати посилання на даний момент видимого фрагмента, припустимо , що у вас є посилання на ViewPagerякості 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 індексу-

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

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

}

1

У мене була така ж проблема і вирішено її за допомогою цього коду.

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

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


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 існує, якщо події меню обробляються в межах діяльності, що містить фрагменти, і не існує, якщо події обробляються в межах самого фрагмента. Посилання показує, як фрагмент може додавати власні елементи меню.
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).

Якщо ви хочете зробити це в 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)
    }
        ...

}

1

У попередній реалізації я зберігав список дочірніх фрагментів, щоб мати можливість отримати доступ до них пізніше, але це виявилося помилковою реалізацією, що спричинило величезні витоки пам'яті.

Я закінчую за допомогою instantiateItem(...)методу, щоб отримати поточний фрагмент:

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

Або отримати будь-який інший фрагмент на позицію:

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

З документації :

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


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 при публічній недійсності onPageSelected (остаточна позиція int) , а потім

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

Ви можете реалізувати широкомовний приймач у фрагменті та надсилати наміри з будь-якого місця. Одержувач фрагмента може прослухати певну дію та викликати метод екземпляра.

Одне застереження переконує, що компонент «Перегляд» вже створено (і для деяких операцій, таких як прокрутка списку, 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)
}

Якщо ви вирішите піти цим шляхом, вам також слід впровадити killItem () та видалити знищений екземпляр з зареєстрованихFragments, іншим розумним у вас буде витік пам'яті.
dephinera

Це гарна порада. Ви можете внести зміни у відповідь.
Хамза Хан

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.