Définir le thème d'un fragment


117

J'essaie de définir le thème d'un fragment.

La définition du thème dans le manifeste ne fonctionne pas:

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

En regardant les blogs précédents, il semble que je doive utiliser un ContextThemeWrapper. Quelqu'un peut-il me référer à un exemple codé? Je ne trouve rien.

Réponses:


187

La définition du thème dans le manifeste est généralement utilisée pour l'activité.

Si vous souhaitez définir le thème pour le fragment, ajoutez le code suivant dans le onCreateView () du fragment:

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

30
Cela ne fonctionne pas pour moi. Le fragment a toujours le même thème que celui spécifié dans le fichier manifeste.
Giorgi

1
Dans le manifeste, vous spécifiez le thème de l'activité, pas le fragment. utilisez-vous fragment ou fragmentActivity?
David

1
A travaillé pour moi. Avec Fragment classique dans l'activité.
David

8
@David "Le thème de réglage dans le manifeste est utilisé pour l'activité". Ce n'est pas entièrement vrai. Si vous utilisez une FragmentTransaction pour ajouter votre Fragment au moment de l'exécution, ce thème est également appliqué aux Fragments.
sebster

4
Cela ne semble pas fonctionner pour un SherlockFragmentActivity de la bibliothèque ActionBarSherlock.
toobsco42

18

Fragment tire son thème de son activité. Chaque fragment se voit attribuer le thème de l'activité dans laquelle il existe.

Le thème est appliqué dans la méthode Fragment.onCreateView, où votre code crée des vues, qui sont en fait des objets où le thème est utilisé.

Dans Fragment.onCreateView, vous obtenez le paramètre LayoutInflater, qui gonfle les vues, et il contient le contexte utilisé pour le thème, en fait il s'agit de l'activité. Ainsi, vos vues gonflées utilisent le thème d'Activité.

Pour remplacer le thème, vous pouvez appeler LayoutInflater.cloneInContext , qui mentionne dans Docs qu'il peut être utilisé pour changer de thème. Vous pouvez utiliser ContextThemeWrapper ici. Ensuite, utilisez un gonfleur cloné pour créer des vues de fragment.


Comme le dit la documentation Google: "... Renvoie une marque avec un nouvel objet LayoutInflater associé au contexte donné ..." - developer.android.com/reference/android/view/…
Chris

ajout très utile à la solution de code Davids. Merci!
muetzenflo le

13

Pour appliquer un seul style que j'ai utilisé juste

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

dans onCreateView()le fragment avant de gonfler la vue racine du fragment et cela fonctionne pour moi.


1
min api 23 forgetContext()
vigilancer

@vigilancer Vérifiez cette réponse pour une solution à votre problème d'API min: stackoverflow.com/questions/36736244/…
rm8x

1
Excellente solution. J'ai ajouté le code dans onAttach (Context) qui applique également le thème sur tous les fragments enfants
crysxd

Cela peut avoir des conséquences inattendues car il modifie le thème du contexte (activité dans la plupart des cas). Un futur gonflement (par exemple, après une rotation) de l'activité utilisera le nouveau thème partout
Irhala

12

J'essayais également d'afficher ma boîte de dialogue de fragment avec un thème différent de son activité et j'ai suivi cette solution . Comme certaines personnes mentionnées dans les commentaires, je ne le faisais pas fonctionner et le dialogue continuait à s'afficher avec le thème spécifié dans le manifeste. Le problème s'est avéré être que je construisais le dialogue en utilisant AlertDialog.Builderdans la onCreateDialogméthode et que je n'utilisais donc pas la onCreateViewméthode comme indiqué dans la réponse à laquelle j'ai lié. Et quand j'instanciais le AlertDialog.Builderje passais dans le contexte en utilisant getActivity()quand j'aurais dû utiliser l'instancié à la ConstextThemeWrapperplace.

Voici le code de mon 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;
}

J'ai eu à l'origine l' AlertDialog.Builderêtre instancié comme suit:

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

que j'ai changé en:

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

Après cette modification, la boîte de dialogue de fragment a été affichée avec le thème correct. Donc, si quelqu'un d'autre a un problème similaire et utilise le, AlertDialog.Buildervérifiez le contexte transmis au générateur. J'espère que cela t'aides! :)


9

Assurez-vous que vous avez android:minSdkVersion="11"défini dans votre manifeste. Cela pourrait expliquer pourquoi l' exemple de David n'a pas fonctionné pour vous.

Définissez également l' android:theme="@android:style/Theme.Holo.Light"attribut de la <application>balise et NON la <activity>balise.

Un autre problème possible pourrait être la façon dont vous obtenez votre contexte lorsque vous utilisez un ContextThemeWrapper(). Si vous utilisez quelque chose comme, getActivity().getApplicationContext()remplacez-le par getActivity().

Normalement, le Theme.Holo doit s'appliquer aux fragments liés à MainActivity.

Veuillez noter que vous utilisez un ContextThemeWrapper lorsque vous souhaitez appliquer un thème différent pour votre Fragment. Cela peut aider si vous fournissez le morceau de code, à partir de votre MainActivity, où vous ajoutez vos fragments.


Quelques liens utiles:

La vue de liste personnalisée dans le fragment n'adhère pas au thème parent


8

J'ai essayé la solution suggérée par David, cela fonctionne mais pas dans tous les scénarios:
1. pour le premier fragment ajouté à la pile, le thème de l'activité et non celui défini dans onCrateView, mais sur le deuxième fragment que je ajouter à la pile les corriger a été appliqué sur le fragment.

2. Sur le deuxième fragment que le leur était affiché correctement, j'ai fait ce qui suit j'ai forcé l'application à être fermée en nettoyant la mémoire, rouvrez l'application et lorsque l'activité a été recréée avec le fragment Le fragment a changé les mauvais eux de l'activité et pas la même que celle définie dans onCrateView du fragment.

Pour résoudre le problème, j'ai fait un petit changement et remplacé l'argument conteneur de inflater.inflate par un null.

Je ne sais pas comment le gonfleur utilise dans certains scénarios le contexte de la vue du conteneur.

Remarque - que j'utilise 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);
} 

Merci, votre solution me sauve. Le thème de mon DialogFragment était en quelque sorte différent des autres fragments. Cela a rendu mon EditText devenu bizarre parce que j'ai utilisé le gonfleur fourni. J'ai trouvé des aides concernant ContextThemeWrapper mais elles n'ont pas montré comment cela se faisait. Votre solution fonctionne pour moi. Merci beaucoup.
Phuong Dao

4

Je sais que c'est un peu tard mais cela pourrait aider quelqu'un d'autre car cela m'a aidé.Vous pouvez également essayer d'ajouter la ligne de code ci-dessous à l'intérieur de la fonction onCreatView du fragment

    inflater.context.setTheme(R.style.yourCustomTheme)

2

Créez une classe java, puis utilisez la mise en page dont vous souhaitez modifier le thème dans la méthode onCreate, puis mentionnez-la dans le manifeste comme d'habitude


1

Si vous souhaitez simplement appliquer un style à un fragment particulier, ajoutez simplement ces lignes avant d'appeler onCreateView()ou onAttach()du fragment,

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

et si vous souhaitez définir la barre d'état transparente, définissez false sur la fitsSystemWindowspropriété de votre disposition racine,

android:fitsSystemWindows="false"

1

Je l'ai fait fonctionner en définissant le thème sur le contexte du fragment avant d'appeler le gonfleur.

REMARQUE: il s'agit d'un exemple pour Xamarin.Android en combinaison avec MvvmCross. Je ne suis pas sûr à 100% si cela fonctionnera également pour les programmeurs Java. Mais tu peux essayer :)

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

Le code de la méthode d'extension SetTheme

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

    context.SetTheme(themeStyleResId);
}

J'espère que cela aidera certaines personnes, bravo!


1

J'ai résolu le problème en utilisant android:theme = "@style/myTheme"dans le fichier de mise en page du fragment. Par exemple, cela change le style du LinearLayoutet de son contenu, mais rien en dehors du LinearLayout. Ainsi, afin de décorer le fragment entier avec n'importe quel style, appliquez le thème à sa mise en page parent la plus externe.

Remarque: au cas où vous n'avez pas encore trouvé de solution, vous pouvez l'essayer.

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

-1

vous pouvez essayer ceci pour une sucette dans onAttach

fenêtre finale de la fenêtre = activity.getWindow (); window.setStatusBarColor (myStatusBarColor)

et le remettre par défaut dans ondettach

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.