2010-01-22 10 views
39

Tengo un tema que especifica textColor para TextView como rojo.El tema/estilo no se aplica cuando se usa un inflado con ApplicationContext

Estoy usando LayoutInflater para crear una instancia de TextView. El problema es que los estilos no se aplican a TextView cuando se crea un inflater con ApplicationContext, el color no es rojo. Todo funciona bien cuando LayoutInflater crea usando la actividad.

¿Por qué sucede esto y cómo se puede corregir?

/res/values/styles.xml:

<?xml version="1.0" encoding="utf-8"?> 
<resources> 
    <style name="MyTheme"> 
     <item name="android:textViewStyle">@style/MyTextView</item> 
    </style> 

    <style name="MyTextView" parent="@android:style/Widget.TextView"> 
     <item name="android:textColor">#f00</item> 
    </style> 
</resources> 

AndroidManifest.xml:

<application 
    android:icon="@drawable/icon" 
    android:label="@string/app_name" 
    android:theme="@style/MyTheme" 
    > 

Código:

public class A extends Activity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.test_a); 

     final LayoutInflater goodInflater = getInflater((Activity)this); 
     final LayoutInflater badInflater = getInflater(getApplicationContext()); 
     final LinearLayout container = (LinearLayout)findViewById(R.id.container); 

     findViewById(R.id.add_with_appContext).setOnClickListener(new OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       add(container, badInflater); // Creates gray TextView 
      }    
     }); 

     findViewById(R.id.add_with_activity).setOnClickListener(new OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       add(container, goodInflater); // Creates red TextView 
      }    
     }); 
    } 

    private LayoutInflater getInflater(Context context) { 
     return (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    } 

    private void add(LinearLayout container, LayoutInflater inflater) { 
     inflater.inflate(R.layout.my_template, container, true); 
    } 
} 

/res/layout/test_a.xml

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:orientation="vertical"> 

    <Button 
     android:text="Add with AppContext" 
     android:id="@+id/add_with_appContext" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     /> 

    <Button 
     android:text="Add with Activity" 
     android:id="@+id/add_with_activity" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     /> 

    <LinearLayout 
     android:id="@+id/container" 
     android:layout_width="fill_parent" 
     android:layout_height="wrap_content" 
     android:orientation="vertical" 
     /> 

</LinearLayout> 

/res/layout/my_template.xml:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    > 

    <TextView 
     android:id="@+id/text" 
     android:text="Some text..." 
     android:layout_width="fill_parent" 
     android:layout_height="wrap_content" 
    /> 

</LinearLayout> 

Respuesta

45

Solución # 1

El método de inflado acepta opcional 'ViewGroup root' argumento:

public View inflate (int resource, ViewGroup root, boolean attachToRoot) 

Si tenemos el valor de pasar como parámetro 'raíz', que por lo tanto podemos usarlo para obtener 'contexto de actividad' desde donde podemos obtener la corrección correcta LayoutInflater:

ViewGroup root > activity context > LayoutInflater 

Así que mi código podría ser:

private void add(LinearLayout container) { 
    LayoutInflater inflater = getInflater(container.getContext()); 
    inflater.inflate(R.layout.my_template, container, true); 
} 

Solución # 2

acaba de intentar establecer el tema de contexto de aplicación mediante programación, y obras:

getApplicationContext().setTheme(R.style.MyTheme); 

pienso era lógico esperar este marcado:

<application 
    android:icon="@drawable/icon" 
    android:label="@string/app_name" 
    android:theme="@style/MyTheme" 
    > 

para configurarlo automáticamente, pero no es así.

+0

Señor, me salvó el día. Gracias –

+0

Esto está tan mal. Hay una razón por la cual no funciona de la manera que crees que funciona: se supone que no funciona de esa manera. El atributo de tema en la etiqueta es simplemente el predeterminado que se aplica a todas las actividades. Muchas otras cosas no funcionan realmente con el contexto de la aplicación, por ejemplo, se perderán recursos que cambian en respuesta a cambios de configuración, etc. – dcow

+0

La solución n. ° 2 funcionaba como un amuleto. Mi aplicación se ve hermosa ahora. ¡Gracias! – Mauker

31

Nunca utilice un contexto de aplicación para inflar las vistas, porque el estilo no funciona en este contexto. Utilice siempre el contexto de una actividad cuando juegue con vistas. La única excepción es cuando necesita crear RemoteViews desde un servicio.

Más información sobre los diferentes tipos de contextos y sus capacidades se puede encontrar in this excellent article.

+2

Eso no es realmente cierto, también se recomienda usar Contexto de aplicación para crear vistas para evitar pérdidas de memoria con las que estoy lidiando en este momento. – David

+2

Depende de cómo se usan sus vistas. Si sus puntos de vista no son parte de una actividad, entonces no debe usar el contexto de la actividad, por supuesto. – BladeCoder

+0

Señor, me salvaste el día. Gracias –

0

Normalmente encuentro este problema al inflar una vista personalizada.Esto es lo que personalmente hago para mantener el mismo tema de la actividad en CustomView

public class CustomView extends ViewGroup{ 

public CustomView (Context context) { 
    super(context); 
    init(context); 
} 

public CustomView (Context context, AttributeSet attrs) { 
    super(context, attrs); 
    init(context); 
} 

public CustomView (Context context, AttributeSet attrs, int defStyle) { 
    super(context, attrs, defStyle); 
    init(context); 
} 

@TargetApi(21) 
public CustomView (Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 
    super(context, attrs, defStyleAttr, defStyleRes); 
    init(context); 
} 

private void init(Context context) { 
    LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    View v = mInflater.inflate(R.layout.review_list_item, this, true); 
    //rest of view initialization  
} 
} 
Cuestiones relacionadas