Данная статья является переводом статьи Emrullah Luleci, а также её продолжения.
Нижний экран (Здесь и далее под «нижним экраном/слоем» будет подразумеваться элемент bottom sheet — прим. пер.) — компонент, выезжающий снизу экрана, который используется для отображения дополнительного контента. Подробнее об этом элементе можно узнать на официальной сайте посвященном материальному дизайну.
![image](https://d262ilb51hltx0.cloudfront.net/max/800/1*rVXVKtX9iaj-JEmSWoor8Q.gif)
Зависимости
Для использования этого элемента, добавьте последние версии библиотек поддержки в свой проект:
dependencies {
//замените X.X.X номером последней версии
compile 'com.android.support:appcompat-v7:X.X.X'
compile 'com.android.support:design:X.X.X'
}
Создайте класс наследник от AppCompatActivity:
public class ButtonActivity extends AppCompatActivity {
...
}
Создание макетов
Содержимое нижнего экрана
Для удобства воспользуемся макетами. Назовем файл с нижним слоем bottom_sheet.xml.
bottom_sheet.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/bottom_sheet"
android:layout_width="match_parent"
android:layout_height="340dp"
android:background="@android:color/darker_gray"
android:orientation="vertical"
app:behavior_hideable="true"
app:behavior_peekHeight="80dp"
app:layout_behavior="android.support.design.widget.BottomSheetBehavior">
<TextView
android:layout_width="match_parent"
android:layout_height="80dp"
android:background="@color/colorAccent"
android:gravity="center"
android:text="@string/bottom_sheet_peek"
android:textColor="@android:color/white" />
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="@string/bottom_sheet_content"
android:textColor="@android:color/white" />
</LinearLayout>
behavior_peekHeight: Определяет высоту видимой части.
behavior_hideable: Определяет, может ли нижний экран скрываться свайпом вниз.
Container view
Создайте CoordinatorLayout в качестве корневого вью. Добавьте в него прямым наследником bottom_sheet.xml. Элементы app_bar и activity_bottom_sheet_content не имеют прямого отношения к нижнему экрану, поэтому их можно заменить или удалить.
Макет
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.androidsample.BottomSheetActivity">
<!-- подключение элемента app bar -->
<include layout="@layout/app_bar" />
<!-- подключение основного контента -->
<include layout="@layout/activity_bottom_sheet_content" />
<!-- подключение нижнего экрана -->
<include layout="@layout/bottom_sheet" />
</android.support.design.widget.CoordinatorLayout>
На данном этапе нижний экран должен работать примерно так:
![image](https://d262ilb51hltx0.cloudfront.net/max/800/1*9KAX6CSzpBKwN7v4NHc2BQ.gif)
Динамическое управление
Поведением и свойствами нижнего экрана можно также управлять динамически с помощью Java.
Спойлер
// получение вью нижнего экрана
LinearLayout llBottomSheet = (LinearLayout) findViewById(R.id.bottom_sheet);
// настройка поведения нижнего экрана
BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(llBottomSheet);
// настройка состояний нижнего экрана
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
// настройка максимальной высоты
bottomSheetBehavior.setPeekHeight(340);
// настройка возможности скрыть элемент при свайпе вниз
bottomSheetBehavior.setHideable(false);
// настройка колбэков при изменениях
bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
}
});
Прикрепление элементов к нижнему экрану
Также можно прикрепить вью к нижнему экрану, чтобы прикрепленный элемент перемещался одновременно с нижним слоем.
![image](https://d262ilb51hltx0.cloudfront.net/max/600/1*baeTzc730xwWNqBDLxbVfA.gif)
Добавим Floating Action Button в макет созданный выше. Новый компонент должен являться непосредственным наследником CoordinatorLayout также как и bottom_sheet. Для прикрепления элемента к нижнему экрану необходимо добавить app:layout_anchor с id вью нижнего экрана, а также app:layout_anchorGravity со значением top|end.
Макет
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.androidsample.BottomSheetActivity">
<!-- подключение элемента app bar -->
<include layout="@layout/app_bar" />
<!-- подключение основного контента -->
<include layout="@layout/activity_bottom_sheet_content" />
<!-- подключение нижнего экрана -->
<include layout="@layout/bottom_sheet" />
<android.support.design.widget.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/activity_vertical_margin"
android:src="@drawable/ic_add_shopping_cart_white_24dp"
android:theme="@style/PrimaryActionButton"
app:layout_anchor="@+id/bottom_sheet"
app:layout_anchorGravity="top|end" />
</android.support.design.widget.CoordinatorLayout>
Теперь плавающая кнопка закреплена в верхнем углу нашего нижнего экрана и перемещается вместе с ним.
Скрытие плавающей кнопки при скроле
Для скрытия кнопки при скроле необходимо добавить слушатель к нижнему экрану и отображать/скрывать кнопку. Для начала найдем необходимые вью:
Спойлер
fab = findViewById(R.id.fab);
View llBottomSheet = findViewById(R.id.bottom_sheet);
// настройка поведения нижнего экрана
BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(llBottomSheet);
Если хотите, чтоб кнопка масштабировалась во время скрола, используйте это:
// настройка колбэков при изменениях
bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
fab.animate().scaleX(1 - slideOffset).scaleY(1 - slideOffset).setDuration(0).start();
}
});
Для скрытия кнопки в момент начала скрола и отображения после полного сворачивания нижнего экрана, используйте следующее:
Спойлер
// настройка колбэков при изменениях
bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
// этот код скрывает кнопку сразу же
// и отображает после того как нижний экран полностью свернется
if (BottomSheetBehavior.STATE_DRAGGING == newState) {
fab.animate().scaleX(0).scaleY(0).setDuration(300).start();
} else if (BottomSheetBehavior.STATE_COLLAPSED == newState) {
fab.animate().scaleX(1).scaleY(1).setDuration(300).start();
}
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
}
});
Результат обоих вариантов можно увидеть ниже:
![image](https://d262ilb51hltx0.cloudfront.net/max/800/1*s9xRCClsmwD6lqCinm5BWw.gif)
Вот и всё!
Поделиться с друзьями
Комментарии (7)
ittakir
05.09.2016 16:57В новом мобильном 2ГИС есть такая панелька.
Бесит неимоверно тем, что анимацию сдвига они считают самостоятельно и короткое резкое движение пальцем ни к чему не приводит (панелька прыгает на пару пикселей и возвращается назад).
Хотя, если она будет работать также, как и весь остальной UI Android (верхняя панель, разблокировка экрана), то может и нормально будет.andreich
06.09.2016 11:13боюсь, что в 2гис они полностью все сами писали, потому что там QT используется
izzholtik
А как предполагается доставать этот элемент после полного задвигания под панель навигации, которое видно в конце гифок?
GreenNick
Думаю, что програмно или по какому-нибудь событию
ArtiomCX75
Можно программно установить состояние нижнего экрана, например:
Возможные варианты: STATE_COLLAPSED, STATE_EXPANDED, STATE_HIDDEN.
Agrass
Автор заботливо оставил комментарий, я думаю если не указывать этот параметр, то шторка будет открываться во весь экран :)
StanZakharov
Из-за этого параметра в коде шторка не закрывается полностью. Поэтому его вообще лучше не юзать.