getTheme().applyStyle() несколько раз без перезаписи предыдущего

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

Основная активность:

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {

    getTheme().applyStyle(R.style.AppTheme_OverlayPrimaryRed);

    // If you change `false` to `true`, the overlay above is overwritten.
    if (false) {
        getTheme().applyStyle(R.style.AppTheme_OverlayAccentRed);
    }

    super.onCreate(savedInstanceState);

    ...
}

AppTheme.OverlayPrimaryRed:

<style name="AppTheme.OverlayPrimaryRed">
    <item name="colorPrimary">@color/material_red_500</item>
    <item name="colorPrimaryDark">@color/material_red_700</item>
</style>

AppTheme.OverlayAccentRed:

<style name="AppTheme.OverlayAccentRed">
    <item name="colorAccent">@color/material_red_A200</item>
</style>

Любые идеи, как я могу решить эту проблему?


person Thomas Vos    schedule 21.01.2017    source источник


Ответы (3)


Определения вашего стиля AppTheme.OverlayPrimaryRed и AppTheme.OverlayAccentRed неявно наследуются от AppTheme. Поскольку AppTheme, вероятно, также содержит определение для colorPrimary и colorPrimaryDark, второй оператор applyStyle также установит эти атрибуты, отменив первый вызов applyStyle.

По этой причине я не использовал точки в именах наложений стилей в своем ответе на этот вопрос.

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

<style name="Overlay">
</style>

<style name="Overlay.PrimaryRed">
    <item name="colorPrimary">@color/material_red_500</item>
    <item name="colorPrimaryDark">@color/material_red_700</item>
</style>

<style name="Overlay.AccentRed">
    <item name="colorAccent">@color/material_red_A200</item>
</style>
person devconsole    schedule 23.01.2017
comment
Удивительно, я понятия не имел, что существует такое неявное расширение тем. Это решило мою проблему исчезновения флагов при использовании applyStyle, таких как android:windowDrawsSystemBarBackgrounds, android:statusBarColor и т.д. - person 0101100101; 17.06.2020
comment
Целый день билась головой о стену, пока не нашла это. Благодарю вас! - person VIN; 16.06.2021

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

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

<!-- This is a parent style -->
<style name="AppTheme.OverlayPrimaryRed">
    <item name="colorPrimary">@color/material_red_500</item>
    <item name="colorPrimaryDark">@color/material_red_700</item>
</style>

<!-- This is a child of above style -->
<style name="AppTheme.OverlayAccentRed" parent="AppTheme.OverlayPrimaryRed">
    <item name="colorAccent">@color/material_red_A200</item>
</style>

Прочитайте Определение стилей на ресурсе для разработчиков Android. Кроме того, если вы не хотите использовать атрибут parent:

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

<style name="MyTextStyle">
    <item name="android:textAllCaps">false</item>
    <item name="android:textColor">#FFFFFF</item>  <!-- white text (default) -->
    <item name="android:textStyle">bold</item>
    <item name="android:textSize">12dp</item>
</style>

<!-- red text -->
<style name="MyTextStyle.RED">
    <item name="android:textColor">#FF0000</item>
</style>

<!-- green text -->
<style name="MyTextStyle.GREEN">
    <item name="android:textColor">#00FF00</item>
</style>

<!-- blue text -->
<style name="MyTextStyle.BLUE">
    <item name="android:textColor">#0000FF</item>
</style>

Обратите внимание, что в теге нет родительского атрибута, но поскольку атрибут имени начинается с имени стиля MyTextStyle (это стиль, который вы создали), этот стиль наследует все свойства стиля от этого стиля. Этот стиль может переопределить свойство android:textColor, чтобы сделать текст красным. Вы можете ссылаться на этот новый стиль как @style/MyTextStyle.RED.

Вы можете продолжать наследование таким образом столько раз, сколько захотите, соединяя имена с точками. Например, вы можете расширить MyTextStyle.RED, чтобы он стал больше, с помощью:

<style name="MyTextStyle.RED.Big">
    <item name="android:textSize">30sp</item>
</style>

Редактировать 1:

<!-- this is your root style -->
<style name="AppTheme.Overlay">
    <!-- default styles for primary, primaryDark (you can add accent too) -->
</style>

<!-- 1. add Custom Primary Color to root style -->
<style name="AppTheme.Overlay.PrimaryRed">
    <item name="colorPrimary">@color/material_red_500</item>
    <item name="colorPrimaryDark">@color/material_red_700</item>
</style>

<!-- 1. add Custom Accent Color to root style -->    
<style name="AppTheme.Overlay.AccentRed">
    <item name="colorAccent">@color/material_red_A200</item>
</style>

<!-- 2. add Custom Primary Color to root style -->
<style name="AppTheme.Overlay.PrimaryBlue">
    <item name="colorPrimary">@color/material_blue_500</item>
    <item name="colorPrimaryDark">@color/material_blue_700</item>
</style>

<!-- 2. add Custom Accent Color to root style -->    
<style name="AppTheme.Overlay.AccentBlue">
    <item name="colorAccent">@color/material_blue_A200</item>
</style>

<!-- add 10 for each...... -->

Создайте 10 стилей для основного цвета и 10 стилей для акцентного цвета.

Затем в вашем коде:

// if root style has some styles to add (default)
getTheme().applyStyle(R.style.AppTheme_Overlay);

// first color selection
getTheme().applyStyle(R.style.AppTheme_Overlay_PrimaryRed);
getTheme().applyStyle(R.style.AppTheme_Overlay_AccentRed);

// when you want blue color
getTheme().applyStyle(R.style.AppTheme_Overlay_PrimaryBlue);
getTheme().applyStyle(R.style.AppTheme_Overlay_AccentBlue);

// when you want bluePrimary, but redAccent color (bad choice)
getTheme().applyStyle(R.style.AppTheme_Overlay_PrimaryBlue);
getTheme().applyStyle(R.style.AppTheme_Overlay_AccentRed);

Здесь AppTheme_Overlay_PrimaryBlue перекрывает AppTheme_Overlay_PrimaryRed. И так далее.

Вы только что добавили один основной стиль, десять основных цветовых стилей и десять акцентных цветовых стилей = 21 стиль.

person rupinderjeet    schedule 21.01.2017
comment
Спасибо за ваш подробный ответ. В моем приложении мне нужна возможность изменить основной (темный) цвет и цвет акцента. Для 10 цветов это: 10 + 10 = 20 возможных тем наложения. Ваш метод имеет 10 * 10 = 100 возможных тем оверлея. Это много, чтобы поместить в styles.xml. Вы это понимаете или хотите, чтобы я объяснил подробнее? - person Thomas Vos; 21.01.2017
comment
Я только что узнал об этом, прежде чем ответить вам. Пожалуйста, проверьте мое редактирование. Если он по-прежнему не отвечает на ваш вопрос, давайте продолжим обсуждение в этой комнате, скажите, что я упустил ? - person rupinderjeet; 21.01.2017

применяется стиль

textInputStyle = R.style.TextInputFilled;
recreate();

сохранить стиль перед уничтожением активности:

@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putInt("textInputStyle", textInputStyle);
}

применить стиль при создании активности:

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (savedInstanceState != null) {
        textInputStyle = savedInstanceState.getInt("textInputStyle", 
        R.style.TextInputFilled);
    }
    getTheme().applyStyle(textInputStyle, true);
    setContentView(R.layout.act_text_field);
}
person wslaimin    schedule 16.12.2020