Установить тему для фрагмента - PullRequest
98 голосов
/ 27 февраля 2012

Я пытаюсь установить тему для фрагмента.

Установка темы в манифесте не работает:

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

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

Ответы [ 12 ]

165 голосов
/ 19 марта 2013

Установка темы в манифесте обычно используется для действия.

Если вы хотите установить тему для фрагмента, добавьте следующий код в 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);
}
11 голосов
/ 19 июля 2014

Я также пытался заставить мой фрагментный диалог отображать тему, отличную от его активности, и следовал этому решению .Как и некоторые люди, упомянутые в комментариях, я не заставлял его работать, и диалог продолжал отображаться с темой, указанной в манифесте.Проблема оказалась в том, что я строил диалог, используя 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, проверьте контекст, передаваемый сборщику.Надеюсь это поможет!:)

11 голосов
/ 28 марта 2013

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

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

В Fragment.onCreateView вы получаете параметр LayoutInflater, который раздувает представления и содержит контекст, используемый для темы, на самом деле это Activity. Так что ваши раздутые взгляды используют тему Активности.

Чтобы переопределить тему, вы можете вызвать LayoutInflater.cloneInContext , которая упоминает в Документах, что она может быть использована для изменения темы. Вы можете использовать ContextThemeWrapper здесь. Затем используйте клонированный инфлатер для создания представлений фрагмента.

9 голосов
/ 09 января 2016

Для применения одного стиля я использовал только

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

в onCreateView() фрагмента до , надувая корневой вид фрагмента, и это работает для меня.

9 голосов
/ 25 марта 2013

Убедитесь, что в манифесте установлено android:minSdkVersion="11".Это может быть причиной того, что пример Дэвида не сработал для вас.

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

Другая возможная проблема может заключаться в способе полученияКонтекст при использовании ContextThemeWrapper().Если вы используете что-то вроде getActivity().getApplicationContext(), просто замените его на getActivity().

Обычно Theme.Holo следует применять к фрагментам, связанным с MainActivity.

Обратите внимание, что вы используете ContextThemeWrapper, когда хотите применить другую тему для своего фрагмента.Это может помочь, если вы предоставите фрагмент кода из MainActivity, в который вы добавите свои фрагменты.


Некоторые полезные ссылки:

ПользовательскийListView во фрагменте не соответствует родительской теме

7 голосов
/ 23 марта 2016

Я попробовал решение, которое Дэвид предположил, что оно работает, но не во всех сценариях:1. для первого фрагмента, который был добавлен в стек, есть тема действия, а не та, которая определена в onCrateView, но для второго фрагмента, который я добавляю в стек, исправьте их, примененные к фрагменту.2. На втором фрагменте, который был отображен правильно, я сделал следующее: принудительно закрыл приложение, очистив память, заново открыв приложение, и когда действие было воссоздано с фрагментом, фрагмент изменил их неправильноАктивность, а не та, что была установлена ​​в onCrateView фрагмента.

Чтобы исправить проблему, я сделал небольшое изменение и заменил аргумент контейнера из inflater.inflate на ноль.* Я не знаю, как в некоторых сценариях инфлятор использует контекст из представления контейнера.

Обратите внимание - я использую 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);
} 
2 голосов
/ 19 июня 2015

Создайте класс Java, а затем используйте макет, тему которого вы хотите изменить, в методе onCreate. Затем укажите его в манифесте как обычный

1 голос
/ 06 августа 2018

Если вы просто хотите применить стиль для определенного фрагмента, просто добавьте эти строки перед вызовом 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 голос
/ 29 августа 2017

Я решил проблему, используя 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>
0 голосов
/ 14 июня 2019

У меня все работает, установив тему в контексте фрагмента перед вызовом инфлятора.

ПРИМЕЧАНИЕ. Это пример 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);
}

Надеюсь, это поможет некоторым людям, ура!

...