Androidx AppCompatButton выглядит иначе, чем Button даже на устройстве с высоким уровнем API.

Согласно документации

Кнопка, которая поддерживает совместимые функции на более старых версиях платформы, в том числе:

Разрешает динамический оттенок своего фона с помощью методов оттенка фона в ViewCompat. Позволяет установить оттенок фона с помощью R.attr.backgroundTint и R.attr.backgroundTintMode. Это будет автоматически использоваться, когда вы используете кнопку в своих макетах, а действие/диалог верхнего уровня предоставляется appcompat. Вам нужно только вручную использовать этот класс при написании пользовательских представлений.

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

<androidx.appcompat.widget.AppCompatButton
        android:text="AppCompatButton"
        android:id="@+id/appcompatbutton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

<Button
        android:layout_below="@id/appcompatbutton"
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:text="Button"
        android:layout_height="wrap_content" />

Однако вот как это выглядит на самом деле:

введите описание изображения здесь

Я запустил это на следующем эмуляторе: Galaxy Nexus, API: 28 (720 x 1280 xhdpi)

И когда я применяю buttonStyle в своем appTheme следующим образом:

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="buttonStyle">@style/Widget.MaterialComponents.Button</item>
</style>

Он изменяет AppCompatButton, но не обычную кнопку, например: (Обратите внимание на небольшую разницу в закругленных краях)

введите описание изображения здесь

Я также попытался создать пользовательскую кнопку, которая унаследована от android.widget.Button, а также от androidx.appcompat.widget.AppCompatButton, обе эти кнопки показывают то же поведение, что и использование AppCompatButton в xml. Так что кажется, что единственным исключением является Button в XML.

Вопрос 1:

Как по мне, все это кажется невероятно запутанным. Может ли кто-нибудь объяснить это как ошибку или функцию?

ИЗМЕНИТЬ 1

Выполняя отладку, я обнаружил, что Button фактически преобразуется в MaterialButton, см. следующее: введите здесь описание изображения

Вопрос 2:

Почему происходит эта трансформация?

ИЗМЕНИТЬ 2

Ответ на вопрос 2:

Преобразование Button в MaterialButton связано с родительской темой, которую я использовал.

Вопрос 3:

Как вы реализуете пользовательскую кнопку, которая работает так же, как кнопка в xml?

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


person Ludvig W    schedule 21.06.2019    source источник
comment
я обычно просто устанавливаю фон, который можно рисовать, для моих кнопок, чтобы они всегда выглядели одинаково, хотя я обычно делаю рисование с помощью кода xml, там вы можете установить нужные цвета и закругленные края   -  person ivan    schedule 21.06.2019
comment
Я жаловался в Google на движок Theme/Style/Attributes с конца 2012 года. Ответом было полное молчание примерно до 2017 года, когда они сказали: да… мы должны сосредоточиться на возможности обнаружения в Reddit AMA. Затем они выпустили все библиотеки Material Design, но Android была настолько неполной (до сих пор), что это было своего рода шуткой. Перенесемся в 2019 год... они сохранили все это (Material 2.0), оно все еще не завершено, но теперь Android Studio (возможно, 3.5?) должен помочь вам найти, откуда взялись ваши материалы. Так что... да, система ужасна.   -  person Martin Marconcini    schedule 21.06.2019
comment
@MartinMarconcini Спасибо за этот ответ, он не решает проблему, но дает мне и другим утешение, что они не одиноки в этой проблеме.   -  person Ludvig W    schedule 23.06.2019
comment
@LudvigW Хороший вопрос! Может уже поздно отвечать. Я просто попытался объяснить все пункты с примерами и ссылками на текущий код. И да, получить всю информацию о компонентах и ​​стилях непросто. Не проблема обсудить каждый пункт, если он не ясен.   -  person Gabriele Mariotti    schedule 04.09.2019


Ответы (2)


Короткие ответы.

Как по мне, все это кажется невероятно запутанным. Может ли кто-нибудь объяснить это как ошибку или функцию?

Они используют разные стили.

Почему происходит эта трансформация?

Включена автоматическая инфляция, которая заменит <Button на <com.google.android.material.button.MaterialButton во время выполнения.

Как вы реализуете пользовательскую кнопку, которая работает так же, как кнопка в xml?

Вы можете настроить атрибуты в xml или атрибуты темы.

Длинные ответы.

  1. Они используют разные стили.

Стиль MaterialButton по умолчанию — Widget.MaterialComponents.Button. Этот стиль наследуется от Widget.AppCompat.Button, но изменяет некоторые атрибуты. Здесь вы можете найти различия.

Основное отличие здесь:

<item name="shapeAppearance">?attr/shapeAppearanceSmallComponent</item>

Подробнее о формировании можно прочитать в официальный документ. Если вы будете перемещаться по стилю, вы найдете:

  <style name="ShapeAppearance.MaterialComponents.SmallComponent">
    <item name="cornerSize">@dimen/mtrl_shape_corner_size_small_component</item>
  </style>

где mtrl_shape_corner_size_small_component = 4dp. Это объясняет небольшую разницу в закругленных краях.

Также вы используете <item name="buttonStyle">@style/Widget.MaterialComponents.Button</item>.

Это не работает для MaterialButton. Вы должны использовать:

<item name="materialButtonStyle">@style/Widget.MaterialComponents.Button</item>
  1. Автонаполнение — это здесь.

MaterialComponentsViewInflater заменяет некоторые виджеты фреймворка на Material Components во время инфляции, при условии, что используется тема Material Components.
Нечто подобное происходит и с AppCompat (вы можете проверить это MaterialComponentsViewInflater extends AppCompatViewInflater).

Это означает, что <Button заменяется <com.google.android.material.button.MaterialButton во время выполнения, если вы используете материальную тему.

  1. Есть разные варианты. Одним из них является определение пользовательского стиля для кнопок.
<style name="AppTheme" parent="Theme.MaterialComponents.Light">
    ...
    <item name="materialButtonStyle">@style/MyButtonStyle</item>
</style>
<style name="MyButtonStyle" parent="Widget.MaterialComponents.Button">
   <item name="cornerRadius">xxx</item>
</style>

or

  <style name="MyButtonStyle" parent="Widget.MaterialComponents.Button">
    <item name="shapeAppearanceOverlay">@style/SShapeAppearanceOverlay.MyApp.Button.Rounded</item>
  </style>

  <style name="ShapeAppearanceOverlay.MyApp.Button.Rounded" parent="">
    <item name="cornerFamily">rounded</item>
    <item name="cornerSize">xxdp</item>
  </style>
person Gabriele Mariotti    schedule 03.09.2019

Я изменил <Button> на <ImageButton>

Быстрый и короткий путь.

Не забудьте проверить и изменить ссылки в файлах java/kotlin. Компилятор предупредит вас в любом случае.

person Rahul Kahale    schedule 29.05.2020