Tetapkan tema untuk Fragmen

117

Saya mencoba menyetel tema untuk sebuah fragmen.

Menyetel tema di manifes tidak berfungsi:

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

Dari melihat blog sebelumnya, sepertinya saya harus menggunakan ContextThemeWrapper. Adakah yang bisa merujuk saya ke contoh berkode? Saya tidak dapat menemukan apa pun.

pengguna1232691
sumber

Jawaban:

187

Mengatur Tema dalam manifes biasanya digunakan untuk Aktivitas.

Jika Anda ingin menyetel Tema untuk Fragmen, tambahkan kode berikutnya di onCreateView () dari Fragmen:

@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
sumber
30
ini tidak berhasil untuk saya. Fragmen tersebut masih memiliki tema yang sama dengan yang ditentukan dalam file manifes.
Giorgi
1
Di manifes Anda menentukan Tema untuk aktivitas, bukan fragmennya. apakah Anda menggunakan fragment atau fragmentActivity?
David
1
Bekerja untuk saya. Dengan Fragmen klasik dalam Aktivitas.
David
8
@David "Tema Pengaturan dalam manifes digunakan untuk Aktivitas". Ini tidak sepenuhnya benar. Jika Anda menggunakan FragmentTransaction untuk menambahkan Fragment pada waktu proses, tema tersebut juga akan diterapkan ke Fragmen.
sebster
4
Tampaknya ini tidak berfungsi untuk SherlockFragmentActivity dari pustaka ActionBarSherlock.
toobsco42
18

Fragmen mengambil temanya dari Aktivitasnya. Setiap fragmen diberi tema Activity tempatnya ada.

Tema diterapkan dalam metode Fragment.onCreateView, di mana kode Anda membuat tampilan, yang sebenarnya merupakan objek tempat tema digunakan.

Di Fragment.onCreateView Anda mendapatkan parameter LayoutInflater, yang memekarkan tampilan, dan memegang Konteks yang digunakan untuk tema, sebenarnya ini adalah Aktivitas. Jadi tampilan meningkat Anda menggunakan tema Activity.

Untuk mengganti tema, Anda dapat memanggil LayoutInflater.cloneInContext , yang menyebutkan di Dokumen bahwa itu mungkin digunakan untuk mengubah tema. Anda dapat menggunakan ContextThemeWrapper di sini. Kemudian gunakan inflater kloning untuk membuat tampilan fragmen.

Pointer Null
sumber
Seperti yang dinyatakan oleh Google Dokumen: "... Mengembalikan objek LayoutInflater baru yang terkait dengan Konteks yang diberikan ..." - developer.android.com/reference/android/view/…
Chris
tambahan yang sangat membantu untuk solusi kode Davids. Terima kasih!
muetzenflo
13

Untuk menerapkan satu gaya yang baru saja saya gunakan

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

di onCreateView()dalam fragmen sebelum meluaskan tampilan root dari fragmen tersebut dan itu berfungsi untuk saya.

Tomask
sumber
1
min api 23 untukgetContext()
vigilancer
@vigilancer Periksa jawaban ini untuk memperbaiki masalah min api Anda: stackoverflow.com/questions/36736244/…
rm8x
1
Solusi yang bagus. Saya menambahkan kode di onAttach (Konteks) yang juga menerapkan tema pada semua fragmen anak
crysxd
Hal ini dapat memiliki konsekuensi yang tidak terduga karena mengubah tema konteks (aktivitas dalam banyak kasus). Pemekaran masa depan (misalnya, setelah rotasi) dari Kegiatan akan menggunakan tema baru di mana
Irhala
12

Saya juga mencoba menampilkan dialog fragmen dengan tema yang berbeda dengan aktivitasnya, dan mengikuti solusi ini . Seperti beberapa orang yang disebutkan dalam komentar, saya tidak membuatnya berfungsi dan dialog terus ditampilkan dengan tema yang ditentukan dalam manifes. Masalahnya ternyata bahwa saya membangun dialog menggunakan AlertDialog.Builderdalam onCreateDialogmetode dan jadi tidak membuat penggunaan onCreateViewmetode seperti ditunjukkan pada jawaban yang saya terhubung. Dan ketika saya memberi contoh, AlertDialog.Buildersaya meneruskan dalam konteks menggunakan getActivity()ketika saya seharusnya menggunakan yang dipakai ConstextThemeWrappersebagai gantinya.

Ini kode untuk onCreateDialog saya:

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

Saya awalnya memiliki AlertDialog.Builderyang dipakai sebagai berikut:

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

yang saya ubah menjadi:

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

Setelah perubahan ini, dialog fragmen ditampilkan dengan tema yang benar. Jadi, jika ada orang lain yang mengalami masalah serupa dan memanfaatkannya, AlertDialog.Builderperiksa konteks yang diteruskan ke pembuat. Semoga ini membantu! :)

BruceHill
sumber
9

Pastikan Anda telah android:minSdkVersion="11"mengatur dalam manifes Anda. Ini bisa menjadi penyebab mengapa teladan David tidak berhasil untuk Anda.

Juga, mengatur android:theme="@android:style/Theme.Holo.Light"atribut untuk <application>tag dan TIDAK yang <activity>tag.

Masalah lain yang mungkin mungkin adalah cara Anda mendapatkan Konteks saat menggunakan file ContextThemeWrapper(). Jika Anda menggunakan sesuatu seperti getActivity().getApplicationContext()ganti getActivity()saja.

Biasanya, Theme.Holo harus diterapkan ke Fragmen yang ditautkan ke MainActivity.

Harap dicatat bahwa Anda menggunakan ContextThemeWrapper saat Anda ingin menerapkan tema yang berbeda untuk Fragmen Anda. Mungkin membantu jika Anda memberikan potongan kode, dari MainActivity, tempat Anda menambahkan Fragmen.


Beberapa tautan berguna:

ListView Kustom di Fragmen tidak mengikuti tema induk

sebster
sumber
8

Saya mencoba solusi yang disarankan David itu berhasil tetapi tidak di semua skenario:
1. untuk fragmen pertama yang ditambahkan ke tumpukan memiliki tema aktivitas dan bukan yang ditentukan di onCrateView, tetapi pada fragmen kedua yang saya tambahkan ke tumpukan yang benar, mereka diterapkan pada fragmen.

2. Pada fragmen kedua yang ditampilkan dengan benar, saya melakukan hal berikut saya memaksa Aplikasi ditutup dengan membersihkan memori, membuka kembali Aplikasi dan ketika Aktivitas dibuat ulang dengan fragmen Fragmen itu mengubahnya menjadi salah Aktivitas dan tidak sama dengan yang disetel di onCrateView dari fragmen.

Untuk memperbaiki masalah saya melakukan perubahan kecil dan mengganti argumen kontainer dari inflater.inflate dengan null.

saya tidak tahu cara inflater menggunakan dalam beberapa skenario konteks dari tampilan kontainer.

Catatan - bahwa saya menggunakan 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);
} 
avi
sumber
Terima kasih, solusi Anda menyelamatkan saya. Tema DialogFragment saya entah bagaimana berbeda dari fragmen lainnya. Itu membuat EditText saya menjadi aneh karena saya menggunakan inflater yang disediakan. Saya menemukan beberapa bantuan terkait ContextThemeWrapper tetapi mereka belum menunjukkan bagaimana hal itu dilakukan. Solusi Anda berhasil untuk saya. Terimakasih banyak.
Phuong Dao
4

Saya tahu ini agak terlambat tetapi mungkin membantu orang lain karena ini membantu saya. Anda juga dapat mencoba menambahkan baris kode di bawah ini di dalam fungsi onCreatView dari fragmen

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

Buat kelas java dan kemudian gunakan tata letak yang ingin Anda ubah temanya di metode onCreate. Lalu sebutkan di manifes seperti biasa

Devam03
sumber
1

Jika Anda hanya ingin menerapkan gaya untuk fragmen tertentu, cukup tambahkan baris ini sebelum memanggil onCreateView()atau onAttach()fragmen,

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

dan Jika Anda ingin menyetel status bar transparan kemudian menyetel false ke fitsSystemWindowsproperti tata letak root Anda,

android:fitsSystemWindows="false"
Siddharth Sheth
sumber
1

Saya membuatnya bekerja dengan menyetel tema pada konteks fragmen sebelum memanggil inflator.

CATATAN: Ini adalah contoh untuk Xamarin.Android yang dikombinasikan dengan MvvmCross. Saya tidak 100% yakin apakah ini juga akan berhasil untuk programmer Java. Tapi Anda bisa mencoba :)

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

Kode metode ekstensi 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);
}

Saya harap ini membantu beberapa orang, cheers!

Jop Middelkamp
sumber
1

Saya memecahkan masalah menggunakan android:theme = "@style/myTheme"file tata letak fragmen. Misalnya ini mengubah gaya dari LinearLayoutdan isinya tetapi tidak ada hal di luar LinearLayout. Jadi, untuk mendekorasi seluruh fragmen dengan gaya apa pun, terapkan tema ke tata letak induk paling luarnya.

Catatan: Untuk berjaga-jaga jika Anda belum menemukan solusi, Anda dapat mencobanya.

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

Anda dapat mencoba ini untuk lollipop di onAttach

Jendela terakhir jendela = activity.getWindow (); window.setStatusBarColor (myStatusBarColor)

dan setel kembali ke default di ondettach

Amjed Baig
sumber