Использование ViewPager для слайдов экрана

Слайды экрана это переходы между одним экраном и другим, и являются распространенными для интерфейсов, таких как мастер настройки или слайд-шоу. Этот урок покажет вам, как делать слайды экрана с помощью ViewPager предоставляемым библиотекой поддержки. ViewPagerможет анимировать слайды экрана автоматически. Это выглядит как переходы от одного экрана с содержанием к другому:

Анимация слайдов экрана
 

Если вы хотите перейти вперед и увидеть полный рабочий пример, скачать и запустить пример приложения, выберите пример Screen Slide. Смотрите следующие файлы для реализации кода:

  • src/ScreenSlidePageFragment.java
  • src/ScreenSlideActivity.java
  • layout/activity_screen_slide.xml
  • layout/fragment_screen_slide_page.xml

Создайте представления

Создайте файл макета, который вы будете в дальнейшем использовать как содержимое фрагмента. Следующий пример содержит текстовое представление для отображения текста:

<!-- fragment_screen_slide_page.xml -->
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/content"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <TextView style="?android:textAppearanceMedium"
        android:padding="16dp"
        android:lineSpacingMultiplier="1.2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/lorem_ipsum" />
</ScrollView>

Определить также строку для содержания фрагмента.

Создание фрагмента

Создайте Fragment класс, который возвращает макет, который вы только что создали в onCreateView() методе. После этого вы можете создавать экземпляры этого фрагмента в родительской деятельности, когда вам нужно отобразить новую страницу пользователю:

import android.support.v4.app.Fragment;
...
public class ScreenSlidePageFragment extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        ViewGroup rootView = (ViewGroup) inflater.inflate(
                R.layout.fragment_screen_slide_page, container, false);

        return rootView;
    }
}

Добавить ViewPager

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

Для начала, создайте макет, который содержит ViewPager:

<!-- activity_screen_slide.xml -->
<android.support.v4.view.ViewPager
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

Создайте деятельность, которая делает следующие вещи:

  • Устанавливает представление содержимого быть макетом с ViewPager.
  • Создает класс, расширяющий FragmentStatePagerAdapter абстрактный класс и реализует getItem() метод для предоставления экземпляров ScreenSlidePageFragment как новых страниц. Адаптер страниц также требует, чтобы вы реализовали getCount() метод, который возвращает количество страниц, которые адаптер будет создать (пять в данном примере).
  • Подключает PagerAdapter к ViewPager.
  • Обрабатывает кнопку Назад устройства путем перемещения фрагментов назад в виртуальный стек. Если пользователь уже на первой странице, возвращает активность обратно стек.
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
...
public class ScreenSlidePagerActivity extends FragmentActivity {
    /**
     * The number of pages (wizard steps) to show in this demo.
     */
    private static final int NUM_PAGES = 5;

    /**
     * The pager widget, which handles animation and allows swiping horizontally to access previous
     * and next wizard steps.
     */
    private ViewPager mPager;

    /**
     * The pager adapter, which provides the pages to the view pager widget.
     */
    private PagerAdapter mPagerAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_screen_slide);

        // Instantiate a ViewPager and a PagerAdapter.
        mPager = (ViewPager) findViewById(R.id.pager);
        mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
        mPager.setAdapter(mPagerAdapter);
    }

    @Override
    public void onBackPressed() {
        if (mPager.getCurrentItem() == 0) {
            // If the user is currently looking at the first step, allow the system to handle the
            // Back button. This calls finish() on this activity and pops the back stack.
            super.onBackPressed();
        } else {
            // Otherwise, select the previous step.
            mPager.setCurrentItem(mPager.getCurrentItem() - 1);
        }
    }

    /**
     * A simple pager adapter that represents 5 ScreenSlidePageFragment objects, in
     * sequence.
     */
    private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
        public ScreenSlidePagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            return new ScreenSlidePageFragment();
        }

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

Пользовательская анимация с PageTransformer

Для отображения анимации отличной от анимации слайдов экрана по умолчанию, реализуйте ViewPager.PageTransformer интерфейс и используйте его во ViewPager. Интерфейс предоставляет единственный метод, transformPage(). В каждой точке перехода экрана, этот метод вызывается один раз для каждой видимой страницы (как правило, есть только одна видимая страница) и для соседних страниц в непосредственной близости от экрана. Например, если страница три видна и пользователь перемещается к странице четыре, transformPage() вызывается для страниц два, три, и четыре на каждом шаге этого жеста.

В вашей реализации transformPage(), вы можете создавать собственные анимация слайдов, определяя какие страницы должны быть преобразованы в зависимости от положения страницы на экране, которое можно получить из position параметра transformPage() метода.

position параметр указывает, где данная страница расположена относительно центра экрана. Это динамическое свойство, которое изменяется, когда пользователь перемещается по страницам. Когда страница заполняет экран, значение его позиции равно 0. Когда страница прорисовывается в непосредственной близости от правой стороны экрана, значение ее позиции равно 1. Если пользователь прокручивает страницы, то на полпути между первой и второй страницами, положение первой страницы будет -0.5, а положение страницы два будет 0.5. Основываясь на позиции страниц на экране, вы можете создавать собственные анимации слайдов, установив свойства страниц с помощью методов, таких как setAlpha(), setTranslationX(), или setScaleY().

Если у вас есть реализация PageTransformer, вызовите setPageTransformer() с вашей реализации для применения пользовательской анимации. Например, если у вас есть PageTransformer названный ZoomOutPageTransformer, вы можете установить пользовательскую анимацию, как здесь:

ViewPager mPager = (ViewPager) findViewById(R.id.pager);
...
mPager.setPageTransformer(true, new ZoomOutPageTransformer());

Смотрите Преобразователь уменьшения страницы и Преобразователь глубины страницы разделы для примеров и видео PageTransformer.

Преобразователь уменьшения страницы

Этот преобразователь страниц сжимает и заставляет страницы исчезать при прокрутке между соседними страницами. Как только страница приближается к центру, она растет обратно к своему нормальному размеру и появляется.

ZoomOutPageTransformer пример
 
public class ZoomOutPageTransformer implements ViewPager.PageTransformer {
    private static final float MIN_SCALE = 0.85f;
    private static final float MIN_ALPHA = 0.5f;

    public void transformPage(View view, float position) {
        int pageWidth = view.getWidth();
        int pageHeight = view.getHeight();

        if (position < -1) { // [-Infinity,-1)
            // This page is way off-screen to the left.
            view.setAlpha(0);

        } else if (position <= 1) { // [-1,1]
            // Modify the default slide transition to shrink the page as well
            float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
            float vertMargin = pageHeight * (1 - scaleFactor) / 2;
            float horzMargin = pageWidth * (1 - scaleFactor) / 2;
            if (position < 0) {
                view.setTranslationX(horzMargin - vertMargin / 2);
            } else {
                view.setTranslationX(-horzMargin + vertMargin / 2);
            }

            // Scale the page down (between MIN_SCALE and 1)
            view.setScaleX(scaleFactor);
            view.setScaleY(scaleFactor);

            // Fade the page relative to its size.
            view.setAlpha(MIN_ALPHA +
                    (scaleFactor - MIN_SCALE) /
                    (1 - MIN_SCALE) * (1 - MIN_ALPHA));

        } else { // (1,+Infinity]
            // This page is way off-screen to the right.
            view.setAlpha(0);
        }
    }
}

Преобразователь глубины страницы

Этот преобразователь страниц использует анимацию слайдов по умолчанию для перемещения страниц влево, при этом он использует анимацию «глубины» для перемещения страниц вправо. Эта анимация глубины заставляет исчезать страницу, уменьшая её линейно.

DepthPageTransformer пример
 

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

view.setTranslationX(-1 * view.getWidth() * position);
В следующем примере показано, как противодействовать слайдам экрана анимации по умолчанию в рабочем преобразователе страниц:


public class DepthPageTransformer implements ViewPager.PageTransformer {
    private static final float MIN_SCALE = 0.75f;

    public void transformPage(View view, float position) {
        int pageWidth = view.getWidth();

        if (position < -1) { // [-Infinity,-1)
            // This page is way off-screen to the left.
            view.setAlpha(0);

        } else if (position <= 0) { // [-1,0]
            // Use the default slide transition when moving to the left page
            view.setAlpha(1);
            view.setTranslationX(0);
            view.setScaleX(1);
            view.setScaleY(1);

        } else if (position <= 1) { // (0,1]
            // Fade the page out.
            view.setAlpha(1 - position);

            // Counteract the default slide transition
            view.setTranslationX(pageWidth * -position);

            // Scale the page down (between MIN_SCALE and 1)
            float scaleFactor = MIN_SCALE
                    + (1 - MIN_SCALE) * (1 - Math.abs(position));
            view.setScaleX(scaleFactor);
            view.setScaleY(scaleFactor);

        } else { // (1,+Infinity]
            // This page is way off-screen to the right.
            view.setAlpha(0);
        }
    }
}