Статьи

Как использовать нижние листы с библиотекой поддержки дизайна

Одно из самых значительных изменений в дизайне Android было представлено во время конференции Google I / O 2014 года — дизайн материалов . Несмотря на то, что Google представила набор рекомендаций для своей новой философии дизайна, разработчики отвечали за внедрение новых шаблонов с нуля.

Это привело ко многим сторонним библиотекам, которые достигли целей дизайна материалов с похожими, но разными реализациями. Чтобы облегчить некоторые трудности разработки материалов, Google представил библиотеку поддержки проектирования во время основного выступления на конференции Google I / O 2015 года .

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

Для реализации нижнего листа у вас есть два варианта: представление контейнера с BottomSheetBehavior в файле макета или BottomSheetDialogFragment . Чтобы использовать любой из них, вам необходимо импортировать в ваш проект библиотеку поддержки проектирования с минимальной версией 23.2 . Вы можете сделать это в build.gradle , включив следующую строку в dependencies :

1
compile ‘com.android.support:design:23.2.0’

После синхронизации проекта с библиотекой поддержки проектирования вы можете открыть файл макета, который должен содержать нижний лист. В нашем примере проекта я использую следующий XML, который отображает три кнопки в activity_main.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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
<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»>
 
    <ScrollView
        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»>
 
            <Button
                android:id=»@+id/button_1″
                android:layout_width=»match_parent»
                android:layout_height=»wrap_content»
                android:text=»Button 1″
                android:padding=»16dp»
                android:layout_margin=»8dp»
                android:textColor=»@android:color/white»
                android:background=»@android:color/holo_green_dark»/>
 
            <Button
                android:id=»@+id/button_2″
                android:layout_width=»match_parent»
                android:layout_height=»wrap_content»
                android:padding=»16dp»
                android:layout_margin=»8dp»
                android:text=»Button 2″
                android:textColor=»@android:color/white»
                android:background=»@android:color/holo_blue_light»/>
 
            <Button
                android:id=»@+id/button_3″
                android:layout_width=»match_parent»
                android:layout_height=»wrap_content»
                android:padding=»16dp»
                android:layout_margin=»8dp»
                android:text=»Button 3″
                android:textColor=»@android:color/white»
                android:background=»@android:color/holo_red_dark»/>
 
        </LinearLayout>
 
    </ScrollView>
 
    <android.support.v4.widget.NestedScrollView
        android:id=»@+id/bottom_sheet»
        android:layout_width=»match_parent»
        android:layout_height=»350dp»
        android:clipToPadding=»true»
        android:background=»@android:color/holo_orange_light»
        app:layout_behavior=»android.support.design.widget.BottomSheetBehavior»
        >
 
        <TextView
            android:layout_width=»match_parent»
            android:layout_height=»match_parent»
            android:text=»@string/ipsum»
            android:padding=»16dp»
            android:textSize=»16sp»/>
 
    </android.support.v4.widget.NestedScrollView>
 
</android.support.design.widget.CoordinatorLayout>

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

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

В файле макета есть несколько ключевых моментов, о которых вам нужно знать. Чтобы использовать виджет нижних листов, вы должны использовать контейнер CoordinatorLayout для представлений. Внизу файла вы заметили, что есть NestedScrollView содержащий TextView . Хотя любое представление контейнера можно использовать на нижнем листе, прокрутка может происходить надлежащим образом, только если вы используете контейнер, поддерживающий вложенную прокрутку, например NestedScrollView или RecyclerView .

Чтобы контейнер распознавался библиотекой поддержки проектирования как контейнер нижнего листа, необходимо включить атрибут layout_behavior и присвоить ему значение android.support.design.widget.BottomSheetBehavior . Вы можете видеть это, использованное выше в NestedScrollView .

Другим ключевым атрибутом, который следует отметить для контейнера нижнего листа, является layout_height . Какими бы ни были размеры вашего элемента контейнера, он контролирует отображение нижнего листа. Есть одна оговорка, о которой следует помнить с высотой нижнего листа. Если вы используете CoordinatorLayout для перемещения других объектов View , например, с помощью CollapsingToolbarLayout , то высота вашего нижнего листа изменится. Это может вызвать нежелательный эффект прыжка.

После того, как вы добавили контейнер вида и правильно настроили его в файле макета, вы можете открыть действие или Fragment который использует нижний лист. В примере проекта это MainActivity.java .

Чтобы ваш нижний лист отображался, вам нужно создать BottomSheetBehavior . Это создается путем получения ссылки на представление контейнера и вызова BottomSheetBehavior.from() для этого контейнера. В этом примере вы также ссылаетесь на три кнопки из макета и вызываете на них setOnClickListener() .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
private BottomSheetBehavior mBottomSheetBehavior;
 
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
 
    View bottomSheet = findViewById( R.id.bottom_sheet );
    Button button1 = (Button) findViewById( R.id.button_1 );
    Button button2 = (Button) findViewById( R.id.button_2 );
    Button button3 = (Button) findViewById( R.id.button_3 );
 
    button1.setOnClickListener(this);
    button2.setOnClickListener(this);
    button3.setOnClickListener(this);
 
    mBottomSheetBehavior = BottomSheetBehavior.from(bottomSheet);
}

Теперь, когда вы создали BottomSheetBehavior , последнее, что вам нужно сделать, это показать свой нижний лист View . Вы можете сделать это, установив состояние вашего BottomSheetBehavior в STATE_EXPANDED , что мы делаем в примере приложения при нажатии верхней Button .

1
2
3
4
5
6
7
8
9
@Override
public void onClick(View v) {
    switch( v.getId() ) {
        case R.id.button_1: {
            mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
            break;
        }
    }
}

Когда это будет сделано, ваше приложение должно выглядеть так:

Расширенный нижний лист

Чтобы скрыть нижний лист, пользователь может провести его вниз, чтобы скрыть от экрана, или вы можете установить BottomSheetBehavior в STATE_COLLAPSED .

Возможно, вы заметили, что в различных приложениях и виджетах для Android от Google, таких как Place Picker из Places API , шаблон нижнего листа используется для отображения предварительного просмотра нижнего листа, который можно развернуть для получения дополнительной информации. Этого можно достичь с помощью нижнего листа библиотеки поддержки проектирования, установив свернутый размер представления с помощью setPeekHeight() . Если вы хотите показать более короткую версию нижнего листа, вы можете установить для BottomSheetBehavior значение STATE_COLLAPSED .

1
2
mBottomSheetBehavior.setPeekHeight(300);
mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);

Если щелкнуть среднюю кнопку, вы получите нижний лист в режиме просмотра, который можно растянуть до полной высоты, перетащив его вверх.

Нижний лист в свернутом состоянии с набором высоты взгляда

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

01
02
03
04
05
06
07
08
09
10
11
12
mBottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
    @Override
    public void onStateChanged(View bottomSheet, int newState) {
        if (newState == BottomSheetBehavior.STATE_COLLAPSED) {
            mBottomSheetBehavior.setPeekHeight(0);
        }
    }
 
    @Override
    public void onSlide(View bottomSheet, float slideOffset) {
    }
});

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

В setupDialog() вы можете накачать новый файл макета и получить BottomSheetBehavior представления контейнера в вашем Activity . Если у вас есть такое поведение, вы можете создать и связать с ним BottomSheetCallback чтобы отклонить Fragment когда лист скрыт.

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
public class TutsPlusBottomSheetDialogFragment extends BottomSheetDialogFragment {
 
    private BottomSheetBehavior.BottomSheetCallback mBottomSheetBehaviorCallback = new BottomSheetBehavior.BottomSheetCallback() {
 
        @Override
        public void onStateChanged(@NonNull View bottomSheet, int newState) {
            if (newState == BottomSheetBehavior.STATE_HIDDEN) {
                dismiss();
            }
 
        }
 
        @Override
        public void onSlide(@NonNull View bottomSheet, float slideOffset) {
        }
    };
 
    @Override
    public void setupDialog(Dialog dialog, int style) {
        super.setupDialog(dialog, style);
        View contentView = View.inflate(getContext(), R.layout.fragment_bottom_sheet, null);
        dialog.setContentView(contentView);
 
        CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) ((View) contentView.getParent()).getLayoutParams();
        CoordinatorLayout.Behavior behavior = params.getBehavior();
 
        if( behavior != null && behavior instanceof BottomSheetBehavior ) {
            ((BottomSheetBehavior) behavior).setBottomSheetCallback(mBottomSheetBehaviorCallback);
        }
    }
}

Наконец, вы можете вызвать show() для экземпляра вашего Fragment чтобы отобразить его на нижнем листе.

1
2
BottomSheetDialogFragment bottomSheetDialogFragment = new TutsPlusBottomSheetDialogFragment();
bottomSheetDialogFragment.show(getSupportFragmentManager(), bottomSheetDialogFragment.getTag());
BottomSheetDialogFragment в расширенном состоянии

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