Статьи

Создание интерфейса с вкладками «Дизайн материала» в приложении для Android

Конечный продукт
Что вы будете создавать

Команда разработчиков материалов в Google просто определяет функциональность вкладок в Android следующим образом:

Вкладки позволяют легко исследовать и переключаться между различными представлениями.

В этом посте вы узнаете, как отображать вкладки с помощью API TabLayout и ViewPager . В этом практическом уроке мы рассмотрим следующее:

  • Компоненты TabLayout и ViewPager .
  • Различные режимы вкладок: прокручиваемый и фиксированный.
  • Как отображать иконки вместо текста для заголовков вкладок.
  • В качестве бонуса вы также узнаете, как использовать функцию шаблонов Android Studio для быстрой загрузки проекта с помощью интерфейса с вкладками.

Пример проекта для этого урока можно найти в нашем репозитории GitHub, чтобы вы могли легко следить за ним.

Чтобы следовать этому руководству, вам понадобится:

Вы также можете изучить все тонкости языка Kotlin в моей серии Kotlin From Scratch .

  • Котлин
    Kotlin From Scratch: обнуляемость, циклы и условия
  • Котлин
    Котлин с нуля: классы и объекты

Согласно официальной документации Android на TabLayout , он гласит:

TabLayout предоставляет горизонтальный макет для отображения вкладок.

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

Компонент TabLayout может иметь функции отображаемых вкладок одним из двух способов: фиксированным и прокручиваемым. Если вкладки зафиксированы, все вкладки будут отображаться на экране одновременно.

На приведенном ниже TabLayout последнее официальное Android-приложение WhatsApp (на момент написания статьи), в котором используется TabLayout с фиксированной конфигурацией режима.

WhatsApp исправил пример TabLayout

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

Вот пример TabLayout с прокручиваемым режимом вкладок, представленный в последней версии Android-приложения News & Weather от Google.

Режим прокручиваемой вкладки в приложении Google News Weather

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

Иконки на вкладках в приложении Twitter для Android

В следующих разделах мы TabLayout в кодирование простого приложения, которое использует TabLayout с ViewPager . Давай прокатимся!

Дизайн — это не только то, на что он похож и что чувствует. Дизайн — это то, как он работает. — Стив Джобс

TabLayoutDemo Android Studio 3 и создайте новый проект (вы можете назвать его TabLayoutDemo ) с пустым действием MainActivity .

Создать страницу проекта Android

Мы собираемся создать TabLayout только с тремя вкладками. Когда выбрана каждая вкладка, она отображает отдельный фрагмент или страницу Android. Итак, давайте теперь создадим три фрагмента Android для каждой из вкладок. Мы начнем с первого класса фрагментов, и вы должны следовать аналогичному процессу для остальных двух классов фрагментов — FragmentTwo.kt и FragmentThree.kt .

Вот мой FragmentOne.kt :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
import android.os.Bundle
import android.support.v4.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
 
class FragmentOne : Fragment() {
 
    override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?,
                              savedInstanceState: Bundle?): View?
            inflater!!.inflate(R.layout.fragment_one, container, false)
 
    companion object {
        fun newInstance(): FragmentOne = FragmentOne()
    }
}

Вот также мой R.layout.fragment_one :

01
02
03
04
05
06
07
08
09
10
11
12
13
<LinearLayout xmlns:android=»https://schemas.android.com/apk/res/android»
             xmlns:tools=»http://schemas.android.com/tools»
             android:layout_width=»match_parent»
             android:layout_height=»match_parent»
             android:orientation=»vertical»>
 
    <TextView
            android:layout_width=»match_parent»
            android:layout_height=»match_parent»
            android:text=»FragmentOne»
            android:gravity=»center_vertical|center_horizontal»/>
 
</LinearLayout>

Чтобы начать использовать TabLayout и ViewPager в своем проекте, убедитесь, что вы импортируете поддержку проектирования, а также артефакт поддержки Android — поэтому добавьте их в файл build.gradle вашего модуля, чтобы импортировать их.

1
2
3
4
dependencies {
    implementation ‘com.android.support:design:26.1.0’
    implementation ‘com.android.support:support-v4:26.1.0’
}

Кроме того, перейдите в файл res / layout / activlty_main.xml, чтобы включить виджет TabLayout и представление ViewPager .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<?xml version=»1.0″ encoding=»utf-8″?>
<android.support.design.widget.CoordinatorLayout
        xmlns:android=»http://schemas.android.com/apk/res/android»
        xmlns:app=»http://schemas.android.com/apk/res-auto»
        android:id=»@+id/main_content»
        android:layout_width=»match_parent»
        android:layout_height=»match_parent»
        android:fitsSystemWindows=»true»>
 
    <android.support.design.widget.AppBarLayout
            android:id=»@+id/appbar»
            android:layout_width=»match_parent»
            android:layout_height=»wrap_content»
            android:theme=»@style/AppTheme.AppBarOverlay»>
 
        <android.support.v7.widget.Toolbar
                android:id=»@+id/toolbar»
                android:layout_width=»match_parent»
                android:layout_height=»?attr/actionBarSize»
                android:background=»?attr/colorPrimary»
                app:contentInsetStartWithNavigation=»0dp»
                app:layout_scrollFlags=»scroll|enterAlways»
                app:popupTheme=»@style/AppTheme.PopupOverlay»/>
 
        <android.support.design.widget.TabLayout
                android:id=»@+id/tab_layout»
                style=»@style/CustomTabLayout»
                android:layout_width=»match_parent»
                android:layout_height=»?attr/actionBarSize»
                android:layout_gravity=»left»
                android:background=»@color/colorPrimary»
                app:tabGravity=»fill»
                app:tabMode=»fixed»/>
 
    </android.support.design.widget.AppBarLayout>
 
    <android.support.v4.view.ViewPager
            android:id=»@+id/view_pager»
            android:layout_width=»match_parent»
            android:layout_height=»match_parent»
            app:layout_behavior=»@string/appbar_scrolling_view_behavior»/>
 
</android.support.design.widget.CoordinatorLayout>

Здесь мы создали простой TabLayout с идентификатором tab_layout . В нашем TabLayout XML вы можете видеть, что мы включили некоторые атрибуты — например, app:tabMode который нужно fixed и app:tabGravity который нужно fill . Свойство app:tabGravity используется для настройки способа отображения элементов вкладки, чтобы они app:tabGravity доступное пространство. Мы устанавливаем это для fill , что будет равномерно распределять элементы по ширине TabLayout . Обратите внимание, что это будет более заметно на более широких дисплеях, таких как планшеты.

Я также включил атрибут нашего стиля ( @style/CustomTabLayout ) в наш виджет TabLayout .

1
2
3
4
5
6
7
<style name=»CustomTabLayout» parent=»Widget.Design.TabLayout»>
    <item name=»tabIndicatorColor»>@android:color/white</item>
    <item name=»tabIndicatorHeight»>3dp</item>
    <item name=»tabBackground»>?attr/selectableItemBackground</item>
    <item name=»tabTextAppearance»>@style/CustomTabTextAppearance</item>
    <item name=»tabSelectedTextColor»>@android:color/white</item>
</style>

Мы начинаем настраивать наш TabLayout , устанавливая значения атрибутов, которые будут применяться к TabLayout . Вот подробности для некоторых из примененных атрибутов:

  • tabIndicatorColor : устанавливает цвет индикатора вкладки для текущей выбранной вкладки. Это также может быть установлено программно путем вызова setSelectedTabIndicatorColor() для экземпляра TabLayout .
  • tabIndicatorHeight : устанавливает высоту индикатора вкладки для текущей выбранной вкладки. Это также может быть установлено программно путем вызова setSelectedTabIndicatorHeight() для экземпляра TabLayout .
  • tabSelectedTextColor : устанавливает цвета текста для различных состояний (нормальное, выбранное), используемых для вкладок. Эквивалентом этого атрибута в Java является setTabTextColors() .

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

Менеджер по расположению, который позволяет пользователю пролистывать страницы данных влево и вправо …

Нам нужно создать подкласс в SampleAdapter.kt, который расширяет FragmentPagerAdapter . Этот класс отвечает за управление различными фрагментами, которые будут отображаться на вкладках.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentManager
import android.support.v4.app.FragmentPagerAdapter
 
class SampleAdapter(fm: FragmentManager) : FragmentPagerAdapter(fm) {
 
    override fun getItem(position: Int): Fragment?
        0 -> FragmentOne.newInstance()
        1 -> FragmentTwo.newInstance()
        2 -> FragmentThree.newInstance()
        else -> null
    }
 
    override fun getPageTitle(position: Int): CharSequence = when (position) {
        0 -> «Tab 1 Item»
        1 -> «Tab 2 Item»
        2 -> «Tab 3 Item»
        else -> «»
    }
 
    override fun getCount(): Int = 3
}

Здесь мы переопределяем три метода из родительского класса: getItem() , getCount() и getPageTitle() . Вот объяснения для методов:

  • getItem() : возвращает Fragment для определенной позиции в ViewPager .
  • getCount() : указывает, сколько страниц будет в ViewPager .
  • getPageTitle() : этот метод вызывается ViewPager для получения строки заголовка для описания указанной вкладки.

Например, если выбранная вкладка является первой вкладкой с заголовком "Tab 1 Item" вкладки "Tab 1 Item" , страница FragmentOne будет немедленно показана пользователю.

Далее мы собираемся инициализировать экземпляры нашего TabLayout , ViewPager и SampleAdapter . Инициализация будет происходить внутри onCreate() в MainActivity.kt .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import android.os.Bundle
import android.support.design.widget.TabLayout
import android.support.v4.view.ViewPager
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.Toolbar
 
class MainActivity : AppCompatActivity() {
 
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
 
        initToolbar()
 
        val tabLayout: TabLayout = findViewById(R.id.tab_layout)
 
        val viewPager: ViewPager = findViewById(R.id.view_pager)
 
        val adapter = SampleAdapter(supportFragmentManager)
 
        viewPager.adapter = adapter
        tabLayout.setupWithViewPager(viewPager)
         
        tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
            override fun onTabSelected(tab: TabLayout.Tab) {
 
            }
 
            override fun onTabUnselected(tab: TabLayout.Tab) {
 
            }
 
            override fun onTabReselected(tab: TabLayout.Tab) {
 
            }
        })
    }
 
    private fun initToolbar() {
        val toolbar: Toolbar = findViewById(R.id.toolbar)
        setSupportActionBar(toolbar)
        supportActionBar!!.title = «TabLayout Demo»
    }
}

Мы получили ссылки на наш TabLayout и ViewPager из R.layout.activity_main и инициализировали их. Мы также создали экземпляр нашего SampleAdapter передав в качестве аргумента экземпляр FragmentManager . Нам нужно предоставить представления для нашего ViewPager , поэтому мы вызвали setAdapter() и передали в него созданный нами адаптер. Наконец, мы вызвали setupWithViewPager() для экземпляра TabLayout чтобы выполнить некоторую работу:

  • создание необходимой вкладки для каждой страницы
  • настройка необходимых слушателей

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

onTabSelectedListener() используется для включения прослушивателя, который будет вызываться при изменении выбора вкладки. Мы переопределили следующие обратные вызовы:

  • onTabSelected() : срабатывает, когда вкладка входит в выбранное состояние.
  • onTabUnselected() : вызывается, когда вкладка выходит из выбранного состояния.
  • onTabReselected() : вызывается, когда пользователь снова выбирает уже выбранную вкладку.

Обратите внимание, что мы также можем установить режим вкладки программно — вместо XML-макета — используя setTabMode() в экземпляре TabLayout . Мы передаем режим (фиксированный или прокручиваемый) этому методу в качестве аргументов. Например, мы можем передать TabLayout.MODE_FIXED для фиксированного режима или TabLayout.MODE_SCROLLABLE для режима TabLayout.MODE_SCROLLABLE .

1
2
tabLayout.tabMode = TabLayout.MODE_FIXED
tabLayout.tabMode = TabLayout.MODE_SCROLLABLE

Обратите внимание, что если вы хотите явно создавать вкладки вместо использования вспомогательного метода setUpWithViewPager() , вы можете вместо этого использовать newTab() в экземпляре TabLayout .

1
2
3
4
5
val tabLayout: TabLayout = findViewById(R.id.tab_layout)
 
tabLayout.addTab(tabLayout.newTab().setText(«Songs»))
tabLayout.addTab(tabLayout.newTab().setText(«Albums»))
tabLayout.addTab(tabLayout.newTab().setText(«Artists»))

Также обратите внимание, что мы можем явно создавать вкладки с помощью XML, а не программно.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<android.support.design.widget.TabLayout
        android:id=»@+id/tabs»
        android:layout_width=»match_parent»
        android:layout_height=»wrap_content»>
 
    <android.support.design.widget.TabItem
            android:id=»@+id/tabItem»
            android:layout_width=»wrap_content»
            android:layout_height=»wrap_content»
            android:text=»Songs»/>
 
    <android.support.design.widget.TabItem
            android:id=»@+id/tabItem2″
            android:layout_width=»wrap_content»
            android:layout_height=»wrap_content»
            android:text=»Albums»/>
 
    <android.support.design.widget.TabItem
            android:id=»@+id/tabItem3″
            android:layout_width=»wrap_content»
            android:layout_height=»wrap_content»
            android:text=»Artists»/>
 
</android.support.design.widget.TabLayout>

Наконец, вы можете запустить приложение!

Финальное демо-приложение

Попробуйте взаимодействовать с приложением, проведя пальцем влево или вправо и нажав вкладки.

Официальные рекомендации по дизайну материалов на вкладках говорят о прокручиваемых вкладках:

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

Давайте посмотрим, как создавать вкладки в режиме прокрутки. Я сделал заголовок для каждой вкладки длиннее, чем раньше. Вот результат в фиксированном режиме:

Более длинный заголовок вкладки в TabLayout

Вы можете видеть, что TabLayout использовал несколько строк для отображения каждого из заголовков вкладки. В некоторых ситуациях это будет даже урезать названия! Это создает плохой пользовательский опыт, поэтому, если заголовки ваших вкладок должны быть очень длинными, вам следует рассмотреть возможность использования режима прокрутки. Также обратите внимание, что если у вас будет более четырех вкладок, рекомендуется сделать режим вкладок прокручиваемым.

Давайте app:tabMode свойство app:tabMode с fixed на scrollable .

1
2
3
<android.support.design.widget.TabLayout
       <!— … —>
       app:tabMode=»scrollable»/>

Помните, что вы также можете установить режим вкладки программно, как обсуждалось ранее.

Режим прокрутки для вкладок

Давайте теперь рассмотрим, как заменить текст элемента вкладки значками.

01
02
03
04
05
06
07
08
09
10
11
12
13
class MainActivity : AppCompatActivity() {
 
    override fun onCreate(savedInstanceState: Bundle?) {
        // …
        tabLayout.setupWithViewPager(viewPager)
        tabLayout.getTabAt(0)!!.setIcon(android.R.drawable.ic_dialog_email)
        tabLayout.getTabAt(1)!!.setIcon(android.R.drawable.ic_dialog_info)
        tabLayout.getTabAt(2)!!.setIcon(android.R.drawable.ic_dialog_alert)
        // …
    }
     
    // …
}

Здесь мы вызвали getTabAt() для экземпляра TabLayout . Вызов этого метода вернет вкладку с указанным индексом. Далее мы вызываем setIcon() . Вызов этого метода установит значок, отображаемый на этой вкладке.

Я также установил режим вкладки, чтобы быть исправленным.

1
2
<android.support.design.widget.TabLayout
       app:tabMode=»fixed»/>

Я все еще переопределяю getPageTitle() внутри SampleAdapter .

01
02
03
04
05
06
07
08
09
10
11
12
13
class SampleAdapter(fm: FragmentManager) : FragmentPagerAdapter(fm) {
     
    // …
     
    override fun getPageTitle(position: Int): CharSequence = when (position) {
        0 -> «TAB 1»
        1 -> «TAB 2»
        2 -> «TAB 3»
        else -> «»
    }
     
    // …
}

Вот результат:

Демонстрация приложения с иконками вкладок и заголовками

Теперь, если вам нужны только значки, вы просто не переопределяете getPageTitle() .

Демонстрация приложения с иконками вкладок

Вместо того, чтобы писать так много кода просто для создания интерфейса с вкладками или деятельности с нуля, в Android Studio 3.0 есть несколько уже существующих шаблонов кода (доступных на Java и Kotlin), которые помогут запустить ваш проект. Один такой шаблон можно использовать для создания вкладок.

Я покажу вам, как использовать эту удобную функцию в Android Studio 3.

Для нового проекта запустите Android Studio 3.

Android Studio создать диалог проекта

Введите имя приложения и нажмите кнопку « Далее» .

Вы можете оставить настройки по умолчанию такими, как они есть в диалоговом окне « Целевые устройства Android » Нажмите кнопку Далее еще раз.

Диалог добавления активности на мобильный

В диалоговом окне « Добавить действие на мобильный » прокрутите вниз и выберите вкладку « Активность». Нажмите кнопку Далее после этого.

Диалоговое окно «Настроить активность»

В последнем диалоговом окне прокрутите вниз до раскрывающегося меню « Стиль навигации» и выберите « Вкладки панели действий» (с ViewPager) . Наконец, нажмите кнопку Готово , чтобы принять все конфигурации.

Android Studio теперь помогла нам создать проект с вкладками. Очень круто!

Android Studio XML дизайн-представление для макета

Вам настоятельно рекомендуется изучить сгенерированный код.

В уже существующем проекте Android Studio, чтобы использовать этот шаблон, просто выберите «Файл»> «Активность»> «Активность с вкладками» . И выполните аналогичные шаги, которые были описаны ранее.

Переход к кнопке с вкладками в Android Studio

Шаблоны, которые входят в состав Android Studio, хороши для простых макетов и создания базовых приложений, но если вы хотите запустить свое приложение еще дальше, вы можете рассмотреть некоторые из шаблонов приложений, доступных на Envato Market .

Они значительно экономят время опытных разработчиков, помогая им сократить время создания приложения с нуля и сосредоточить свои таланты вместо этого на уникальных и настраиваемых частях создания нового приложения.

  • Шаблоны приложений
    20 лучших шаблонов для Android-приложений 2019 года
    Нона Блэкман

Из этого руководства вы узнали, как создать интерфейс с вкладками в Android с помощью API TabLayout и ViewPager с нуля. Мы также узнали, как легко и быстро использовать шаблоны Android Studio для создания интерфейса с вкладками.

Я настоятельно рекомендую ознакомиться с официальными рекомендациями по разработке материалов для вкладок, чтобы узнать больше о том, как правильно проектировать и использовать вкладки в Android.

Чтобы узнать больше о кодировании для Android, ознакомьтесь с другими нашими курсами и учебными пособиями здесь, на Envato Tuts +!

  • Android SDK
    Создать приложение для музыкального плеера с Anko
    Ашраф Хатхибелагал
  • Android SDK
    Создание музыкального приложения с помощью шаблона приложения для Android
  • Android SDK
    Реализация шины событий с LiveData