Thema für ein Fragment festlegen

117

Ich versuche, das Thema für ein Fragment festzulegen.

Das Festlegen des Themas im Manifest funktioniert nicht:

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

Aus früheren Blogs geht hervor, dass ich einen ContextThemeWrapper verwenden muss. Kann mich jemand auf ein codiertes Beispiel verweisen? Ich kann nichts finden

user1232691
quelle

Antworten:

187

Das Festlegen des Themas im Manifest wird normalerweise für Aktivitäten verwendet.

Wenn Sie das Thema für das Fragment festlegen möchten, fügen Sie den nächsten Code in onCreateView () des Fragments hinzu:

@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);
}
David
quelle
30
das funktioniert bei mir nicht. Das Fragment hat immer noch das gleiche Thema, das in der Manifestdatei angegeben ist.
Giorgi
1
Im Manifest geben Sie das Thema für die Aktivität an, nicht das Fragment. Verwenden Sie fragment oder fragmentActivity?
David
1
Hat für mich gearbeitet. Mit klassischem Fragment innerhalb der Aktivität.
David
8
@David "Das Festlegen des Themas im Manifest wird für Aktivitäten verwendet". Dies ist nicht ganz richtig. Wenn Sie ein FragmentTransaction verwenden, um Ihr Fragment zur Laufzeit hinzuzufügen, wird dieses Thema auch auf die Fragmente angewendet.
sebster
4
Dies scheint für eine SherlockFragmentActivity aus der ActionBarSherlock-Bibliothek nicht zu funktionieren.
toobsco42
18

Fragment nimmt sein Thema von seiner Aktivität. Jedem Fragment wird das Thema der Aktivität zugewiesen, in der es vorhanden ist.

Das Thema wird in der Fragment.onCreateView-Methode angewendet, bei der Ihr Code Ansichten erstellt, bei denen es sich tatsächlich um Objekte handelt, bei denen das Thema verwendet wird.

In Fragment.onCreateView erhalten Sie den Parameter LayoutInflater, der die Ansichten aufbläst und den für das Thema verwendeten Kontext enthält. Dies ist eigentlich die Aktivität. Ihre aufgeblasenen Ansichten verwenden also das Thema der Aktivität.

Um das Thema zu überschreiben, können Sie LayoutInflater.cloneInContext aufrufen , in dem in den Dokumenten erwähnt wird, dass es zum Ändern des Themas verwendet werden kann. Sie können ContextThemeWrapper hier verwenden. Verwenden Sie dann den geklonten Inflater, um die Ansichten des Fragments zu erstellen.

Zeiger Null
quelle
In den Google-Dokumenten heißt es: "... gibt ein brandneues LayoutInflater-Objekt zurück, das dem angegebenen Kontext zugeordnet ist ..." - developer.android.com/reference/android/view/…
Chris
sehr hilfreiche Ergänzung zu Davids Code-Lösung. Vielen Dank!
Muetzenflo
13

Für die Anwendung eines einzelnen Stils habe ich gerade verwendet

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

in onCreateView()des Fragments vor dem Aufblasen der Wurzelansicht des Fragments und es funktioniert für mich.

Maskieren
quelle
1
min api 23 forgetContext()
vigilancer
@vigilancer Überprüfen Sie diese Antwort für eine Lösung für Ihr Min-API-Problem: stackoverflow.com/questions/36736244/…
rm8x
1
Tolle Lösung. Ich habe den Code in onAttach (Kontext) hinzugefügt, der auch das Thema auf alle
untergeordneten
Dies kann unerwartete Konsequenzen haben, da das Thema des Kontexts (in den meisten Fällen Aktivität) geändert wird. Ein zukünftiges Aufblasen (zum Beispiel nach einer Rotation) der Aktivität wird das neue Thema überall verwenden
Irhala
12

Ich habe auch versucht, meinen Fragmentdialog mit einem anderen Thema als seiner Aktivität anzuzeigen, und bin dieser Lösung gefolgt . Wie einige in den Kommentaren erwähnte Personen haben ich es nicht zum Laufen gebracht und der Dialog wurde immer wieder mit dem im Manifest angegebenen Thema angezeigt. Es stellte sich heraus, dass ich den Dialog mit AlertDialog.Builderder onCreateDialogMethode erstellt habe und daher die onCreateViewMethode nicht wie in der Antwort, mit der ich verlinkt habe, verwendet habe. Und als ich das instanziierte, AlertDialog.Builderübergab ich im Kontext, getActivity()wann ich ConstextThemeWrapperstattdessen das instanziierte hätte verwenden sollen.

Hier ist der Code für meinen 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;
}

Ich hatte das AlertDialog.BuilderWesen ursprünglich wie folgt instanziiert:

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

was ich geändert habe zu:

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

Nach dieser Änderung wurde der Fragmentdialog mit dem richtigen Thema angezeigt. Wenn also jemand anderes ein ähnliches Problem hat und das verwendet, AlertDialog.Builderüberprüfen Sie den Kontext, der an den Builder übergeben wird. Hoffe das hilft! :) :)

BruceHill
quelle
9

Stellen Sie sicher, dass Sie android:minSdkVersion="11"in Ihrem Manifest festgelegt haben. Dies könnte der Grund sein, warum Davids Beispiel für Sie nicht funktioniert hat.

Legen Sie außerdem das android:theme="@android:style/Theme.Holo.Light"Attribut für das <application>Tag und NICHT das <activity>Tag fest.

Ein weiteres mögliches Problem könnte die Art und Weise sein, wie Sie Ihren Kontext erhalten, wenn Sie a verwenden ContextThemeWrapper(). Wenn Sie so etwas wie verwenden, getActivity().getApplicationContext()ersetzen Sie es getActivity()stattdessen durch.

Normalerweise sollte das Theme.Holo für Fragmente gelten, die mit der Hauptaktivität verknüpft sind.

Bitte beachten Sie, dass Sie einen ContextThemeWrapper verwenden, wenn Sie ein anderes Thema für Ihr Fragment anwenden möchten . Es kann hilfreich sein, wenn Sie den Code aus Ihrer MainActivity bereitstellen, in dem Sie Ihre Fragmente hinzufügen.


Einige nützliche Links:

Benutzerdefinierte ListView in Fragment, die nicht dem übergeordneten Thema entspricht

sebster
quelle
8

Ich habe die von David vorgeschlagene Lösung ausprobiert, aber nicht in allen Szenarien:
1. Für das erste Fragment, das dem Stapel hinzugefügt wurde, ist das Thema der Aktivität und nicht das in onCrateView definierte, sondern das zweite Fragment, das i Zum Stapel hinzufügen, richtig, sie wurden auf das Fragment angewendet.

2. Auf dem zweiten Fragment, auf dem sie korrekt angezeigt wurden, habe ich Folgendes getan: Ich habe die App durch Bereinigen des Speichers geschlossen, die App erneut geöffnet und als die Aktivität mit dem Fragment neu erstellt wurde, hat das Fragment die falschen Werte geändert die Aktivität und nicht dieselbe, die in der onCrateView des Fragments festgelegt wurde.

Um das Problem zu beheben, habe ich eine kleine Änderung vorgenommen und das Container-Argument aus der inflater.inflate durch eine Null ersetzt.

Ich weiß nicht, wie der Inflater in einigen Szenarien den Kontext aus der Containeransicht verwendet.

Hinweis - dass ich android.support.v4.app.Fragment & android.support.v7.app.AppCompatActivity verwende.

@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);
} 
avi
quelle
Danke, deine Lösung rettet mich. Das Thema meines DialogFragments war irgendwie anders als die anderen Fragmente. Dadurch wurde mein EditText seltsam, weil ich den bereitgestellten Inflater verwendet habe. Ich habe einige Hilfen in Bezug auf ContextThemeWrapper gefunden, aber sie haben nicht gezeigt, wie es gemacht wird. Ihre Lösung funktioniert bei mir. Danke vielmals.
Phuong Dao
4

Ich weiß, dass es etwas spät ist, aber es könnte jemand anderem helfen, weil mir das geholfen hat. Sie können auch versuchen, die folgende Codezeile in die onCreatView-Funktion des Fragments einzufügen

    inflater.context.setTheme(R.style.yourCustomTheme)
cbizzy
quelle
2

Erstellen Sie eine Java-Klasse und verwenden Sie dann das Layout, dessen Thema Sie in der onCreate-Methode ändern möchten. Erwähnen Sie es dann wie gewohnt im Manifest

Devam03
quelle
1

Wenn Sie nur den Stil für ein bestimmtes Fragment anwenden möchten, fügen Sie diese Zeilen einfach vor dem Aufruf onCreateView()oder onAttach()des Fragments hinzu.

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

und Wenn Sie eine transparente Statusleiste festlegen möchten, setzen Sie false auf die fitsSystemWindowsEigenschaft Ihres Root-Layouts.

android:fitsSystemWindows="false"
Siddharth Sheth
quelle
1

Ich habe es zum Laufen gebracht, indem ich das Thema auf den Fragmentkontext gesetzt habe, bevor ich den Inflator aufgerufen habe.

HINWEIS: Dies ist ein Beispiel für Xamarin.Android in Kombination mit MvvmCross. Ich bin mir nicht 100% sicher, ob dies auch für die Java-Programmierer funktioniert. Aber du kannst es versuchen :)

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

Der Code der SetTheme-Erweiterungsmethode

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

    context.SetTheme(themeStyleResId);
}

Ich hoffe das hilft einigen Leuten, Prost!

Jop Middelkamp
quelle
1

Ich habe das Problem mithilfe android:theme = "@style/myTheme"der Layoutdatei des Fragments gelöst . Zum Beispiel ändert dies den Stil des LinearLayoutund seinen Inhalt, aber nichts außerhalb des LinearLayout. Um das gesamte Fragment mit einem beliebigen Stil zu dekorieren, wenden Sie das Thema auf das äußerste übergeordnete Layout an.

Hinweis: Falls Sie noch keine Lösung gefunden haben, können Sie sie ausprobieren.

           <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>
Niraj Niroula
quelle
-1

Sie können dies für Lutscher in onAttach versuchen

letztes Fenster window = activity.getWindow (); window.setStatusBarColor (myStatusBarColor)

und setzen Sie es in ondettach auf den Standard zurück

Amjed Baig
quelle