Не удалось получить текущий просмотр в Viewpager

Я использую viewpager для отображения текста на нескольких страницах. Я пытаюсь получить текущее представление, я выбираю новую страницу. Причина, по которой я хочу получить текущее представление, состоит в том, что, основываясь на номере страницы, я меняю некоторые свойства некоторых компонентов вида, таких как textview, изображение и т.д.  Я использую приведенный ниже код для того же

ViewPager mPager = (ViewPager) findViewById(R.id.pager);
mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
View CurrView;
OnPageChangeListener pageChangelistener = new OnPageChangeListener() {
  @Override
       public void onPageSelected(int pageSelected) {
          currView = mPager.getChildAt(mPager.getCurrentItem());
      myTextView = (TextView)currView.findViewById(R.id.myTextView);
              loadBookmarkSetting(pageSelected);//do some changes in myTextView    properties based on the page number  }
 mPager.setOnPageChangeListener(pageChangelistener);

Теперь проблема, с которой я сталкиваюсь, после того, как я прокручиваю 3 страницы, и когда я прихожу на 4-ю страницу, я получаю исключение nullpointer в строке "myTextView = (TextView) currView.findViewById(R.id.myTextView);". Это так, потому что currView имеет значение null. Любые идеи, если я делаю что-то неправильно здесь. Есть ли другой способ захвата текущего представления (страницы) в viewpager, так как я могу делать изменения в представлении, основываясь на том, на каком номере страницы я нахожусь?

Ответ 1

Вы можете использовать setTag с представлением, которое вы возвращаете в методе instantiateItem (PagerAdapter).

Итак, когда вы создаете свои представления в PagerAdapter, метод также instantiateItem(ViewGroup container, int position)), вы должны использовать setTag для вашего представления.

Вот так:

view.setTag("myview" + position);
return view;

когда вам нужен текущий вид:

View view = (View) pager.findViewWithTag("myview" + pager.getCurrentItem());

Ответ 2

Вы используете такой подход:

@Nullable
    public static View getActiveView(@Nonnull final ViewPager viewPager) {
        final PagerAdapter adapter = viewPager.getAdapter();
        if (null == adapter || adapter.getCount() == 0 || viewPager.getChildCount() == 0) {
            return null;
        }

        int position;
        final int currentPosition = viewPager.getCurrentItem();

        for (int i = 0; i < viewPager.getChildCount(); i++) {
            final View child = viewPager.getChildAt(i);
            final LayoutParams layoutParams = (LayoutParams) child.getLayoutParams();
            if (layoutParams.isDecor) {
                continue;
            }
            final Field positionField;
            try {
                positionField = LayoutParams.class.getDeclaredField("position");
                positionField.setAccessible(true);
                position = positionField.getInt(layoutParams);
            } catch (NoSuchFieldException e) {
                break;
            } catch (IllegalAccessException e) {
                break;
            }
            if (position == currentPosition) {
                return child;
            }
        }
        return null;
    }

Ответ 3

Я добавил SparseArray в свой адаптер и добавил представление в instantiateItem() и удалил его в destroyItem()

val views = SparseArray<View>()

...

override fun instantiateItem(container: ViewGroup, position: Int): Any 
{
    //...

    container.addView(view)
    views.put(position, view)
    return view
}

override fun destroyItem(container: ViewGroup, position: Int, obj: Any) 
{
    views.remove(position)
    container.removeView(obj as View)
}

fun showFooter(currentItem: Int) {
    views[currentItem].footer_layout.animate().alpha(1f)
}

fun hideFooter(currentItem: Int) {
    views[currentItem].footer_layout.animate().alpha(0f)
}

И тогда я могу вызвать методы на адаптере:

viewPager.addOnPageChangeListener(object: ViewPager.OnPageChangeListener {
    override fun onPageScrollStateChanged(state: Int) {
        when (state) {
            SCROLL_STATE_IDLE -> adapter.showFooter(viewPager.currentItem)
            SCROLL_STATE_DRAGGING -> adapter.hideFooter(viewPager.currentItem)
        }
    }

    override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}

    override fun onPageSelected(position: Int) {}

})

Ответ 4

Я использую этот метод с 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;
    }

Ответ 5

Вы получаете исключение нулевого указателя, потому что вы установили offscreenPageLimit равным 3. ViewPager будет хранить только 3 pages.mPager.getChildAt(4) получит нулевое значение. Чтобы установить просмотр текста, вы можете использовать менеджер фрагментов адаптера, чтобы получить все фрагменты и получить вид фрагмента в позиции.

adapter.fragmentManager.fragments[position1].view

Ответ 6

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