Як: Визначити тему (стиль) для спеціального віджету


86

Я написав спеціальний віджет для елемента керування, який ми широко використовуємо у всій програмі. Клас віджетів походить від ImageButtonі розширює його кількома простими способами. Я визначив стиль, який я можу застосувати до віджету, коли він використовується, але я вважаю за краще встановити це за допомогою теми. У R.styleableя бачу атрибути стилю віджетів, такі як imageButtonStyleі textViewStyle. Чи є спосіб створити щось подібне для спеціального віджету, який я написав?

Відповіді:


209

Так, є один спосіб:

Припустимо, у вас є декларація атрибутів для вашого віджету (у attrs.xml):

<declare-styleable name="CustomImageButton">
    <attr name="customAttr" format="string"/>
</declare-styleable>

Заявіть атрибут, який ви будете використовувати для посилання на стиль (in attrs.xml):

<declare-styleable name="CustomTheme">
    <attr name="customImageButtonStyle" format="reference"/>
</declare-styleable>

Оголосіть набір значень атрибутів за замовчуванням для віджета (у styles.xml):

<style name="Widget.ImageButton.Custom" parent="android:style/Widget.ImageButton">
    <item name="customAttr">some value</item>
</style>

Оголосіть власну тему (у themes.xml):

<style name="Theme.Custom" parent="@android:style/Theme">
    <item name="customImageButtonStyle">@style/Widget.ImageButton.Custom</item>
</style>

Використовуйте цей атрибут як третій аргумент у конструкторі вашого віджета (in CustomImageButton.java):

public class CustomImageButton extends ImageButton {
    private String customAttr;

    public CustomImageButton( Context context ) {
        this( context, null );
    }

    public CustomImageButton( Context context, AttributeSet attrs ) {
        this( context, attrs, R.attr.customImageButtonStyle );
    }

    public CustomImageButton( Context context, AttributeSet attrs,
            int defStyle ) {
        super( context, attrs, defStyle );

        final TypedArray array = context.obtainStyledAttributes( attrs,
            R.styleable.CustomImageButton, defStyle,
            R.style.Widget_ImageButton_Custom ); // see below
        this.customAttr =
            array.getString( R.styleable.CustomImageButton_customAttr, "" );
        array.recycle();
    }
}

Тепер вам потрібно застосувати Theme.Customдо всіх видів діяльності, які використовують CustomImageButton(в AndroidManifest.xml):

<activity android:name=".MyActivity" android:theme="@style/Theme.Custom"/>

Це все. Тепер CustomImageButtonнамагається завантажити значення атрибута за замовчуванням з customImageButtonStyleатрибута поточної теми. Якщо такого атрибута в темі або значенні атрибуту не знайдено, @nullтоді obtainStyledAttributesбуде використано остаточний аргумент для : Widget.ImageButton.Customу цьому випадку.

Ви можете змінити імена всіх екземплярів та всіх файлів (крім AndroidManifest.xml), але краще було б використовувати конвенцію імен Android.


4
Чи є спосіб зробити те саме, не використовуючи тему? У мене є кілька спеціальних віджетів, але я хочу, щоб користувачі могли використовувати ці віджети з будь-якою темою, яку вони хочуть. Якщо зробити це так, як ви розмістили, користувачі повинні використовувати мою тему.
theDazzler

3
@theDazzler: Якщо ви маєте на увазі бібліотеку, яку можуть використовувати розробники, тоді вони зможуть створювати власні теми та визначати стиль віджета, використовуючи атрибут style у темі ( customImageButtonStyleу цій відповіді). Ось як налаштована панель дій на Android. І якщо ви маєте на увазі зміну теми під час виконання, тоді такий підхід неможливий.
Michael

@Michael, так, я мав на увазі бібліотеку, якою можуть користуватися розробники. Ваш коментар вирішив мою проблему. Дякую!
theDazzler

31
Найдивовижніше у всьому цьому полягає в тому, що хтось із Google вважає, що це нормально.
Гленн Мейнард,

1
Чи name="CustomTheme"має declare-styleableобгортка атрибутів якусь мету? Це лише для організації, бо я не бачу, щоб це було десь використано. Чи можу я просто помістити всі свої атрибути стилю для різних віджетів в одну обгортку?
Tenfour04

4

Інший аспект на додаток до чудової відповіді Майкла - це перевизначення спеціальних атрибутів у темах. Припустимо, у вас є кілька власних подань, які всі посилаються на спеціальний атрибут "custom_background".

<declare-styleable name="MyCustomStylables">
    <attr name="custom_background" format="color"/>
</declare-styleable>

У темі ви визначаєте значення

<style name="MyColorfulTheme" parent="AppTheme">
    <item name="custom_background">#ff0000</item>
</style>

або

<style name="MyBoringTheme" parent="AppTheme">
    <item name="custom_background">#ffffff</item>
</style>

Ви можете посилатися на атрибут у стилі

<style name="MyDefaultLabelStyle" parent="AppTheme">
    <item name="android:background">?background_label</item>
</style>

Зверніть увагу на знак питання, який також використовується для посилання на атрибут android, як у

?android:attr/colorBackground

Як більшість з вас помітили, ви можете - і, мабуть, повинні - використовувати посилання @color замість жорстко закодованих кольорів.

То чому б просто не зробити

<item name="android:background">@color/my_background_color</item>

Ви не можете змінити визначення "my_background_color" під час виконання, тоді як ви можете легко перемикати теми.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.