ViewPager с представлениями

ViewPager — это диспетчер макетов, который позволяет реализовать навигацию gestural. Навигация gestural позволяет пользователю проводите пальцем влево и вправо на страницы данных. В этом руководстве объясняется, как реализовать экранируемый пользовательский интерфейс с viewPager и PagerTabStrip, используя представления в качестве страниц данных (последующее руководство описывает использование фрагментов для страниц).

Обзор

Это пошаговое руководство, которое предоставляет пошаговую демонстрацию использования ViewPager для реализации коллекции образов лиственных и вечнозеленых деревьев. В этом приложении пользователь проводит пальцем влево и вправо через "каталог деревьев" для просмотра изображений дерева. В верхней части каждой страницы каталога имя дерева отображается в спискеPagerTabStrip, а изображение дерева отображается в виде ImageView. Адаптер используется для интерфейса ViewPager базовой модели данных. Это приложение реализует адаптер, производный от PagerAdapter.

Хотя ViewPagerприложения на основе часто реализуются с помощью FragmentS, существуют некоторые относительно простые варианты использования, где дополнительная сложность Fragments не требуется. Например, базовое приложение коллекции образов Fragment, иллюстрированное в этом пошаговом руководстве, не требует использования s. Так как содержимое является статическим, и пользователь проводит пальцем вправо и вперед между различными изображениями, реализация может быть проще с помощью стандартных представлений и макетов Android.

Запуск проекта приложения

Создайте новый проект Android с именем TreePager (дополнительные сведения о создании проектов Android см. в разделе Hello, Android ). Затем запустите диспетчер пакетов NuGet. (Дополнительные сведения об установке пакетов NuGet см. в разделе .Пошаговое руководство. Включение NuGet в проект). Найдите и установите библиотеку поддержки Android версии 4:

Screenshot of Support v4 NuGet selected in the NuGet Package Manager

Это также установит все дополнительные пакеты, повторно запрашиваемые библиотекой поддержки Android версии 4.

Добавление примера источника данных

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

TreeCatalog treeCatalog = new TreeCatalog();

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

int imageId = treeCatalog[2].imageId;

Поскольку сведения о TreeCatalog реализации не относятся к пониманию ViewPager, TreeCatalog код не указан здесь. Исходный код TreeCatalog доступен по адресу TreeCatalog.cs. Скачайте этот исходный файл (или скопируйте и вставьте код в новый файл TreeCatalog.cs ) и добавьте его в проект. Кроме того, скачайте и распакуйте файлы изображений в папку Resources/drawable и включите их в проект.

Создание макета ViewPager

Откройте файл Resources/layout/Main.axml и замените его содержимое следующим XML-кодом:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.view.ViewPager
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/viewpager"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

</android.support.v4.view.ViewPager>

Этот XML-код определяет ViewPager , который занимает весь экран. Обратите внимание, что необходимо использовать полное имя android.support.v4.view.ViewPager , так как ViewPager упаковано в библиотеку поддержки. ViewPager доступна только из библиотеки поддержки Android версии 4. Она недоступна в пакете SDK для Android.

Настройка ViewPager

Измените MainActivity.cs и добавьте следующую using инструкцию:

using Android.Support.V4.View;

Замените метод OnCreate следующим кодом:

protected override void OnCreate(Bundle bundle)
{
    base.OnCreate(bundle);
    SetContentView(Resource.Layout.Main);
    ViewPager viewPager = FindViewById<ViewPager>(Resource.Id.viewpager);
    TreeCatalog treeCatalog = new TreeCatalog();
}

Этот код выполняет следующие действия:

  1. Задает представление из ресурса макета Main.axml .

  2. Извлекает ссылку на ViewPager макет.

  3. Создает экземпляр нового TreeCatalog источника данных.

При сборке и запуске этого кода вы увидите дисплей, похожий на следующий снимок экрана:

Screenshot of app displaying an empty ViewPager

На этом этапе он пуст, ViewPager так как он не имеет адаптера для доступа к содержимому в TreeCatalog. В следующем разделе создается PagerAdapter для подключения ViewPager к TreeCatalog.

Создание адаптера

ViewPager использует объект контроллера адаптера, который находится между ViewPager источником данных и источником данных (см. иллюстрацию в адаптере). Для доступа к этим данным требуется предоставить пользовательский адаптер, ViewPager производный от PagerAdapter. Этот адаптер заполняет каждую ViewPager страницу содержимым из источника данных. Так как этот источник данных зависит от приложения, настраиваемый адаптер — это код, который понимает, как получить доступ к данным. По мере того как пользователь проводит пальцем по страницам ViewPager, адаптер извлекает сведения из источника данных и загружает его на страницы для ViewPager отображения.

При реализации PagerAdapterнеобходимо переопределить следующее:

  • InstantiateItem — создает страницу (View) для заданной позиции и добавляет ее в ViewPagerколлекцию представлений.

  • DestroyItem — удаляет страницу из заданной позиции.

  • Count — свойство только для чтения, которое возвращает количество доступных представлений (страниц).

  • IsViewFromObject — определяет, связана ли страница с определенным ключевым объектом. (Этот объект создается методом InstantiateItem .) В этом примере ключевой TreeCatalog объект является объектом данных.

Добавьте новый файл с именем TreePagerAdapter.cs и замените его содержимое следующим кодом:

using System;
using Android.App;
using Android.Runtime;
using Android.Content;
using Android.Views;
using Android.Widget;
using Android.Support.V4.View;
using Java.Lang;

namespace TreePager
{
    class TreePagerAdapter : PagerAdapter
    {
        public override int Count
        {
            get { throw new NotImplementedException(); }
        }

        public override bool IsViewFromObject(View view, Java.Lang.Object obj)
        {
            throw new NotImplementedException();
        }

        public override Java.Lang.Object InstantiateItem (View container, int position)
        {
            throw new NotImplementedException();
        }

        public override void DestroyItem(View container, int position, Java.Lang.Object view)
        {
            throw new NotImplementedException();
        }
    }
}

Этот код заглушает основную PagerAdapter реализацию. В следующих разделах каждый из этих методов заменяется рабочим кодом.

Реализация конструктора

Когда приложение создает экземпляр TreePagerAdapter, оно предоставляет контекст (the MainActivity) и создает экземпляр TreeCatalog. Добавьте следующие переменные-члены и конструктор в начало TreePagerAdapter класса в TreePagerAdapter.cs:

Context context;
TreeCatalog treeCatalog;

public TreePagerAdapter (Context context, TreeCatalog treeCatalog)
{
    this.context = context;
    this.treeCatalog = treeCatalog;
}

Цель этого конструктора заключается в хранении контекста и TreeCatalog экземпляра TreePagerAdapter , который будет использоваться.

Реализация счетчика

Реализация Count относительно проста: она возвращает количество деревьев в каталоге деревьев. Замените Count следующим кодом:

public override int Count
{
    get { return treeCatalog.NumTrees; }
}

Свойство NumTreesTreeCatalog возвращает количество деревьев (количество страниц) в наборе данных.

Реализация InstantiateItem

Метод InstantiateItem создает страницу для заданной позиции. Он также должен добавить только что созданное представление в коллекцию представлений ViewPager. Чтобы сделать это возможным, он ViewPager передает себя в качестве параметра контейнера.

Замените метод InstantiateItem следующим кодом:

public override Java.Lang.Object InstantiateItem (View container, int position)
{
    var imageView = new ImageView (context);
    imageView.SetImageResource (treeCatalog[position].imageId);
    var viewPager = container.JavaCast<ViewPager>();
    viewPager.AddView (imageView);
    return imageView;
}

Этот код выполняет следующие действия:

  1. Создает экземпляр нового ImageView для отображения изображения дерева в указанной позиции. Приложение MainActivity — это контекст, который будет передан конструктору ImageView .

  2. ImageView Задает ресурс идентификатору TreeCatalog ресурса изображения в указанной позиции.

  3. Приведение переданного контейнера View к ссылке ViewPager . Обратите внимание, что для правильного выполнения этого приведения необходимо использовать JavaCast<ViewPager>() (это необходимо, чтобы Android выполнял преобразование типа, проверка среды выполнения).

  4. Добавляет экземпляр ImageViewViewPager в вызывающий объект и возвращает вызывающий ImageView объект.

При отображении ViewPager изображения positionотображается это ImageView. Изначально вызывается дважды, InstantiateItem чтобы заполнить первые две страницы представлениями. По мере прокрутки пользователя он снова вызывается для поддержания представлений непосредственно за пределами и впереди отображаемого в данный момент элемента.

Реализация DestroyItem

Метод DestroyItem удаляет страницу из заданной позиции. В приложениях, где представление с любой заданной позицией может измениться, ViewPager должен иметь некоторый способ удаления устаревшего представления на этой позиции, прежде чем заменить его новым представлением. TreeCatalog В примере представление на каждой позиции не изменяется, поэтому представление, удаленное DestroyItem путем, просто будет повторно добавлено при InstantiateItem вызове этой позиции. (Для повышения эффективности можно реализовать пул для перезапуска View, который будет повторно отображаться в той же позиции.)

Замените метод DestroyItem следующим кодом:

public override void DestroyItem(View container, int position, Java.Lang.Object view)
{
    var viewPager = container.JavaCast<ViewPager>();
    viewPager.RemoveView(view as View);
}

Этот код выполняет следующие действия:

  1. Приведение переданного контейнера View в ссылку ViewPager .

  2. Приведение переданного объекта Java (view) в C# View (view as View);

  3. Удаляет представление из ViewPager.

Реализация IsViewFromObject

По мере того как пользователь перемещается влево и вправо через страницы содержимого, ViewPager вызывается IsViewFromObject проверка того, что дочерний элемент View в заданной позиции связан с объектом адаптера для той же позиции (следовательно, объект адаптера называется ключом объекта). Для относительно простых приложений связь является одной из удостоверений — ключ объекта адаптера в этом экземпляре — это представление, которое ранее было возвращено через ViewPagerInstantiateItem. Однако для других приложений ключ объекта может быть другим экземпляром класса, связанным с (но не таким же, как) дочерним представлением, ViewPager отображающимся в этой позиции. Только адаптер знает, связаны ли переданные представления и ключ объекта.

IsViewFromObject необходимо реализовать PagerAdapter для правильной работы. Если IsViewFromObject возвращается false для заданной позиции, ViewPager представление не будет отображаться в этой позиции. TreePager В приложении ключ объекта, возвращаемыйInstantiateItemстраницей View дерева, поэтому код должен проверка для удостоверения (т. е. ключ объекта и представление одинаковые). Замените IsViewFromObject следующим кодом:

public override bool IsViewFromObject(View view, Java.Lang.Object obj)
{
    return view == obj;
}

Добавление адаптера в ViewPager

Теперь, когда TreePagerAdapter реализация реализована, пришло время добавить его в ViewPager. В MainActivity.cs добавьте следующую строку кода в конец OnCreate метода:

viewPager.Adapter = new TreePagerAdapter(this, treeCatalog);

Этот код создает TreePagerAdapterэкземпляр , передаваемый в MainActivity качестве контекста (this). Экземпляр TreeCatalog передается во второй аргумент конструктора. Свойство ViewPager's Adapter задано для экземпляра TreePagerAdapter объекта; он подключается к объекту TreePagerAdapterViewPager.

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

Screenshots of TreePager app swiping through tree images

Добавление индикатора pager

Эта минимальная ViewPager реализация отображает изображения каталога деревьев, но не указывает, где пользователь находится в каталоге. Следующий шаг — добавить PagerTabStrip. Пользователь PagerTabStrip сообщает пользователю о том, какая страница отображается и предоставляет контекст навигации, отображая намек на предыдущие и следующие страницы. PagerTabStrip Предназначено для использования в качестве индикатора текущей страницы объекта ViewPager; она прокручивает и обновляется, когда пользователь проводит пальцем по каждой странице.

Откройте resources/layout/Main.axml и добавьте в PagerTabStrip макет:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.view.ViewPager
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/viewpager"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <android.support.v4.view.PagerTabStrip
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:layout_gravity="top"
          android:paddingBottom="10dp"
          android:paddingTop="10dp"
          android:textColor="#fff" />

</android.support.v4.view.ViewPager>

ViewPager и PagerTabStrip предназначены для совместной работы. При объявлении PagerTabStrip внутри макета ViewPagerViewPager он будет автоматически находить PagerTabStrip и подключать его к адаптеру. При сборке и запуске приложения должно отображаться пустое PagerTabStrip в верхней части каждого экрана:

Closeup screenshot of an empty PagerTabStrip

Отображение заголовка

Чтобы добавить заголовок на каждую вкладку страницы, реализуйте GetPageTitleFormatted метод в производном PagerAdapterклассе. ViewPager вызовы GetPageTitleFormatted (если реализованы), чтобы получить строку заголовка, описывающую страницу в указанной позиции. Добавьте следующий метод в TreePagerAdapter класс в TreePagerAdapter.cs:

public override Java.Lang.ICharSequence GetPageTitleFormatted(int position)
{
    return new Java.Lang.String(treeCatalog[position].caption);
}

Этот код извлекает дерево подпись строку из указанной страницы (позиции) в каталоге деревьев, преобразует его в Java Stringи возвращает его в ViewPager. При запуске приложения с этим новым методом на каждой странице отображается дерево подпись в PagerTabStrip. Имя дерева должно отображаться в верхней части экрана без подчеркивания:

Screenshots of pages with text-filled PagerTabStrip tabs

Вы можете проводите пальцем вправо и вперед, чтобы просмотреть каждый подпись изображении дерева в каталоге.

Вариант PagerTitleStrip

PagerTitleStrip очень похоже на то, что PagerTabStripPagerTabStrip добавляет подчеркивание для выбранной в данный момент вкладки. Вы можете заменить PagerTabStrip его PagerTitleStrip в приведенном выше макете и снова запустить приложение, чтобы увидеть, как он выглядит следующим PagerTitleStripобразом:

PagerTitleStrip with underlines removed from text

Обратите внимание, что подчеркивание удаляется при преобразовании PagerTitleStripв .

Итоги

В этом пошаговом руководстве представлен пошаговый пример создания базового ViewPagerприложения без использования FragmentS. В нем представлен пример источника данных, содержащего изображения и строки подпись, ViewPager макет для отображения изображений и PagerAdapter подкласс, который подключается ViewPager к источнику данных. Чтобы помочь пользователю перемещаться по набору данных, были включены инструкции, которые объясняют, как добавить PagerTabStrip или PagerTitleStrip отобразить изображение подпись в верхней части каждой страницы.