Статьи

Дизайн материалов с помощью библиотеки поддержки Android Design

Material Design, новый язык дизайна, который дает рекомендации по дизайну для приложений Android и приложений на других платформах, был представлен с выпуском Android 5.0 Lollipop.

Вместе с ним появились новые компоненты пользовательского интерфейса, такие как «Плавающая кнопка действия». Реализация этих новых компонентов при обеспечении обратной совместимости обычно была утомительным процессом. Обычно для упрощения процесса необходимы сторонние библиотеки.

На конференции Google IO в этом году Google представила библиотеку поддержки дизайна Android, которая предоставляет разработчикам ряд важных компонентов дизайна материалов. Компоненты имеют обратную совместимость с поддержкой Android 2.1, и их реализация проще, чем раньше. Библиотека включает в себя панель навигации, плавающие надписи для редактирования текста, плавающую кнопку действий, панель с закусками, вкладки и структуру движения и прокрутки для их объединения. В этом уроке мы создадим приложение, которое демонстрирует эти компоненты.

Начиная

Вы можете найти окончательный код проекта на gitHub .

Прежде чем начать работу с компонентами, мы настроим проект и настроим несколько стилей. Используя Android Studio, создайте новый проект Android. Назовите его «Design Demo» и оставьте другие настройки по умолчанию, убедитесь, что минимальная версия SDK находится на уровне API 15.

Добавьте следующие зависимости в файл build.gradle (Module: app).

compile 'com.android.support:design:22.2.1' compile 'com.android.support:cardview-v7:22.2.1' 

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

Создайте файл ресурсов в папке res / values ​​с именем colors.xml . Измените его, как показано ниже:

 <?xml version="1.0" encoding="utf-8"?> <resources> <color name="primary">#3F51B5</color> <color name="primary_dark">#303F9F</color> <color name="accent">#FF4081</color> </resources> 

Измените res / values ​​/ strings.xml, как показано ниже. Это все строки, которые нам понадобятся для проекта:

 <resources> <string name="app_name">Design Demo</string> <string name="hello_world">Hello world!</string> <string name="action_settings">Settings</string> <string name="nav_item_attachment">Attachment</string> <string name="nav_item_images">Images</string> <string name="nav_item_location">My Location</string> <string name="nav_sub_menu">Sub Menu</string> <string name="nav_sub_menu_item01">Sub Menu Item 1</string> <string name="nav_sub_menu_item02">Sub Menu Item 2</string> <string name="drawer_header_text">Drawer Header</string> <string name="second_activity_text">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin consectetur diam id aliquam scelerisque. Donec ultrices lacus vel dignissim pharetra. Vivamus pharetra augue quis rhoncus placerat. Sed ultricies at risus non cursus. Nam rutrum leo nec placerat consectetur. Vestibulum feugiat eleifend diam, nec interdum augue tincidunt sit amet. Praesent feugiat est auctor lacus consectetur, vitae pellentesque dolor laoreet.</string> <string name="title_activity_second">SecondActivity</string> </resources> 

Измените res/values/styles.xml как res/values/styles.xml ниже:

 <resources> <!-- Base application theme. --> <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> <!-- Customize your theme here. --> <item name="colorPrimary">@color/primary</item> <item name="colorPrimaryDark">@color/primary_dark</item> <item name="colorAccent">@color/accent</item> </style> </resources> 

В приведенном выше коде мы настраиваем цветовую палитру приложения, устанавливая основной, основной и темный цвета, как указано в руководстве по дизайну материала.

Другие настройки темы, которые можно настроить, показаны на рисунке ниже.

Обратите внимание, что мы не включаем префикс android: перед именем элемента (например, android:colorPrimaryDark ). Это для обратной совместимости. Для android: annotation требуется минимальный уровень API, NoActionBar 21. Мы используем тему с NoActionBar потому что мы будем использовать панель инструментов в качестве панели действий (или AppBar, как она теперь называется).

Материал Дизайн Цветовая палитра

(ИСТОЧНИК: https://developer.android.com/training/material/theme.html )

Чтобы создать панель инструментов, измените res / layout / activity_main :

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" android:theme="@style/ThemeOverlay.AppCompat.Dark" /> </RelativeLayout> 

Выше мы удаляем заполнение по умолчанию для RelativeLayout и добавляем панель инструментов из библиотеки поддержки. Если вы поддерживаете устройства уровня API 21 и выше, вам нужно будет использовать только компонент панели инструментов по умолчанию, а не один из библиотеки поддержки.

В MainActivity.java измените метод onCreate(Bundle) :

 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); ActionBar actionBar = getSupportActionBar(); actionBar.setHomeAsUpIndicator(R.drawable.ic_menu); actionBar.setDisplayHomeAsUpEnabled(true); } 

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

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

В приведенном выше коде мы получаем ссылку на панель инструментов и устанавливаем ее как панель действий. Затем мы получаем ссылку на панель действий и устанавливаем ее значок Home на значок печально известного меню гамбургера .

Запустите приложение, и вы увидите панель инструментов, установленную как панель приложения.

Панель инструментов в качестве панели приложений

Навигационный ящик является общим компонентом в приложениях для Android. Это один из способов построения иерархии навигации на Android, другие — это Tab и Spinners. Реализация никогда не была быстрым процессом, но теперь с библиотекой поддержки проектирования, ее реализация стала намного проще.

Чтобы начать, измените Activity_main.xml, как показано.

 <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" android:theme="@style/ThemeOverlay.AppCompat.Dark" /> </RelativeLayout> <android.support.design.widget.NavigationView android:id="@+id/navigation_view" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" app:headerLayout="@layout/drawer_header" app:menu="@menu/drawer"/> </android.support.v4.widget.DrawerLayout> 

В приведенном выше коде мы добавляем NavigationView к макету. NavigationView находится внутри DrawerLayout . Следует отметить два важных атрибута: app:headerLayout который контролирует (необязательный) макет, используемый для заголовка, и app:menu который является ресурсом меню, накачанным для элементов навигации (это также можно обновить во время выполнения).

Создайте файл с именем box_header.xml в папке res/layout и измените его, как показано на рисунке.

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="150dp" android:background="?attr/colorPrimaryDark" android:padding="16dp" android:theme="@style/ThemeOverlay.AppCompat.Dark" android:gravity="bottom"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/drawer_header_text" android:textAppearance="@style/TextAppearance.AppCompat.Body1"/> </LinearLayout> 

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

Затем создайте файл по имени box.xml в папке res/menu и измените его, как показано на рисунке.

 <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <group android:checkableBehavior="single"> <item android:id="@+id/navigation_item_attachment" android:checked="true" android:icon="@drawable/ic_attachment" android:title="@string/nav_item_attachment" /> <item android:id="@+id/navigation_item_images" android:icon="@drawable/ic_image" android:title="@string/nav_item_images" /> <item android:id="@+id/navigation_item_location" android:icon="@drawable/ic_place" android:title="@string/nav_item_location" /> </group> <item android:title="@string/nav_sub_menu"> <menu> <item android:icon="@drawable/ic_emoticon" android:title="@string/nav_sub_menu_item01" /> <item android:icon="@drawable/ic_emoticon" android:title="@string/nav_sub_menu_item02" /> </menu> </item> </menu> 

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

В MainActivity.java добавьте следующую переменную-член.

 private DrawerLayout mDrawerLayout; 

Затем добавьте следующее в onCreate(Bundle) .

 mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); 

Измените onOptionsItemSelected(MenuItem) как показано:

 @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); switch (id) { case android.R.id.home: mDrawerLayout.openDrawer(GravityCompat.START); return true; case R.id.action_settings: return true; } return super.onOptionsItemSelected(item); } 

Это выведет ящик на экран при нажатии кнопки «Домой» (со значком меню гамбургера). Запустите приложение, и вы должны увидеть следующее.

Вид навигации

Для захвата событий щелчка по пунктам меню нам нужно установить OnNavigationItemSelectedListener в NavigationView . Поместите следующее в нижней части onCreate(Bundle) .

 NavigationView navigationView = (NavigationView) findViewById(R.id.navigation_view); navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() { @Override public boolean onNavigationItemSelected(MenuItem menuItem) { menuItem.setChecked(true); mDrawerLayout.closeDrawers(); Toast.makeText(MainActivity.this, menuItem.getTitle(), Toast.LENGTH_LONG).show(); return true; } }); 

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

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

Плавающая кнопка действия (FAB)

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

В дополнение к плавающей кнопке обычного размера (56 дп), она поддерживает мини-размер (40 дп), когда визуальная непрерывность с другими элементами имеет решающее значение.

Чтобы добавить FAB в макет, измените res/layout/activity_main.xml как показано.

 <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" android:theme="@style/ThemeOverlay.AppCompat.Dark" /> <android.support.design.widget.FloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:layout_marginRight="@dimen/activity_horizontal_margin" android:layout_marginBottom="@dimen/activity_vertical_margin" android:src="@drawable/ic_done" /> </RelativeLayout> <android.support.design.widget.NavigationView android:id="@+id/navigation_view" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" app:headerLayout="@layout/drawer_header" app:menu="@menu/drawer"/> </android.support.v4.widget.DrawerLayout> 

Выше мы добавляем FloatingActionButton в нижнем правом углу макета. android:src устанавливает значок, отображаемый внутри кнопки. В коде вы можете установить это с помощью setImageDrawable() .

Запустите приложение, и вы должны увидеть FAB.

Плавающая кнопка действия

Мы установим onClickListener на FAB в следующем разделе.

Снэк-бар

Традиционно, если вы хотите представить краткий краткий отзыв пользователю, вы должны использовать тост. Теперь есть еще один вариант — Снэк-бар.

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

Благодаря возможности взаимодействовать со снэк-баром с помощью действий и пролистывания, они значительно более эффективны, чем тосты, и API знаком.

В MainActivity.java добавьте следующее в onCreate(Bundle) :

 FloatingActionButton fab = (FloatingActionButton)findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Snackbar.make(findViewById(R.id.drawer_layout), "I'm a Snackbar", Snackbar.LENGTH_LONG).setAction("Action", new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this, "Snackbar Action", Toast.LENGTH_LONG).show(); } }).show(); } }); 

Выше мы установили onClickListener на FAB, чтобы при его нажатии отображалась панель Snackbar. Мы создаем Action на Snackbar и устанавливаем onClickListener который отображает тост при касании.

Обратите внимание на использование View в качестве первого параметра make() . Snackbar попытается найти подходящего родителя вида Snackbar, чтобы убедиться, что он привязан к нижней части. Запустите приложение, чтобы проверить это.

Снэк-бар

Обратите внимание, что Snackbar перекрывает FAB. Мы исправим это в разделе CoordinatorLayout .

TabLayout

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

Чтобы добавить TabLayout в приложение, измените TabLayout res/layout/activity_main.xml как показано.

 <android.support.v4.widget.DrawerLayout android:id="@+id/drawer_layout" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" android:theme="@style/ThemeOverlay.AppCompat.Dark" /> <android.support.design.widget.TabLayout android:id="@+id/tablayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/colorPrimary" app:tabGravity="fill" android:theme="@style/ThemeOverlay.AppCompat.Dark" /> <android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"/> </LinearLayout> <android.support.design.widget.FloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:layout_marginBottom="@dimen/activity_vertical_margin" android:layout_marginRight="@dimen/activity_horizontal_margin" android:src="@drawable/ic_done"/> </RelativeLayout> <android.support.design.widget.NavigationView android:id="@+id/navigation_view" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" app:headerLayout="@layout/drawer_header" app:menu="@menu/drawer"/> </android.support.v4.widget.DrawerLayout> 

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

В MainActivity.java добавьте следующие подклассы.

 public static class DesignDemoFragment extends Fragment { private static final String TAB_POSITION = "tab_position"; public DesignDemoFragment() { } public static DesignDemoFragment newInstance(int tabPosition) { DesignDemoFragment fragment = new DesignDemoFragment(); Bundle args = new Bundle(); args.putInt(TAB_POSITION, tabPosition); fragment.setArguments(args); return fragment; } @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Bundle args = getArguments(); int tabPosition = args.getInt(TAB_POSITION); TextView tv = new TextView(getActivity()); tv.setGravity(Gravity.CENTER); tv.setText("Text in Tab #" + tabPosition); return tv; } } 
 static class DesignDemoPagerAdapter extends FragmentStatePagerAdapter { public DesignDemoPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { return DesignDemoFragment.newInstance(position); } @Override public int getCount() { return 3; } @Override public CharSequence getPageTitle(int position) { return "Tab " + position; } } 

Затем в нижней части onCreate(Bundle) добавьте следующее.

 DesignDemoPagerAdapter adapter = new DesignDemoPagerAdapter(getSupportFragmentManager()); ViewPager viewPager = (ViewPager)findViewById(R.id.viewpager); viewPager.setAdapter(adapter); TabLayout tabLayout = (TabLayout)findViewById(R.id.tablayout); tabLayout.setupWithViewPager(viewPager); 

Выше мы создаем класс Fragment который создает простой фрагмент с единственным TextView качестве его содержимого. Затем мы создаем FragmentStatePagerAdapter который будет использоваться в качестве ViewPager . Функция getCount() класса DesignDemoPagerAdapter возвращает количество страниц / вкладок. getItem(int) возвращает фрагмент, который будет размещен на странице просмотра, а getPageTitle(int) возвращает заголовок, который появится на определенной вкладке. Чтобы это работало, мы используем setupWithViewPager() для TabLayout . Это гарантирует, что события выбора вкладок обновят ViewPager а изменения страницы обновят выбранную вкладку.

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

TabLayout

CoordinatorLayout

Библиотека Design представляет CoordinatorLayout , макет, который обеспечивает дополнительный уровень управления событиями касания между дочерними представлениями, то, чем пользуются многие компоненты библиотеки Design.

Примером этого является случай, когда вы добавляете FloatingActionButton в качестве дочернего элемента вашего CoordinatorLayout а затем передаете этот CoordinatorLayout в свой Snackbar.make() .

Вместо того, чтобы снэк-бар отображался над плавающей кнопкой действия, как было показано ранее, FloatingActionButton использует дополнительные обратные вызовы, предоставляемые CoordinatorLayout для автоматического перемещения вверх по мере того, как снэк-бар анимируется и возвращается в свое положение, когда анимируется снэк-бар. Это поддерживается на устройствах Android 3.0 и выше.

Чтобы использовать CoordinatorLayout в нашем макете, измените файл res / layout / activity_main.xml, как показано ниже:

 <android.support.v4.widget.DrawerLayout android:id="@+id/drawer_layout" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true"> <android.support.design.widget.CoordinatorLayout android:id="@+id/coordinator" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" android:theme="@style/ThemeOverlay.AppCompat.Dark" /> <android.support.design.widget.TabLayout android:id="@+id/tablayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/colorPrimary" app:tabGravity="fill" android:theme="@style/ThemeOverlay.AppCompat.Dark" /> <android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"/> </LinearLayout> <android.support.design.widget.FloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_gravity="bottom|right" android:layout_marginBottom="@dimen/activity_vertical_margin" android:layout_marginRight="@dimen/activity_horizontal_margin" android:src="@drawable/ic_done"/> </android.support.design.widget.CoordinatorLayout> <android.support.design.widget.NavigationView android:id="@+id/navigation_view" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" app:headerLayout="@layout/drawer_header" app:menu="@menu/drawer"/> </android.support.v4.widget.DrawerLayout> 

Как видно выше, FAB должен быть дочерним по отношению к CoordinatorLayout , поэтому мы заменяем предыдущий RelativeLayout на CoordinatorLayout . Также обратите внимание, что мы изменили настройку положения FAB на android:layout_gravity="bottom|right" .

Далее в MainActivity.java при создании Snackbar передайте CoordinatorLayout в качестве параметра представления.

 Snackbar.make(findViewById(R.id.coordinator), "I'm a Snackbar", Snackbar.LENGTH_LONG).setAction("Action", new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this, "Snackbar Action", Toast.LENGTH_LONG).show(); } }).show(); 

Запустите приложение, и теперь, когда вы нажмете на FAB, Snackbar будет скользить в поле зрения, но на этот раз он не будет перекрывать FAB, FAB будет скользить вместе с ним, а когда Snackbar отклоняется либо по тайм-ауту, либо с Проведите, FAB вернется на свое место.

Снэк-бар работает с CoordinatorLayout

Другой основной вариант использования CoordinatorLayout касается панели приложения и методов прокрутки. Библиотека дизайна предоставляет AppBarLayout который позволяет панели инструментов и другим представлениям (таким как вкладки, предоставляемые TabLayout ) реагировать на события прокрутки в одноуровневом представлении, помеченном как ScrollingViewBehavior .

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

Примечание : я потратил около часа, пытаясь заставить CoordinatorLayout работать с ListView , но поведение прокрутки просто не работало. Простой поиск привел меня к этому посту , этому посту и этому посту . Если вы проверите эти ссылки, кажется, что CoordinatorLayout не работает ScrollViews с ListViews (и, по-видимому, GridViews и ScrollViews ). Последние две ссылки показывают обходной путь к тому, чтобы заставить его работать с ListView , но он не имеет обратной совместимости. Я хотел, чтобы вы знали, если вы застряли на том же вопросе. Поддержка ListViews , вероятно, будет добавлена ​​в будущем обновлении.

Я расскажу о создании RecyclerView без особых объяснений, поскольку это выходит за рамки данного руководства, и вы можете легко найти помощь в Интернете относительно RecyclerViews .

Поместите следующее в свой файл build.gradle (Module: app) и синхронизируйте файлы gradle.

 compile 'com.android.support:recyclerview-v7:22.2.1' 

Создайте файл в res / layout с именем frag_list_view.xml . Измените его, как показано.

 <?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/recyclerview" android:layout_width="match_parent" android:layout_height="match_parent"/> 

Создайте другой файл макета в res / layout и назовите его list_row.xml . Замените его содержимое на содержание ниже.

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:padding="16dp" android:layout_width="match_parent" android:layout_height="56dp"> <TextView android:id="@+id/list_item" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout> 

Создайте файл Java с именем DesignDemoRecyclerAdapter.java и вставьте следующее.

 package com.echessa.designdemo; // Rename as Appropriate import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import java.util.List; /** * Created by echessa on 7/24/15. */ public class DesignDemoRecyclerAdapter extends RecyclerView.Adapter<DesignDemoRecyclerAdapter.ViewHolder> { private List<String> mItems; DesignDemoRecyclerAdapter(List<String> items) { mItems = items; } @Override public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_row, viewGroup, false); return new ViewHolder(v); } @Override public void onBindViewHolder(ViewHolder viewHolder, int i) { String item = mItems.get(i); viewHolder.mTextView.setText(item); } @Override public int getItemCount() { return mItems.size(); } public class ViewHolder extends RecyclerView.ViewHolder { private final TextView mTextView; ViewHolder(View v) { super(v); mTextView = (TextView)v.findViewById(R.id.list_item); } } } 

Измените DesignDemoFragment.onCreateView() в MainActivity.java, как показано:

 @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Bundle args = getArguments(); int tabPosition = args.getInt(TAB_POSITION); ArrayList<String> items = new ArrayList<String>(); for (int i = 0; i < 50; i++) { items.add("Tab #" + tabPosition + " item #" + i); } View v = inflater.inflate(R.layout.fragment_list_view, container, false); RecyclerView recyclerView = (RecyclerView)v.findViewById(R.id.recyclerview); recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); recyclerView.setAdapter(new DesignDemoRecyclerAdapter(items)); return v; } 

Это раздувает ранее созданный файл макета. Теперь вид фрагмента будет содержать список элементов. Запустите приложение, чтобы подтвердить это.

RecyclerView

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

Модифицируйте Activity_main.xml как показано.

 <android.support.v4.widget.DrawerLayout android:id="@+id/drawer_layout" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true"> <android.support.design.widget.CoordinatorLayout android:id="@+id/coordinator" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/ThemeOverlay.AppCompat.Dark"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:layout_scrollFlags="scroll|enterAlways"/> <android.support.design.widget.TabLayout android:id="@+id/tablayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/colorPrimary" app:tabGravity="fill"/> </android.support.design.widget.AppBarLayout> <android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"/> <android.support.design.widget.FloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_gravity="bottom|right" android:layout_marginBottom="@dimen/activity_vertical_margin" android:layout_marginRight="@dimen/activity_horizontal_margin" android:src="@drawable/ic_done"/> </android.support.design.widget.CoordinatorLayout> <android.support.design.widget.NavigationView android:id="@+id/navigation_view" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" app:headerLayout="@layout/drawer_header" app:menu="@menu/drawer"/> </android.support.v4.widget.DrawerLayout> 

Выше мы TabLayout Toolbar и TabLayout в AppBarLayout . AppBarLayout позволяет Toolbar и другим представлениям (таким как вкладки, предоставляемые TabLayout ) реагировать на события прокрутки в одноуровневом представлении, помеченном ScrollingViewBehavior . Когда пользователь прокручивает RecyclerView , AppBarLayout отвечает, используя свои дочерние флаги прокрутки, чтобы контролировать, как они входят (прокрутка на экране) и выходят (выкл прокручивают экран).

Флаги включают в себя:

  • scroll : этот флаг должен быть установлен для всех видов, которые хотят прокрутить с экрана. Для представлений, которые не используют этот флаг, они останутся закрепленными в верхней части экрана.
  • enterAlways : этот флаг гарантирует, что любая прокрутка вниз приведет к тому, что это представление станет видимым, включив шаблон «быстрого возврата»
  • enterAlwaysCollapsed : когда ваш вид объявил minHeight и вы используете этот флаг, ваш вид будет входить только на своей минимальной высоте (то есть «свернутый»), только повторно расширяясь до полной высоты, когда прокручиваемый вид достигнет своей вершины.
  • exitUntilCollapsed : этот флаг заставляет представление прокручиваться до тех пор, пока оно не будет minHeight ( minHeight ) перед выходом

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

В нашем приложении мы используем флаги scroll и enterAlways на панели инструментов, что приводит к тому, что панель прокрутки отключается от экрана при прокрутке вверх и возвращается на экран при прокрутке вниз. Обратите внимание на использование app:layout_behavior="@string/appbar_scrolling_view_behavior" в ViewPager. Библиотека поддержки содержит специальный строковый ресурс @string/appbar_scrolling_view_behavior который сопоставляется с AppBarLayout.ScrollingViewBehavior , который используется для уведомления AppBarLayout при возникновении событий прокрутки в конкретном представлении. Поведение должно быть установлено в представлении, которое вызывает событие.

Запустите приложение, чтобы увидеть эффект прокрутки на панели приложений.

Прокрутка панели инструментов и TabLayout

CollapsingToolbarLayout

CollapsingToolbarLayour предоставляет другой тип прокрутки в AppBar . Чтобы увидеть его в действии, мы сначала создадим еще одно действие с Toolbar , но без TabLayout .

Создайте пустое действие ( Файл -> Создать -> Деятельность -> Пустое действие ) и назовите его SecondActivity .

Измените res / layout / activity_second.xml, как показано.

 <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="250dp" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> <android.support.design.widget.CollapsingToolbarLayout android:id="@+id/collapsing_toolbar" android:layout_width="match_parent" android:layout_height="match_parent" app:contentScrim="?attr/colorPrimary" app:layout_scrollFlags="scroll|exitUntilCollapsed"> <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" android:src="@drawable/image" app:layout_collapseMode="parallax"/> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:layout_collapseMode="pin"/> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout> <android.support.v4.widget.NestedScrollView android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingTop="24dp"> <android.support.v7.widget.CardView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="16dp"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="16dp"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Lorem ipsum"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/second_activity_text"/> </LinearLayout> </android.support.v7.widget.CardView> <android.support.v7.widget.CardView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="16dp" android:layout_marginLeft="16dp" android:layout_marginRight="16dp"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="16dp"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Sed quam eros"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/second_activity_text"/> </LinearLayout> </android.support.v7.widget.CardView> <android.support.v7.widget.CardView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="16dp" android:layout_marginLeft="16dp" android:layout_marginRight="16dp"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="16dp"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Sed a euismod dui"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/second_activity_text"/> </LinearLayout> </android.support.v7.widget.CardView> <android.support.v7.widget.CardView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="16dp" android:layout_marginLeft="16dp" android:layout_marginRight="16dp"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="16dp"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Fusce nec lacinia mi"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/second_activity_text"/> </LinearLayout> </android.support.v7.widget.CardView> <android.support.v7.widget.CardView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="16dp" android:layout_marginLeft="16dp" android:layout_marginRight="16dp"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="16dp"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Praesent hendrerit"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/second_activity_text"/> </LinearLayout> </android.support.v7.widget.CardView> </LinearLayout> </android.support.v4.widget.NestedScrollView> </android.support.design.widget.CoordinatorLayout> 

Выше мы используем CollapsingToolbarLayout с флагами scroll и exitUntilCollapsed которые заставят его подпредставления прокручиваться за пределы экрана. Для панели инструментов, однако, мы устанавливаем app:layout_collapseMode="pin" который гарантирует, что сама панель инструментов останется закрепленной в верхней части экрана, пока вид сворачивается. Еще один эффект, который мы получим, заключается в том, что заголовок в CollapsingToolbarLayout будет выглядеть больше, когда макет полностью виден, а затем будет свернут в размер по умолчанию, когда он свернут. Мы установим этот заголовок в коде. Остальная часть макета содержит NestedScrollView с несколькими картами в качестве NestedScrollView .

В SecondActivity.java измените onCreate(Bundle) как показано.

 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); getSupportActionBar().setDisplayHomeAsUpEnabled(true); CollapsingToolbarLayout collapsingToolbar = (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar); collapsingToolbar.setTitle("Second Activity"); } 

Здесь мы устанавливаем курсор вверх на панели инструментов, а затем устанавливаем заголовок для CollapsingToolbarLayout .

Чтобы каретка Up работала, поместите следующее в файл манифеста как дочерний SecondActivity тега activity SecondActivity .

 <meta-data android:name="android.support.PARENT_ACTIVITY" android:value="com.echessa.designdemo.MainActivity" /> 

В DesignDemoRecyclerAdapter.java измените `onBindViewHolder (), как показано.

 @Override public void onBindViewHolder(ViewHolder viewHolder, int i) { String item = mItems.get(i); viewHolder.mTextView.setText(item); viewHolder.mTextView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Context context = view.getContext(); context.startActivity(new Intent(context, SecondActivity.class)); } }); } 

Выше мы установили onClick onClick для TextView в каждой строке RecyclerView . Это не лучший способ настройки прослушивателя для элементов RecyclerView , потому что если вы запустите приложение, цель касания слушателя будет покрывать только область с текстом строки, а не всю строку. Я делаю это здесь, потому что все, что я хочу, — это способ начать новое действие, и поэтому я выбрал способ написать наименьшее количество кода.

Запустите приложение, и вы увидите следующее поведение прокрутки.

CollapsingToolbarLayout

Плавающие метки для EditText

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

Чтобы увидеть это, поместите следующее в один из CardViews в activity_second.xml . Вы можете разместить его после второго TextView карты.

 <android.support.design.widget.TextInputLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textEmailAddress" android:hint="Email" /> </android.support.design.widget.TextInputLayout> 

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

Плавающая метка для EditText

В дополнение к отображению подсказок, вы можете отобразить сообщение об ошибке под EditText , вызвав setError() .

Вывод

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