Отримайте фрагмент із ViewPager


248

Я використовую ViewPagerразом з a FragmentStatePagerAdapterдля розміщення трьох різних фрагментів:

  • [Фрагмент1]
  • [Фрагмент2]
  • [Фрагмент3]

Коли я хочу дістатись Fragment1з ViewPagerв FragmentActivity.

У чому проблема, і як її виправити?

Відповіді:


504

Основна відповідь спирається на ім’я, що генерується рамкою. Якщо це колись зміниться, то воно більше не буде працювати.

Як щодо цього рішення, що передусім, instantiateItem()і destroyItem()вашого Fragment(State)PagerAdapter:

public class MyPagerAdapter extends FragmentStatePagerAdapter {
    SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>();

    public MyPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public int getCount() {
        return ...;
    }

    @Override
    public Fragment getItem(int position) {
        return MyFragment.newInstance(...); 
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Fragment fragment = (Fragment) super.instantiateItem(container, position);
        registeredFragments.put(position, fragment);
        return fragment;
    }

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

    public Fragment getRegisteredFragment(int position) {
        return registeredFragments.get(position);
    }
}

Це, здається, працює для мене, коли ми маємо справу з доступними фрагментами. Фрагменти, які ще не були встановлені, повернеться до нуля під час дзвінка getRegisteredFragment. Але я використовую це в основному , щоб отримати поточну Fragmentз ряду ViewPager: adapater.getRegisteredFragment(viewPager.getCurrentItem())і це не повернеться null.

Я не знаю жодних інших недоліків цього рішення. Якщо є, я хотів би знати.


41
Це найкраще рішення, про яке я можу також придумати. Тільки пропозиція була б можливо обернути Fragmentв , WeakReferenceщоб гарантувати , що ви не заважаєте зруйнований фрагмент зі збирача сміття? Просто здається, що це правильно зробити ...
Алекс Локвуд

7
Що станеться, коли MyPagerAdapterруйнується через життєвий цикл (тобто обертається), не registerdFragmentsбуде втрачено? Чи Activity/ / Fragmentкористувачі MyPagerAdapterповинні зберегти його в onSaveInstanceState, а потім потрібно оновити його новим FragmentManagerпосиланням?
Стівен Біле

10
Якщо я не помиляюся (і ви повинні це перевірити), метод getItem не називається - як відомо - але метод instantiateItem викликається для кожного фрагмента, який відновлюється рамкою після обертання.
Вулиці Бостона

6
Так, я перевірив, що getItemне повертається знову при повороті (для будь-яких фрагментів, які вже були створені), оскільки FragmentManagerвідновлює стани цього вмісту Fragmentsв пейджері. Якщо instantiateItemвиклик, коли кожне Fragmentвідновлюється, то це рішення насправді є більш безпечним і майбутнім доказом, ніж моя чи прийнята відповідь. Я буду розглядати це сам.
Стівен Байле

6
@Dori Я це не зламаю. У моєму рішенні не використовується результат виклику 'getItem ()'. Замість цього використовується результат, збережений у виклику 'instantiateItem (). І життєвий цикл фрагмента не порушений, оскільки збережений фрагмент буде вилучений із розрідженого масиву під час виклику 'killItem ()'.
Вулиці Бостона

85

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

Якщо ви FragmentPagerAdapterбачите нижче. Якщо ви користуєтеся, то FragmentStatePagerAdapterварто на це подивитися . Захоплення індексів, які не є поточним у FragmentStateAdapter, не настільки корисне, оскільки за своєю природою вони будуть повністю зірвані вийшли з поля зору / виходу з-за меж екрана.

ШЛЯХИ НЕЧАСТІ

Неправильно: зберігайте власний внутрішній список фрагментів, доданих до FragmentPagerAdapter.getItem()виклику

  • Зазвичай, використовуючи SparseArrayабоMap
  • Не один із численних прикладів, які я бачив, пояснюють події життєвого циклу, тому це рішення є крихким. Як getItemназивається лише перший раз, коли сторінка прокручується до (або отримується, якщо ваш ViewPager.setOffscreenPageLimit(x)> 0) у ViewPager, якщо хостинг Activity/ Fragmentвбито або перезапущено, то внутрішня SpaseArrayбуде викреслена, коли відтворений користувальницький FragmentPagerActivity, але поза кадром ViewPagers внутрішні фрагменти будуть відтворені, і getItemбуде НЕ називатися будь-який з індексів, тому можливість отримати фрагмент з індексу будуть втрачені назавжди. Ви можете пояснити це за рахунок економії, і відновлення цих посилань фрагментів з допомогою FragmentManager.getFragment()і , putFragmentале це починає заплутатися ІМХО.

Неправильно: Створіть власний ідентифікатор тегу, який відповідає тому, що використовується під капотом,FragmentPagerAdapter і використовуйте це для отримання фрагментів сторінки зFragmentManager

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

Метод, відтворений для цього рішення, є

private static String makeFragmentName(int viewId, long id) {
    return "android:switcher:" + viewId + ":" + id;
}

ЧЕСТИЙ ПІТ: ViewPager.instantiateItem()

Аналогічний підхід до getItem()вище, але не порушує життєвий цикл, полягає в тому, щоб підключити instantiateItem()замість того, getItem()як буде називатися колишній щоразу, коли індекс створюється / отримує доступ. Дивіться цю відповідь

ЧЕСТИЙ ШЛЯХ: Створіть свій власний FragmentViewPager

Створіть власний FragmentViewPagerклас із джерела останньої версії підтримки та змініть метод, який використовується внутрішньо для створення тегів фрагментів. Ви можете замінити його нижче. Це перевага, що ви знаєте, що створення тегів ніколи не зміниться, і ви не покладаєтесь на приватний api / метод, який завжди небезпечний.

/**
 * @param containerViewId the ViewPager this adapter is being supplied to
 * @param id pass in getItemId(position) as this is whats used internally in this class
 * @return the tag used for this pages fragment
 */
public static String makeFragmentName(int containerViewId, long id) {
    return "android:switcher:" + containerViewId + ":" + id;
}

Тоді, як каже doc, коли ви хочете захопити фрагмент, використаний для індексу, просто зателефонуйте на щось подібне до цього методу (який ви можете помістити у звичайний FragmentPagerAdapterабо підклас), знаючи, що результат може бути нульовим, якщо getItem ще не викликався ця сторінка, тобто її ще не створено.

/**
 * @return may return null if the fragment has not been instantiated yet for that position - this depends on if the fragment has been viewed
 * yet OR is a sibling covered by {@link android.support.v4.view.ViewPager#setOffscreenPageLimit(int)}. Can use this to call methods on
 * the current positions fragment.
 */
public @Nullable Fragment getFragmentForPosition(int position)
{
    String tag = makeFragmentName(mViewPager.getId(), getItemId(position));
    Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag);
    return fragment;
}

Це просте рішення і вирішує проблеми в двох інших рішеннях, які можна знайти в Інтернеті


6
Це буде працювати, але для цього потрібно скопіювати клас ViewPager у власний вихідний код. Спираючись на 'instantiateItem ()' і 'killItem ()' пейджер-адаптера ViewPager, буде працювати і буде вшановувати життєві цикли фрагментів (ці два способи викликаються також, коли фрагменти створюються із збереженого стану екземпляра). Ви правильні, що покладатися на виклик getItem () не є хорошою ідеєю, а використання приватних API - це не те.
Вулиці Бостона

+1 Я погоджуюся, що це також рішення, і відредагували вище. Єдина відмінність полягає в тому, що вищезазначене працює у ще одному випадку використання instantiateItem(), коли саме ви хочете отримати доступ до фрагменту, який ще не був відвіданий після події життєвого циклу та був відвіданий перед подією життєвого циклу. Я знаю невелику різницю, але її одна, що призвела до тонкої помилки в моїй програмі, отже, я розглядаю це.
Дорі

Якщо setOffscreenPageLimit = 1 (за замовчуванням), FragmentStatePageAdapter почне міняти фрагменти в пам'ять і виходити з неї в міру доступу до оглядових сторінок. Після виклику getItem () буде створений новий екземпляр переглянутих сторінок / фрагментів. Після такого перегляду, чи є спосіб доручити системі відновити раніше створені екземпляри, а не створювати новий?
Карл

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

@Dori getItemId(pos)всередині немаєFragmentStatePagerAdapter
Jemshit Iskenderov

70

Додайте наступні методи до свого FragmentPagerAdapter:

public Fragment getActiveFragment(ViewPager container, int position) {
String name = makeFragmentName(container.getId(), position);
return  mFragmentManager.findFragmentByTag(name);
}

private static String makeFragmentName(int viewId, int index) {
    return "android:switcher:" + viewId + ":" + index;
}

getActiveFragment (0) повинен працювати.

Ось рішення, впроваджене в ViewPager https://gist.github.com/jacek-marchwicki/d6320ba9a910c514424d . Якщо щось не вдасться, ви побачите хороший журнал аварій.


Дуже дякую:) . Через це я провів його іншим способом, який використовую обробник, щоб розмістити фрагмент. Це не дуже підходить, але це врешті вирішило проблему. До речі, вам приємно :)
Qun Qin

12
Я використовував цей метод, але я вважаю, що він перестав працювати, коли я перейшов на API 17 (?). Я рекомендував би інший метод, і я вважаю за краще, якщо Google просто опублікував API, щоб отримати фрагмент із ViewPager, враховуючи його положення.
gcl1

У мене є проблема, коли викликати другий фрагмент, метод створити новий
Василь Валчев

2
Оскільки деякі версії API методу makeFragmentName змінено на приватний статичний String makeFragmentName (int viewId, long id) {return "android: switchcher:" + viewId + ":" + id; }, тому метод getActiveFragment тепер повинен виглядати так (використовуйте getItemId замість позиції для другого аргументу) public Fragment getActiveFragment (контейнер ViewPager, int position) {String name = makeFragmentName (container.getId (), getItemId (position)); повернути mFragmentManager.findFragmentByTag (ім'я); }
Євген Попович

1
Це дійсно працює, але це дійсно небезпечно, тому що він переходить на внутрішню реалізацію пейджера перегляду, і якщо Google змінить реалізацію (і вони можуть) поганих речей, це станеться. Я дуже сподіваюся, що goole зробить доступним для отримання фрагменту в реальному часі
shem

38

Ще одне просте рішення:

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

1
Це здається ідеальним для моїх поточних потреб у фрагменті.
danny117

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

1
Це звучить як приємне рішення, але як setPrimaryItem()називається після того, як ViewPager.OnPageChangeListener#onPageSelected() я не можу його використати :-(
hardysim

21

Я знаю, що на це є кілька відповідей, але, можливо, це комусь допоможе. Я використовував порівняно просте рішення, коли мені потрібно було отримати Fragmentсвоє ViewPager. Ви можете використовувати цей код у своєму Activityабо Fragmentутримуванні ViewPagerцього коду, щоб переглядати всі Fragmentйого вмісти.

FragmentPagerAdapter fragmentPagerAdapter = (FragmentPagerAdapter) mViewPager.getAdapter();
for(int i = 0; i < fragmentPagerAdapter.getCount(); i++) {
    Fragment viewPagerFragment = fragmentPagerAdapter.getItem(i);
    if(viewPagerFragment != null) {
        // Do something with your Fragment
        // Check viewPagerFragment.isResumed() if you intend on interacting with any views.
    }
}
  • Якщо ви знаєте свою позицію Fragmentу складі ViewPager, ви можете просто зателефонувати getItem(knownPosition).

  • Якщо ви не знаєте , позиції вашого Fragmentв ViewPager, ви можете мати ваші дитина Fragmentsреалізувати інтерфейс з методом , як getUniqueId()і використовувати, щоб розрізняти їх. Або ви можете перейти через усі Fragmentsта перевірити тип класу, наприкладif(viewPagerFragment instanceof FragmentClassYouWant)

!!! РЕДАКТУЙТЕ !!!

Я виявив, що getItemвикликається лише FragmentPagerAdapterтоді, коли кожен Fragmentповинен бути створений вперше , після цього виявляється, що Fragmentsрециркуляція використовується за допомогою FragmentManager. Таким чином, багато реалізацій FragmentPagerAdapterстворення нових Fragment s в getItem. Використовуючи мій вище метод, це означає, що ми будемо створювати нові Fragments кожен раз, коли getItemвикликається, коли ми проходимо всі елементи в FragmentPagerAdapter. Завдяки цьому я знайшов кращий підхід, використовуючи натомість FragmentManagerотримання кожного Fragment(використовуючи прийняту відповідь). Це більш повне рішення, і добре працює для мене.

FragmentPagerAdapter fragmentPagerAdapter = (FragmentPagerAdapter) mViewPager.getAdapter();
for(int i = 0; i < fragmentPagerAdapter.getCount(); i++) {
    String name = makeFragmentName(mViewPager.getId(), i);
    Fragment viewPagerFragment = getChildFragmentManager().findFragmentByTag(name);
    // OR Fragment viewPagerFragment = getFragmentManager().findFragmentByTag(name);
    if(viewPagerFragment != null) {

        // Do something with your Fragment
        if (viewPagerFragment.isResumed()) {
            // Interact with any views/data that must be alive
        }
        else {
            // Flag something for update later, when this viewPagerFragment
            // returns to onResume
        }
    }
}

І вам знадобиться цей метод.

private static String makeFragmentName(int viewId, int position) {
    return "android:switcher:" + viewId + ":" + position;
}

1
Ви просто знайдетеFragmentByTag (), але де ми могли б встановити TAG з фрагментом ??
VinceStyling

@vince ViewPagerСам встановлює ці теги. Це рішення є крихким, оскільки воно спирається на знання «прихованої» конвенції про іменування ViewPager. Відповіді вулиць Бостона - це набагато більш комплексне рішення, яке я зараз використовую у своєму проекті (замість цього підходу).
Стівен Байле

Це чудово працює! Але я видалив умовно "if (viewPagerFragment.isResumed ())", оскільки мені потрібно оновити мої сторінки ListFragment, які перебувають поза екраном. Потім, коли користувач повертається на сторінку ListFragment, він оновлюється новими даними.
JDJ

10

У моєму випадку жодне з перерахованих вище рішень не спрацювало.

Однак, оскільки я використовую Дитячий менеджер фрагментів у фрагменті, було використано наступне:

Fragment f = getChildFragmentManager().getFragments().get(viewPager.getCurrentItem());

Це працюватиме лише в тому випадку, якщо ваші фрагменти в диспетчері відповідають елементу перегляду сторінок.


Це ідеальна відповідь, щоб отримати старі фрагменти з пейджера перегляду при відтворенні активності чи фрагменту.
Сміт

7

Для того, щоб отримати поточний фрагмент Visible від ViewPager . Я використовую це просте твердження, і воно працює чудово.

      public Fragment getFragmentFromViewpager()  
      {
         return ((Fragment) (mAdapter.instantiateItem(mViewPager, mViewPager.getCurrentItem())));
      }

3

Я обробив це, спершу склавши список усіх фрагментів (List<Fragment> fragments; ), які я збирався використовувати, потім додав їх до пейджера, що полегшує обробку фрагмента, який зараз переглядають.

Так:

@Override
onCreate(){
    //initialise the list of fragments
    fragments = new Vector<Fragment>();

    //fill up the list with out fragments
    fragments.add(Fragment.instantiate(this, MainFragment.class.getName()));
    fragments.add(Fragment.instantiate(this, MenuFragment.class.getName()));
    fragments.add(Fragment.instantiate(this, StoresFragment.class.getName()));
    fragments.add(Fragment.instantiate(this, AboutFragment.class.getName()));
    fragments.add(Fragment.instantiate(this, ContactFragment.class.getName()));


    //Set up the pager
    pager = (ViewPager)findViewById(R.id.pager);
    pager.setAdapter(new MyFragmentPagerAdapter(getSupportFragmentManager(), fragments));
    pager.setOffscreenPageLimit(4);
}

тож це можна назвати:

public Fragment getFragment(ViewPager pager){   
    Fragment theFragment = fragments.get(pager.getCurrentItem());
    return theFragment;
}

тож я міг би зафіксувати це у операторі if, який запускався б лише за умови правильного фрагмента

Fragment tempFragment = getFragment();
if(tempFragment == MyFragmentNo2.class){
    MyFragmentNo2 theFrag = (MyFragmentNo2) tempFragment;
    //then you can do whatever with the fragment
    theFrag.costomFunction();
}

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


1
найкраща відповідь для мене
Сону Кумар

3

Це ґрунтується на відповіді Стівена вище. Це поверне фактичний екземпляр фрагмента, який уже приєднаний до батьківської діяльності.

FragmentPagerAdapter fragmentPagerAdapter = (FragmentPagerAdapter) mViewPager.getAdapter();
    for(int i = 0; i < fragmentPagerAdapter.getCount(); i++) {

        Fragment viewPagerFragment = (Fragment) mViewPager.getAdapter().instantiateItem(mViewPager, i);
        if(viewPagerFragment != null && viewPagerFragment.isAdded()) {

            if (viewPagerFragment instanceof FragmentOne){
                FragmentOne oneFragment = (FragmentOne) viewPagerFragment;
                if (oneFragment != null){
                    oneFragment.update(); // your custom method
                }
            } else if (viewPagerFragment instanceof FragmentTwo){
                FragmentTwo twoFragment = (FragmentTwo) viewPagerFragment;

                if (twoFragment != null){
                    twoFragment.update(); // your custom method
                }
            }
        }
    }

2

Я не міг знайти простий, чистий спосіб зробити це. Однак віджет ViewPager - це лише інший ViewGroup, в якому розміщені ваші фрагменти. ViewPager має ці фрагменти як безпосередні діти. Таким чином, ви можете просто повторити їх (використовуючи .getChildCount () та .getChildAt ()), і побачити, чи екземпляр фрагмента, який ви шукаєте, зараз завантажений у ViewPager і отримати посилання на нього. Наприклад, ви можете використовувати якесь статичне унікальне поле ідентифікатора, щоб розрізнити фрагменти.

Зауважте, що ViewPager, можливо, не завантажив шуканий фрагмент, оскільки це віртуалізуючий контейнер типу ListView.


1
Дякую за вашу відповідь, я отримую його за допомогою adpter.getItem (); Я першокурсник в програмуванні Android. дуже ціную тебе. Тепер я можу отримати ListFragment і хочу додати footerView до нього. Хоча я це роблю в своїй діяльності, тоді друк logcat: "java.lang.IllegalStateException: Перегляд вмісту ще не створено". Я знаю, чому у мене виникають труднощі з цим.
Qun Qin

1
FragmentActivity мають метод onAttachFragment (), дозуйте цю роботу для ViewPager з вмістом фрагмента?
Василь Валчев

2

FragmentPagerAdapter - це фабрика фрагментів. Щоб знайти фрагмент, виходячи з його положення, якщо все ще є в пам'яті, використовуйте це:

public Fragment findFragmentByPosition(int position) {
    FragmentPagerAdapter fragmentPagerAdapter = getFragmentPagerAdapter();
    return getSupportFragmentManager().findFragmentByTag(
            "android:switcher:" + getViewPager().getId() + ":"
                    + fragmentPagerAdapter.getItemId(position));
}

Приклад коду для v4 підтримки api.


Він повертає нуль у onresume (). Будь-яка ідея, чому і мотика, щоб виправити це?
seema

2

Вам не потрібно зателефонувати getItem()чи іншим способом на пізньому етапі, щоб отримати посилання на Fragmentрозміщеного всередині ViewPager. Якщо ви хочете оновити деякі дані всередині, Fragmentскористайтеся таким підходом: Динамічно оновити ViewPager?

Ключовим є встановлення нових даних всередині Adaperта дзвінок, notifyDataSetChanged()який, у свою чергу, зателефонує getItemPosition(), передаючи вам посилання на своє Fragmentта надаючи можливість оновити його. Усі інші способи вимагають від вас посилання на себе або якийсь інший хакер, що не є хорошим рішенням.

@Override
public int getItemPosition(Object object) {
    if (object instanceof UpdateableFragment) {
        ((UpdateableFragment) object).update(xyzData);
    }
    //don't return POSITION_NONE, avoid fragment recreation. 
    return super.getItemPosition(object);
}

Я не розумію тут, вам потрібна посилання на фрагмент, щоб використовувати getItemPosition (), так що ви можете також не використовувати getItemPosition, так?

getItemPosition()- це метод у вашому адаптері. Ви не будете телефонувати безпосередньо. У вас є посилання на ваш адаптер, тому ви зателефонуєте, adapter.notifyDataSetChanged()який у свою чергу зателефонує getItemPosition()вашому адаптеру, передавши посилання вашого Fragments. Ви можете побачити повну реалізацію в дії тут stackoverflow.com/questions/19891828 / ...
M-WaJeEh

Я це прочитав, і досі не розумію. Вам все одно знадобиться пряме посилання на ці фрагменти, щоб телефонувати проти них, правда? Ви згадуєте це як хакер, але я не бачу альтернативи; adapter.getItem (i), очевидно, не працює.

2
Гаразд я оновив свою відповідь, щоб уточнити більше. Звичайно, для оновлення потрібна довідка, Fragmentале про те, як отримати довідку, можна обговорити. Інші рішення отримати довідку з FragmentManagerдопомогою рядка аналогічна "android:switcher:"+idабо повернення POSITION_NONEз getItemosition()чого все фрагменти відтворити себе.
M-WaJeEh

Дякую, це має набагато більше сенсу і відповідає моєму досвіду (тому я, можливо, щось не так роблю, га).

2

Повинен поширюватися FragmentPagerAdapterна ваш клас адаптера ViewPager.
Якщо ви користуєтеся, FragmentStatePagerAdapterто не зможете знайти своє Fragmentза своїмID

public static String makeFragmentName(int viewPagerId, int index) {
  return "android:switcher:" + viewPagerId + ":" + index;
}

Як використовувати цей метод: -

Fragment mFragment = ((FragmentActivity) getContext()).getSupportFragmentManager().findFragmentByTag(
       AppMethodUtils.makeFragmentName(mViewPager.getId(), i)
);
InterestViewFragment newFragment = (InterestViewFragment) mFragment;

2

Гей , я відповів на це питання тут . В основному, вам потрібно перекрити

public Object instantiateItem (контейнер ViewGroup, позиція int)

метод FragmentStatePagerAdapter.


1

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


0

Найпростіший і найкоротший спосіб. Якщо всі ваші фрагменти в ViewPagerрізних класах, ви можете отримати та виділити їх наступним чином:

public class MyActivity extends Activity
{

    @Override
    public void onAttachFragment(Fragment fragment) {
        super.onAttachFragment(fragment);
        if (fragment.getClass() == MyFragment.class) {
            mMyFragment = (MyFragment) fragment;
        }
    }

}

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

0

Я реалізував це легко з дещо іншим підходом.

Мій власний метод FragmentAdapter.getItem повернув не новий MyFragment (), а екземпляр MyFragment, який був створений в конструкторі FragmentAdapter.

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


0

Створіть цілий ідентифікатор ресурсу в /values/integers.xml

<integer name="page1">1</integer>
<integer name="page2">2</integer>
<integer name="page3">3</integer>

Потім у функції PagerAdapter getItem:

public Fragment getItem(int position) {

        Fragment fragment = null;

        if (position == 0) {
            fragment = FragmentOne.newInstance();
            mViewPager.setTag(R.integer.page1,fragment);

        }
        else if (position == 1) {

            fragment = FragmentTwo.newInstance();
            mViewPager.setTag(R.integer.page2,fragment);

        } else if (position == 2) {

            fragment = FragmentThree.newInstance();
            mViewPager.setTag(R.integer.page3,fragment);

        }

        return fragment;
        }

Потім у діяльності запишіть цю функцію, щоб отримати посилання на фрагмент:

private Fragment getFragmentByPosition(int position) {
    Fragment fragment = null;

    switch (position) {
        case 0:
            fragment = (Fragment) mViewPager.getTag(R.integer.page1);
            break;

        case 1:

            fragment = (Fragment) mViewPager.getTag(R.integer.page2);
            break;

        case 2:
            fragment = (Fragment) mViewPager.getTag(R.integer.page3);
            break;
            }

            return fragment;
    }

Отримайте посилання на фрагмент, зателефонувавши до вищевказаної функції, а потім перекиньте його на свій власний фрагмент:

Fragment fragment = getFragmentByPosition(position);

        if (fragment != null) {
                    FragmentOne fragmentOne = (FragmentOne) fragment;
                    }

0

Простий спосіб ітерації фрагментів у менеджері фрагментів. Знайдіть viewpager, який має аргумент положення розділу, розміщений у загальнодоступному статичному PlaceholderFragment newInstance (int sectionNumber) .

public PlaceholderFragment getFragmentByPosition(Integer pos){
    for(Fragment f:getChildFragmentManager().getFragments()){
        if(f.getId()==R.id.viewpager && f.getArguments().getInt("SECTNUM") - 1 == pos) {
            return (PlaceholderFragment) f;
        }
    }
    return null;
}

0

У фрагменті

public int getArgument(){
   return mPage;
{
public void update(){

}

У FragmentActivity

List<Fragment> fragments = getSupportFragmentManager().getFragments();
for(Fragment f:fragments){
    if((f instanceof PageFragment)&&(!f.isDetached())){
          PageFragment pf = (PageFragment)f;   
          if(pf.getArgument()==pager.getCurrentItem())pf.update();
    }
}

0

у TabLayout є кілька вкладок для Fragment. ви можете знайти фрагмент за тегом, використовуючи індекс фрагмента.

Для екс. індекс для Fragment1 дорівнює 0, тому в findFragmentByTag()методі передайте тег для Viewpager. Після цього за допомогою fragmentTransaction ви можете додати, замінити фрагмент.

String tag = "android:switcher:" + R.id.viewPager + ":" + 0; Fragment1 f = (Fragment1) getSupportFragmentManager().findFragmentByTag(tag);


-1

Добре для адаптера FragmentStatePagerAdapter я фінансую рішення:

у вашому FragmentActivity:

ActionBar mActionBar = getSupportActionBar(); 
mActionBar.addTab(mActionBar.newTab().setText("TAB1").setTabListener(this).setTag(Fragment.instantiate(this, MyFragment1.class.getName())));
mActionBar.addTab(mActionBar.newTab().setText("TAB2").setTabListener(this).setTag(Fragment.instantiate(this, MyFragment2.class.getName())));
mActionBar.addTab(mActionBar.newTab().setText("TAB3").setTabListener(this).setTag(Fragment.instantiate(this, MyFragment3.class.getName())));

viewPager = (STViewPager) super.findViewById(R.id.viewpager);
mPagerAdapter = new MyPagerAdapter(getSupportFragmentManager(), mActionBar);
viewPager.setAdapter(this.mPagerAdapter);

і створити метод у своєму класі FragmentActivity - Отже, цей метод надає вам доступ до вашого фрагмента, вам просто потрібно надати йому потрібний фрагмент:

public Fragment getActiveFragment(int position) {
String name = MyPagerAdapter.makeFragmentName(position);
return getSupportFragmentManager().findFragmentByTag(name);
}

у своєму адаптері:

public class MyPagerAdapter extends FragmentStatePagerAdapter {

private final ActionBar actionBar;
private final FragmentManager fragmentManager;

public MyPagerAdapter(FragmentManager fragmentManager, com.actionbarsherlock.app.ActionBarActionBar mActionBar) {super(fragmentManager);
this.actionBar = mActionBar;
this.fragmentManager = fragmentManager;
}

@Override
public Fragment getItem(int position) {
getSupportFragmentManager().beginTransaction().add(mTchatDetailsFragment, makeFragmentName(position)).commit();
return (Fragment)this.actionBar.getTabAt(position);
}

@Override
public int getCount() {
return this.actionBar.getTabCount();
}

@Override
public CharSequence getPageTitle(int position) {
return this.actionBar.getTabAt(position).getText();
}

private static String makeFragmentName(int viewId, int index) {
return "android:fragment:" + index;
}

}

-1
Fragment yourFragment = yourviewpageradapter.getItem(int index);

index- це місце фрагмента в адаптері, як ви додали fragment1спочатку такий ретриверний fragment1пропуск indexяк 0 і так далі для відпочинку

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