2010-01-22 4 views
39

J'ai un thème qui spécifie textColor pour TextView en rouge. J'utilise LayoutInflater pour instancier TextView. Le problème est que les styles ne sont pas appliqués à TextView lorsque inflater est créé en utilisant ApplicationContext - la couleur n'est pas rouge. Tout fonctionne correctement lorsque LayoutInflater a été créé en utilisant l'activité. Pourquoi cela arrive-t-il et comment peut-il être réparé?Le thème/style n'est pas appliqué lorsque inflat est utilisé avec ApplicationContext

/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" 
    > 

code:

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> 

Répondre

45

Solution # 1

La méthode décompressé accepte en option 'ViewGroup root' argument:

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

Si nous avons la valeur à passer comme paramètre 'root', alors d'où nous pouvons l'utiliser pour obtenir le 'contexte de l'activité' d'où nous pouvons obtenir correct LayoutInflater:

ViewGroup root > activity context > LayoutInflater 

donc mon code pourrait être:

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

Solution # 2

juste essayé de définir le thème de contexte d'application par programme, et il fonctionne:

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

Je pense il était logique d'attendre ce balisage:

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

pour le définir automatiquement, mais ce n'est pas le cas. Ne jamais utiliser un contexte d'application pour gonfler des vues, car le style ne fonctionne pas avec ce contexte.

+0

Monsieur, vous avez sauvé ma journée. Merci –

+0

C'est tellement faux. Il y a une raison pour que ça ne marche pas comme vous le pensez: ça n'est pas supposé fonctionner de cette façon. L'attribut de thème sur la balise est simplement la valeur par défaut qui est appliquée à toutes les activités. Beaucoup d'autres choses ne fonctionnent pas vraiment avec le contexte de l'application, par exemple, vous ferez couler des ressources qui changent en réponse aux changements de configuration, etc. – dcow

+0

La solution 2 a fonctionné comme un charme. Mon application est magnifique maintenant. Merci! – Mauker

31

Utilisez toujours le contexte d'une activité lorsque vous jouez avec des vues. La seule exception est lorsque vous devez créer RemoteViews à partir d'un service.

Plus d'informations sur les différents types de Contextes et leurs capacités peuvent être trouvés in this excellent article.

+2

Ce n'est pas vraiment vrai, en utilisant Application Context pour créer des vues est également recommandé pour éviter les fuites de mémoire avec lesquelles je fais face maintenant. – David

+2

Dépend de la façon dont vos vues sont utilisées. Si vos opinions ne font pas partie d'une activité, vous ne devez pas utiliser le contexte de l'activité, bien sûr. – BladeCoder

+0

Monsieur, vous avez sauvé ma journée. Merci –

0

Je rencontre généralement ce problème sur gonfler une vue personnalisée.Voici ce que je fais personnellement pour garder le même thème de l'activité dans le 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  
} 
} 
Questions connexes