Viewpager + изменение конфигурации = не по центру текущий элемент

У меня есть приложение, основной функцией навигации которого является ViewPager с практически бесконечными страницами. Я использую что-то похожее на InfiniteViewPagerFragmentStatePagerAdapter), начиная навигацию в середине ViewPager. поэтому есть страницы слева и справа для начала. Я также использую отрицательные поля mPager.setPageMargin(-50);, чтобы страницы с обеих сторон были немного видны.

Я загружаю много данных из Интернета, поэтому я сам обрабатываю изменения конфигурации, используя android:configChanges="orientation|keyboardHidden" и переопределение onConfigurationChanged в своей деятельности. В основном я не хочу воссоздавать свою активность, потому что я думаю, что изменение ориентации займет слишком много времени.

Проблема

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

Если я коснусь страницы, ViewPager прокрутится до текущей страницы и отобразится, как и ожидалось, но если я этого не сделаю, отображение будет неправильным. У меня возникает эта проблема при переходе от пейзажа к портрету и от портрета к пейзажу. Я пытался установить OnGlobalLayoutListener и выполнить mViewPager.setCurrentItem(mViewPager.getCurrentItem()), но ViewPager игнорирует setCurrentItem, если вы попросите его установить текущий элемент на то, что на самом деле является текущим элементом.

Код

Основная деятельность

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    //whatever I do in here doesn't make a difference.
    //my viewpager still displays off center, even if I do nothing custom
}

Адаптер пейджера

private class MyAdapter extends FragmentStatePagerAdapter{

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

    @Override
    public Fragment getItem(int position) {
        PageData dataForThisPage = mModel.getDataForPage(position);
        PageContainerFragment f = PageContainerFragment.create(position, dataForThisPage);

        return f;
    }

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

Я пытался понять это в течение нескольких часов, и я ничего не могу получить. Любая помощь будет принята с благодарностью!

Изменить: стиль


person peteross    schedule 22.01.2014    source источник


Ответы (2)


Я нашел ответ на свою проблему здесь: https://code.google.com/p/android/issues/detail?id=39287. Изменения размера не очень хорошо сочетаются с ViewPager с ненулевым полем, поэтому обходным решением является расширение ViewPager и добавление следующего метода Override.

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w-this.getPageMargin(), h, oldw-this.getPageMargin(), oldh);
}
person peteross    schedule 12.02.2014
comment
Это решило проблему. Это хорошее решение. - person xrnd; 08.04.2021

onConfigurationChanged не вызывается, когда вы меняете ориентацию, потому что вы не отметили ориентацию в манифесте. Этот метод следует переопределить, ТОЛЬКО если вы планируете вручную обрабатывать изменения ориентации.

Вам следует обратить внимание на следующие методы: http://developer.android.com/reference/android/app/Activity.html#onSaveInstanceState(android.os.Bundle)

а также

http://developer.android.com/reference/android/app/Activity.html#onRestoreInstanceState(android.os.Bundle)

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

person piotrpo    schedule 22.01.2014
comment
Я отметил ориентацию в своем манифесте, android:configChanges=keyboardHidden|orientation|screenSize. Мне нужно вручную обрабатывать изменения ориентации, потому что я думаю, что уничтожение и воссоздание активности займет слишком много времени. Как я уже сказал, у меня много данных из Интернета и, следовательно, много макетов. Я обрабатываю изменения ориентации, изменяя количество столбцов в GridViews, и это работает, поэтому я знаю, что вызывается onConfigurationChanged. - person peteross; 23.01.2014