0,1
рейтинг
20 августа 2015 в 09:49

Разработка → Введение в новый CoordinatorLayout перевод

В этом году на конференции Google IO компания Google представила новую библиотеку Android Design Support Library, которая создана для того, чтобы помочь разработчикам внедрять материальный дизайн в их приложения. Билиотека содержит много компонентов, нужных для этого нового стиля, и работает со всеми уровнями API, начиная с седьмого. Если по какой-то причине вы пропустили её анонс, можете ознакомиться с постом Ian Lake, выложенным на Android Developers Blog.

Встречайте Android CoordinatorLayout


Из всех компонентов, включенных в Android Design Support Library, наиболее интересным выглядит новый «прокачанный FrameLayout», он же герой нашей статьи — CoordinatorLayout. По названию можно догадаться, что CoordinatorLayout позволяет координировать некие зависимости между включенными в него виджетами.

Всё, что нужно сделать — обернуть необходимые нам виджеты в CoordinatorLayout. Давайте посмотрим, как это будет выглядеть в коде. Наш демонстрационный код очень прост — Floating Action Button, по нажатию на которую на экране появляется Snackbar.

Сначала добавим Support Design Library в gradle:

compile 'com.android.support:design:22.2.0'

Теперь создадим разметку для нашей Activity:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="end|bottom"
        android:layout_margin="16dp"
        android:src="@drawable/ic_done" />

</android.support.design.widget.CoordinatorLayout>

И, заодно, саму MainActivity:

public class MainActivity extends AppCompatActivity {

  @Override  
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    findViewById(R.id.fab).setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view) {
        Snackbar.make(view, "Hello Snackbar", Snackbar.LENGTH_LONG).show();
      }
    });
  }
}

Посмотрим на демо:



Круто, правда?

Но что если мы захотим использовать другую реализацию FAB? FAB из Support Library не умеет разворачиваться по нажатию на неё в список доступных опций (прим. переводчика: так, как это показано в спецификациях дизайна от самой Google), поэтому давайте-ка попробуем другую реализацию FAB:

compile 'com.getbase:floatingactionbutton:1.9.1'

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.getbase.floatingactionbutton.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="end|bottom"
        android:layout_margin="16dp"
        app:fab_icon="@drawable/ic_done" />

</android.support.design.widget.CoordinatorLayout>



В этом случае CoordinatorLayout не работает из коробки, и связано это с тем, что наша новая FAB не имеет подключенной к ней реализации класса CoordinatorLayout.Behavior (прим. переводчика: далее по тексту будет использоваться слово «поведение»). Что можно сделать? Можно подождать, пока кто-нибудь не добавит её…

… или написать свою собственную реализацию CoordinatorLayout.Behavior, специфичную для FAB в нашем проекте.

Виджеты учатся вести себя правильно


Чем по-настоящему хорош CoordinatorLayout, так это тем, что нам не нужно иметь доступа к исходникам того виджета, для которого нужно реализовать его поведение. Также можно изменить поведение по умолчанию для любого виджета.

Сначала отнаследуемся от класса CoordinatorLayout.Behavior:

public class FloatingActionButtonBehavior extends CoordinatorLayout.Behavior<FloatingActionButton>

Добавим конструктор с параметрами Context и AttributeSet для того, чтобы наша реализация могла получить необходимые ей аттрибуты из xml-файла:

public FloatingActionButtonBehavior(Context context, AttributeSet attrs) {}

Следующий шаг — переопределить метод layoutDependsOn() и возвращать true только тогда, когда мы хотим отреагировать на происходящие в разметке изменения. В нашем случае, мы хотим реагировать только на изменения виджета Snackbar:

@Override
public boolean layoutDependsOn(CoordinatorLayout parent, FloatingActionButton child, View dependency) {
  return dependency instanceof SnackbarLayout;
}

Теперь перейдем к реализации поведения. Метод onDependentViewChanged вызывается всякий раз, когда с виджетом, который находится в CoordinatorLayout и изменения которого мы отслеживаем, что-то происходит (прим. переводчика: имеются в виду изменения, приводящие к тому, что нужно пересчитать положение на экране виджета, для которого мы реализуем поведение, то есть понятно, что изменение, скажем, цвета Snackbar нас никак не интересует). В этом методе мы можем узнать текущее состояние Snackbar, и, соответственно, подвинуть FAB вверх, когда Snackbar появляется на экране. Для этого нужно изменить значение translationY у FAB на величину, равную высоте Snackbar. В начале анимации Snackbar, свойство translationY SnackBar'a выставлено в величину, равную высоте самого Snackbar, а значит, чтобы получить правильное значение translationY для FAB, нам нужно вычесть высоту Snackbar из его же translationY. Согласно документации, нам нужно вернуть true тогда, когда объект меняет своё положение на экране.

@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton child, View dependency) {
  float translationY = Math.min(0, dependency.getTranslationY() - dependency.getHeight());
  child.setTranslationY(translationY);
  return true;
}

Последнее, что остаётся сделать — указать, что CoordinatorLayout должен использовать FloatingActionButtonBehavior. Сделать это можно в разметке:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.getbase.floatingactionbutton.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="end|bottom"
        android:layout_margin="16dp"
        app:layout_behavior="com.getbase.coordinatorlayoutdemo.FloatingActionButtonBehavior"
        app:fab_icon="@drawable/ic_done" />

</android.support.design.widget.CoordinatorLayout>

И вот результат:



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

Хотите взглянуть на полную реализацию? Вам на github.

Приятного вам кодинга!
Перевод: Grzesiek Gajewski
Артём Гапченко @artemgapchenko
карма
43,0
рейтинг 0,1
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (5)

  • 0
    Разработчики конечно постарались, молодцы, отличное обновление. Ну и автору спасибо за статью.
    P.S.: Это только я не успеваю из-за работы над кучей проектов следить за последними обновлениями? :))
    • 0
      Когда увидел, что вместе с 23 SDK добавили еще несколько support библиотек, то о том же подумал.
      • +1
        наконец-то преференсы и процентный лейаут, надо пробовать.
        • +1
          Я, кстати, так и не понял, в чем отличие процентных лэйаутов от LinearLayout с weights. А библиотека preferences оказалась мне не релевантна — там PreferenceFragment наследуются от android.app.Fragment (так как добавлены в support library v14), а у меня приложение целиком построено на android.support.v4.app.Fragment, которые, соответственно, умеют работать только с support activity и support fragment manager.
          • 0
            PreferenceFragment наследуются от android.app.Fragment

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

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

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