Establecer tema para un fragmento

117

Estoy tratando de establecer el tema de un fragmento.

Establecer el tema en el manifiesto no funciona:

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

Al mirar blogs anteriores, parece que tengo que usar un ContextThemeWrapper. ¿Alguien puede referirme a un ejemplo codificado? No encuentro nada.

usuario1232691
fuente

Respuestas:

187

La configuración del tema en el manifiesto se usa generalmente para la actividad.

Si desea configurar Theme for Fragment, agregue el siguiente código en onCreateView () del Fragment:

@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
fuente
30
Esto no funciona para mi. El fragmento todavía tiene el mismo tema que se especifica en el archivo de manifiesto.
Giorgi
1
En el manifiesto, especificas el tema de la actividad, no el fragmento. ¿estás usando fragment o fragmentActivity?
David
1
Trabajó para mi. Con Fragmento clásico dentro de Actividad.
David
8
@David "El tema de configuración en el manifiesto se usa para la actividad". Esto no es enteramente verdad. Si usa FragmentTransaction para agregar su Fragmento en tiempo de ejecución, ese tema también se aplica a los Fragmentos.
septiembre
4
Esto no parece funcionar para un SherlockFragmentActivity de la biblioteca ActionBarSherlock.
toobsco42
18

Fragmento toma su tema de su Actividad. A cada fragmento se le asigna el tema de la Actividad en la que existe.

El tema se aplica en el método Fragment.onCreateView, donde su código crea vistas, que en realidad son objetos donde se usa el tema.

En Fragment.onCreateView obtienes el parámetro LayoutInflater, que infla las vistas y contiene el contexto utilizado para el tema, en realidad esta es la actividad. Entonces, sus vistas infladas usan el tema de Actividad.

Para anular el tema, puede llamar a LayoutInflater.cloneInContext , que menciona en Docs que puede usarse para cambiar el tema. Puede utilizar ContextThemeWrapper aquí. Luego use el inflador clonado para crear las vistas del fragmento.

Puntero nulo
fuente
Como dice Google Docs: "... Devuelve un nuevo objeto LayoutInflater asociado con el contexto dado ..." - developer.android.com/reference/android/view/…
Chris
adición muy útil a la solución de código de David. ¡Gracias!
muetzenflo
13

Para aplicar un solo estilo que he usado solo

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

en onCreateView()el fragmento antes de inflar la vista de raíz del fragmento y funciona para mí.

Para enmascarar
fuente
1
min api 23 paragetContext()
vigilancer
@vigilancer Compruebe esta respuesta para obtener una solución a su problema de API mínima: stackoverflow.com/questions/36736244/…
rm8x
1
Gran solucion Agregué el código en onAttach (Context) que también aplica el tema en todos los fragmentos secundarios
crysxd
Esto puede tener consecuencias inesperadas ya que modifica el tema del contexto (actividad en la mayoría de los casos). Una futura inflación (por ejemplo, después de una rotación) de la Actividad utilizará el nuevo tema en todas partes
Irhala
12

También estaba tratando de que mi diálogo de fragmentos se mostrara con un tema diferente a su actividad, y seguí esta solución . Como algunas personas mencionaron en los comentarios, no lo estaba haciendo funcionar y el diálogo seguía mostrándose con el tema especificado en el manifiesto. El problema resultó ser que estaba construyendo el diálogo usando AlertDialog.Builderel onCreateDialogmétodo y, por lo tanto, no estaba haciendo uso del onCreateViewmétodo como se muestra en la respuesta a la que me vinculé. Y cuando estaba instanciando el AlertDialog.Builder, estaba pasando en el contexto usando getActivity()cuando debería haber estado usando el instanciado en su ConstextThemeWrapperlugar.

Aquí está el código para mi 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;
}

Originalmente tuve la AlertDialog.Builderinstancia de la siguiente manera:

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

que cambié a:

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

Después de este cambio, el diálogo del fragmento se mostró con el tema correcto. Entonces, si alguien más tiene un problema similar y está utilizando el AlertDialog.Builder, verifique el contexto que se pasa al constructor. ¡Espero que esto ayude! :)

BruceHill
fuente
9

Asegúrese de haber android:minSdkVersion="11"establecido en su manifiesto. Esta podría ser la causa por la que el ejemplo de David no funcionó para usted.

Además, establezca el android:theme="@android:style/Theme.Holo.Light"atributo para la <application>etiqueta y NO la <activity>etiqueta.

Otro posible problema podría ser la forma en que obtiene su contexto cuando usa un ContextThemeWrapper(). Si usa algo como getActivity().getApplicationContext()simplemente reemplácelo congetActivity() .

Normalmente, Theme.Holo debería aplicarse a Fragmentos vinculados a MainActivity.

Tenga en cuenta que utiliza un ContextThemeWrapper cuando desea aplicar un tema diferente para su Fragmento. Podría ayudar si proporciona el fragmento de código, desde su MainActivity, donde agrega sus Fragmentos.


Algunos enlaces útiles:

ListView personalizado en Fragmento no se adhiere al tema principal

sebster
fuente
8

Probé la solución que David sugirió que funcionaba, pero no en todos los escenarios:
1. para el primer fragmento que se agregó a la pila tiene el tema de la actividad y no el que se definió en onCrateView, sino en el segundo fragmento que agregar a la pila corregirlos se aplicó en el fragmento.

2. En el segundo fragmento que los mostraba correctamente, hice lo siguiente: obligué a cerrar la aplicación limpiando la memoria, volví a abrir la aplicación y cuando la actividad se recreó con el fragmento El fragmento cambió los errores de la Actividad y no la misma que se estableció en el onCrateView del fragmento.

Para solucionar el problema, hice un pequeño cambio y reemplacé el argumento del contenedor de inflater.inflate con un valor nulo.

No sé cómo el inflador usa en algunos escenarios el contexto de la vista del contenedor.

Nota: estoy 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
fuente
Gracias, tu solución me salva. El tema de mi DialogFragment era de alguna manera diferente de los otros fragmentos. Hizo que mi EditText se volviera extraño porque usé el inflador provisto. Encontré algunas ayudas con respecto a ContextThemeWrapper pero no han mostrado cómo se hace. Tu solución funciona para mí. Muchas gracias.
Phuong Dao
4

Sé que es un poco tarde, pero podría ayudar a alguien más porque esto me ayudó.También puede intentar agregar la línea de código a continuación dentro de la función onCreatView del fragmento

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

Cree una clase Java y luego use el diseño del que desea cambiar el tema en el método onCreate.Luego menciónelo en el manifiesto como normal

Devam03
fuente
1

Si solo desea aplicar estilo para un fragmento en particular, simplemente agregue estas líneas antes de llamar onCreateView()o onAttach()del fragmento,

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

y si desea establecer una barra de estado transparente, establezca falso en la fitsSystemWindowspropiedad de su diseño raíz,

android:fitsSystemWindows="false"
Siddharth Sheth
fuente
1

Lo hice funcionar configurando el tema en el contexto del fragmento antes de llamar al inflador.

NOTA: Este es un ejemplo de Xamarin.Android en combinación con MvvmCross. No estoy 100% seguro de si esto también funcionará para los programadores de Java. Pero puedes intentar :)

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

El código del método de extensión 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 esto ayude a algunas personas, ¡salud!

Jop Middelkamp
fuente
1

Resolví el problema usando android:theme = "@style/myTheme"el archivo de diseño del fragmento. Por ejemplo, esto cambia el estilo del LinearLayouty su contenido, pero nada fuera del LinearLayout. Por lo tanto, para decorar todo el fragmento con cualquier estilo, aplique el tema a su diseño principal externo.

Nota: en caso de que aún no haya encontrado una solución, puede intentarlo.

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

puedes probar esto para piruletas en onAttach

ventana final de la ventana = activity.getWindow (); window.setStatusBarColor (myStatusBarColor)

y vuelva a configurarlo por defecto en ondettach

Amjed Baig
fuente