TextViewのtextColorを赤に指定するテーマがあります。
TextViewをインスタンス化するためにLayoutInflaterを使用しています。問題は、ApplicationContextを使用して作成されたインフレータの場合、スタイルがTextViewに適用されないことです。色は赤ではありません。 LayoutInflaterがアクティビティを使用して作成した場合、すべて正常に動作します。
なぜこれが発生し、どのように修正できますか?
/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"
>
コード:
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>
ソリューション#1
Inflateメソッドは、オプションの「ViewGroup root」引数を受け入れます。
public View inflate (int resource, ViewGroup root, boolean attachToRoot)
「ルート」パラメーターとして渡す値がある場合は、それを使用して、正しいLayoutInflaterを取得できる場所から「アクティビティコンテキスト」を取得できます。
ViewGroup root > activity context > LayoutInflater
だから私のコードは次のようになります:
private void add(LinearLayout container) {
LayoutInflater inflater = getInflater(container.getContext());
inflater.inflate(R.layout.my_template, container, true);
}
ソリューション#2
プログラムでアプリケーションコンテキストテーマを設定しようとしたところ、works:
getApplicationContext().setTheme(R.style.MyTheme);
このマークアップを期待するのは理にかなっていると思います:
<application
Android:icon="@drawable/icon"
Android:label="@string/app_name"
Android:theme="@style/MyTheme"
>
自動的に設定しますが、設定しません。
アプリケーションコンテキストを使用してビューをインフレートしないでください。スタイル設定はこのコンテキストでは機能しないためです。ビューで遊ぶときは常にアクティビティのコンテキストを使用します。唯一の例外は、サービスからRemoteViewを作成する必要がある場合です。
さまざまな種類のコンテキストとその機能に関する詳細情報は、 この優れた記事 にあります。
私は通常、カスタムビューを拡張するときにこの問題に遭遇します。これは、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
}
}