Android ViewPager отримує поточний вигляд


75

У мене є ViewPager, і я хотів би отримати поточний вибраний та видимий вигляд, а не позицію.

  1. getChildAt(getCurrentItem) повертається неправильно View
  2. Це працює не завжди. Іноді повертає null, іноді просто повертає неправильний View.

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
    
        if (isVisibleToUser == true) { 
            mFocusedListView = ListView; 
        }
    }
    
  3. PageListener на ViewPagerз getChildAt()теж не працює, не даючи мені правильний вид кожен раз.

Як я можу отримати поточний видимий вигляд?

View view = MyActivity.mViewPager.getChildAt(MyActivity.mViewPager.getCurrentItem()).getRootView();
ListView listview = (ListView) view.findViewById(R.id.ListViewItems);

Відповіді:


133

Я це зрозумів. Що я зробив, це зателефонував setTag()з іменем усім Views / ListViews, і просто зателефонував findViewWithTag(mytag), mytagбудучи тегом.

На жаль, іншого способу вирішити це немає.


1
Це дасть мені підказку. Дякую!
rahstame

7
Не можу повірити, що це найкращий варіант, але він працює. Я просто встановлюю індекс як тег, коли адаптер створює елемент.
повагаTheCode

13
+1 до абсурду цього рішення, але воно, безумовно, найкраще. Використання позиції як тегу в PagerAdapter.instantiateView та отримання подання за допомогою findViewBy (getCurrentItem ()) - найелегантніша форма цього зламу.
nathanielwolf

ще +1 @lacas за пошук цього рішення
Адді

4
Скажіть, будь ласка, є кращий спосіб зробити це майже через шість років !?
Теорія графіків

9

Я щойно натрапив на ту саму проблему та вирішив її за допомогою:

View view = MyActivity.mViewPager.getFocusedChild();

5
Це не завжди працює, іноді фокус знаходиться деінде, навіть на даний момент відображається вид з ViewPager
Pimp Trizkit

Це може бути так, але спрацьовує, якщо ви вимагаєте зосередити увагу на тій сторінці, яка стає видимою
ZeCodea 04.03.13

1
Хіба що, я тут щось непорозумів. Що ви конкретно маєте на увазі під "запитом фокусу"? Тому що, якщо я роблю це mViewPager.getChildAt(i).isFocused()для всіх дітей, це звітує falseдля всіх дітей. Можливо, тому, що я вкладаю цей код у меню параметрів, яке є частиною MainActivity, переносячи таким чином фокус із ViewPager. Тому такий спосіб не працює в певних ситуаціях.
Pimp Trizkit 05.03.13

так, це може бути спливаюче вікно діалогу або об’єкт Toast. Тож використовуйте замість цього метод isVisible ()
CodeToLife

Здається, не працює для AndroidX ViewPager 1.0.0 / Бібліотека підтримки ViewPager 28.0.0
Тім Кіст

7

Ви можете отримати поточний елемент, отримавши доступ до вашого списку імен із виклику адаптера. myAdapter.yourListItens.get(myViewPager.getCurrentItem()); Як бачите, ViewPager може отримати поточний індекс елемента вашого адаптера (поточна сторінка).

Якщо ви використовуєте FragmentPagerAdapter, ви можете зробити цей приклад:

FragmentPagerAdapter adapter = (FragmentPagerAdapter)myViewPager.getAdapter();

і дзвоніть

adapter.getItem(myViewPager.getCurrentItem());

Для мене це дуже добре працює;)


2
Працює лише у тому випадку, якщо вашим адаптером є FragmentPagerAdapter
Борис Странджев,

22
Зверніть увагу, що getItem()передбачається завжди повертати новий екземпляр Фрагменту при підкласифікації Fragment(State)PagerAdapter. Отже, це неправильно, оскільки воно просто створює новий екземпляр замість повернення "старого".
ComFreek

Наведений коментар є помилковим. Безпосередньо з документів: "Повернути фрагмент, пов’язаний із вказаною позицією." Про повернення нового Фрагменту нічого не сказано.
працював

2
Ваша відповідь повертає Фрагмент, але для мене Фрагмент порожній. adapter.getItem (myViewPager.getCurrentItem ()). getView () повертає null.
працював

7

Я використовую цей метод з android.support.v4.view.ViewPager

View getCurrentView(ViewPager viewPager) {
        try {
            final int currentItem = viewPager.getCurrentItem();
            for (int i = 0; i < viewPager.getChildCount(); i++) {
                final View child = viewPager.getChildAt(i);
                final ViewPager.LayoutParams layoutParams = (ViewPager.LayoutParams) child.getLayoutParams();

                Field f = layoutParams.getClass().getDeclaredField("position"); //NoSuchFieldException
                f.setAccessible(true);
                int position = (Integer) f.get(layoutParams); //IllegalAccessException

                if (!layoutParams.isDecor && currentItem == position) {
                    return child;
                }
            }
        } catch (NoSuchFieldException e) {
            Log.e(TAG, e.toString());
        } catch (IllegalArgumentException e) {
            Log.e(TAG, e.toString());
        } catch (IllegalAccessException e) {
            Log.e(TAG, e.toString());
        }
        return null;
    }

Дуже дякую. Це саме те, що я хочу
Ерфан Егтерафі

2

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

Рішення, яке я пропоную:

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

2

Я використовую ViewPagerUtils від FabulousFilter :

ViewPagerUtils.getCurrentView(ViewPager viewPager)

Я використовую цей метод і можу підтвердити, що він працює.
Aleksandar Acić

Це не є частиною основного андроїд SDK. Ймовірно, ви використовуєте сторонні бібліотеки. Це, мабуть, тому вас проголосували.
aeskreis

1
Чи користуєтесь ви цією бібліотекою? github.com/Krupen/FabulousFilter . Ця бібліотека має метод ViewPagerUtils. Він використовує простір імен android.support.v4, який ВІДОМО підозрілий. НІКОЛИ НІКОЛИ не використовуйте простори імен для своїх класів, оскільки це може призвести до плутанини (це прекрасний приклад такої плутанини). Здається, автор зробив це для доступу до полів, захищених пакетами, що вкотре є жахливою практикою коду. Я б не рекомендував цей метод.
aeskreis

У відповіді я написав, що це бібліотека підтримки Android v4. developer.android.com/topic/libraries/support-library
Aleksandar Acić

А ViewPager є частиною бібліотеки підтримки, тому додаткових залежностей додавати не потрібно.
Aleksandar Acić,

2

Використовуйте адаптер, що розширює PagerAdapter, і перевизначте метод setPrimaryItem всередині вашого PagerAdapter.

https://developer.android.com/reference/android/support/v4/view/PagerAdapter.html

class yourPagerAdapter extends PagerAdapter
{
    // .......

    @Override
    public void setPrimaryItem (ViewGroup container, int position, Object object)
    {
        int currentItemOnScreenPosition = position;
        View onScreenView = getChildAt(position);
    }

    // .......

}

2
Не відповідає на вихідне запитання, щоб отримати фактичний вигляд. Крім того, якщо вам потрібна позиція, чому б не використовувати getCurrentItem () ?
Тім Кіст

Так. Я забув написати це, щоб отримати представлення, яке вам просто потрібно використовувати: getChildAt (currentItemOnScreenPosition).
Андрес,

З іншого боку, функція getCurrentItem () не повертає поточний вибраний та видимий вигляд, як сказано в оригінальному запитанні, getChildAt (getCurrentItem) повертає неправильний вигляд. Я думаю, що функція getCurrentItem () повертає елемент, який наразі обчислюється viewPager, і цей елемент може бути не таким, як зараз на екрані
Андрес,

1

Спробуйте це

 final int position = mViewPager.getCurrentItem();
    Fragment fragment = getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.rewards_viewpager + ":"
            + position);

1

Мені довелося робити це більш загально, тому я вирішив використати приватну `` позицію '' ViewPager.LayoutParams

        final int childCount = viewPager.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = viewPager.getChildAt(i);
            final ViewPager.LayoutParams lp = (ViewPager.LayoutParams) child.getLayoutParams();
            int position = 0;
            try {
                Field f = lp.getClass().getDeclaredField("position");
                f.setAccessible(true);
                position = f.getInt(lp); //IllegalAccessException
            } catch (NoSuchFieldException | IllegalAccessException ex) {ex.printStackTrace();}
            if (position == viewPager.getCurrentItem()) {
                viewToDraw = child;
            }
        }

1

Якщо у вас мало сторінок, і ви можете сміливо застосовувати, setOffscreenPageLimit(N-1) де N - загальна кількість сторінок, не витрачаючи занадто багато пам'яті, тоді ви можете зробити наступне:

public Object instantiateItem(final ViewGroup container, final int position) {      
    CustomHomeView RL = new CustomHomeView(context);
    if (position==0){
        container.setId(R.id.home_container);} ...rest of code

тоді ось код для доступу до вашої сторінки

((ViewGroup)pager.findViewById(R.id.home_container)).getChildAt(pager.getCurrentItem()).setBackgroundColor(Color.BLUE);

Якщо ви хочете, ви можете налаштувати спосіб доступу до сторінки

RelativeLayout getPageAt(int index){
    RelativeLayout rl =  ((RelativeLayout)((ViewGroup)pager.findViewById(R.id.home_container)).getChildAt(index));
    return rl;
}

2
getChildAt(pager.getCurrentItem())не роби те, що ти хочеш. Наприклад, ViewPager може мати 1000 сторінок, але лише 5 дітей, тому ви виходите за межі, якщо поточний елемент є останньою сторінкою.
fdermishin

@fdermishin це правда, якщо у вас немає опції 'setOffscreenPageLimit (N-1)', де N - кількість сторінок. Однак це не рекомендується, якщо у вас багато сторінок, оскільки це може бути непотрібною
Майкл Керн,

0

це ваша перша активність на екрані чи ви вже накладали один на одного вище?

спробуйте це:

findViewById(android.R.id.content).getRootView()

або просто:

findViewById(android.R.id.content) 

також залежно від того, що ви хочете спробувати:

((ViewGroup)findViewById(android.R.id.content)).getChildAt(0)

перші два просто дають мені елемент TAB 0 весь час, а третій код - нуль
lacas

спробував це? this.findViewById (android.R.id.content) .getRootView () Можливо, вам слід надати трохи більше інформації про свою діяльність та про те, як ви будуєте та переміщаєтесь між ними.
SunnySonic

Жодна з цих пропозицій не спрацює. Третій отримає сторінку на пейджері, але не в центрі, а одну ліворуч, а ОП хотів, щоб сторінка була відцентрована / поточна.
Тім Кіст

0

Ви можете знайти фрагмент за системним тегом. Це робота для мене. Я використовував його у OnMeasureфункції.

id - viewPager ID

position - фрагмент, який ви хочете отримати

Важливо! Ви отримуєте цей фрагмент, якщо ваш фрагмент був створений в адаптері. Тож ви повинні перевіритиsupportedFragmentManager.findFragmentByTag("android:switcher:" + id + ":" + position) нуль

Ви можете отримати такий вигляд:

supportedFragmentManager.findFragmentByTag("android:switcher:" + id + ":" + position).view

Ви не повинні вводити власний тег в адаптері


0
viewpager.getChildAt(0)

це завжди повертає мій вибраний подання. це спрацювало для мене, але я не знаю як.


-3

Якщо ви ретельно вивчите, ViewPager зберігає не більше 3 переглядів. Ви можете легко отримати поточний вигляд за

view     = MyActivity.mViewPager.getChildAt(1);

1
Це не працює. Що робити, якщо переглядач показує свою першу або останню сторінку? Що робити, якщо є більше 1 екранна сторінка?
foo64

1
Помилково, ви можете встановити ViewPager для кешування більше 3 переглядів за допомогоюsetOffscreenPageLimit(int)
zyamys

-3

Будь ласка, перевірте це

((ViewGroup))mViewPager.getChildAt(MyActivity.mViewPager.getCurrentItem()));

ще перевірити це посилання .


не працює, це отримує не той вигляд, який видно, на жаль, і іноді стає нульовим
lacas

3
Це не працює. Діапазон getChildAt()відрізняється від діапазону getCurrentItem(). Наприклад, якщо ваш ViewPager показує 20 елементів і 1 позаекранну сторінку, тоді getChildAt()діапазон становить 0-2, а getCurrentItem()діапазон 0-19. В основному ви отримували б нульові значення повернення.
foo64
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.