2

I've got the following two themes:

<!-- 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>

The theme Theme.MyDemoApp is being used my my application or actually my entire application.

One activity opens a special fragment. The fragment is using a prominent app bar with an image, where the image is also displayed on the status bar. Thus, I've created an own theme called Theme.MyDemoApp.Prominent.Image which enables me to display the image on the status bar.

Since the fragment will be called from different actities AND fragments, I want to set the Theme.MyDemoApp.Prominent.Image to the fragment. I've looked many solutions to set the theme to fragment such as:

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);
}

Setting the theme directly in the fragment xml file

<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>

However, NONE of the above tried solutions worked for me. The theme won't change aka the status bar is not transparent. If I put the fragment theme parameters into the activity theme, it work's like a charm, but that is not what I'm planning to do.....

What might the problem be and any idea how can I set the theme in my fragment correctly?

Funny Moments
  • 421
  • 2
  • 13
  • @snachmsm thanks for the input, unfortunately it wasn't a success. It seems that the issue is ```android:statusBarColor``` and ```android:windowTranslucentNavigation``` cause it seems the the color attributes will get changed(if i override it in my fragment theme) , but not the statusbar color – Funny Moments Nov 23 '22 at 21:22
  • posted as answer with some explanation – snachmsm Nov 23 '22 at 21:33

1 Answers1

1

try to return localInflater.inflate(... in 2. try

@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);
}

edit: now I see problem more clearly...

you are trying to set statusBarColor and windowTranslucentNavigation - those are params for Activity, not Fragment. so your theme should be applied to Activity, setting up theme on Fragment or View layer/level (kind-of child of Fragment, which is a child of Activity) by Context wrapping or setting programmtacially/by XML is just "too low", hosting Activity just won't apply these attributes

so you have to set up Theme for whole Activity - translucent status bar when your Fragment shows up and returning to default (black?) color when detaching it. but you can set Theme for whole Activity programmatically only by calling setTheme( before super.onCreate( call, so only at very beginning, when you probably won't be sure that translucent-status-Fragment will be shown... (e.g. it may show on some click during runtime)

so you need to restart Activity then, with some additional flag customising setTheme(, also your Fragment should pop-up then at start... you may use Bundle passed for Intent starting this Activity again just after finish() call

I do believe that this is just too much effort and your Fragment should be in fact another Activity with this transparent-status theme set up by XML, optionally it may be some extension of some transparet-Activity-theme instead of your "Theme.MyDemoApp"

snachmsm
  • 17,866
  • 3
  • 32
  • 74
  • Thanks for detailed answer. :) Now it makes sence why my approach didn't work. You mentioned that I should replace the fragment with an activity (which works perfect btw thanks to you) , but wouldn't fragments be better, even in this case if the fragment approach worked? Cause I call the fragment, or now the activity, from different fragments and since fragments are meant to be reusable code, I decided to go for it. Cause now I have many fragments and one "random" activity in this case which kinda looks strange. – Funny Moments Nov 23 '22 at 21:46
  • 1
    well, `Fragment`s are "pieces of `Activity`" and your purpose is to change param of an `Activity`, not some interal piece of it, so for this you need to have specially stylled `Activity`. Note that you still can have all your logic as `Fragment` and you may still open it in any `Activity`, but statusbar won't change, as "`Activity` decides". But in some circumstances you may instead start some "dummy-transparent-Activity" passing to it your `Fragment` (or some data indicating `Fragment` init inside), then status bas will be transparent – snachmsm Nov 23 '22 at 21:52
  • 1
    And here you have the idea of fragmenting and reusability - your `Fragment` can be attached in multiple ways/statusbar-colors, but you probably need only transparent one (so new `Activity`), and also dummy-transparent-`Activity` may take and run some another `Fragment` showing it with translucent/no statusbar – snachmsm Nov 23 '22 at 21:54