Привет, Хабрахабр! Не так давно мы подводили итоги конкурса по Material Design, и в комментариях нас просили показать реально популярные и красивые Material-приложения. Что же, встречайте: «Сбербанк Онлайн» в новом, современном интерфейсе. Про процесс создания приложения интереснее узнать от самих создателей.

Мы передаём слово команде разработчиков Android-приложения Сбербанка, чтобы вы услышали об опыте создания такой сложной штуки, как UI мобильного банк-клиента, из первых уст. Большую часть поста написал freeuser, так что спасибо говорите ему. ;)


Предыстория


Android 5, основанный на Material Design, доступен пользователям уже полтора года. 18 месяцев — срок немалый, и сейчас можно с уверенностью сказать, что и пользователям, и разработчикам пришлась по душе философия визуального языка представления информации от Google.

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

Постановка задачи


Наша основная задача — сделать удобное и понятное приложение, которым было бы приятно пользоваться. Вместе с тем, переход на Material Design позволил бы качественно улучшить и процесс разработки. То есть, программисты и дизайнеры меньше будут отвлекаться на «процесс», больше — на результате.

Единый визуальный язык, который разработали в Google, позволил меньше задумываться о том, «что делать», сосредоточившись на вопросе «как делать». И если предыдущая попытка (Holo) не остановила калькирование интерфейсов с iOS или придумывание велосипедов, то новая система (MD) практически полностью «убила» зоопарк дизайнерских изысков. Приложения не стали скучнее или однообразнее, но стали единообразнее: MD позволяет крайне свободно использовать имеющиеся инструменты и возможности визуального языка, вместе с тем сохраняя преемственность интерфейсов, что удобно и пользователям, и разработчикам. Когда все приложения работают одинаково и различные элементы интерфейса в них работают одинаково, вам не требуется привыкать к новым приложениям. Берёте и пользуетесь.

Простота, удобство для пользователя и эффективность — вот ключевые понятия, от которых мы отталкивались в работе над новым приложением.

Имеющиеся проблемы


Общие проблемы для разработки почти всегда одни и те же:
  1. Программисты не всегда внимательно относятся к макетам;
  2. Дизайнеры слабо осведомлены о том, насколько трудозатратна для программиста реализация того или иного варианта верстки;
  3. Изменения в одной разметке (layout) не масштабируются автоматом на другие.

В корне этих «общих» проблем лежат вполне конкретная беда, которую, увы, очень тяжело уладить. Дизайнеры и программисты говорят на своих языках и не понимают друг друга. В чём заключается недопонимание?
  • Программист не может смоделировать мышление дизайнера, из-за чего не может установить от чего ему отталкиваться в верстке;
  • Дизайнер не знает, какую именно информацию выдавать программисту для того, чтобы тот сверстал масштабируемо и с точным соответствием макету.

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

Далее, исполнитель верстки либо жестко забивает значения в разметку, либо заводит новый ресурс (size, color), либо пытается по значению отыскать уже имеющийся ресурс.

Жесткое зашивание значений в разметку либо несистематизированное заведение ресурсов влекут за собой невозможность повторного использования одних и тех же значений: нарушается и принцип DRY, и вообще сама логика разделения конструкции и её стилей. Работать над таким приложением примерно также «приятно», как над веб-страницей, на которой половина значений стилей указана прямо внутри div’ов.
Если встает необходимость изменить цвет текста на информационных ячейках, то необходимо пройтись по каждой разметке (при этом есть ненулевая вероятность пропустить какой-либо файл). Стоимость операции возрастает многократно при экспериментах «Последовательно проверить несколько цветов/отступов».

Наконец, если псевдоним заведен для ресурса не системным образом, то, скорее всего, его название неактуально для нового экрана, и программист вместо использования готового ресурса создаст новую сущность.

Чтобы всего этого бардака избежать, требуется наладить здоровую атмосферу в рабочем коллективе:
  1. Между программистами и дизайнерами должна быть налажена коммуникация: они должны понимать и принимать потребности и возможности друг друга;
  2. Список требуемых данных для построения универсальной и масштабируемой вёрстки приложения должен быть чётко закреплён: так программисты получат все необходимые для них значения, а дизайнеры смогут отталкиваться от имеющихся значений при построении новых экранов.


Doing it right way


Своеобразным «первым мостиком» в построении коммуникации между программистами и дизайнерами выступили Google Material Guidelines. Гайдлайны достаточно гибки, чтобы не стеснять творческую мысль дизайнера и одновременно они определяют закономерности, удобные для моделирования программистом.

Для масштабируемой верстки в OS Android используется такой инструмент как стили. Стили — это набор пар «атрибут-значение». Значениями атрибутов могут выступать цвета, ColorStateList, Drawable, текст, размеры и другие стили.

При исследовании ресурсов последних платформ и библиотеки AppCompat можно обнаружить, что стили делятся на следующие группы:
  • TextAppearance — внешний вид текстового поля. Определяют цвета текста и ссылок, подсказок в текстовом поле, фон выделенного текста, стиль и гарнитуру шрифта;
  • Widget-стиль — стиль View. Определяют специфические для конкретного виджета атрибуты (например, progressDrawable для ProgressBar), виджет-стили TextView и его наследников могут указывать используемый TextAppearance;
  • Theme — тема. Темы — это своего рода «стили стилей», стили активити; Определяют ключевые атрибуты, характерные для данного экрана, стили виджетов. Грамотно составив тему, мы избежим прямых ссылок на цвета и стили виджетов внутри разметок (layout), установим единообразный внешний вид для View в рамках приложения;
  • ThemeOverlay — занимают промежуточное положение между виджет-стилями и темами. Если обычный виджет-стиль применяется только к одному View, тема — ко всем View в пределах экрана, то ThemeOverlay проставляют на определенный контейнер (ViewGroup) в разметке. В дальнейшем мы покажем, где именно он применяется и как.


В нашем случае нормально построенный рабочий процесс выглядит так:
  1. Программисты и дизайнеры, основываясь на Google Material Guidelines, формируют единые таблицы ресурсов (далее в статье вы их увидите);
  2. Каждому ресурсу (размеру, стилю, цвету) присваивается псевдоним;
  3. Дизайнер в макете указывает именно псевдоним. По этому псевдониму программист находит ресурс (размер, стиль) и указывает его в разметке.


Свойства стилей


Прежде чем мы займемся настройкой стилей, давайте рассмотрим свойства этого инструмента поближе — чтобы воспользоваться им с максимальной эффективностью.

Наследование стилей


Стили могут наследоваться друг от друга двумя способами. Вот первый:
<style name="Theme">
   <item name="android:isLightTheme">false</item>
   <item name="android:colorBackground">@color/bright_foreground_dark</item>
</style>

<style name="Theme.Material">
   <item name="android:colorBackground">@color/foreground_material_dark</item>
</style>


Theme.Material в таком случае унаследует у родительской темы Theme значение атрибута isLightTheme и переопределит значение colorBackground.

Второй способ — указать родителя явно.

<style name="Theme.Material">
   <item name="android:isLightTheme">false</item>
</style>

<style name="Theme.AppCompat.Light.NoActionBar">
   <item name="android:isLightTheme">true</item>
</style>

<style name="Theme.Material.Sbrf" parent="Theme.AppCompat.Light.NoActionBar">
</style>


В таком случае Theme.Material.Sbrf унаследует значение атрибута isLightTheme у Theme.AppCompat.Light.NoActionBar.

Ссылки на значения атрибутов


Стили низкого уровня (TextAppearance и Widget-стили) могут ссылаться на значение атрибута, установленного темой.
Допустим, в приложении есть 2 темы: красная и желтая. Нам необходимо, чтобы на экранах с желтой темой некоторый TextAppearance задавал своим TextView желтый бэкграунд, а на экранах с красной темой — красный бэкграунд.

<style name="TextAppearance.Example" parent="TextAppearance.AppCompat.Title">
   <item name="android:textColor">?attr/colorPrimary</item>
</style>

   <style name="Theme.Example" parent="Theme.AppCompat.Light.NoActionBar">
   </style>

   <style name="Theme.Example.Red">
       <item name="colorPrimary">@color/color_primary_red</item>
       <item name="colorPrimaryDark">@color/color_primary_red_dark</item>
   </style>

   <style name="Theme.Example.Yellow">
       <item name="colorPrimary">@color/color_primary_yellow</item>
       <item name="colorPrimaryDark">@color/color_primary_yellow_dark</item>
   </style>


Пусть TextAppearance.Example проставлен на некоторый TextView.

<TextView
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:layout_gravity="center"
   android:textAppearance="@style/TextAppearance.Example"
   android:text="Test Text"/>


Тогда при применении TextAppearance для этого виджета Андроид подставит в качестве значения textColor именно то значение colorPrimary, которое прописано в данной теме.




Настройка стилей и тем


Основные цвета приложения


Рассмотрим атрибуты, указывающие основные цвета приложения.

Атрибут
Назначение
colorPrimary
Главный цвет приложения. Обычно в него красят AppBar
colorPrimaryDark
Более темная версия главного цвета — используется для статус-бара
colorAccent
Акцентный цвет приложения. Используется косвенным образом для кнопок, SeekBar, ProgressBar
android:colorBackground
Дефолтный цвет фона
android:colorForeground
Противоположность вторичному цвету фона
android:colorForegroundInverse
Вторичный цвет фона
dividerHorizontal
Цвет горизонтального разделителя
dividerVertical
Цвет вертикального разделителя


У Сбербанка есть брендбук, в соответствии с которым требуется оформлять всё: печатную продукцию, интернет-рекламу, сайты, визитки, пакеты и т.д. Официальные цвета регламентированы, их «ближайшие аналоги» — тоже. В соответствии с брендбуком Главным цветом (colorPrimary) для нашего приложения стал зелёный, а Акцентным (colorAccent) — оранжевый. Кроме того, colorPrimary относился к позитивным действиям (подтверждение, покупка), а colorAccent, как правило, — к негативным (отмена).

Стилизация TextView


Настало время разобраться с цветами для текстов, которые предлагаются библиотекой AppCompat. Всего есть две темы (тёмная и светлая), в каждой из которых есть две группы цветов: стандартные и инвертированные. Для тёмной темы (наследницы Theme.AppCompat) стандартными будут светлые оттенки, инвертированными — тёмные. Для светлой темы (которая также наследует значения у Theme.AppCompat), соответственно, наоборот.

Заданные библиотекой цвета имеют свои «названия» и функциональные назначения:
  • textColorPrimary — наиболее «сочная» форма цвета.
  • textColorSecondary — чуть более бледная форма цвета.
  • textColorTertiary — еще более бледная форма.
  • textColorHint — цвет подсказок в EditText.
  • textColorLink — цвет ссылок.
  • textColorHighlight — цвет фона выделенного текста.
  • textColorPrimaryActivated — в обычном состоянии то же, что и textColorPrimary, в активированном состоянии — textColorPrimaryInverse
  • textColorSecondaryActivated — аналогично textColorPrimaryActivated, только со вторичным цветом.


Кроме того, есть цвета с «жутковатыми» названиями типа textColorPrimaryDisableOnly (используются для текста CompoundButton’ов: радиокнопки, чекбоксы), или textColorPrimaryNoDisable, textColorSecondaryDisableOnly, textColorSecondaryNoDisable — использование последних трех в стилях и Text Appearance обнаружить не удалось.

Мы составили таблицу цветов, используемых в приложении. Каждому атрибуту мы поставим значением ColorStateList — пару из цветов для доступного элемента и недоступного:

Атрибут
Цвет обычного состояния
Цвет недоступного состояния (disabled-элементов)
textColorPrimary
#E6000000 (90% черного)
#44000000 (26% черного)
textColorSecondary
#CC000000 (80% черного)
#44000000 (26% черного)
textColorTertiary
#88000000 (53% черного)
#44000000 (26% черного)
textColorHint
#61000000 (38% черного)
#19000000 (10% черного)
textColorPrimaryInverse
#FFFFFFFF (100% белого)
#44FFFFFF (26% белого)
textColorSecondaryInverse
#E8FFFFFF (91% белого)
#44FFFFFF (26% белого)
textColorTertiaryInverse
#96FFFFFF (59% белого)
#44FFFFFF (26% белого)
textColorHintInverse
#61FFFFFF (38% белого)
#19FFFFFF (10% белого)


Для наглядного отображения текстовой информации AppCompat работает не только с цветами, но и с размером шрифта и его начертанием. Данный набор параметров называется TextAppearance.
Название
Цвет текста
Размер шрифта
Гарнитура шрифта
Caption
Secondary
12sp
Regular
Body1
Primary
14sp
Regular
Body2
Primary
14sp
Medium
Button
Primary
14sp
Medium
Subhead
Primary
16sp
Regular
Menu
Primary
16sp
Medium
Title
Primary
20sp
Medium
Headline
Primary
24sp
Regular
Display1
Secondary
34sp
Regular
Display2
Secondary
45sp
Regular
Display3
Secondary
56sp
Regular
Display4
Secondary
112sp
Light

Хоть в таблице это и не указано, но для Title и для Menu определены также инвертированные Text Appearance.

Наглядные примеры правильно сформированных Text Appearance можно увидеть в спецификации гайдлайнов Google Material Design. На основе этих стилей и информации из гайдлайнов разработчики совместно с дизайнерами создали следующее семейство Text Appearance:

Название
Цвет текста
Размер шрифта
Гарнитура шрифта
Caption
Tertiary
12sp
Regular
Hint
Hint
14sp
Regular
Subheader
Tertiary
14sp
Medium
Button
Primary
14sp
Medium
Body0
Tertiary
14sp
Regular
Body1
Secondary
14sp
Regular
Body2
Primary
16sp
Regular
Body3
Secondary
16sp
Medium
Input1
Primary
20sp
Regular
Input2
Tertiary
20sp
Regular
Title
Primary
20sp
Medium
Headline
Primary
24sp
Regular
Display1
Primary
32sp
Regular
Display2
Tertiary
32sp
Regular


Из каждого TextAppearance, приведенного выше (за исключением Button), мы формируем Inverse, Primary и Accent-варианты (для цвета текста используются заданные ранее значения атрибутов textColor*Inverse, colorPrimary, colorAccent).

Когда дизайнеры передают нам макеты, то напротив текстовых полей (TextView) они указывают сокращенное имя «Title Default» соответствует TextAppearance.Material.Sbrf.Title, а «Subheader Inverse» соответствует TextAppearance.Material.Sbrf.Subheader.Inverse.



Стилизация EditText


С цветами и оформлением текста мы более-менее разобрались, и осталось ещё одно место, в котором надо всё привести в порядок: речь идёт о элементах EditText и TextInputLayout. Проблема в том, что «тема по умолчанию» выглядит неаккуратно, и её надо причесать по фен-шую. :)



Для невнимательных поясним:
  1. Линия EditText в несфокусированном и задисейбленном состоянии должна быть бледнее;
  2. Линия EditText в сфокусированном состоянии должна быть сплошной зелёной (colorPrimary), а не черной-оранжевой;
  3. Ошибка выделяется оранжевым цветом (colorAccent), а не красным;.
  4. Размер шрифта EditText-а должен быть крупнее.


Внутри библиотеки AppCompat мы обнаружили что при создании View из разметки AppCompatActivity подменяет определенные виджеты на их AppCompat-наследников. Делается это, судя по всему, для поддержки background tinting и подтягивания стилей из AppCompat-тем. В частности, EditText заменяется на AppCompatEditText. (Следовательно, если вам нужен кастомный виджет, то создавать подкласс нужно не непосредственно из EditText, а из AppCompatEditText).

Стиль AppCompatEditText-у задается в теме через атрибут editTextStyle. По умолчанию стиль — Widget.AppCompat.EditText, задающий определенный TextAppearance, фон и цвет текста (то есть, цвет из TextAppearance игнорируется).

Взглянем на разметку бэкграунда EditText-а для версии 5.0 (для старых версий background в целом похож, разница только в том, где происходит его подкрашивание (tinting) — в самой разметке, как на 5.x, или в конструкторе виджета на более ранних версиях).

<inset xmlns:android="http://schemas.android.com/apk/res/android"
      android:insetLeft="@dimen/edit_text_inset_horizontal_material"
      android:insetRight="@dimen/edit_text_inset_horizontal_material"
      android:insetTop="@dimen/edit_text_inset_top_material"
      android:insetBottom="@dimen/edit_text_inset_bottom_material">
   <selector>
       <item android:state_enabled="false">
           <nine-patch android:src="@drawable/textfield_default_mtrl_alpha"
               android:tint="?attr/colorControlNormal"
               android:alpha="?attr/disabledAlpha" />
       </item>
       <item android:state_pressed="false" android:state_focused="false">
           <nine-patch android:src="@drawable/textfield_default_mtrl_alpha"
               android:tint="?attr/colorControlNormal" />
       </item>
       <item>
           <nine-patch android:src="@drawable/textfield_activated_mtrl_alpha"
               android:tint="?attr/colorControlActivated" />
</item>
</selector>
</inset>


А вот сами ресурсы textfield_default_mtrl_alpha и textfield_activated_mtrl_alpha:

     


Как видно из разметки, тонкая линия подкрашивается цветом, являющимся значением атрибута colorControlNormal. Заменим этот цвет.

<color name="color_control_normal">#1A000000</color>

<style name="Theme.Material.Sbrf" parent="@style/Theme.AppCompat.Light.NoActionBar">
<item name="colorControlNormal">@color/color_control_normal</item>
</style>


За сфокусированное состояние (а также за цвет курсора и text-select-handle-ов) отвечает colorControlActivated — изменим и его, пусть он имеет то же значение, что и colorPrimary:

<style name="Theme.Material.Sbrf" parent="@style/Theme.AppCompat.Light.NoActionBar">
<item name="colorControlActivated">?attr/colorPrimary</item>
</style>


Размер шрифта EditText-а — задаётся через TextAppearance.

<style name="TextAppearance.Material.Sbrf.EditText" parent="@style/TextAppearance.Material.Sbrf.Input1">
</style>

<style name="Widget.Material.Sbrf.EditText" parent="@style/Widget.AppCompat.EditText">
<item name="android:textAppearance">@style/TextAppearance.Material.Sbrf.EditText</item>
</style>

<style name="Theme.Material.Sbrf" parent="@style/Theme.AppCompat.Light.NoActionBar">
<item name="editTextStyle">@style/Widget.Material.Sbrf.EditText</item>
</style>


Результат:


Со стилизацией EditText покончено. Настало время TextInputLayout. По умолчанию он применяет к себе стиль Widget.Design.TextInputLayout, извлекая из него следующие атрибуты:
  • hintTextAppearance — TextAppearance плавающего лейбла (на нашем скрине в нем написано слово «Подсказка») в сфокусированном состоянии;
  • android:textColorHint — цвет плавающего лейбла в несфокусированном состоянии, цвет подсказки в EditText. Если значение атрибута у TextInputLayout не указано, то подтянется значение этого же атрибута у EditText;
  • android:hint — собственно текст плавающего лейбла, перегружает подсказку самого EditText;
  • hintAnimationEnabled — применять ли анимацию при «переходе» подсказки из EditText-а в плавающий лейбл.
  • errorTextAppearance — TextAppearance лейбла с ошибкой. В данном случае подкрашивается линия EditText-а;
  • errorEnabled — следует ли при отрисовке TextInputLayout заранее закладывать место под лейбл с ошибкой;
  • counterTextAppearance — TextAppearance счетчика длины текста.
  • counterEnabled — следует ли при отрисовке TextInputLayout показывать счетчик длины текста.
  • counterMaxLength — максимально допустимая длина текста.
  • counterOverflowTextAppearance — TextAppearance индикатора ошибки превышения длины текста.


Составим таблицу свойств TextAppearance вспомогательных TextView. Все они наследуются от TextAppearance.AppCompat.Caption (textColorSecondary, 12sp, regular), изменяется только цвет.

Название
Цвет текста
TextAppearance.Design.Hint
?attr/colorControlActivated
TextAppearance.Design.Error
#FFDD2C00
TextAppearance.Design.Counter
?attr/colorControlActivated
TextAppearance.Design.Counter.Overflow
#FFDD2C00



Дальше всё просто: заменим цвет текста на colorAccent:

<style name="TextAppearance.Material.Sbrf.Error" parent="@style/TextAppearance.Material.Sbrf.Caption">
<item name="android:textColor">?attr/colorAccent</item>
</style>


Применим этот TextAppearance в стиле TextInputLayout:

<style name="Widget.Material.Sbrf.TextInputLayout" parent="@style/Widget.Design.TextInputLayout">
<item name="errorTextAppearance">@style/TextAppearance.Material.Sbrf.Error</item>
</style>


Применим свежесозданный стиль к TextInputLayout в разметке. Вот что у нас получилось:



Напоследок внесем важное улучшение. Обычно для каждого виджета существует атрибут в теме, по которому он в своем конструкторе может взять актуальный для данной темы стиль. TextInputLayout (как и другие виджеты библиотеки Design) такого атрибута в теме не имеет. Введем его на стороне приложения:

<declare-styleable name="Theme.Material.Sbrf">
<attr name="textInputLayoutStyle" format="reference"/>
</declare-styleable>


Внедрим его в тему:

<style name="Theme.Material.Sbrf" parent="@style/Theme.AppCompat.Light.NoActionBar">
<item name="textInputLayoutStyle">@style/Widget.Material.Sbrf.TextInputLayout</item>
</style>


Теперь мы можем по этому атрибуту подтягивать стиль виджета в разметке:

<android.support.design.widget.TextInputLayout
style="?attr/textInputLayoutStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content">


Стилизация AppBar-а


С текстовыми полями, шрифтами и цветами мы справились. Осталась ещё пара важных элементов, в которых надо навести порядок: AppBar и Toolbar. В типичном Activity при использовании Material-дизайна верхняя панель по стилю отличается от контента Activity: она отличается другим фоном, другим цветом текста. Google предполагает, что мы для этого будем пользоваться атрибутом actionBarTheme. С ним и будем работать.

Атрибут actionBarTheme ссылается на ThemeOverlay — своего рода мини-тему, применяемую к отдельному ViewGroup, его дочерним элементам, их дочерним элементам и так далее. При применении ThemeOverlay одноименные атрибуты темы Activity получают новое значение. Для большей наглядности рассмотрим 3 скриншота: на первом к верхнему бару и виджетам в нем не применяются ни стиль, ни ThemeOverlay, на втором применяются зелёный стиль и ThemeOverlay с белым текстом, на третьем — белый стиль и ThemeOverlay с зелёным текстом.



Цвет фона AppBarLayout. В ресурсах библиотеки Design указано, что Background этого виджета красится в первичный цвет приложения (colorPrimary). Создадим стили для AppBarLayout:

<style name="Widget.Material.Sbrf.AppBarLayout" parent="@style/Widget.Design.AppBarLayout">
</style>

<style name="Widget.Material.Sbrf.AppBarLayout.Colored">
</style>

<style name="Widget.Material.Sbrf.AppBarLayout.White">
   <item name="android:background">?android:attr/colorForegroundInverse</item>
</style>


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

Стиль TabLayout. Решается аналогично задаче с AppBarLayout.

Цвет иконок в toolbar’е задается посредством атрибута colorControlNormal. Однако, здесь есть некоторые проблемы, которые надо решить. Цвет colorControlNorman мы использовали для линии EditText-а в несфокусированном состоянии (автоматом цвет также применился для цвета незаполненного прогресса в детерминированном ProgressBar и в SeekBar). ThemeOverlay с белым текстом переопределяет colorControlNormal как #FFFFFF (белый). ThemeOverlay с зелёным переопределяет colorControlNormal как ?attr/colorPrimary (у нас он, как вы помните, зелёный).
Определим ThemeOverlay.

<style name="Theme.Material.Sbrf" parent="@style/Theme.AppCompat.Light.NoActionBar">
   <item name="colorControlNormal">@color/color_control_normal</item>
   <item name="appBarLayoutStyle">@style/Widget.Material.Sbrf.AppBarLayout</item>
</style>

<style name="Theme.Material.Sbrf.Colored">
<i></i>   <item name="actionBarTheme">@style/ThemeOverlay.Material.Sbrf.ActionBar.Colored</item>
   <item name="appBarLayoutStyle">@style/Widget.Material.Sbrf.AppBarLayout.Colored</item>
</style>

<style name="Theme.Material.Sbrf.WhiteActionBar">
<i></i>   <item name="actionBarTheme">@style/ThemeOverlay.Material.Sbrf.ActionBar.White</item>
   <item name="appBarLayoutStyle">@style/Widget.Material.Sbrf.AppBarLayout.White</item>
</style>

<style name="ThemeOverlay.Material.Sbrf" parent="@style/ThemeOverlay.AppCompat.Light">
   <item name="colorControlNormal">@color/color_control_normal</item>
</style>

<style name="ThemeOverlay.Material.Sbrf.ActionBar">
<i></i>   <item name="searchViewStyle">@style/Widget.AppCompat.SearchView.ActionBar</item>
</style>

<style name="ThemeOverlay.Material.Sbrf.ActionBar.Colored">
<i></i>   <item name="colorControlNormal">?android:attr/textColorPrimaryInverse</item>
</style>

<style name="ThemeOverlay.Material.Sbrf.ActionBar.White">
<i></i>   <item name="android:colorForeground">@color/color_foreground</item>
   <item name="android:colorForegroundInverse">@color/color_foreground_inverse</item>
   <item name="colorControlNormal">?attr/colorPrimary</item>
</style>


И применим их в разметке:

<android.support.design.widget.AppBarLayout
   android:id="@+id/app_bar_layout"
   style="?attr/appBarLayoutStyle"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   app:theme="?attr/actionBarTheme">

   <android.support.v7.widget.Toolbar
       android:id="@+id/toolbar"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"/>

<i></i>   <android.support.design.widget.TabLayout
       android:id="@+id/tab_layout"
       style="?attr/tabLayoutStyle"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:clipToPadding="false"
       android:paddingLeft="0dp"
       app:tabMode="fixed"/>
</android.support.design.widget.AppBarLayout>


Отступ текста в toolbar’е от левого края. Google Material Guidelines предписывают его выставлять в 72dp, если есть кнопка Up, и 16dp, если её нет. Как вариант, мы можем в двух разных темах для таких Activity проставить два разных стиля toolbar’а с двумя разными отступами. Мы решили не менять весь стиль из-за одного незначительного параметра, а менять сам этот параметр.

Заведем новый атрибут в теме:

   <<b>declare-styleable name="Theme.Material.Sbrf"</b>>
       <<b>attr name="toolbarContentInsetStart" format="dimension"</b>/>
   </<b>declare-styleable</b>>


Определим новый стиль toolbar’а:

<style name="Widget.Material.Sbrf.Toolbar" parent="@style/Widget.AppCompat.Toolbar">
   <item name="contentInsetLeft">?attr/toolbarContentInsetStart</item>
   <item name="contentInsetStart">?attr/toolbarContentInsetStart</item>
</style>


Определим новый атрибут в 2 темах, в родительской теме переопределим стиль toolbar’а.

<style name="Theme.Material.Sbrf" parent="@style/Theme.AppCompat.Light.NoActionBar">
<item name="toolbarContentInsetStart">72dp</item>
<item name="toolbarStyle">@style/Widget.Material.Sbrf.Toolbar</item>
</style>
<style name="Theme.Material.Sbrf.Colored">
  <i><!-- Здесь мы переопределим различные атрибуты, специфичные для данной темы --></i>
</style>

<style name="Theme.Material.Sbrf.Colored.IconlessList">
<i></i>   <item name="toolbarContentInsetStart">16dp</item>
</style>


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

Цвет текста в toolbar’е. В стилях AppCompat по умолчанию задан цвет для текста: textColorPrimary. В самой теме textColorPrimary заведён как 90% черный. зелёный ThemeOverlay переопределяет textColorPrimary как 100% белый. Белый ThemeOverlay переопределяет его как ?attr/colorPrimary.

Ограничения ThemeOverlay. Не применяются к View фрагментов, лежащих внутри AppBarLayout.

Заключение


Приложение стало доступно в Google Play на днях, и самое время подвести итоги наших реформ.

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

Программисты понимают, от чего отталкиваются и что подразумевают дизайнеры при решении UX-задач. Они учитывают это при стилизации виджета. Например, если дизайнер отрисовал зелёную кнопку на макете, то в приложении должен быть не безликий кирпич-заглушка, а кнопка, реагирующая на нажатие. Дизайнеры осознают, какой элемент для платформы Андроид родной, а какой — требуется сильно дорабатывать и сложно поддерживать.

Налаженное взаимопонимание между программистами и дизайнерами позволило выдавать результат быстрее и надежнее. Правки в верстку вносились по щелчку пальцев: чего стоит одна только замена зелёного аппбара на белый (достаточно добавить новый стиль AppBarLayout, новый ThemeOverlay, соединить их в одной теме и назначить её основной для всего проекта).

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

Несмотря на это, основная масса принятых правил оказалась чрезвычайно эффективной на практике. С помощью новых инструментов мы создали гармоничное приложение в стиле Material. Приглашаем всех в Google Play, где можно на деле оценить результаты нашей работы.

Спасибо за внимание, в следующем выпуске мы расскажем про процесс создания интерфейса нашего приложения.

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


  1. artsnz
    24.12.2015 14:33
    -1

    Не пойму что за тренд делать приложения / ос в стиле детсад? Друзья, кто в курсе объясните в чем смысл?


    1. bromzh
      24.12.2015 14:50
      +1

      А Вы считаете, что чем больше элементов на видимой части приложения, тем это приложение «взрослее»?


      1. artsnz
        24.12.2015 15:14
        +18

        Причем тут кол-во элементов? Я совсем не про то, посмотрите в общем на приложение, что это за приветственный экран с солнышком в стиле рисунки в детском саду? Кому это надо? На главном экране, абсолютно не нужная информация, такая как разделы, занимает приличную часть экрана, при переводе денег на карту другому клиенту, нужная информация висит где-то в шапке, а снизу какое-то не понятное поле для обмена сообщениями, а по середине дырка, ДЫРКА, КАРЛ! Было же хорошо, зачем испортили — не понятно.


        1. UksusoFF
          24.12.2015 22:23
          +3

          Лучше бы оно грузилось быстрее чем 5 минут наблюдать это солнышко.


          1. artsnz
            25.12.2015 09:23
            +1

            Полностью с вами согласен! Кстати после обновления приложение стало вылетать часто, при переключении между приложениями.


            1. UksusoFF
              25.12.2015 09:50

              Огорчает отсутсвие лайт-версии со встроеным АВ и оплатой только по шаблонам. Текущая версия весит 100 мб. Конечно на топовых телефонах это не проблема, но на, даже относительно свежих, среднего сегмента это боль.


              1. artsnz
                25.12.2015 11:08
                +1

                Согласен, при учете, что мобильное приложение все равно не работает без интернета, можно просто сделать оптимизированную веб версию под мобильники, а приложением просто подстраивать веб версию под определенный телефон и кешировать графику, получилось бы гораздо легче и работало бы быстрее, говорю на том основании, что обычная веб версия в браузере на мобильнике работает быстрее чем приложение.


                1. Serator
                  25.12.2015 14:07

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


                  1. artsnz
                    25.12.2015 14:18

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


                    1. Serator
                      25.12.2015 15:16

                      Ну вот, собственно, это и позволяют делать современные браузеры, учитывая, что под Android, о котором речь в посте, по сути это Chrome и ему подобные.


  1. token
    24.12.2015 14:34

    Скажите а мобильное приложение тоже Backbase делал?


  1. bougakov
    24.12.2015 15:03
    +8

    Дорогой Сбер! Спасибо за улучшения дизайна, но не ломай при этом фичи, пожалуйста. Это важнее, чем приветствовать меня по имени, чесслово.

    Под Windows Phone перестал работать раздел «мои расходы»: если кликнуть по любому сегменту «пирога» моих расходов за месяц, вместо списка операций выводится пустая страница.


  1. kidar2
    24.12.2015 15:08
    -19

    Дорогой сбер, как бы ни старался, но я всё равно тебя буду ненавидеть. Это как IE, он вроде бы обновляется и меняется, и даже переименовался, но всё равно его не любят.


    1. gwer
      24.12.2015 15:54
      +7

      А я люблю Сбербанк.

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


    1. Rastishka
      24.12.2015 16:57
      +2

      Тоже по привычке не люблю сбербанк.
      Но он исправился, так что еще чуть-чуть — и может полюблю.

      ЗЫ Еще бы ужасные шрифты в банкоматах исправили, а то из глаз кровь течет когда вижу картинку пикселявую 800х600 растянутую на огромный монитор…


      1. ploop
        24.12.2015 17:16
        +2

        Мне вот любить больше некого, приходится любить сбербанк. Но после какого-то года (лет 5 назад примерно, может больше) он начал отвечать взаимностью!


    1. artyums
      25.12.2015 19:52

      Ну и зря, сейчас Сбербанк стал очень хорошим банком. Активно пользуюсь услугами с лета 2014 года, за это время никаких стоящих описания проблем не испытал.

      Существенные плюсы для меня — это отделения на каждом шагу, а банкоматы и того чаще (девиз «Всегда рядом» — правда). Бесплатный полноценный мобильный банк (пользователям кредитных карт).

      Единственные минусы, в моем случае, это региональное разделение банка и его клиентов (имею две карточки, открытые одна в Москве, другая в МО — вынужден обслуживать каждый счет при случае отдельно) и невозможность влияния клиента на изменение лимита кредитной карты (ни справку принести, ничего) — в итоге сижу уже год с запрошенным изначально лимитом.


    1. FireSecure
      26.12.2015 03:10

      Тоже не люблю сбер. Года 3 назад управляющий отделением пыталась развести на деньги обманным путем скрывая истинную информацию при открытии счета. Звонил в ТП писал заявление реакции 0. Правда на данный момент отделение закрыли, уж не знаю по каким причинам. Ситуация почти повторилась в другом отделении, в которое я вынужден был обратиться, если бы я не поймал их за руку. Постоянные очереди, отсутствие желания помогать клиентам разбираться с терминалами, хамство, архаизмы в виде сбер книжек, высокие ставки по кредитам и низчайшие по вкладам(6-8% в среднем просто смех). Чего я только там не насмотрелся.

      Дважды приглашали на собеседования в разное время на Java developer, оба раза отказывал именно из-за негативного отношения к банку. Но надо сказать, приложение выглядит действительно достойно, судя по скринам функционал не хуже программ фин учета. Сбер старается, тащит разработчиков, очевидно держит планку, но сама суть взаимодействия с клиентом, уверен, останется прежней. Иметь какие-либо отношения с мошенниками не захочет никто.


      1. vlivyur
        28.12.2015 09:49

        Открывал счёт два года назад, сберкнижку даже не предложили.


  1. ipavlenko
    24.12.2015 15:35
    -3

    Ребята, спасибо! Очень удобно.
    И было удобно, а стало ещё и красиво.

    Есть правда Feature Request:
    Удаление шаблонов платежей, сейчас это нельзя сделать.

    Скажите куда вам писать просьбы и сообщения об ошибках, будем помогать.


    1. bean
      24.12.2015 15:54
      -1

      Удаление шаблонов вроде есть, нужно сделать свайп справа на шаблоне.


      1. LSiazsaHrd
        24.12.2015 16:27
        -1

        Да, точно есть.


      1. ipavlenko
        24.12.2015 17:14
        -1

        Спасибо!
        Не догадался бы, если честно


        1. wrewolf
          25.12.2015 13:23
          -1

          а это родная механика андроида


  1. Azya
    24.12.2015 16:55
    +1

    В новой версии заметил два недочета:
    — В течении нескольких секунд после старта приложение показывает старые суммы баланса, что уже пару раз меня вводило в заблуждение.
    — Вкладка «вклады и счета» имеет шапку в красных тонах, что подсознательно наводит на мысль о каких-то проблемах.

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


    1. loreglean
      24.12.2015 19:07

      У меня иногда секунд 40 запускается, за это время пару раз появляется окно «проверка на вирусы не была завершена», где жмется «повторить». Но прошлая версия на этом моменте висла, так что уже лучше :) А новый дизайн очень здоровский.


  1. kamushken
    24.12.2015 19:13
    -3

    вот я дизайнер… а мне рассказали всё какими-то странными буковками, математическими знаками и прочими непонятностями. в результате пришлось проскроллить, не осилив. печаль.


    1. Valle
      24.12.2015 19:41

      Смысл в том что программистам гораздо проще сделать material дизайн основанный на изменении цветов стандартных элементов по всему приложению а не полностью наколеночный который меняется раз в месяц от экрана к экрану.


  1. Valle
    24.12.2015 19:37

    Есть подозрение что у серого текста на сером и у черного на темно-зеленом есть проблемы с контрастом — для многих людей такое сложно читать contrastrebellion.com


  1. dmitrienkop
    24.12.2015 20:26
    +2

    Сбер молодцы. Одно из лучших банковских приложений которыми приходилось пользоваться. Что самое обидное, несравнимо лучше приложения «основного» используемого мной банка.


    1. Zordhauer
      25.12.2015 19:09
      +1

      Мне вот QBank Связного больше всего нравился, пока банк не лишился лицензии…


    1. artyums
      25.12.2015 19:54

      У Тинькофф Банка еще хорошее приложение. Примерно на уровне Сбербанка.


      1. alexpp
        26.12.2015 00:46

        Судя по отзывам, едва ли не самое лучшее.


        1. KIBIs
          27.12.2015 19:59

          Лично для меня да. Пользуюсь услугами обоих банков, но в последнее время все перевел на Тинькофф, это действительно удобно).


  1. BIanF
    25.12.2015 02:49
    +2

    Ещё бы вы что-то сделали с некоторыми проблемами на рутованных смартфонах. У меня например, при отсутствии интернета приложение наглухо виснет.
    А солнышко крутое. Да =)


    1. negasus
      25.12.2015 07:42

      Если правильно помню, то на айфонах с джейлом приложение не дает проводить платежи.
      Может быть, это недоделанная аналогичная защита на андроиде


      1. ploop
        25.12.2015 09:47

        На андроиде тоже не даёт, и это плохо. Могли бы куда-нибудь в глубь запрятать настройку, что "… я понимаю риск и согласен использовать дальше… "


  1. Denxc
    25.12.2015 09:02

    Для чего функцию «Мои финансы» вынесли на самый верх? Она, по сути, чисто для информации. Лично для меня эта функция не нужна или нужна очень редко, но место она занимает много и бесполезно.

    Было бы не плохо иметь возможность сортировать вкладки или включать/выключать их в главном окне.


  1. achekalin
    25.12.2015 11:45
    -1

    Честно говоря, Сбер, конечно, рулит. Но мобильное приложение, из которого (раньше) было невозможно сделано ничего толкового — это нечто. С тех пор решил им не пользоваться, но деньги за возможность пользования с меня снимают до сих пор. Потому что в веб-личном кабинете отключить эту платную возможность нельзя, а девочки в отделении банка затрудняются помочь. Такая вот фича с однонаправленным переключателем.

    Зашел на статью, не заметив, что это блог Гугла. Сверху увидел баннер «личные вещи храню в облаке», и аж вздрогнул. Вверху страницы такая легкомысленная барышня, ниже — про сбер )


    1. ploop
      25.12.2015 11:51

      но деньги за возможность пользования с меня снимают до сих пор

      Это как? Деньги вроде снимают только за мобильный банк, а онлайн и приложение — уже в нагрузку.


    1. UksusoFF
      25.12.2015 11:54

      За что с Вас снимают деньги? Я пользуюсь абсолютно бесплатно, даже за обслуживание карты (Моментум) не плачу.
      На сколько я помню там в полу-принудительном порядке активируется смс-банкинг без которого нельзя активировать первичный доступ в интернет-банкинг. А потом оно спокойно отключается написанием заявления.


    1. artyums
      25.12.2015 19:57

      Использования приложения, Сбербанк-Онлайн — все бесплатно.

      Платным является полная версия Мобильного банка (по смс), при которой главная «фишка» — это получение смс об операциях. Услуга без проблем переводится в «экономичный» вариант, который не включает уведомления, но полностью бесплатен. Попробуйте позвонить в контакт-центра банка по номеру 900, проконсультируйтесь у них.


  1. Stmf
    25.12.2015 23:10
    +2

    Все классно. Все нравится. Но пользоваться никогда не буду, глупые ограничения для рутованых телефонов без возможности поставить галку «я в курсе, что это не безопасно, пропустите»…


    1. GamePad64
      26.12.2015 07:12

      Ещё и «антивирус» какой-то встроили, от которого приложение минут пять стартует. Когда я вижу «антивирус», который я не устанавливал, сразу появляется чувство, что подцепил малварь.


      1. mairos
        28.12.2015 11:37

        А нам тут недавно пользователь писал, что мы оказывается вирусы в своё приложение встраиваем :-) Ему так Сбербанк сказал! Пол-часа успокаивали… А что приложению Сбера в нашем не понравилось, понять так и не смогли.


    1. iandarken
      28.12.2015 13:50

      Это защита не пользователей от малвары, а банка от претензий пользователей «А это не я, это вирус перевел все мои деньги в Никарагуа, отмените, верните!».


  1. maseal
    28.12.2015 10:56

    Feature request:
    Добавьте в приложении возможность обратной связи с разработчиками.

    Теоретически, можно конечно писать в Спортлото Google Play, надеясь что там сообщение прочитает кто-то из разработчиков. Но, как показывает практика, на писанину в Google play далеко не всегда реагируют. Наверное, потому что там количество неадеквата зашкаливает.

    Хотел написать о баге, который напрягает в последних версиях приложения, но непонятно куда. Через «Написать в банк» (из приложения) приходит какая-то стандартная отписка, не имеющая ничего общего с ссобщением.

    А баг такой: в списке операций по карточке некорректно указывается время. Моё время GMT+5 и если я только что совершил операцию, то в там в списке рядом с ней надпись «5 часов назад». Время на телефоне у меня выставлено корректно. Скорее всего какая-то несогласованность по поводу UTC в приложении.


  1. MaxF
    29.12.2015 13:02
    +1

    Не тем вы занимаетесь.
    Вы основные функции делайте работоспособными, пожалуйста.
    У вас до сих пор в шаблонах оплаты нелепая детсадовская ошибка: выбираешь сохраненный шаблон — он пишет что реквизиты неправильные (потому что номер телефона при сохранении шаблона записывает с +7, а потом сам же в свое же поле вставляет неправильно +7+7)
    И подобных косяков — не один.


    1. Denxc
      30.12.2015 09:02

      Плюсую.
      Выполняю операцию по переводу денег, сразу открываю историю операций и вижу, что она проведена 4 часа назад.
      Это связано с разницей в часовых поясах. Время операции фиксируется московское, а при отображении в истории отображается время телефона (локальное) минус время операции (московское), как итог «операция проведена 4 часа назад».
      Не критично, но сбивает с толку и не приятно.


    1. Denxc
      30.12.2015 09:03

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