Material Drawer: новые материалы от Google

«Всё течёт, всё меняется» — говорил когда-то Гераклит Эфесский. И если течь в наших программах вообще-то ничего не должно, то уж меняться им в любом случае приходится постоянно. Правила нашего айтишного зазеркалья никто не отменял: «нужно бежать со всех ног, чтобы только оставаться на месте, а чтобы куда-то попасть, надо бежать как минимум вдвое быстрее».

Казалось бы, прошло совсем не так уж много времени с момента написания прошлой заметки про DrawerLayout, но Google уже успел выпустить новые требования к оформлению приложений, известные как Material Design. Дизайнерам и пользователям Материал явно пришёлся по вкусу, а потому придётся ему соответствовать.

SlidingDrawer в Material на примере Gmail
SlidingDrawer в Material на примере Gmail

Собственно, на скриншоте можно увидеть все новые требования к drawer-ам:

  1. Панель должна открываться поверх action bar (а не под ним, как ранее)
  2. Панель должна «подъезжать» под status bar на Lollipop и выше.

Забегая вперёд — то и другое реализуется без особых сложностей, всё уже готово, но… как водится, некоторые хитрости придётся применить. Итак:

Prerequisites

Для начала — определимся с необходимым инструментарием.

Здесь всё не просто, а очень просто: убедитесь, что в проекте используется appcompat-v7 версии 21 и выше. Например, при сборке через gradle, это соответствует конфигурации:

Именно по версии 21 проходит принципиальный «водораздел» поддержки Lollipop вообще и Material Design в частности, потому обновиться придётся. Ну а если с настройками сборки всё уже в порядке, то можно приступать.

Gingerbread умер, но дело его живёт
Gingerbread умер, но дело его живёт: без appcompat вновь никуда

Ну а теперь можем перейти к нашему списку из двух пунктов.

1. Drawer поверх ActionBar

Первая проблема решается несложно.

Скажу сразу — обычный ActionBar не засунуть под drawer никак, от слова «совсем». В Android он рисуется как часть специального layout-а, прямого потомка GroupView, который умеет раскладывать все дочерние View только ниже action bar-а. Ну а раз этот путь тупиковый, а живые работающие приложения вполне существуют, то сразу напрашивается вывод: action bar должен быть заменён полным двойником.

Собственно, такой двойник появился в Android Lollipop (API 21), и зовут его android.widget.Toolbar. Но поскольку нас интересует совместимость приложения версиями помладше, то придётся использовать support-версию: android.support.v7.widget.Toolbar. Содрогнулись при мысли о долгом переписывании всей логики? Спокойствие!

Более-менее серьёзное изменение потребуется только в том случае, если appcompat в проекте вообще отсутствовал. Тогда — увы, потребуется перенаследоваться от ActionBarActivity. Эта задача, в принципе, сводится к прогону действия Replace in Path по проекту и не будет слишком масштабной, но можете попытаться и собственноручно интегрировать support-версию Toolbar, хотя в этом случае я уже не помощник. Ну а если библиотека уже использована и наследование уже правильное, то можно приступать.

Во-первых, выключим в теме оформления системный action bar. Например, так:

Во-вторых, добавим Toolbar в layout наших активити, внутрь DrawerLayout. Если action bar использовался раньше в обычном режиме, то удобнее всего завернуть весь контент в LinearLayout, если плавал поверх — FrameLayout, соответственно. Как-то так:

Обратите внимание, что стиль задаётся в атрибуте app:theme! Объявлен стиль тулбара в простейшем случае может быть, например, следующим образом:

В-третьих — немного магии. Всё, что потребуется сделать для восстановления работоспособности 99% приложений, — это…

…где-нибудь внутри onCreate() у активити, сразу после setContentView(). Всё! Toolbar будет завёрнут в проксирующий класс и с нашей точки зрения продолжит работать как обычный appcompat action bar.

А мы внесём необходимые изменения для второго пункта:

2. Navigation drawer, заезжающий под статусбар

Вот здесь и начинается обещанное колдунство.

Фокус в том, что на самом деле status bar в Lollipop может быть только полностью прозрачным. Соответственно, мы должны сделать его именно таким (внутри values-v21):

Далее, мы должны разрешить нашему drawer-у (который будет корневым в активити) залезать на системные панели:

А сейчас и потребуется колдовать. Видите, что status bar на скриншоте как бы полупрозрачный? Так вот, в реальности это полоска, нарисованная на самом drawer-е! И «дымчатой» верхняя панель кажется благодаря правильному подбору цветов!

Взгляните на цвета поближе, на примере того же Gmail:

Шапка Gmail

Toolbar —   ярко-красный. Status bar —   тёмно-красный. А верх drawer-а —   чёрный, с прозрачностью, примерно соответствующей разнице в яркости этих двух цветов! Именно так создаётся иллюзия «въезда под статусбар»:

Take a closer look! ©
Take a closer look! ©

Но понимать суть фокуса — половина дела, нужно ещё и грамотно нарисовать эту самую полоску. Забивать определённые значения ширины нельзя — устройства все разные, настройки accessibility — тоже, может получиться «ступенька», или вовсе нарисуется отсутствующая панель. И тут нам в помощь вновь приходит Google, подготовивший в рамках I/O специальный класс — ScrimInsetsFrameLayout (исходный код по ссылке). Он и умеет нарисовать полосу нужного размера, нам остаётся лишь задать цвет. Скачайте исходные коды, добавьте к себе в проект, поменяйте имена пакетов и не забудьте положить в res/values следующее описание атрибутов:

В итоге для всей активити получается нечто подобное:

Наконец, последнее. Напоминаю, мы решили рисовать системные панели самостоятельно и сделали их прозрачными, т.е. без нашего вмешательства — чёрными. Потому нарисуем тот цвет, который нам нужен на самом деле. К счастью, DrawerLayout это умеет:

Наконец, во многих случаях потребуется подогнать дизайн выезжающей панели в зависимости от наличия или отсутствия наверху системной области. Для этого «из коробки» предусмотрен интерфейс ScrimInsetsFrameLayout.OnInsetsCallback и, соответственно, метод setOnInsetsCallback().

И вот теперь это действительно ВСЁ!

Послесловие

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

Lollipop

Демо-исходников в этот раз не выкладываю, извините: совсем нет на это времени. Еле-еле нашлось для написания текста, да и то (наверняка!) корявого, но вычитывать уже некогда.

И — да, Material Design крут, а drawer под статусбаром меня однозначно радует. Даже жаль, что видят его лишь обладатели последних версий системы.

Но им — я уверен — такое внимание к деталям понравится!

Material Drawer: новые материалы от Google
5, голосов: 3


Комментарии:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Капча (решите пример) *