Установка темы для фрагмента

У меня есть следующие две темы:

<!-- Base application theme. -->
<style name = "Theme.MyDemoApp" parent = "Theme.MaterialComponents.DayNight.NoActionBar">
    <!-- Primary brand color. -->
    <item name = "colorPrimary">@color/purple_500</item>
    <item name = "colorPrimaryVariant">@color/purple_700</item>
    <item name = "colorOnPrimary">@color/white</item>
    <!-- Secondary brand color. -->
    <item name = "colorSecondary">@color/teal_200</item>
    <item name = "colorSecondaryVariant">@color/teal_700</item>
    <item name = "colorOnSecondary">@color/purple_500</item>
</style>

<!-- Base application theme with a prominent app bar incl. image -->
<style name = "Theme.MyDemoApp.Prominent.Image" parent = "Theme.MyDemoApp">

    <!-- Transparent status bar, so that the image extents to the status bar-->
    <item name = "android:statusBarColor">@android:color/transparent</item>
    <item name = "android:windowTranslucentNavigation">true</item>
</style>

Тема Theme.MyDemoApp используется в моем приложении или на самом деле во всем моем приложении.

Одно действие открывает специальный фрагмент. Фрагмент использует заметную панель приложения с изображением, где изображение также отображается в строке состояния. Поэтому я создал собственную тему под названием Theme.MyDemoApp.Prominent.Image, которая позволяет отображать изображение в строке состояния.

Поскольку фрагмент будет вызываться из разных действий И фрагментов, я хочу установить Theme.MyDemoApp.Prominent.Image на фрагмент. Я просмотрел много решений, чтобы установить тему на фрагмент, например:

1)

@Override
public void onAttach(@NonNull Context context) {
    context.setTheme(R.style.Theme_MyDemoApp_Prominent_Image);
    super.onAttach(context);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    //create ContextThemeWrapper from the original Activity Context with the custom theme
    final Context contextThemeWrapper = new ContextThemeWrapper(getActivity(), R.style.Theme_MyDemoApp_Prominent_Image);

    //clone the inflater using the ContextThemeWrapper
    LayoutInflater localInflater = inflater.cloneInContext(contextThemeWrapper);
    
    return inflater.inflate(R.layout.fragment_demo_appbar_image, container, false);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    getContext().getTheme().applyStyle(R.style.Theme_MyDemoApp_Prominent_Image, true);
    return inflater.inflate(R.layout.fragment_demo_appbar_image, container, false);
}

Установка темы прямо в xml файле фрагмента

<androidx.coordinatorlayout.widget.CoordinatorLayout
    xmlns:android = "http://schemas.android.com/apk/res/android"
    xmlns:app = "http://schemas.android.com/apk/res-auto"
    android:layout_width = "match_parent"
    android:layout_height = "match_parent"
    style = "@style/Theme.MyDemoApp.Prominent.Image"
    android:theme = "@style/Theme.MyDemoApp.Prominent.Image"
    >
<!-- bla bla bla bla -->
</androidx.coordinatorlayout.widget.CoordinatorLayout>

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

В чем может быть проблема и есть идеи, как правильно установить тему в моем фрагменте?

@snachmsm спасибо за вклад, к сожалению, это не удалось. Кажется, проблема в android:statusBarColor и android:windowTranslucentNavigation, потому что кажется, что атрибуты цвета будут изменены (если я переопределю их в своей теме фрагмента), но не цвет строки состояния

Funny Moments 23.11.2022 22:22

опубликовано как ответ с некоторыми пояснениями

snachmsm 23.11.2022 22:33
2
2
88
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

попробуй return localInflater.inflate(... через 2. попробуй

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    //create ContextThemeWrapper from the original Activity Context with the custom theme
    final Context contextThemeWrapper = 
        new ContextThemeWrapper(getActivity(), R.style.Theme_MyDemoApp_Prominent_Image);

    //clone the inflater using the ContextThemeWrapper
    LayoutInflater localInflater = inflater.cloneInContext(contextThemeWrapper);
    return localInflater.inflate(R.layout.fragment_demo_appbar_image, container, false);
}

редактировать: теперь я вижу проблему более четко...

вы пытаетесь установить statusBarColor и windowTranslucentNavigation - это параметры для Activity, а не Fragment. поэтому ваша тема должна быть применена к Activity, установка темы на Fragment или View слой/уровень (что-то вроде дочернего элемента Fragment, который является дочерним элементом Activity) с помощью Context обертывания или установки программно/с помощью XML просто «слишком низкая», хостинг Activity просто не будет применять эти атрибуты

поэтому вам нужно настроить Theme для всего Activity - полупрозрачная строка состояния, когда отображается ваш Fragment, и возвращающийся к цвету по умолчанию (черный?) при его отсоединении. но вы можете установить Theme для всего Activity программно, только вызвав setTheme( перед вызовом super.onCreate(, так что только в самом начале, когда вы, вероятно, не будете уверены, что полупрозрачный-статус-Fragment будет показан... (например, это может отображаться при щелчке во время выполнения)

поэтому вам нужно перезапустить Activity, затем, с некоторой дополнительной настройкой флага setTheme(, также ваш Fragment должен появиться, затем при запуске ... вы можете использовать Bundle, переданный для Intent, начиная это Activity снова сразу после finish() вызова

Я действительно считаю, что это слишком много усилий, и ваш Fragment должен быть на самом деле другим Activity с этой темой прозрачного статуса, настроенной с помощью XML, опционально это может быть какое-то расширение какой-то прозрачной темы активности вместо вашей "Theme.MyDemoApp"

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

Funny Moments 23.11.2022 22:46

ну, Fragments - это "кусочки Activity", и ваша цель - изменить параметр Activity, а не какую-то его внутреннюю часть, поэтому для этого вам нужно иметь специально стилизованный Activity. Обратите внимание, что у вас по-прежнему может быть вся ваша логика как Fragment, и вы по-прежнему можете открыть ее в любом Activity, но строка состояния не изменится, как «решает Activity». Но в некоторых случаях вы можете вместо этого запустить какую-то "dummy-transparent-Activity", передав ей свой Fragment (или некоторые данные, указывающие на Fragment init внутри), тогда статусная база будет прозрачной

snachmsm 23.11.2022 22:52

И вот вам идея фрагментации и повторного использования - ваш Fragment может быть прикреплен несколькими способами/цвета статусбара, но вам, вероятно, нужен только прозрачный (такой новый Activity), а также фиктивный-прозрачный-Activity может взять и запустить какой-то другой Fragment показывает его с полупрозрачной/без строки состояния

snachmsm 23.11.2022 22:54

Другие вопросы по теме