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

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

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 является нулевым. Любые идеи, если я делаю что-то не так здесь. Есть ли другой способ записать текущее представление (страницу) в viewpager, чтобы я мог вносить изменения в представление в зависимости от того, на каком номере страницы я нахожусь?

4 ответа

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

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

Как это:

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

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

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

Вы используете этот подход:

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

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

adapter.fragmentManager.fragments[position1].view

Я добавил 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) {}

})

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

Другие вопросы по тегам