Set theme for a Fragment
Asked Answered
S

13

133

I'm trying to set the theme for a fragment.

Setting the theme in the manifest does not work:

android:theme="@android:style/Theme.Holo.Light"

From looking at previous blogs, it appears as though I have to use a ContextThemeWrapper. Can anyone refer me to a coded example? I can't find anything.

Sybarite answered 27/2, 2012 at 17:13 Comment(0)
E
219

Setting Theme in manifest is usually used for Activity.

If you want to set Theme for Fragment, add next code in the onGetLayoutInflater() of the Fragment:

override fun onGetLayoutInflater(savedInstanceState: Bundle?): LayoutInflater {
    val inflater = super.onGetLayoutInflater(savedInstanceState)
    val contextThemeWrapper: Context = ContextThemeWrapper(requireContext(), R.style.yourCustomTheme)
    return inflater.cloneInContext(contextThemeWrapper)
}
Eldoria answered 19/3, 2013 at 10:4 Comment(11)
this does not work for me. The fragment still has the same theme that is specified in the manifest file.Randolf
In the manifest you specify the Theme for the activity, not the fragment. are you using fragment or fragmentActivity?Eldoria
I'm using a ListFragment in a FragmentActivityRandolf
Worked for me. With classic Fragment within Activity.Eldoria
@Eldoria "Setting Theme in manifest is used for Activity". This is not entirely true. If you use a FragmentTransaction to add your Fragment at runtime that theme is applied to the Fragments as well.Deutzia
This does not seem to work for a SherlockFragmentActivity from the ActionBarSherlock library.Omnidirectional
i had same problem and it worked for me but i have fragment not fragment activityCalculous
@Randolf Were you able to get this working? I've a requirement of setting theme in Fragment, which is inside FragmentActivity.Patent
@Patent This was 6 years ago, I definitely don't remember it :)Randolf
Does anyone know, is this expensive? Should the ContextWrapper be cached?Hudnut
Make sure you have applied the custom attributes in the XML file. Using ContextWrapper instead of Context also worksMaddy
P
26

Fragment takes its theme from its Activity. Each fragment gets assigned the theme of the Activity in which it exists.

The theme is applied in Fragment.onCreateView method, where your code creates views, which are actually objects where theme is used.

In Fragment.onCreateView you get LayoutInflater parameter, which inflates views, and it holds Context used for theme, actually this is the Activity. So your inflated views use Activity's theme.

To override theme, you may call LayoutInflater.cloneInContext, which mentions in Docs that it may be used for changing theme. You may use ContextThemeWrapper here. Then use cloned inflater to create fragment's views.

Psychophysics answered 28/3, 2013 at 8:35 Comment(1)
As the google docs states it: "...Returns a brand spanking new LayoutInflater object associated with the given Context..." - developer.android.com/reference/android/view/…Redo
M
24

For applying a single style I've used just

getContext().getTheme().applyStyle(styleId, true);

in onCreateView() of the fragment before inflating root view of the fragment and it works for me.

Mendie answered 8/1, 2016 at 21:30 Comment(4)
min api 23 for getContext()Avid
@Avid Check this answer for a fix to your min api issue: #36736744Dustcloth
Great solution. I added the code in onAttach(Context) which also applies the theme on all child fragmentCommencement
This can have unexpected consequences as it modifies the context's (activity in most cases) theme. A future inflating (for example, after a rotation) of the Activity will use the new theme everywhereTrudy
R
13

I solved the problem using android:theme = "@style/myTheme" in the layout file of the fragment. For instance this changes the style of the LinearLayout and it's content but not any thing out side the LinearLayout. So, in order to decor the whole fragment with any style apply the theme to it's outer most parent layout.

Note: Just in case if you haven't found a solution yet, you can give it a try.

<LinearLayout 
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:theme = "@style/myTheme" >

    <TextView
        android:id="@+id/tc_buttom_text1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Time elapsed"/>

    <TextView
        android:id="@+id/tc_buttom_text2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:text="00:00:00 00"/>
</LinearLayout>
Retirement answered 29/8, 2017 at 7:23 Comment(0)
K
12

I was also trying to get my fragment dialog to display with a different theme to its activity, and followed this solution. Like some people mentioned in the comments, I was not getting it to work and the dialog kept showing with the theme specified in the manifest. The problem turned out to be that I was building the dialog using AlertDialog.Builder in the onCreateDialog method and so was not making use of the onCreateView method as shown in the answer that I linked to. And when I was instantiating the AlertDialog.Builder I was passing in the context using getActivity() when I should have been using the instantiated ConstextThemeWrapper instead.

Here is the code for my onCreateDialog:

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    // Create ContextThemeWrapper from the original Activity Context
    ContextThemeWrapper contextThemeWrapper = new ContextThemeWrapper(getActivity(), android.R.style.Theme_DeviceDefault_Light_Dialog);
    LayoutInflater inflater =   getActivity().getLayoutInflater().cloneInContext(contextThemeWrapper);
    // Now take note of the parameter passed into AlertDialog.Builder constructor
    AlertDialog.Builder builder = new AlertDialog.Builder(contextThemeWrapper);
    View view = inflater.inflate(R.layout.set_server_dialog, null);
    mEditText = (EditText) view.findViewById(R.id.txt_server);
    mEditText.requestFocus();  // Show soft keyboard automatically
    mEditText.setOnEditorActionListener(this);
    builder.setView(view);
    builder.setTitle(R.string.server_dialog);
    builder.setPositiveButton(android.R.string.ok, this);
    Dialog dialog = builder.create();
    dialog.setCanceledOnTouchOutside(false);
    return dialog;
}

I originally had the AlertDialog.Builder being instantiated as follows:

AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

which I changed to:

AlertDialog.Builder builder = new AlertDialog.Builder(contextThemeWrapper);

After this change the fragment dialog was shown with the correct theme. So if anyone else is having a similar problem and is making using of the AlertDialog.Builder then check the context being passed to the builder. Hope this helps! :)

Kain answered 18/7, 2014 at 23:24 Comment(0)
D
9

Make sure you have android:minSdkVersion="11" set in your manifest. This could be the cause why David's example didn't work for you.

Also, set the android:theme="@android:style/Theme.Holo.Light" attribute for the <application> tag and NOT the <activity> tag.

Another possible problem might be the way you get your Context when using a ContextThemeWrapper(). If you use something like getActivity().getApplicationContext() just replace it with getActivity() instead.

Normally, the Theme.Holo should apply to Fragments linked to the MainActivity.

Please note that you use a ContextThemeWrapper when you want to apply a different theme for your Fragment. It might help if you provide the piece of code, from your MainActivity, where you add your Fragments.


Some useful links:

Custom ListView in Fragment not adhering to parent theme

Deutzia answered 24/3, 2013 at 22:57 Comment(0)
B
8

I tried the solution that David suggested it did works but not in all scenarios:
1. for the first fragment that added to the stack has the the theme of the activity and not the one that defined in onCrateView , but on the second fragment that i add to the stack correct them was applied on the fragment.

2. On the second fragment that the them was displayed correctly ,i did the following i forced the App to be closed by clean the memory , re open the App and when the Activity was recreated with the fragment The fragment changed the them wrong them of the Activity and not the same that was set in the onCrateView of the fragment .

To fix the issue i did a small change and replaced the container argument from the inflater.inflate with a null.

i don't know way the inflater uses in some scenarios the context from the container view .

Note - that im using android.support.v4.app.Fragment & android.support.v7.app.AppCompatActivity .

@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.yourCustomTheme);

// clone the inflater using the ContextThemeWrapper 
LayoutInflater localInflater = inflater.cloneInContext(contextThemeWrapper);

// inflate the layout using the cloned inflater, not default inflater 
return localInflater.inflate(R.layout.yourLayout, null, false);
} 
Boredom answered 23/3, 2016 at 13:2 Comment(1)
Thanks, your solution saves me. My DialogFragment's theme was somehow different from the other fragments. It made my EditText become weird because I used provided inflater. I found some helps regarding ContextThemeWrapper but they haven't showed how it is done. Your solution works for me. Many thanks.Byrnie
B
7

I know its a bit late but it might help someone else because this helped me.You can also try adding the line of code below inside the onCreatView function of the fragment

inflater.context.setTheme(R.style.yourCustomTheme)
Boneyard answered 28/2, 2019 at 7:9 Comment(1)
It worked for me but I'm wondering if the approach can have side effects on other views. In my case the context is the MainActivity, I'm then overriding the MainActivity's theme. Does it make sense?Kila
S
3

If you just want to apply style for particular fragment then just add this lines before calling onCreateView() or onAttach() of the fragment,

getActivity().getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
getActivity().getWindow().setStatusBarColor(Color.TRANSPARENT);

and If you want to set transparent status bar then set false to fitsSystemWindows property of your root layout,

android:fitsSystemWindows="false"
Shaver answered 6/8, 2018 at 9:9 Comment(0)
T
2

Create a java class and then use the layout you want to change the theme of in the onCreate method.Then mention it in manifest as normal

Tedtedd answered 19/6, 2015 at 9:46 Comment(0)
T
0

I've got it to work by setting the theme on the fragment context before calling the inflator.

NOTE: This is an example for Xamarin.Android in combination with MvvmCross. I'm not 100% sure if this will also work for the Java programmers. But you can try :)

public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
    Context.SetTheme(Theme);

    base.OnCreateView(inflater, container, savedInstanceState);

    var view = this.BindingInflate(FragmentLayoutId, container, false);

    // Doing some other stuff

    return view;
}

The SetTheme extension method code

public static void SetTheme(this Context context, AppThemeStyle themeStyle)
{
    var themeStyleResId = themeStyle == AppThemeStyle.Dark ? Resource.Style.AppTheme : Resource.Style.AppTheme_Light;

    context.SetTheme(themeStyleResId);
}

I hope this helps some people out, cheers!

Tidings answered 14/6, 2019 at 10:32 Comment(0)
E
0

Use this in fragment which you want different theme:

@Override
public void onAttach(@NonNull Context context) {
    context.setTheme(R.style.your_them);
    super.onAttach(context);
}
Edwyna answered 9/6, 2022 at 5:13 Comment(0)
I
-1

you can try this for lollipop in onAttach

final Window window = activity.getWindow(); window.setStatusBarColor(myStatusBarColor)

and set it back to default in ondettach

Indicant answered 13/1, 2016 at 23:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.