Definir tema para um fragmento

117

Estou tentando definir o tema de um fragmento.

Definir o tema no manifesto não funciona:

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

Olhando para blogs anteriores, parece que tenho que usar um ContextThemeWrapper. Alguém pode me indicar um exemplo codificado? Não consigo encontrar nada.

user1232691
fonte

Respostas:

187

Definir Tema no manifesto geralmente é usado para Atividade.

Se você deseja definir o tema para fragmento, adicione o próximo código em onCreateView () do fragmento:

@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
fonte
30
isso não funciona para mim. O fragmento ainda tem o mesmo tema especificado no arquivo de manifesto.
Giorgi de
1
No manifesto, você especifica o Tema para a atividade, não o fragmento. você está usando fragment ou fragmentActivity?
David de
1
Funcionou para mim. Com o clássico Fragment em Activity.
David
8
@David "Definir tema no manifesto é usado para atividade". Isso não é inteiramente verdade. Se você usar uma FragmentTransaction para adicionar seu Fragment no tempo de execução, esse tema será aplicado aos Fragments também.
sebster
4
Isso não parece funcionar para um SherlockFragmentActivity da biblioteca ActionBarSherlock.
toobsco42
18

Fragment toma seu tema de sua atividade. Cada fragmento é atribuído ao tema da atividade em que existe.

O tema é aplicado no método Fragment.onCreateView, onde seu código cria visualizações, que são na verdade objetos onde o tema é usado.

Em Fragment.onCreateView você obtém o parâmetro LayoutInflater, que aumenta as visualizações e mantém o Contexto usado para o tema, na verdade, esta é a Activity. Portanto, suas visualizações infladas usam o tema de Activity.

Para substituir o tema, você pode chamar LayoutInflater.cloneInContext , que menciona no Docs que pode ser usado para alterar o tema. Você pode usar ContextThemeWrapper aqui. Em seguida, use o inflater clonado para criar visualizações do fragmento

Pointer Null
fonte
Como afirma o Google Docs: "... Retorna um novo objeto LayoutInflater associado ao Contexto fornecido ..." - developer.android.com/reference/android/view/…
Chris
adição muito útil para a solução de código Davids. Obrigado!
muetzenflo
13

Para aplicar um único estilo, usei apenas

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

no onCreateView()fragmento antes de inflar a visão da raiz do fragmento e funciona para mim.

Para mascarar
fonte
1
min api 23 paragetContext()
vigilancer
@vigilancer Verifique esta resposta para uma solução para seu problema de API mínima: stackoverflow.com/questions/36736244/…
rm8x
1
Ótima solução. Eu adicionei o código em onAttach (Contexto) que também aplica o tema em todos os fragmentos filho
crysxd
Isso pode ter consequências inesperadas, pois modifica o tema do contexto (atividade na maioria dos casos). Uma futura inflação (por exemplo, após uma rotação) da Atividade usará o novo tema em todos os lugares
Irhala
12

Eu também estava tentando fazer com que meu diálogo de fragmento fosse exibido com um tema diferente para sua atividade e segui esta solução . Como algumas pessoas mencionadas nos comentários, eu não estava fazendo funcionar e o diálogo continuava aparecendo com o tema especificado no manifesto. O problema acabou sendo que eu estava construindo o diálogo usando AlertDialog.Buildero onCreateDialogmétodo e, portanto, não estava fazendo uso do onCreateViewmétodo como mostrado na resposta que vinculei. E quando estava instanciando o AlertDialog.Builder, estava passando no contexto usando getActivity()quando deveria estar usando o instanciado ConstextThemeWrapper.

Aqui está o código para meu 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;
}

Eu originalmente tive o AlertDialog.Builderser instanciado da seguinte maneira:

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

que mudei para:

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

Após esta alteração, a caixa de diálogo do fragmento foi exibida com o tema correto. Portanto, se alguém mais está tendo um problema semelhante e está fazendo uso do AlertDialog.Builder, verifique o contexto que está sendo passado para o construtor. Espero que isto ajude! :)

BruceHill
fonte
9

Certifique-se de ter android:minSdkVersion="11"definido em seu manifesto. Esse pode ser o motivo pelo qual o exemplo de Davi não funcionou para você.

Além disso, defina o android:theme="@android:style/Theme.Holo.Light"atributo para a <application>tag e NÃO a <activity>tag.

Outro possível problema pode ser a maneira como você obtém seu Contexto ao usar um ContextThemeWrapper(). Se você usar algo como, getActivity().getApplicationContext()basta substituí-lo por getActivity().

Normalmente, o Theme.Holo deve ser aplicado aos Fragments vinculados à MainActivity.

Observe que você usa um ContextThemeWrapper quando deseja aplicar um tema diferente para o seu Fragment. Pode ajudar se você fornecer a parte do código, de sua MainActivity, onde você adiciona seus Fragments.


Alguns links úteis:

ListView personalizado no fragmento não aderindo ao tema pai

sebster
fonte
8

Eu tentei a solução que David sugeriu que funcionou, mas não em todos os cenários:
1. para o primeiro fragmento adicionado à pilha tem o tema da atividade e não aquele definido em onCrateView, mas no segundo fragmento que i adicione à pilha corrija-os foi aplicado no fragmento.

2. No segundo fragmento em que os mesmos foram exibidos corretamente, fiz o seguinte: forcei o aplicativo a ser fechado limpando a memória, reabrindo o aplicativo e quando a atividade foi recriada com o fragmento O fragmento alterou os errados a Activity e não a mesma que foi configurada no onCrateView do fragmento.

Para corrigir o problema, fiz uma pequena alteração e substituí o argumento do contêiner de inflater.inflate por um nulo.

Não sei como o inflador usa em alguns cenários o contexto da visualização do contêiner.

Observação - estou usando 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
fonte
Obrigado, sua solução me salva. O tema do meu DialogFragment era de alguma forma diferente dos outros fragmentos. Isso fez com que meu EditText se tornasse estranho porque eu usei o fornecido inflator. Encontrei algumas ajudas em relação ao ContextThemeWrapper, mas eles não mostraram como isso é feito. Sua solução funciona para mim. Muito Obrigado.
Phuong Dao
4

Eu sei que é um pouco tarde, mas pode ajudar alguém porque isso me ajudou. Você também pode tentar adicionar a linha de código abaixo dentro da função onCreatView do fragmento

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

Crie uma classe java e, em seguida, use o layout cujo tema deseja alterar no método onCreate. Em seguida, mencione-o no manifesto normalmente

Devam03
fonte
1

Se você deseja apenas aplicar o estilo a um fragmento específico, basta adicionar essas linhas antes de chamar onCreateView()ou onAttach()do fragmento,

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

e se você deseja definir a barra de status transparente, defina false para a fitsSystemWindowspropriedade do seu layout raiz,

android:fitsSystemWindows="false"
Siddharth Sheth
fonte
1

Eu tenho que trabalhar definindo o tema no contexto do fragmento antes de chamar o inflator.

NOTA: Este é um exemplo para Xamarin.Android em combinação com MvvmCross. Não tenho 100% de certeza se isso também funcionará para os programadores Java. Mas você pode tentar :)

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

O código do método de extensão 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);
}

Espero que isso ajude algumas pessoas, saúde!

Jop Middelkamp
fonte
1

Resolvi o problema usando android:theme = "@style/myTheme"no arquivo de layout do fragmento. Por exemplo, isso muda o estilo do LinearLayoute seu conteúdo, mas nada fora do LinearLayout. Portanto, para decorar todo o fragmento com qualquer estilo, aplique o tema ao layout pai mais externo.

Nota: Caso ainda não tenha encontrado uma solução, você pode tentar.

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

você pode tentar isso para pirulito em onAttach

janela final da janela = activity.getWindow (); window.setStatusBarColor (myStatusBarColor)

e defini-lo de volta para o padrão em ondettach

Amjed Baig
fonte