company_banner

Сбербанк делится опытом создания приложения в Material Design: стили и темы

    Привет, Хабрахабр! Не так давно мы подводили итоги конкурса по 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, где можно на деле оценить результаты нашей работы.

    Спасибо за внимание, в следующем выпуске мы расскажем про процесс создания интерфейса нашего приложения.
    Google 92,14
    Филин Лаки
    Поделиться публикацией
    Комментарии 57
    • –1
      Не пойму что за тренд делать приложения / ос в стиле детсад? Друзья, кто в курсе объясните в чем смысл?
      • +1
        А Вы считаете, что чем больше элементов на видимой части приложения, тем это приложение «взрослее»?
        • +18
          Причем тут кол-во элементов? Я совсем не про то, посмотрите в общем на приложение, что это за приветственный экран с солнышком в стиле рисунки в детском саду? Кому это надо? На главном экране, абсолютно не нужная информация, такая как разделы, занимает приличную часть экрана, при переводе денег на карту другому клиенту, нужная информация висит где-то в шапке, а снизу какое-то не понятное поле для обмена сообщениями, а по середине дырка, ДЫРКА, КАРЛ! Было же хорошо, зачем испортили — не понятно.
          • +3
            Лучше бы оно грузилось быстрее чем 5 минут наблюдать это солнышко.
            • +1
              Полностью с вами согласен! Кстати после обновления приложение стало вылетать часто, при переключении между приложениями.
              • 0
                Огорчает отсутсвие лайт-версии со встроеным АВ и оплатой только по шаблонам. Текущая версия весит 100 мб. Конечно на топовых телефонах это не проблема, но на, даже относительно свежих, среднего сегмента это боль.
                • +1
                  Согласен, при учете, что мобильное приложение все равно не работает без интернета, можно просто сделать оптимизированную веб версию под мобильники, а приложением просто подстраивать веб версию под определенный телефон и кешировать графику, получилось бы гораздо легче и работало бы быстрее, говорю на том основании, что обычная веб версия в браузере на мобильнике работает быстрее чем приложение.
                  • 0
                    Так технологии в вебе уже сейчас позволяют и кэшировать, и подстраивть.
                    • 0
                      ну собственное приложение позволило бы добиться корректного отображения интерфейса на всех устройствах, тк не смотря на стандарты некоторые элементы каждый браузер интерпретирует с различиями, ну и плюс в оффлайн режиме можно показывать окно входа, а не «страница не найдена», ну это уже так чисто с эстетической точки зрения. юзерфрендли
                      • 0
                        Ну вот, собственно, это и позволяют делать современные браузеры, учитывая, что под Android, о котором речь в посте, по сути это Chrome и ему подобные.
      • 0
        Скажите а мобильное приложение тоже Backbase делал?
        • +8
          Дорогой Сбер! Спасибо за улучшения дизайна, но не ломай при этом фичи, пожалуйста. Это важнее, чем приветствовать меня по имени, чесслово.

          Под Windows Phone перестал работать раздел «мои расходы»: если кликнуть по любому сегменту «пирога» моих расходов за месяц, вместо списка операций выводится пустая страница.
          • –19
            Дорогой сбер, как бы ни старался, но я всё равно тебя буду ненавидеть. Это как IE, он вроде бы обновляется и меняется, и даже переименовался, но всё равно его не любят.
            • +7
              А я люблю Сбербанк.

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

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

                • +2
                  Мне вот любить больше некого, приходится любить сбербанк. Но после какого-то года (лет 5 назад примерно, может больше) он начал отвечать взаимностью!
                • 0
                  Ну и зря, сейчас Сбербанк стал очень хорошим банком. Активно пользуюсь услугами с лета 2014 года, за это время никаких стоящих описания проблем не испытал.

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

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

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

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

                    Скажите куда вам писать просьбы и сообщения об ошибках, будем помогать.
                    • –1
                      Удаление шаблонов вроде есть, нужно сделать свайп справа на шаблоне.
                      • –1
                        Да, точно есть.
                        • –1
                          Спасибо!
                          Не догадался бы, если честно
                          • –1
                            а это родная механика андроида
                      • +1
                        В новой версии заметил два недочета:
                        — В течении нескольких секунд после старта приложение показывает старые суммы баланса, что уже пару раз меня вводило в заблуждение.
                        — Вкладка «вклады и счета» имеет шапку в красных тонах, что подсознательно наводит на мысль о каких-то проблемах.

                        А вообще, по стабильности работы, приложение к сожалению только ухудшается. Все было прекрасно и надежно до встраивания антивируса, теперь же приложение запускается долго (хотя в последней версии стало чуть быстрее), часто рапортует о невозможности авторизации, что лечится только перезапуском приложения. В итоге теряется оперативность, которая очень важна на мобильном устройстве.
                        • 0
                          У меня иногда секунд 40 запускается, за это время пару раз появляется окно «проверка на вирусы не была завершена», где жмется «повторить». Но прошлая версия на этом моменте висла, так что уже лучше :) А новый дизайн очень здоровский.
                        • –3
                          вот я дизайнер… а мне рассказали всё какими-то странными буковками, математическими знаками и прочими непонятностями. в результате пришлось проскроллить, не осилив. печаль.
                          • 0
                            Смысл в том что программистам гораздо проще сделать material дизайн основанный на изменении цветов стандартных элементов по всему приложению а не полностью наколеночный который меняется раз в месяц от экрана к экрану.
                          • 0
                            Есть подозрение что у серого текста на сером и у черного на темно-зеленом есть проблемы с контрастом — для многих людей такое сложно читать contrastrebellion.com
                            • +2
                              Сбер молодцы. Одно из лучших банковских приложений которыми приходилось пользоваться. Что самое обидное, несравнимо лучше приложения «основного» используемого мной банка.
                              • +1
                                Мне вот QBank Связного больше всего нравился, пока банк не лишился лицензии…
                                • 0
                                  У Тинькофф Банка еще хорошее приложение. Примерно на уровне Сбербанка.
                                  • 0
                                    Судя по отзывам, едва ли не самое лучшее.
                                    • 0
                                      Лично для меня да. Пользуюсь услугами обоих банков, но в последнее время все перевел на Тинькофф, это действительно удобно).
                                • +2
                                  Ещё бы вы что-то сделали с некоторыми проблемами на рутованных смартфонах. У меня например, при отсутствии интернета приложение наглухо виснет.
                                  А солнышко крутое. Да =)
                                  • 0
                                    Если правильно помню, то на айфонах с джейлом приложение не дает проводить платежи.
                                    Может быть, это недоделанная аналогичная защита на андроиде
                                    • 0
                                      На андроиде тоже не даёт, и это плохо. Могли бы куда-нибудь в глубь запрятать настройку, что "… я понимаю риск и согласен использовать дальше… "
                                  • 0
                                    Для чего функцию «Мои финансы» вынесли на самый верх? Она, по сути, чисто для информации. Лично для меня эта функция не нужна или нужна очень редко, но место она занимает много и бесполезно.

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

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

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

                                            Платным является полная версия Мобильного банка (по смс), при которой главная «фишка» — это получение смс об операциях. Услуга без проблем переводится в «экономичный» вариант, который не включает уведомления, но полностью бесплатен. Попробуйте позвонить в контакт-центра банка по номеру 900, проконсультируйтесь у них.
                                          • +2
                                            Все классно. Все нравится. Но пользоваться никогда не буду, глупые ограничения для рутованых телефонов без возможности поставить галку «я в курсе, что это не безопасно, пропустите»…
                                            • 0
                                              Ещё и «антивирус» какой-то встроили, от которого приложение минут пять стартует. Когда я вижу «антивирус», который я не устанавливал, сразу появляется чувство, что подцепил малварь.
                                              • 0
                                                А нам тут недавно пользователь писал, что мы оказывается вирусы в своё приложение встраиваем :-) Ему так Сбербанк сказал! Пол-часа успокаивали… А что приложению Сбера в нашем не понравилось, понять так и не смогли.
                                              • 0
                                                Это защита не пользователей от малвары, а банка от претензий пользователей «А это не я, это вирус перевел все мои деньги в Никарагуа, отмените, верните!».
                                              • 0
                                                Feature request:
                                                Добавьте в приложении возможность обратной связи с разработчиками.

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

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

                                                А баг такой: в списке операций по карточке некорректно указывается время. Моё время GMT+5 и если я только что совершил операцию, то в там в списке рядом с ней надпись «5 часов назад». Время на телефоне у меня выставлено корректно. Скорее всего какая-то несогласованность по поводу UTC в приложении.
                                                • +1
                                                  Не тем вы занимаетесь.
                                                  Вы основные функции делайте работоспособными, пожалуйста.
                                                  У вас до сих пор в шаблонах оплаты нелепая детсадовская ошибка: выбираешь сохраненный шаблон — он пишет что реквизиты неправильные (потому что номер телефона при сохранении шаблона записывает с +7, а потом сам же в свое же поле вставляет неправильно +7+7)
                                                  И подобных косяков — не один.
                                                  • 0
                                                    Плюсую.
                                                    Выполняю операцию по переводу денег, сразу открываю историю операций и вижу, что она проведена 4 часа назад.
                                                    Это связано с разницей в часовых поясах. Время операции фиксируется московское, а при отображении в истории отображается время телефона (локальное) минус время операции (московское), как итог «операция проведена 4 часа назад».
                                                    Не критично, но сбивает с толку и не приятно.
                                                    • 0
                                                      В левом меню отображается шаблон, который давно был удален и не используется. Возможности удалить его из меню нет.
                                                    • 0
                                                      Кому-то может и нравится стиль всего в стиле «попроще и поярче», но как-то мобильный банк должен уметь делать всё, что я смогу сделать из личного кабинета с ПК.
                                                      Вместо солнышек и величаний по имени лучше бы сделать загрузку быстрее, тогда и солнышки не нужны. Нужная информация переехала куда-то непонятно куда, а по середине экрана просто дырки. Ну это несерьёзно. Сбер правда старается угодить клиенту хотя бы тут, но получается со скрипом. Со скрипом — потому что мобильное приложение хоть медленно, коряво и непонятным маршрутом, но как-то развивается.
                                                      • 0
                                                        Лучше бы не про иконки думали, а про наглядное информирование пользователей о любых действиях, касающихся их личной информации. При установке приложения Сбербанк онлайн контакты с телефона неизвестными путями проникают на сайт Сбербанк онлайн и там прописываются в разделе Настройки -> Адресная книга. И не удаляются. Если кто не против, мог бы согласиться с этим заботливым копированием адресной книги, нажав раз 10 кнопку согласен, копируйте все мои контакты, размещайте где хотите, мне точно пофиг, я точно согласен, да, да и еще раз да. А мне вот это как-то совсем не понравилось и хочется сделать что-нибудь, чтобы они так больше не делали, нехорошие, только вот не знаю что.
                                                        • 0
                                                          В настройках было что-то типа «не показывать другим что у меня есть сбербанка».
                                                          • 0
                                                            Но только о существовании такой опции (показывать всем, что у тебя сбер) и возможности это отключить тоже не информируют. А по умолчанию всем всех показывают. Это разве секьюрно? Т. е посторонний человек знает ФИО, номер телефона, возможно, дату рождения, паспортные данные (ну бывает, при заключении какого-нибудь договора, например) и теперь еще знает, что этот человек пользуется Сбербанком, привязанным именно к этому номеру телефона. Замечательно!
                                                            • 0
                                                              Так у Сбера это и так можно проверить, попробовав перевести деньги по номеру телефона. Ещё и Имя-Отчество подскажут.
                                                              • 0
                                                                Кажется я параноик. Ведь на самом же деле в этом всем нет ничего такого, в чем можно заподозрить заговор и злой умысел?
                                                                • 0
                                                                  Заговоры-заговорами, однако мои денежки лет пять лежат в сохранности)

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

                                                        Самое читаемое