Пользователь
0,0
рейтинг
25 октября 2014 в 20:25

Разработка → AppCompat v21 — Material Design для пре-Lollipop устройств перевод

image
17 октября был опубликован Android 5.0 SDK, который принес новые виджеты и материальный дизайн. Мы расширили библиотеки поддержки, чтобы вы могли использовать ваши последние разработки и на предыдущих версиях Android. Это изменения включают в себ крупное обновление для AppCompat, а так же библиотеки RecyclerView, CardView и Palette.

В этом посте мы взглянем, что нового появилось в AppCompat и как это использовать для поддержки материального дизайна в ваших приложениях.

Что нового в AppCompat?


Библиотека AppCompat (aka ActionBarCompat) появилась как порт нового ActionBar API из Android 4.0 на устройства с Gingerbread. Она представила общий слой API поверх бэкпортированной либо стандартной реализации. AppCompat v21 же приносит API и набор возможностей из Android 5.0

В этой версии Android появился новый виджет Toolbar. Он представляет собой обобщение шаблона ActionBar и дает больше контроля и гибкости. Toolbar — это элемент view в общей иерархии, что упрощает реализацию его взаимодействия с другими виджетами, анимации и реакции на события прокрутки. Так же вы можете использовать его как Actionbar вашей активности, а это значит, что стандартные элементы меню действий будут показываться в нем.

Вы, вероятно, уже пользовались какое-то время обновленной версией AppCompat. Эта библиотека была включена в обновления различных программ Google, вышедшие в последние недели, в том числе Play Маркет и Play Пресса. Кроме того, он был интегрирован в приложение Google I/O, изображенное выше, которое имеет открытый исходный код.

Установка


Если вы используете Gradle, просто добавьте appcompat как зависимость в ваш файл build.gradle:

dependencies {
    compile "com.android.support:appcompat-v7:21.0.+"
}

Новая интеграция

Если вы ещё не используете AppCompat или начинаете с нуля, вот как её подключить:
  • Все ваши активности должны наследоваться от ActionBarActivity, которая в свою очередь наследуется от FragmentActivity из библиотеки v4 support, поэтому вы можете продолжать использовать фрагменты.
  • Все вашим темы (которые включают Action Bar/Toolbar) должны наследоваться от Theme.AppCompat. Есть несколько вариантов тем, в том числе светлая (Light) и тема без панели действий (NoActionBar).
  • Когда внедряете что-то для отображения в панели (например, SpinnerAdater для навигации), удостоверьтесь, что используете контекст с темой панели, полученный с помощью getSupportActionBar().getThemedContext().
  • Вы должны использовать статические методы класса MenuItemCompat для вызовов MenuItem, относящимся к действиям.

Для получения дополнительной информации обратитесь к руководству по API Action Bar, которое является исчерпывающим руководством по AppCompat.

Миграция с предыдущих версий

Для большинства приложений теперь вам достаточно одного объявления темы в values/:

values/themes.xml:

<style name="Theme.MyTheme" parent="Theme.AppCompat.Light">
    <!-- Set AppCompat’s actionBarStyle -->
    <item name="actionBarStyle">@style/MyActionBarStyle</item>

    <!-- Set AppCompat’s color theming attrs -->
    <item name="colorPrimary">@color/my_awesome_red</item>
    <item name="colorPrimaryDark">@color/my_awesome_darker_red</item>
    
    <!-- The rest of your attributes -->
</style>

Теперь вы можете убрать все стили ActionBar из values-v14+.

Темы оформления


AppCompat поддерживает новые атрибуты цветовой палитры, которые позволяют настроить тему под ваш брэнд, используя основной и акцентный цвета. Например:

values/themes.xml:

<style name="Theme.MyTheme" parent="Theme.AppCompat.Light">
    <!-- colorPrimary is used for the default action bar background -->
    <item name="colorPrimary">@color/my_awesome_color</item>

    <!-- colorPrimaryDark is used for the status bar -->
    <item name="colorPrimaryDark">@color/my_awesome_darker_color</item>

    <!-- colorAccent is used as the default value for colorControlActivated,
         which is used to tint widgets -->
    <item name="colorAccent">@color/accent</item>

    <!-- You can also set colorControlNormal, colorControlActivated
         colorControlHighlight, and colorSwitchThumbNormal. -->
    
</style>

Когда вы зададите эти аттрибуты, AppCompat автоматически применит их как значения атрибутов из API 21+. А это, в свою очередь, окрасит панель статуса и элемент в списке недавних задач.

На более старых платформах, AppCompat эмулирует цветовые темы, когда это возможно. В текущий момент, это ограничивается окрашиванием панели действий и некоторыми виджетами.

Тонировка виджетов

Когда вы запускаете приложение на устройстве с Android 5.0, все виджеты тонируются цветом, указанным в атрибутах темы. Есть две основные возможности, которые позволяют это делать на Lollipop: тонировка drawable и ссылки на аттрибуты тем (в формате ?attr/foo) внутри drawable.

AppCompat предлагает похожее поведение на ранних версиях Android для следующего множества UI виджетов:

  • Все, что предлагается в AppCompat toolbar (режимы действий и прочее)
  • EditText
  • Spinner
  • CheckBox
  • RadioButton
  • Switch (используйте новый класс android.support.v7.widget.SwitchCompat)
  • CheckedTextView

Вам ничего не нужно делать специально, чтобы это заработало. Используйте эти элементы в вашей разметке как обычно, а AppCompat сделает остальное (с некоторыми оговорками, см. FAQ ниже).

Виджет панели инструментов (Toolbar)


image
Toolbar полностью поддерживается библиотекой AppCompat и полностью полностью соответствует как по возможностям, так и по API вызовам, виджету из SDK. В AppCompat, панель инструментов реализуется с помощью класса android.support.v7.widget.Toolbar. Есть два способа её применения:
  • Использовать как ActionBar, если вы хотите использовать существующие возможности Action Bar (такие, как внедрение меню, выделение, ActionBarDrawerToggle и т.д.), но при этом хотите больше контроля над её внешним видом.
  • Использовать автономную панель в ситуациях, когда обычный ActionBar не подходит. Например, чтобы показать несколько панелей на экране, занять только часть экрана по ширине и т.д.

Action Bar

Чтобы использовать Toolbar в качестве ActionBar, во-первых, отключите обычный ActionBar. Самый простой способ сделать это — унаследовать вашу тему от Theme.AppCompat.NoActionBar (или светлого её варианта)

Во-вторых, создайте экземпляр панели инструментов. Например, включив её в ваш xml-файл разметки

<android.support.v7.widget.Toolbar
    android:id="@+id/my_awesome_toolbar"
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:minHeight="?attr/actionBarSize"
    android:background="?attr/colorPrimary" />

Высота, ширина, фон и прочее теперь полностью зависят от вас, это просто хороший пример. Так как Toolbar — это просто ViewGourp, вы можете стилизовать и позиционировать его на своё усмотрение.

И наконец, установите Toolbar в качестве ActionBar в вашей активности или фрагменте:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.blah);

    Toolbar toolbar = (Toolbar) findViewById(R.id.my_awesome_toolbar);
    setSupportActionBar(toolbar);
}

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

Автономное использование

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

В автономном режиме вы можете наполнять Toolbar содержимым или действиями. Например, если вы хотите показать действия, вам нужно внедрить меню:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.blah);

    Toolbar toolbar = (Toolbar) findViewById(R.id.my_awesome_toolbar);

    // Set an OnMenuItemClickListener to handle menu item clicks
    toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
        @Override
        public boolean onMenuItemClick(MenuItem item) {
            // Handle the menu item
            return true;
        }
    });

    // Inflate a menu to be displayed in the toolbar
    toolbar.inflateMenu(R.menu.your_toolbar_menu);
}

Есть множество других вещей, которые можно делать с панелью инструментов. Для получения дополнительной информации, смотрите описание Toolbar API.

Стили

Настройка стиля панели инструментов отличается от того, как это делалось для стандартной панели действий. Стиль применяется прямо к самому виджету.

Вот основной стиль, который вы должны использовать, когда вы используете Toolbar в качестве ActionBar:

<android.support.v7.widget.Toolbar  
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:minHeight="?attr/actionBarSize"
    app:theme="@style/ThemeOverlay.AppCompat.ActionBar" />

Объявление app:theme позволит убедиться, что шрифт и элементы используют чистый цвет (например, 100% непрозрачный белый).

Темная панель действий
Вы можете настроить панель инструментов напрямую, используя атрибуты разметки. Чтобы Toolbar выглядела как «DarkActionBar» (тёмное содержимое, светлое меню переполнения), укажите атрибуты theme и popupTheme:

<android.support.v7.widget.Toolbar
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:minHeight="@dimen/triple_height_toolbar"
    app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
    app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

Виджет поиска (SearchView)


AppCompat предлагает обновленное API для виджета поиска, которое поддается большей настройке и стилизации. Теперь мы используем структуру стилей из Lollipop вместо старых searchView* аттрибутов темы.

Вот как вы можете настроить стиль SearchView:

values/themes.xml:

<style name="Theme.MyTheme" parent="Theme.AppCompat">
    <item name="searchViewStyle">@style/MySearchViewStyle</item>
</style>
<style name="MySearchViewStyle" parent="Widget.AppCompat.SearchView">
    <!-- Background for the search query section (e.g. EditText) -->
    <item name="queryBackground">...</item>
    <!-- Background for the actions section (e.g. voice, submit) -->
    <item name="submitBackground">...</item>
    <!-- Close button icon -->
    <item name="closeIcon">...</item>
    <!-- Search button icon -->
    <item name="searchIcon">...</item>
    <!-- Go/commit button icon -->
    <item name="goIcon">...</item>
    <!-- Voice search button icon -->
    <item name="voiceIcon">...</item>
    <!-- Commit icon shown in the query suggestion row -->
    <item name="commitIcon">...</item>
    <!-- Layout for query suggestion rows -->
    <item name="suggestionRowLayout">...</item>
</style>

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

Toolbar на подходе...


Надеюсь, эта статья поможет приступить к работе с AppCompat и позволит создать удивительные приложения в материальном стиле. Дайте знать в комментариях к оригинальной статье/Google+/Twitter, если у вас есть вопросы о AppCompat или о любой из поддерживаемых библиотек, или где мы можем предоставить больше документации

FAQ


Почему мой EditText (или другой виджет из списка выше) не окрашен корректно на устройстве с Android до Lollipop?
Тонирование виджетов в AppCompat работает с помощью перехвата внедрения разметки и вставки специальных тонированных версий виджетов. Для большинства людей это будет работать правильно. Но есть несколько сценариев, когда это не работает, в том числе:
  • У вас кастомизированная версия виджета (вы отнаследовали EditText)
  • Вы создаете EditText без использования LayoutInflater (например, вызвав new EditText())

Специальные тонированные версии виджетов пока скрыты, так как они находятся в незаконченном состоянии. Это может измениться в будущем.

Почему виджет X не имеет материального стиля на не-Lollipop устройствах?
Пока были обновлены только некоторые, самые распространенные виджеты. В будущих релизах будут добавлены другие.

Почему у моего Action Bar осталась тень на Android Lollipop? Я задал android:windowContentOverlay равный null.
На Lollipop тень под панелью создается с помощью нового API подъема. Чтобы убрать её, вам нужно вызвать getSupportActionBar().setElevation(0) или задать значение атрибута elevation в описании стиля Actionbar.

Почему нет ripple-анимации на устройствах до Lollipop?
Главное, что позволяет RippleDrawable анимироваться плавно в Android 5.0 — это новый RenderThread. Для оптимизации производительности на предыдущих версиях Android мы пока оставили RippleDrawable за бортом.

Как мне использовать AppCompat с Preferences?
Вы можете продолжать использовать PreferenceFragment в ActionBarActivity, когда запускаете приложение на устройстве с API v11+. Для устройств с предыдущей версией API вам придется использовать PreferenceActivity, которая не стилизована под материальный дизайн.

P.S. Это мой первый перевод, прошу писать в личку обо всех неточностях (особенно, что касается русских терминов)
Перевод: Chris Banes, Android Developer Relations
Tishka17 @Tishka17
карма
19,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

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

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

  • –7
    И зачем это? Надо использовать всё нативное и оставить Holo на 4.х. Пока поддерживал 2.х, уже натерпелся подобных костылей.
    • +4
      Ну не писать же две версии приложения — для 4.x и 5.x? А четверку можно будет выкинуть только через года два, не раньше. А тут заодно исправлены некоторые недоразумения 4й версии — например, попробуйте настроить внешний вид SearchView без использования AppCompat
      • 0
        Ну не две версии, а две темы — новую положить в values-v21 и наследовать от какой-нибудь android:Theme.Material.Light.DarkActionBar, а старую оставить как есть. Если хочется и вид самого контента менять, то это тоже достаточно легко делается через ресурсы и в большинстве случаев даже не требует написания кода. Внешний вид SearchView я настраивал и в 4.х, но, каюсь, через reflection.

        Да и просто кажется странным делать приложения с новой темой для версий системы, в которых уже были свои внятные гайдлайны. Портировать Holo на 2.х имело смысл, потому что на 2.х до изобретения Holo нормальных интерфейсов не было в принципе.
        • +2
          Две темы создать — действительно не проблема. Но вот тогда и для использования того же Toolbar придется так же делать layout-v21, и в коде проверки делать для вызова setActionBar
        • +1
          Google портировал Material Design на пре-Lollipop, видимо все таки переделывать приложения нужно, ибо даже Google отказался от Holo на старых версиях.
          • –3
            Сами же гугловцы говорят, что можно делать так, как я предлагаю.
            • +2
              Поялвение AppCompat-v21 с портом Material Design противоречит этому
            • 0
              «Feel free to choose either direction» написал в итоге Адам.
        • 0
          Просто values-v21 и layout-v21 дело не обойдётся. Там много чего в коде придётся менять.
    • –1
      Если пишешь свое собственное приложение — ну да, можно побеседовать на эту тему. Я б так вообще сразу для Android Lollipop только писал.
      Но как правило пишешь для заказчика и для людей, которым даже поддержку от 14 версии приходиться объяснять.
  • 0
    А можно как-то привести старые диалоги к новому внешнему виду с помощью AppCompat?
    • +1
      Насколько понимаю, стандартный AlertDialog не получится. Есть сторонняя библиотека L-Dialogs, можете попробовать её
    • 0
      Можно еще просто нарисовать «material like» диалоги через DialogFragment.
      • +1
        Да это понятно, в любом случае его использовать. Просто «из коробки» не получается, жаль.
    • 0
      Ответ от команды разработчиков насчет включения стилей диалогов в appcompat:
      Not yet, but it's on the todo list.
  • 0
    Ухх… Вот и пришло для меня наконец время разобраться ActionBar'ами! А то как только шерлок появился (давно же это было), я как-то решил, что обойдусь без них.
    • 0
      ActionBar уже достаточно давно официально есть в библиотеках совместимости. Но теперь да, есть лишний повод им заняться.
      • 0
        Кстати, попробовал тему описать как в примере выше, и получаю «No resource found that matches the given name: attr 'colorPrimary'.»
        При этом я могу задать его с префиксом android:colorPrimary, но кажется это немного не то. При этом сама тема подцепилась нормально, т.е. на Theme.AppCompat.Light не ругается.
        Не знаете в чем может быть дело? Использую по старинке эклипс.
        • 0
          Кажется у меня такое было, как решилось — не помню. Попробуйте скомпилировать. У вас точно AppCompat свежей версии?
          • 0
            Точно, я дурак. Не обновил саппорт либы. Спасибо)
        • 0
          Для тех, кому не помогло. После импорта AppCompat, если выскакивают эти ошибки с ресурсами, то в файлике project.properties замените target=android-19 на target=android-21

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