Binding Adapters, создание пользовательских атрибутов
На прошлом уроке мы изучали обработку пользовательских событий ввода и работу с наблюдаемыми данными (observable data), при изменении которых будет меняться их представление.
В этом уроке рассмотрим создание кастомных атрибутов, а также использование нескольких параметров для Binding Adapters.
Когда вы связываете строку (или наблюдаемую строку) с android:text
атрибутом, становится совершенно очевидно, что произойдет, но каким образом это происходит?
Благодаря библиотеке привязки данных почти все вызовы пользовательского интерфейса выполняются в статических методах, называемых адаптерами привязки.
Библиотека предоставляет огромное количество связывающих адаптеров. Посмотрите их здесь . Вот пример для атрибута android:text
:
@BindingAdapter("android:text") public static void setText(TextView view, CharSequence text) { // Some checks removed for clarity view.setText(text); }
Или android:background
:
@BindingAdapter("android:background") public static void setBackground(View view, Drawable drawable) { if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) { view.setBackground(drawable); } else { view.setBackgroundDrawable(drawable); } }
В привязке данных нет магии. Все решается во время компиляции и доступно для чтения в сгенерированном коде.
Продолжим работу над индикатором выполнения в проекте их прошлого урока. Исходный код проекта можно скачать здесь.
Мы хотим, чтобы выполнялись следующие условия:
- Индикатор был невидимым, если нет лайков
- Заполнялся после 5 лайков
- Изменял цвет, если заполнен
Давайте создадим собственные адаптеры привязки для этого.
Создайте файл BindingAdapters.kt
. Неважно, где вы создадите адаптеры, библиотека их найдет. В Kotlin статические методы можно создавать, добавляя функции на верхний уровень Котлин-файла или как функции расширения класса.
Создайте внутри адаптер связывания для первого условияhideIfZero
:
@BindingAdapter("app:hideIfZero") fun hideIfZero(view: View, number: Int) { view.visibility = if (number == 0) View.GONE else View.VISIBLE }
Это обязательный адаптер, который:
- относится к атрибуту
app:hideIfZero
. - может применяться к каждому представлению (поскольку первый параметр является представлением; вы можете ограничить его определенными классами, изменив этот тип)
- принимает Integer , который возвращает выражение макета.
- Выполняет View GONE, если число равно нулю. В противном случае VISIBLE .
В макете разметки найдите индикатор выполнения и добавьте атрибут hideIfZero
:
<ProgressBar android:id="@+id/progressBar" app:hideIfZero="@{viewmodel.likes}" ...
Запустите приложение, и вы увидите, что индикатор выполнения отображается при первом нажатии кнопки. Однако нам все еще нужно изменить его значение и цвет:
Binding Adapters с несколькими параметрами
Для значения прогресса мы будем использовать адаптер привязки, который принимает максимальное значение и количество лайков. Откройте файл BindingAdapters
и добавьте это:
@BindingAdapter(value = ["app:progressScaled", "android:max"], requireAll = true) fun setProgress(progressBar: ProgressBar, likes: Int, max: Int) { progressBar.progress = (likes * max / 5).coerceAtMost(max) }
Этот адаптер привязки не используется, если какие-либо атрибуты отсутствуют. Это определяется во время компиляции. Теперь метод принимает 3 параметра (представление, к которому он применяется + количество атрибутов, определенных в аннотации).
Параметр requireAll
определяет , когда используется связывающий адаптер:
- Если
true
все элементы должны присутствовать в определении XML. - Если
false
отсутствующие атрибуты будут иметь значение null, false, если логическое значение, или 0, если примитивы.
Теперь добавьте атрибуты в XML:
<ProgressBar android:id="@+id/progressBar" app:hideIfZero="@{viewmodel.likes}" app:progressScaled="@{viewmodel.likes}" android:max="@{100}" ...
Мы привязываем атрибут progressScaled
к количеству лайков и просто передаем целое число в атрибут max
. Если вы не добавите формат @{}
, привязка данных не сможет найти правильный адаптер привязки.
Если вы запустите приложение, вы увидите, как индикатор выполнения заполняется, как и ожидалось.
Практика создания Binding Adapters
Практика помогает закрепить материал. В качестве домашнего задания создайте:
- Адаптер связывания, который окрашивает цвет индикатора выполнения в зависимости от значения лайков и добавляет соответствующий атрибут
- Адаптер связывания, который показывает различный значок в зависимости от популярности:
ic_person_black_96dp
в черном цветеic_whatshot_black_96dp
в светло-розовом цветеic_whatshot_black_96dp
в насыщенном розовом цвете
На этом наш урок подошел к концу.
Исходный код проекта можно скачать здесь.
До встречи на следующем уроке, всем добра.
Урок 11. Принципы навигации внутри и между андроид-приложениями
Виталий, ДЗ выполнил но значок не меняется, подскажите пожалуйста в чём ошибка? – https://drive.google.com/open?id=125uOUhihvcU6_WR8NVlo47jBTuPeeboa
Разобрался бы сам, но не понимаю как отлаживать программу с BindingAdapters, эта же система работает на этапе компиляции, а отладчик работает только после компиляции.
В исходном проекте работает? Сверьте ваш код с исходниками. Я бы сделал то же самое.
Виталий, у вас ошибка в тексте урока:
ic_whatshot_black_96dp в светло-розовом цвете
ic_whatshot_black_96dp в насыщенном розовом цвете
два раза повторяется одно и тоже имя файла: “ic_whatshot_black_96dp”.
А в самом проекте лежит всего два файла:
ic_person_black_96dp
ic_whatshot_black_96dp
третьего файла нет!
Это не ошибка, второй файл должен быть закрашен разными цветами