Задайте тему для фрагмента


117

Я намагаюся задати тему для фрагмента.

Налаштування теми в маніфесті не працює:

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

Якщо дивитися на попередні блоги, здається, що мені потрібно використовувати ContextThemeWrapper. Чи може хтось віднести мене до кодованого прикладу? Я нічого не можу знайти.

Відповіді:


187

Налаштування теми в маніфесті зазвичай використовується для діяльності.

Якщо ви хочете встановити Тему для фрагмента, додайте наступний код у onCreateView () фрагмента:

@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
це не працює для мене. У фрагмента все ще є та сама тема, яка вказана у файлі маніфесту.
Джорджі

1
У маніфесті ви вказуєте Тему діяльності, а не фрагмент. ви використовуєте фрагмент або fragmentActivity?
Девід

1
Працювали для мене. З класичним фрагментом в межах діяльності.
Девід

8
@David "Налаштування теми в маніфесті використовується для діяльності". Це не зовсім вірно. Якщо ви використовуєте FragmentTransaction, щоб додати свій фрагмент під час виконання, ця тема також застосовується до фрагментів.
sebster

4
Схоже, це не працює для SherlockFragmentActivity з бібліотеки ActionBarSherlock.
toobsco42

18

Фрагмент бере свою тему зі своєї діяльності. Кожному фрагменту присвоюється тема діяльності, в якій він існує.

Тема застосовується в Fragment.onCreateView методі, де ваш код створює представлення даних, які фактично є об'єктами, де використовується тема.

У Fragment.onCreateView ви отримуєте параметр LayoutInflater, який надуває перегляди, і він містить Контекст, який використовується для теми, насправді це Діяльність. Тож ваші завищені погляди використовують тему діяльності.

Щоб замінити тему, ви можете зателефонувати на LayoutInflater.cloneInContext , який в документах зазначає, що вона може використовуватися для зміни теми. Ви можете використовувати ContextThemeWrapper тут. Потім використовуйте клонований надувний елемент для створення поглядів фрагмента.


Як зазначено в документах google: "... Повертає бренд, що спає новий об'єкт LayoutInflater, пов'язаний із заданим контекстом ..." - developer.android.com/reference/android/view/…
Кріс

дуже корисне доповнення до кодового рішення Девідса. Дякую!
muetzenflo

13

Для застосування єдиного стилю я використовував просто

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

у onCreateView()фрагменті перед надуванням кореневого вигляду фрагмента, і він працює для мене.


1
хв. api 23 заgetContext()
пильнування

@vigilancer Перевірте цей відповідь для виправлення виниклої проблеми хв апі: stackoverflow.com/questions/36736244 / ...
rm8x

1
Прекрасне рішення. Я додав код у OnAttach (контекст), який також застосовує тему до всіх дочірніх фрагментів
crysxd

Це може мати несподівані наслідки, оскільки воно змінює тему контексту (активність у більшості випадків). Майбутнє завищення (наприклад, після ротації) діяльності буде використовувати нову тему всюди
Ірхала

12

Я також намагався отримати діалогове вікно з фрагментами для відображення з іншою темою його діяльності, і я дотримувався цього рішення . Як і деякі згадані в коментарях, я не працював над цим, і діалог постійно відображався з темою, вказаною в маніфесті. Проблема виявилася в тому , що я будувала діалог , використовуючи AlertDialog.Builderв onCreateDialogспособі і тому не робить використання onCreateViewметоду , як показано в відповідь , що я пов'язаний с. І коли я створював інстанцію, AlertDialog.Builderя проходив у контексті, використовуючи, getActivity()коли я повинен був використовувати інстанцію ConstextThemeWrapper.

Ось код для мого 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;
}

Я спочатку мав цю AlertDialog.Builderісторію таким чином:

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

яку я змінив на:

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

Після цієї зміни з'явилося діалогове вікно фрагмента з правильною темою. Тож якщо хтось інший має подібну проблему і використовує AlertDialog.Builderпотім перевірити контекст, який передається будівельнику. Сподіваюся, це допомагає! :)


9

Переконайтеся, що ви вказали android:minSdkVersion="11"у своєму маніфесті. Це може бути причиною того , що приклад Девіда не працював для вас.

Крім того , встановіть android:theme="@android:style/Theme.Holo.Light"атрибут для <application>тега і NOT в <activity>тезі.

Іншою можливою проблемою може бути спосіб отримання контексту під час використання ContextThemeWrapper(). Якщо ви використовуєте щось на зразок, getActivity().getApplicationContext()просто замініть його getActivity().

Як правило, Theme.Holo має застосовуватися до фрагментів, пов'язаних з MainActivity.

Зверніть увагу, що ви використовуєте ContextThemeWrapper, коли ви хочете застосувати іншу тему для вашого фрагмента. Це може допомогти, якщо ви вкажете фрагмент коду зі свого MainActivity, де ви додасте фрагменти.


Деякі корисні посилання:

Спеціальний ListView у фрагменті, який не відповідає родинній темі


8

Я спробував рішення, яке запропонував Девід, воно працює, але не у всіх сценаріях:
1. для першого фрагмента, який додається до стеку, є тема діяльності, а не те, що визначено в onCrateView, а на другий фрагмент, який я Додайте до стека правильне їх нанесення на фрагмент.

2. На другому фрагменті, що їх було відображено правильно, я зробив наступне, я змусив додаток закрити, очистивши пам'ять, повторно відкрити додаток і коли активність відтворилася з фрагментом, фрагмент змінив їх неправильно Діяльність і не та сама, що була встановлена ​​в фрагменті onCrateView.

Щоб виправити проблему, я зробив невелику зміну і замінив аргумент контейнера з inflater.inflate на null.

я не знаю, як надувальник використовує в деяких сценаріях контекст з виду контейнера.

Зауважте - що я використовую 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);
} 

Дякую, ваше рішення рятує мене. Тема мого DialogFragment якось відрізнялася від інших фрагментів. Це зробило мій EditText дивним, тому що я використовував надану надувну машину. Я знайшов допомогу щодо ContextThemeWrapper, але вони не показали, як це робиться. Ваше рішення працює на мене. Велике дякую.
Пхуонг Дао

4

Я знаю, що це трохи пізно, але це може допомогти комусь іншому, тому що це допомогло мені. Ви також можете спробувати додати рядок коду нижче всередині функції onCreatView фрагмента

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

2

Створіть клас java, а потім використовуйте макет, для якого потрібно змінити тему методу onCreate. Потім згадайте про це в маніфесті як звичайному


1

Якщо ви просто хочете застосувати стиль до певного фрагмента, просто додайте ці рядки перед викликом onCreateView()або onAttach()фрагментом,

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

і Якщо ви хочете встановити прозору панель стану, тоді встановіть false для fitsSystemWindowsвласності вашого кореневого макета,

android:fitsSystemWindows="false"

1

Я змусив його працювати, встановивши тему на контекст фрагмента, перш ніж викликати інфлятор.

ПРИМІТКА. Це приклад для Xamarin.Android у поєднанні з MvvmCross. Я не впевнений на 100%, чи це також буде працювати для Java-програмістів. Але ви можете спробувати :)

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

Код методу розширення 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);
}

Я сподіваюся, що це допоможе деяким людям, привіт


1

Я вирішив проблему, використовуючи android:theme = "@style/myTheme"в макеті файл фрагмента. Наприклад, це змінює стиль LinearLayoutі вміст, але не будь-яка річ поза стороною LinearLayout. Отже, для того, щоб декорувати весь фрагмент будь-яким стилем, застосуйте тему до її зовнішнього самого батьківського макета.

Примітка. На всякий випадок, якщо ви ще не знайшли рішення, можете спробувати.

           <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

ви можете спробувати це для льодяника в onAttach

остаточне вікно Window = activity.getWindow (); window.setStatusBarColor (myStatusBarColor)

і поверніть його до замовчування в ondettach

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.