Imposta il tema per un frammento


117

Sto cercando di impostare il tema per un frammento.

L'impostazione del tema nel manifest non funziona:

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

Guardando i blog precedenti, sembra che devo usare un ContextThemeWrapper. Qualcuno può riferirmi a un esempio in codice? Non riesco a trovare niente.

Risposte:


187

L'impostazione del tema nel manifesto viene solitamente utilizzata per l'attività.

Se vuoi impostare il tema per il frammento, aggiungi il codice successivo in onCreateView () del frammento:

@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
questo non funziona per me. Il frammento ha ancora lo stesso tema specificato nel file manifest.
Giorgi

1
Nel manifest specifichi il tema per l'attività, non il frammento. stai usando fragment o fragmentActivity?
David

1
Ha funzionato per me. Con il classico Fragment all'interno di Activity.
David

8
@David "L'impostazione del tema nel manifesto viene utilizzata per l'attività". Questo non è del tutto vero. Se usi un FragmentTransaction per aggiungere il tuo frammento in fase di esecuzione, quel tema viene applicato anche ai frammenti.
sebster

4
Questo non sembra funzionare per SherlockFragmentActivity dalla libreria ActionBarSherlock.
toobsco42

18

Fragment prende il suo tema dalla sua attività. Ad ogni frammento viene assegnato il tema dell'attività in cui esiste.

Il tema viene applicato nel metodo Fragment.onCreateView, in cui il codice crea viste, che in realtà sono oggetti in cui viene utilizzato il tema.

In Fragment.onCreateView ottieni il parametro LayoutInflater, che gonfia le visualizzazioni e contiene Context utilizzato per il tema, in realtà questa è l'attività. Quindi le tue visualizzazioni gonfiate usano il tema di Activity.

Per sovrascrivere il tema, puoi chiamare LayoutInflater.cloneInContext , che menziona in Documenti che può essere utilizzato per cambiare tema. Puoi usare ContextThemeWrapper qui. Quindi usa l'inflater clonato per creare le viste del frammento.


Come afferma la documentazione di Google: "... Restituisce un nuovissimo oggetto LayoutInflater associato al contesto specificato ..." - developer.android.com/reference/android/view/…
Chris

aggiunta molto utile alla soluzione del codice Davids. Grazie!
muetzenflo

13

Per applicare un unico stile ho usato solo

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

nel onCreateView()frammento prima di gonfiare la vista della radice del frammento e per me funziona.


1
min api 23 pergetContext()
vigilancer

@vigilancer Controllare questa risposta per una correzione per il problema min api: stackoverflow.com/questions/36736244/...
rm8x

1
Ottima soluzione. Ho aggiunto il codice in onAttach (Context) che applica anche il tema a tutti i frammenti figlio
crysxd

Ciò può avere conseguenze inaspettate poiché modifica il tema del contesto (attività nella maggior parte dei casi). Un futuro gonfiaggio (ad esempio, dopo una rotazione) dell'attività utilizzerà il nuovo tema ovunque
Irhala

12

Stavo anche cercando di visualizzare la mia finestra di dialogo dei frammenti con un tema diverso rispetto alla sua attività e ho seguito questa soluzione . Come alcune persone menzionate nei commenti, non riuscivo a farlo funzionare e la finestra di dialogo continuava a essere visualizzata con il tema specificato nel manifest. Il problema si è scoperto essere che stavo costruendo la finestra di dialogo usando AlertDialog.Buildernel onCreateDialogmetodo e quindi non stavo usando il onCreateViewmetodo come mostrato nella risposta a cui mi collegavo. E quando stavo creando un'istanza, AlertDialog.Builderstavo passando nel contesto usando getActivity()quando avrei dovuto usare ConstextThemeWrapperinvece l'istanza .

Ecco il codice per il mio 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;
}

Inizialmente avevo AlertDialog.Builderistanziato come segue:

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

che ho cambiato in:

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

Dopo questa modifica è stata mostrata la finestra di dialogo del frammento con il tema corretto. Quindi, se qualcun altro ha un problema simile e sta utilizzando di, AlertDialog.Buildercontrolla il contesto passato al builder. Spero che questo ti aiuti! :)


9

Assicurati di aver android:minSdkVersion="11"impostato nel file manifest. Questa potrebbe essere la causa per cui l' esempio di David non ha funzionato per te.

Inoltre, imposta l' android:theme="@android:style/Theme.Holo.Light"attributo per il <application>tag e NON il <activity>tag.

Un altro possibile problema potrebbe essere il modo in cui ottieni il tuo contesto quando usi un file ContextThemeWrapper(). Se usi qualcosa di simile, getActivity().getApplicationContext()sostituiscilo con getActivity().

Normalmente, il Theme.Holo dovrebbe applicarsi ai frammenti collegati alla MainActivity.

Tieni presente che utilizzi un ContextThemeWrapper quando desideri applicare un tema diverso per il tuo frammento. Potrebbe essere utile fornire il pezzo di codice, dalla tua MainActivity, dove aggiungi i tuoi frammenti.


Alcuni link utili:

ListView personalizzato in Fragment non aderente al tema principale


8

Ho provato la soluzione che David mi ha suggerito funziona ma non in tutti gli scenari:
1. per il primo frammento che aggiunto allo stack ha il tema dell'attività e non quello definito in onCrateView, ma sul secondo frammento che ho aggiungere alla pila correggerli è stato applicato sul frammento.

2. Sul secondo frammento in cui è stato visualizzato correttamente, ho fatto quanto segue ho forzato la chiusura dell'App pulendo la memoria, riaprendo l'App e quando l'attività è stata ricreata con il frammento Il frammento ha cambiato le loro sbagliate di l'attività e non la stessa che è stata impostata in onCrateView del frammento.

Per risolvere il problema ho apportato una piccola modifica e ho sostituito l'argomento container da inflater.inflate con un null.

Non so come il inflater utilizzi in alcuni scenari il contesto dalla visualizzazione del contenitore.

Nota: sto usando android.support.v4.app.Fragment e 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);
} 

Grazie, la tua soluzione mi salva. Il tema del mio DialogFragment era in qualche modo diverso dagli altri frammenti. Ha reso il mio EditText strano perché ho usato inflater fornito. Ho trovato alcuni aiuti per quanto riguarda ContextThemeWrapper ma non hanno mostrato come è fatto. La tua soluzione funziona per me. Grazie molto.
Phuong Dao

4

So che è un po 'tardi ma potrebbe aiutare qualcun altro perché questo mi ha aiutato.Puoi anche provare ad aggiungere la riga di codice qui sotto all'interno della funzione onCreatView del frammento

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

2

Crea una classe java e poi usa il layout di cui vuoi cambiare il tema nel metodo onCreate, quindi menzionalo nel manifest come di consueto


1

Se vuoi solo applicare lo stile per un frammento particolare, aggiungi queste righe prima di chiamare onCreateView()o onAttach()del frammento,

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

e se vuoi impostare la barra di stato trasparente, imposta false sulla fitsSystemWindowsproprietà del layout radice,

android:fitsSystemWindows="false"

1

Devo farlo funzionare impostando il tema sul contesto del frammento prima di chiamare il gonfiatore.

NOTA: questo è un esempio per Xamarin.Android in combinazione con MvvmCross. Non sono sicuro al 100% se questo funzionerà anche per i programmatori Java. Ma puoi provare :)

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

Il codice del metodo di estensione 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);
}

Spero che questo aiuti alcune persone, applausi!


1

Ho risolto il problema utilizzando android:theme = "@style/myTheme"nel file di layout del frammento. Ad esempio, questo cambia lo stile di LinearLayoute il suo contenuto, ma non qualsiasi cosa al di fuori di LinearLayout. Quindi, per decorare l'intero frammento con qualsiasi stile, applica il tema al layout più esterno.

Nota: nel caso in cui non hai ancora trovato una soluzione, puoi provarla.

           <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

puoi provare questo per lollipop in onAttach

finestra finale della finestra = activity.getWindow (); window.setStatusBarColor (myStatusBarColor)

e impostalo di nuovo al valore predefinito in ondettach

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.