user1232691
user1232691

Reputation: 1333

Set theme for a Fragment

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.

Upvotes: 133

Views: 124756

Answers (13)

mostafa3dmax
mostafa3dmax

Reputation: 1017

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

Upvotes: 0

Niraj Niroula
Niraj Niroula

Reputation: 2424

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>

Upvotes: 14

cbizzy
cbizzy

Reputation: 109

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)

Upvotes: 7

David
David

Reputation: 37536

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

Upvotes: 220

Jop Middelkamp
Jop Middelkamp

Reputation: 153

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!

Upvotes: 0

Siddharth Sheth
Siddharth Sheth

Reputation: 217

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"

Upvotes: 3

sebster
sebster

Reputation: 1320

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

Upvotes: 9

Pointer Null
Pointer Null

Reputation: 40370

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.

Upvotes: 26

avi
avi

Reputation: 91

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

Upvotes: 8

Amjed Baig
Amjed Baig

Reputation: 422

you can try this for lollipop in onAttach

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

and set it back to default in ondettach

Upvotes: -1

Tomask
Tomask

Reputation: 2394

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.

Upvotes: 24

Devam03
Devam03

Reputation: 141

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

Upvotes: 2

BruceHill
BruceHill

Reputation: 7164

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

Upvotes: 12

Related Questions