Ustaw motyw dla fragmentu


117

Próbuję ustawić motyw dla fragmentu.

Ustawienie motywu w manifeście nie działa:

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

Patrząc na poprzednie blogi, wydaje się, że muszę użyć ContextThemeWrapper. Czy ktoś może skierować mnie do zakodowanego przykładu? Nie mogę nic znaleźć.

Odpowiedzi:


187

Ustawienie motywu w manifeście jest zwykle używane do działania.

Jeśli chcesz ustawić motyw dla fragmentu, dodaj następny kod w onCreateView () fragmentu:

@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
to nie działa dla mnie. Fragment nadal ma ten sam motyw, który jest określony w pliku manifestu.
Giorgi

1
W manifeście określasz motyw dla działania, a nie fragment. czy używasz fragment czy fragmentActivity?
David

1
Pracował dla mnie. Z klasycznym fragmentem w ramach działania.
David

8
@David „Ustawienie motywu w manifeście służy do działania”. To nie jest do końca prawdą. Jeśli używasz FragmentTransaction, aby dodać fragment w czasie wykonywania, ten motyw jest również stosowany do fragmentów.
sebster,

4
Wydaje się, że to nie działa w przypadku SherlockFragmentActivity z biblioteki ActionBarSherlock.
toobsco42

18

Fragment bierze swój motyw z jego Aktywności. Każdemu fragmentowi przypisywany jest temat Działania, w którym występuje.

Motyw jest stosowany w metodzie Fragment.onCreateView, w której kod tworzy widoki, które w rzeczywistości są obiektami, w których jest używany motyw.

W Fragment.onCreateView dostajesz parametr LayoutInflater, który rozszerza widoki i przechowuje kontekst używany dla motywu, w rzeczywistości jest to Activity. Więc Twoje zawyżone widoki używają motywu Aktywności.

Aby nadpisać motyw, możesz wywołać LayoutInflater.cloneInContext , który wspomina w Dokumentach, że może być używany do zmiany motywu. Możesz tutaj użyć ContextThemeWrapper. Następnie użyj sklonowanego inflatera, aby utworzyć widoki fragmentów.


Jak podaje dokumentacja Google: „... Zwraca nowy obiekt LayoutInflater marki powiązany z danym kontekstem…” - developer.android.com/reference/android/view/ ...
Chris,

bardzo pomocny dodatek do rozwiązania kodu Davids. Dzięki!
muetzenflo

13

Do zastosowania jednego stylu właśnie użyłem

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

w onCreateView()fragmencie przed nadmuchaniem widoku root fragmentu i u mnie działa.


1
min api 23 dlagetContext()
vigilancer

@vigilancer Sprawdź tę odpowiedź, aby rozwiązać problem z minimalnym interfejsem API: stackoverflow.com/questions/36736244/…
rm8x

1
Świetne rozwiązanie. Dodałem kod w onAttach (Context), który również stosuje motyw na wszystkich fragmentach potomnych
crysxd

Może to mieć nieoczekiwane konsekwencje, ponieważ modyfikuje motyw kontekstu (w większości przypadków aktywności). Przyszłe nadmuchanie (na przykład po rotacji) działania spowoduje użycie nowego tematu wszędzie
Irhala

12

Próbowałem również wyświetlić okno dialogowe fragmentów z innym motywem niż jego aktywność i zastosowałem to rozwiązanie . Podobnie jak niektóre osoby wspomniane w komentarzach, nie działało, a okno dialogowe wyświetlało się z tematem określonym w manifeście. Problemem okazało się, że budował dialog używając AlertDialog.Builderw onCreateDialogsposób i tak nie robił stosowanie onCreateViewmetody jak pokazano w odpowiedzi, że powiązany. A kiedy tworzyłem instancję AlertDialog.BuilderI przechodziłem w kontekście używając, getActivity()kiedy powinienem był używać instancji ConstextThemeWrapperzamiast tego.

Oto kod mojego 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;
}

Pierwotnie AlertDialog.Builderutworzyłem instancję w następujący sposób:

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

które zmieniłem na:

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

Po tej zmianie pojawiło się okno dialogowe fragmentu z poprawnym motywem. Więc jeśli ktoś ma podobny problem i korzysta z AlertDialog.Buildertego, sprawdź kontekst przekazywany do buildera. Mam nadzieję że to pomoże! :)


9

Upewnij się, że android:minSdkVersion="11"ustawiłeś w swoim manifeście. To może być powód, dla którego przykład Davida nie zadziałał dla ciebie.

Ustaw również android:theme="@android:style/Theme.Holo.Light"atrybut dla <application>tagu, a NIE dla <activity>tagu.

Innym możliwym problemem może być sposób uzyskiwania kontekstu podczas korzystania z pliku ContextThemeWrapper(). Jeśli używasz czegoś takiego, getActivity().getApplicationContext()po prostu zamień to na getActivity().

Zwykle Theme.Holo powinno dotyczyć fragmentów połączonych z MainActivity.

Zwróć uwagę, że używasz ContextThemeWrapper, gdy chcesz zastosować inny motyw dla swojego fragmentu. Może pomóc, jeśli podasz fragment kodu z MainActivity, w którym dodasz swoje fragmenty.


Kilka przydatnych linków:

Niestandardowy ListView w fragmencie nie jest zgodny z motywem nadrzędnym


8

Wypróbowałem rozwiązanie, które David zasugerował, że działa, ale nie we wszystkich scenariuszach:
1. dla pierwszego fragmentu, który został dodany do stosu, ma temat działania, a nie ten, który zdefiniowano w onCrateView, ale na drugim fragmencie, który i dodaj do stosu popraw, czy zostały nałożone na fragment.

2. Na drugim fragmencie, który wyświetlił się poprawnie, wykonałem następujące czynności: wymusiłem zamknięcie aplikacji poprzez wyczyszczenie pamięci, ponowne otwarcie aplikacji i po odtworzeniu działania z fragmentem Fragment zmienił ich błędnie Activity, a nie to samo, które zostało ustawione w onCrateView fragmentu.

Aby rozwiązać ten problem, dokonałem niewielkiej zmiany i zastąpiłem argument kontenera z inflater.inflate wartością null.

Nie wiem, w jaki sposób inflater wykorzystuje w niektórych scenariuszach kontekst z widoku kontenera.

Uwaga - używam 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);
} 

Dzięki, twoje rozwiązanie mnie ratuje. Motyw My DialogFragment różnił się nieco od pozostałych fragmentów. To sprawiło, że mój EditText stał się dziwny, ponieważ użyłem dostarczonego inflatora. Znalazłem pomoc dotyczącą ContextThemeWrapper, ale nie pokazali, jak to się robi. Twoje rozwiązanie działa dla mnie. Wielkie dzięki.
Phuong Dao

4

Wiem, że jest trochę za późno, ale może pomóc komuś innemu, ponieważ pomogło mi.Możesz także spróbować dodać wiersz kodu poniżej wewnątrz funkcji onCreatView fragmentu

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

2

Utwórz klasę Java, a następnie użyj układu, którego motyw chcesz zmienić w metodzie onCreate, a następnie wspomnij o tym w pliku manifestu jak zwykle


1

Jeśli chcesz tylko zastosować styl do konkretnego fragmentu, po prostu dodaj te linie przed wywołaniem onCreateView()lub onAttach()fragmentem,

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

a jeśli chcesz ustawić przezroczysty pasek stanu, ustaw wartość false dla fitsSystemWindowswłaściwości układu głównego,

android:fitsSystemWindows="false"

1

Mam to do pracy, ustawiając motyw w kontekście fragmentu przed wywołaniem inflatora.

UWAGA: To jest przykład dla platformy Xamarin.Android w połączeniu z MvvmCross. Nie jestem w 100% pewien, czy to zadziała również dla programistów Java. Ale możesz spróbować :)

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

Kod metody rozszerzenia 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);
}

Mam nadzieję, że to pomoże niektórym ludziom, na zdrowie!


1

Rozwiązałem problem używając android:theme = "@style/myTheme"w pliku układu fragmentu. Na przykład zmienia to styl pliku LinearLayouti jego zawartość, ale nie zmienia niczego poza LinearLayout. Tak więc, aby ozdobić cały fragment dowolnym stylem, zastosuj motyw do jego zewnętrznego układu nadrzędnego.

Uwaga: na wszelki wypadek, jeśli jeszcze nie znalazłeś rozwiązania, możesz spróbować.

           <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

możesz spróbować tego dla Lollipopa w onAttach

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

i ustaw go z powrotem na domyślny w ondettach

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.