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

На этой почве возникает интерес, а иногда и необходимость (если заказчик просит) реализовать увиденное. Я не стал исключением и при проектировании нового приложения, дизайн которого был набросан на черновике, присутствовал очень схожий дизайн, хотя и имел всего несколько вкладок. Казалось бы, что сложного? Сейчас откроем официальную документацию, просмотрим необходимые разделы и приступим к делу. Но, изучив документацию, не смог обнаружить соответствующ��х примеров — и тут же возник новый вопрос. Почему Android разработчики из компании Google по умолчанию не предоставляют примеров с необходимой функциональностью, чтобы сделать это довольно просто, ведь это реализовано в каждом их приложении? Также, погуглив, нашлись аналогичные вопросы на Stack Overflow. Исходя из этого, оказалось, что существует проблема или, по крайней мере, нераскрытый вопрос, в котором следует разобраться.
Ниже хочу рассказать о том, как всё же можно реализовать паттерн Navigation Drawer вместе с вкладками, как в популярных приложениях от Google.
В примере будет использоваться интегрированная среда разработки Eclipse, но все действия можно будет воспроизвести, используя и другие среды, к примеру, недавно вышедшую и набирающую популярность Android Studio от компании Google, основанную на IntelliJ IDEA.
Создадим новый проект. Для этого перейдем в File > New > Android Application Project. Заполним поля, такие как имя приложения, пакета и версии SDK. Далее проследуем по экранам, нажимая клавишу Next и оставляя всё по умолчанию.

Среда разработки для нас создаст новый проект со стандартной структурой.
Пример будет работать, начиная с API версии 8. Это обосновано тем, что пользователи ещё пользуются девайсами со старой версией Android. Ниже приведены данные о количестве устройств, работающих под управлением различных версий платформы на состояние 12.08.2014.

Но ActionBar, соч��тающий в себе заголовок и меню, появился начиная с Android 3.0 (API 11). Для того, чтобы его использовать, необходимо подключить к проекту библиотеку Android-Support-v7-Appcompat, любезно предоставленную компанией Google. Детальную инструкцию по добавлению библиотеки к проекту можно найти по адресу: developer.android.com/tools/support-library/setup.html
Есть две возможности добавить библиотеку к проекту — без использования ресурсов и с использованием. В реализации этого проекта будет использоваться библиотека с использованием ресурсов. После того, как библиотека будет добавлена в дерево проектов, необходимо перейти в Properties, нажав по проекту правой клавишей мыши и выбрать в категориях Android, затем нажать клавишу Add. В появившемся списке выбрать android-support-v7-appcompat и нажать OK > Apply > OK. Библиотека добавлена в проект. Но если попытаться запустить приложение, то ActionBar будет ещё не виден. Необходимо в res/values/styles.xml изменить строчку:
в res/values-v11/styles.xml изменить строчку:
в res/values-v14/styles.xml изменить строчку:
на
Также в главной активности необходимо наследоваться не от Activity, а от ActionBarActivity (android.support.v7.app.ActionBarActivity). После проделанных действий и запуска приложения можно увидеть ActionBar, включая и на ранних версиях API.

Зайдем в папку Menu и отредактируем файл main.xml, чтобы выглядел следующим образом:
Необходимо обратить внимание на следующую строчку: xmlns:sabd=http://schemas.android.com/apk/res-auto. Теперь необходимо атрибут showAsAction задавать следующим образом: sabd:showAsAction=" ". Также следует зайти в strings.xml и изменить строчку:
на
Теперь меню будет иметь привыч��ый вид.

Следующим нашим шагом будет внедрение бокового меню (Navigation Drawer). Это панель, которая отображает основные параметры навигации приложения в левом краю экрана. Раскрывается жестом от левого края экрана или по нажатию на значок приложения в панели действий.

Изменим основной ресурс activity_main.xml:
Боковое меню будет заполняться в ListView, для этого добавим в string.xml строковый массив названий:
Необходимо определить, как будет выглядеть позиция в ListView. Для этого создадим в папке layout новый ресурс с названием drawer_list_item.xml:
Для функционирования работы созданного ресурса далее дополнительно создадим в папке res новую папку drawable и в ней создадим селектор activated_background.xml, поместив в него:
В папке values создадим ресурс для цветов color.xml и поместим туда цвет, который будет отвечать за выделение пункта списка в боковом меню:
Следующим шагом будет добавление иконок в приложение, а именно значка бокового меню. Скачать архив иконок можно по прямой ссылке с официального сайта Google по адресу: developer.android.com/downloads/design/Android_Design_Icons_20130926.zip. В архиве будет многочисленное число иконок для разных событий, но нужны иконки из папки Navigation_Drawer_Indicator. Следует каждый графический объект с названием ic_drawer.png поместить в проект с правильной плотностью вида drawable-???..
Для оповещения о том, что меню открыто или закрыто, добавим в string.xml ещё записи:
Заодно удалим из ресурсов следующую строчку, так как она нам уже не понадобится:
Теперь необходимо переписать класс MainActivity. Для поддержки старых устройств мы используем библиотеку поддержки Android Support Library (v4), при создании проекта она автоматически добавляется в папку libs. В листинге присутствуют комментарии, которые смогут дать возможность понять, как работает код. Для дополнительной информации можно воспользоваться официальной документацией: developer.android.com/training/implementing-navigation/nav-drawer.html. Ниже листинг.
Добавим новый пакет fragments, который будет содержать фрагменты. И поместим в него три класса-фрагмента. Для примера я выложу код одного фрагмента, остальные необходимо сделать по аналогии, изменив название класса, конструктора и разметки.
Также добавим в ресурсы разметку для этих классов. Для примера, выложу разметку одного фрагмента screen_one.xml. В остальных необходимо изменить только текст атрибута android:text:
Добавим в string.xml ещё несколько строчек, которые будут информировать о том, какой экран открыт из меню:
На этом этапе реализация Navigation Drawer завершена. Если запустить приложение, мы увидим работу бокового меню. Как на старых устройствах:

Так и на новых:

Теперь приступаем к добавлению вкладок. Первым делом, чтобы нам правильно добавить вкладки, необходимо понять принцип расположения элементов навигации. Существует строгая иерархия, в которой должны располагаться вкладки:
0 — Navigation Drawer занимает самый верхний уровень навигации.
1 — Action Bar второй уровень.
2 — Вкладки нижний уровень.

Для реализации необходимо использовать два дополнительных класса, которые Google снова любезно предоставляет. Это классы SlidingTabLayout и SlidingTabStrip. Добавим их в проект. Для этого создадим новый пакет view, там создадим новые классы с соответствующим названием и переместим в них код. При возникновении ошибок в методе createDefaultTabView(Context context) класса SlidingTabLayout следует подавить предупреждение, дописав над методом @SuppressLint(«NewApi»)
Внесем все новые изменения для фрагмента ScreenOne. Первым делом изменим разметку screen_one.xml:
Важно использовать полное имя пакета для SlidingTabLayout, так как он включен в наш проект. Далее создадим новую разметку в папке layout для вкладок pager_item.xml:
Войдем в string.xml и изменим строчку:
на
Так как нам уже не понадобится строковый ресурс, вместо него мы сразу отобразим ViewPager с номером вкладки. Далее изменим класс ScreenOne соответствующим образом:
Теперь можно запустить приложение и увидеть, как работают вкладки как на старом устройстве:

Так и на новом:

Можно заметить, что боковое меню покрывает вкладки, как в правилах навигации и приложениях от Google:

На этом пример полностью завершён и его можно использовать.
Хочется отметить ещё один последний, важный момент. Многие «путают» реализованные вкладки с вкладками ActionBar, они выглядят похоже:

Но у них реализация другая, поведение и в горизонтальной ориентации переносятся в ActionBar:

Если добавить вкладки через ActionBar, то боковое меню Navigation Drawer не перекроет вкладки, а выедет под ними:

На этом всё. Спасибо за внимание и приятного вам кодинга.
Среда разработки – Eclipse
Минимальная версия Android – >= 8
Dashboards
developer.android.com/about/dashboards/index.html?utm_source=ausdroid.net
Support Library
developer.android.com/tools/support-library/index.html
Creating a Navigation Drawer
developer.android.com/training/implementing-navigation/nav-drawer.html
Android Design in Action: Navigation Anti-Patterns
plus.google.com/photos/+NickButcher/albums/5981768132040708401
SlidingTabsBasic
developer.android.com/samples/SlidingTabsBasic/index.html
Action Bar
developer.android.com/guide/topics/ui/actionbar.html
Готовый пример можно скачать c GitHub.

На этой почве возникает интерес, а иногда и необходимость (если заказчик просит) реализовать увиденное. Я не стал исключением и при проектировании нового приложения, дизайн которого был набросан на черновике, присутствовал очень схожий дизайн, хотя и имел всего несколько вкладок. Казалось бы, что сложного? Сейчас откроем официальную документацию, просмотрим необходимые разделы и приступим к делу. Но, изучив документацию, не смог обнаружить соответствующ��х примеров — и тут же возник новый вопрос. Почему Android разработчики из компании Google по умолчанию не предоставляют примеров с необходимой функциональностью, чтобы сделать это довольно просто, ведь это реализовано в каждом их приложении? Также, погуглив, нашлись аналогичные вопросы на Stack Overflow. Исходя из этого, оказалось, что существует проблема или, по крайней мере, нераскрытый вопрос, в котором следует разобраться.
Ниже хочу рассказать о том, как всё же можно реализовать паттерн Navigation Drawer вместе с вкладками, как в популярных приложениях от Google.
В примере будет использоваться интегрированная среда разработки Eclipse, но все действия можно будет воспроизвести, используя и другие среды, к примеру, недавно вышедшую и набирающую популярность Android Studio от компании Google, основанную на IntelliJ IDEA.
Создание проекта
Создадим новый проект. Для этого перейдем в File > New > Android Application Project. Заполним поля, такие как имя приложения, пакета и версии SDK. Далее проследуем по экранам, нажимая клавишу Next и оставляя всё по умолчанию.

Среда разработки для нас создаст новый проект со стандартной структурой.
Пример будет работать, начиная с API версии 8. Это обосновано тем, что пользователи ещё пользуются девайсами со старой версией Android. Ниже приведены данные о количестве устройств, работающих под управлением различных версий платформы на состояние 12.08.2014.

Action Bar для API 8
Но ActionBar, соч��тающий в себе заголовок и меню, появился начиная с Android 3.0 (API 11). Для того, чтобы его использовать, необходимо подключить к проекту библиотеку Android-Support-v7-Appcompat, любезно предоставленную компанией Google. Детальную инструкцию по добавлению библиотеки к проекту можно найти по адресу: developer.android.com/tools/support-library/setup.html
Есть две возможности добавить библиотеку к проекту — без использования ресурсов и с использованием. В реализации этого проекта будет использоваться библиотека с использованием ресурсов. После того, как библиотека будет добавлена в дерево проектов, необходимо перейти в Properties, нажав по проекту правой клавишей мыши и выбрать в категориях Android, затем нажать клавишу Add. В появившемся списке выбрать android-support-v7-appcompat и нажать OK > Apply > OK. Библиотека добавлена в проект. Но если попытаться запустить приложение, то ActionBar будет ещё не виден. Необходимо в res/values/styles.xml изменить строчку:
<style name="AppBaseTheme" parent="android:Theme.Light">
в res/values-v11/styles.xml изменить строчку:
<style name="AppBaseTheme" parent="android:Theme.Holo.Light ">
в res/values-v14/styles.xml изменить строчку:
<style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
на
<style name="AppBaseTheme" parent="@style/Theme.AppCompat.Light">
Также в главной активности необходимо наследоваться не от Activity, а от ActionBarActivity (android.support.v7.app.ActionBarActivity). После проделанных действий и запуска приложения можно увидеть ActionBar, включая и на ранних версиях API.

Зайдем в папку Menu и отредактируем файл main.xml, чтобы выглядел следующим образом:
<menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:sabd="http://schemas.android.com/apk/res-auto" > <item android:id="@+id/action_search" android:icon="@android:drawable/ic_menu_search" android:orderInCategory="100" android:title="@string/action_search" sabd:showAsAction="ifRoom"/> </menu>
Необходимо обратить внимание на следующую строчку: xmlns:sabd=http://schemas.android.com/apk/res-auto. Теперь необходимо атрибут showAsAction задавать следующим образом: sabd:showAsAction=" ". Также следует зайти в strings.xml и изменить строчку:
<string name="action_settings">Settings</string>
на
<string name="action_search">Search</string>
Теперь меню будет иметь привыч��ый вид.

Внедрение бокового меню
Следующим нашим шагом будет внедрение бокового меню (Navigation Drawer). Это панель, которая отображает основные параметры навигации приложения в левом краю экрана. Раскрывается жестом от левого края экрана или по нажатию на значок приложения в панели действий.

Изменим основной ресурс activity_main.xml:
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <!-- The main content view --> <FrameLayout android:id="@+id/content_frame" android:layout_width="match_parent" android:layout_height="match_parent" /> <!-- The navigation drawer --> <ListView android:id="@+id/left_drawer" android:layout_width="240dp" android:layout_height="match_parent" android:layout_gravity="start" android:choiceMode="singleChoice" android:divider="@android:color/transparent" android:dividerHeight="0dp" android:background="#111"/> </android.support.v4.widget.DrawerLayout>
Боковое меню будет заполняться в ListView, для этого добавим в string.xml строковый массив названий:
<string-array name="screen_array"> <item>Screen 1</item> <item>Screen 2</item> <item>Screen 3</item> </string-array>
Необходимо определить, как будет выглядеть позиция в ListView. Для этого создадим в папке layout новый ресурс с названием drawer_list_item.xml:
<TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/text1" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/activated_background" android:gravity="center_vertical" android:minHeight="?attr/listPreferredItemHeightSmall" android:paddingLeft="16dp" android:paddingRight="16dp" android:textAppearance="?android:attr/textAppearanceMedium" android:textColor="#fff" />
Для функционирования работы созданного ресурса далее дополнительно создадим в папке res новую папку drawable и в ней создадим селектор activated_background.xml, поместив в него:
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@color/blue" android:state_activated="true"/> <item android:drawable="@color/blue" android:state_selected="true"/> <item android:drawable="@color/blue" android:state_pressed="true"/> <item android:drawable="@color/blue" android:state_checked="true"/> <item android:drawable="@android:color/transparent"/> </selector>
В папке values создадим ресурс для цветов color.xml и поместим туда цвет, который будет отвечать за выделение пункта списка в боковом меню:
<?xml version="1.0" encoding="utf-8"?> <resources> <item name="blue" type="color">#FF33B5E5</item> </resources>
Следующим шагом будет добавление иконок в приложение, а именно значка бокового меню. Скачать архив иконок можно по прямой ссылке с официального сайта Google по адресу: developer.android.com/downloads/design/Android_Design_Icons_20130926.zip. В архиве будет многочисленное число иконок для разных событий, но нужны иконки из папки Navigation_Drawer_Indicator. Следует каждый графический объект с названием ic_drawer.png поместить в проект с правильной плотностью вида drawable-???..
Для оповещения о том, что меню открыто или закрыто, добавим в string.xml ещё записи:
<string name="drawer_open">Open navigation drawer</string> <string name="drawer_close">Close navigation drawer</string>
Заодно удалим из ресурсов следующую строчку, так как она нам уже не понадобится:
<string name="hello_world">Hello world!</string>
Главное Activity
Теперь необходимо переписать класс MainActivity. Для поддержки старых устройств мы используем библиотеку поддержки Android Support Library (v4), при создании проекта она автоматически добавляется в папку libs. В листинге присутствуют комментарии, которые смогут дать возможность понять, как работает код. Для дополнительной информации можно воспользоваться официальной документацией: developer.android.com/training/implementing-navigation/nav-drawer.html. Ниже листинг.
Листинг
package com.nikosamples.develop.smp0001navigationdrawertabs; import com.nikosamples.develop.smp0001navigationdrawertabs.fragments.ScreenOne; import com.nikosamples.develop.smp0001navigationdrawertabs.fragments.ScreenThree; import com.nikosamples.develop.smp0001navigationdrawertabs.fragments.ScreenTwo; import android.content.res.Configuration; import android.os.Bundle; import android.support.v4.app.ActionBarDrawerToggle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBarActivity; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.Toast; public class MainActivity extends ActionBarActivity { private String[] mScreenTitles; private DrawerLayout mDrawerLayout; private ListView mDrawerList; private ActionBarDrawerToggle mDrawerToggle; private CharSequence mDrawerTitle; private CharSequence mTitle; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTitle = mDrawerTitle = getTitle(); mScreenTitles = getResources().getStringArray(R.array.screen_array); mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); mDrawerList = (ListView) findViewById(R.id.left_drawer); // Set the adapter for the list view mDrawerList.setAdapter(new ArrayAdapter<String>(this, R.layout.drawer_list_item, mScreenTitles)); // Set the list's click listener mDrawerList.setOnItemClickListener(new DrawerItemClickListener()); getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setHomeButtonEnabled(true); mDrawerToggle = new ActionBarDrawerToggle( this, /* host Activity */ mDrawerLayout, /* DrawerLayout object */ R.drawable.ic_drawer, /* nav drawer icon to replace 'Up' caret */ R.string.drawer_open, /* "open drawer" description */ R.string.drawer_close /* "close drawer" description */ ) { /** Called when a drawer has settled in a completely closed state. */ public void onDrawerClosed(View view) { getSupportActionBar().setTitle(mTitle); supportInvalidateOptionsMenu(); // creates call to onPrepareOptionsMenu() } /** Called when a drawer has settled in a completely open state. */ public void onDrawerOpened(View drawerView) { getSupportActionBar().setTitle(mDrawerTitle); supportInvalidateOptionsMenu(); // creates call to onPrepareOptionsMenu() } }; // Set the drawer toggle as the DrawerListener mDrawerLayout.setDrawerListener(mDrawerToggle); // Initialize the first fragment when the application first loads. if (savedInstanceState == null) { selectItem(0); } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.main, menu); return super.onCreateOptionsMenu(menu); } /* Called whenever we call invalidateOptionsMenu() */ @Override public boolean onPrepareOptionsMenu(Menu menu) { // If the nav drawer is open, hide action items related to the content view boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList); menu.findItem(R.id.action_search).setVisible(!drawerOpen); return super.onPrepareOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { // Pass the event to ActionBarDrawerToggle, if it returns // true, then it has handled the app icon touch event if (mDrawerToggle.onOptionsItemSelected(item)) { return true; } // Handle action buttons switch(item.getItemId()) { case R.id.action_search: // Show toast about click. Toast.makeText(this, R.string.action_search, Toast.LENGTH_SHORT).show(); return true; default: return super.onOptionsItemSelected(item); } } /* The click listener for ListView in the navigation drawer */ private class DrawerItemClickListener implements ListView.OnItemClickListener { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { selectItem(position); } } /** Swaps fragments in the main content view */ private void selectItem(int position) { // Update the main content by replacing fragments Fragment fragment = null; switch (position) { case 0: fragment = new ScreenOne(); break; case 1: fragment = new ScreenTwo(); break; case 2: fragment = new ScreenThree(); break; default: break; } // Insert the fragment by replacing any existing fragment if (fragment != null) { FragmentManager fragmentManager = getSupportFragmentManager(); fragmentManager.beginTransaction() .replace(R.id.content_frame, fragment).commit(); // Highlight the selected item, update the title, and close the drawer mDrawerList.setItemChecked(position, true); setTitle(mScreenTitles[position]); mDrawerLayout.closeDrawer(mDrawerList); } else { // Error Log.e(this.getClass().getName(), "Error. Fragment is not created"); } } @Override public void setTitle(CharSequence title) { mTitle = title; getSupportActionBar().setTitle(mTitle); } /** * When using the ActionBarDrawerToggle, you must call it during * onPostCreate() and onConfigurationChanged()... */ @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); // Sync the toggle state after onRestoreInstanceState has occurred. mDrawerToggle.syncState(); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); // Pass any configuration change to the drawer toggles mDrawerToggle.onConfigurationChanged(newConfig); } }
Добавим фрагменты
Добавим новый пакет fragments, который будет содержать фрагменты. И поместим в него три класса-фрагмента. Для примера я выложу код одного фрагмента, остальные необходимо сделать по аналогии, изменив название класса, конструктора и разметки.
package com.nikosamples.develop.smp0001navigationdrawertabs.fragments; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.nikosamples.develop.smp0001navigationdrawertabs.R; public class ScreenOne extends Fragment { public ScreenOne() { } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.screen_first, container, false); return rootView; } }
Также добавим в ресурсы разметку для этих классов. Для примера, выложу разметку одного фрагмента screen_one.xml. В остальных необходимо изменить только текст атрибута android:text:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:text="@string/screen_one" android:textAppearance="?android:attr/textAppearanceMedium" /> </RelativeLayout>
Добавим в string.xml ещё несколько строчек, которые будут информировать о том, какой экран открыт из меню:
<string name="screen_one">Screen one</string> <string name="screen_two">Screen two</string> <string name="screen_three">Screen three</string>
На этом этапе реализация Navigation Drawer завершена. Если запустить приложение, мы увидим работу бокового меню. Как на старых устройствах:

Так и на новых:

Внедрение вкладок
Теперь приступаем к добавлению вкладок. Первым делом, чтобы нам правильно добавить вкладки, необходимо понять принцип расположения элементов навигации. Существует строгая иерархия, в которой должны располагаться вкладки:
0 — Navigation Drawer занимает самый верхний уровень навигации.
1 — Action Bar второй уровень.
2 — Вкладки нижний уровень.

Для реализации необходимо использовать два дополнительных класса, которые Google снова любезно предоставляет. Это классы SlidingTabLayout и SlidingTabStrip. Добавим их в проект. Для этого создадим новый пакет view, там создадим новые классы с соответствующим названием и переместим в них код. При возникновении ошибок в методе createDefaultTabView(Context context) класса SlidingTabLayout следует подавить предупреждение, дописав над методом @SuppressLint(«NewApi»)
Внесем все новые изменения для фрагмента ScreenOne. Первым делом изменим разметку screen_one.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <com.nikosamples.develop.smp0001navigationdrawertabs.view.SlidingTabLayout android:id="@+id/sliding_tabs" android:layout_width="match_parent" android:layout_height="wrap_content" /> <android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="0px" android:layout_weight="1" android:background="@android:color/white"/> </LinearLayout>
Важно использовать полное имя пакета для SlidingTabLayout, так как он включен в наш проект. Далее создадим новую разметку в папке layout для вкладок pager_item.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical" > <TextView android:id="@+id/item_subtitle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/page"/> android:textAppearance="?android:attr/textAppearanceLarge" /> <TextView android:id="@+id/item_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="80sp" /> </LinearLayout>
Войдем в string.xml и изменим строчку:
<string name="screen_one">Screen one</string>
на
<string name="page">Page:</string>
Так как нам уже не понадобится строковый ресурс, вместо него мы сразу отобразим ViewPager с номером вкладки. Далее изменим класс ScreenOne соответствующим образом:
Код класса ScreenOne
package com.nikosamples.develop.smp0001navigationdrawertabs.fragments; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import com.nikosamples.develop.smp0001navigationdrawertabs.R; import com.nikosamples.develop.smp0001navigationdrawertabs.view.SlidingTabLayout; public class ScreenOne extends Fragment { private SlidingTabLayout mSlidingTabLayout; private ViewPager mViewPager; public ScreenOne() { } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.screen_one, container, false); return rootView; } @Override public void onViewCreated(View view, Bundle savedInstanceState) { // Get the ViewPager and set it's PagerAdapter so that it can display items mViewPager = (ViewPager) view.findViewById(R.id.viewpager); mViewPager.setAdapter(new SamplePagerAdapter()); // Give the SlidingTabLayout the ViewPager, this must be // done AFTER the ViewPager has had it's PagerAdapter set. mSlidingTabLayout = (SlidingTabLayout) view.findViewById(R.id.sliding_tabs); mSlidingTabLayout.setViewPager(mViewPager); } // Adapter class SamplePagerAdapter extends PagerAdapter { /** * Return the number of pages to display */ @Override public int getCount() { return 10; } /** * Return true if the value returned from is the same object as the View * added to the ViewPager. */ @Override public boolean isViewFromObject(View view, Object o) { return o == view; } /** * Return the title of the item at position. This is important as what * this method returns is what is displayed in the SlidingTabLayout. */ @Override public CharSequence getPageTitle(int position) { return "Item " + (position + 1); } /** * Instantiate the View which should be displayed at position. Here we * inflate a layout from the apps resources and then change the text * view to signify the position. */ @Override public Object instantiateItem(ViewGroup container, int position) { // Inflate a new layout from our resources View view = getActivity().getLayoutInflater().inflate(R.layout.pager_item, container, false); // Add the newly created View to the ViewPager container.addView(view); // Retrieve a TextView from the inflated View, and update it's text TextView title = (TextView) view.findViewById(R.id.item_title); title.setText(String.valueOf(position + 1)); // Return the View return view; } /** * Destroy the item from the ViewPager. In our case this is simply * removing the View. */ @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView((View) object); } } }
Теперь можно запустить приложение и увидеть, как работают вкладки как на старом устройстве:

Так и на новом:

Можно заметить, что боковое меню покрывает вкладки, как в правилах навигации и приложениях от Google:

На этом пример полностью завершён и его можно использовать.
Вкладки Action Bar
Хочется отметить ещё один последний, важный момент. Многие «путают» реализованные вкладки с вкладками ActionBar, они выглядят похоже:

Но у них реализация другая, поведение и в горизонтальной ориентации переносятся в ActionBar:

Если добавить вкладки через ActionBar, то боковое меню Navigation Drawer не перекроет вкладки, а выедет под ними:

На этом всё. Спасибо за внимание и приятного вам кодинга.
Среда разработки – Eclipse
Минимальная версия Android – >= 8
Ссылки
Dashboards
developer.android.com/about/dashboards/index.html?utm_source=ausdroid.net
Support Library
developer.android.com/tools/support-library/index.html
Creating a Navigation Drawer
developer.android.com/training/implementing-navigation/nav-drawer.html
Android Design in Action: Navigation Anti-Patterns
plus.google.com/photos/+NickButcher/albums/5981768132040708401
SlidingTabsBasic
developer.android.com/samples/SlidingTabsBasic/index.html
Action Bar
developer.android.com/guide/topics/ui/actionbar.html
Готовый пример можно скачать c GitHub.
