当inflater与ApplicationContext一起使用时,不应用主题/样式

ale*_*2k8 44 android themes coding-style

我有一个主题,将TextView的textColor指定为红色.

我正在使用LayoutInflater来实例化TextView.问题是当使用ApplicationContext创建的inflater时,样式不会应用于TextView - 颜色不是红色.使用activity创建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>
Run Code Online (Sandbox Code Playgroud)

AndroidManifest.xml中:

<application 
    android:icon="@drawable/icon" 
    android:label="@string/app_name"
    android:theme="@style/MyTheme"
    >
Run Code Online (Sandbox Code Playgroud)

码:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

/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>
Run Code Online (Sandbox Code Playgroud)

/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>
Run Code Online (Sandbox Code Playgroud)

ale*_*2k8 52

解决方案#1

inflate方法接受可选的"ViewGroup root"参数:

public View inflate (int resource, ViewGroup root, boolean attachToRoot)
Run Code Online (Sandbox Code Playgroud)

如果我们有值作为'root'参数传递,那么我们可以使用它从我们可以获得正确的LayoutInflater的地方获取'activity context':

ViewGroup root > activity context > LayoutInflater
Run Code Online (Sandbox Code Playgroud)

所以我的代码可能是:

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

解决方案#2

只是尝试以编程方式设置应用程序上下文主题,它的工作原理:

getApplicationContext().setTheme(R.style.MyTheme);
Run Code Online (Sandbox Code Playgroud)

我认为期望这个标记是合乎逻辑的:

<application 
    android:icon="@drawable/icon" 
    android:label="@string/app_name"
    android:theme="@style/MyTheme"
    >
Run Code Online (Sandbox Code Playgroud)

自动设置,但它没有.

  • 这是非常错误的。它不像你想象的那样工作是有原因的:它不应该那样工作。&lt;application&gt; 标记上的主题属性只是应用于所有活动的默认属性。许多其他事情并不真正适用于应用程序上下文,例如,您将泄漏因配置更改而发生变化的资源等。 (2认同)
  • **永远不要使用应用程序上下文来扩充视图**(http://stackoverflow.com/a/25116293/570168) (2认同)

Bla*_*der 34

永远不要使用应用程序上下文来扩展视图,因为样式不适用于此上下文.在播放视图时始终使用活动的上下文.唯一的例外是当您需要从服务创建RemoteView时.

有关不同类型的上下文及其功能的更多信息可以在这篇优秀的文章中找到.

  • 这不是真的,建议使用Application Context创建视图以避免我正在处理的内存泄漏. (2认同)
  • 取决于您的观点的使用方式.如果您的观点不属于活动,那么您当然不应该使用活动的上下文. (2认同)

and*_*per 7

您可能使用了一个没有主题的上下文。

要解决它,请使用以下内容:

val inflater= LayoutInflater.from(context).cloneInContext(ContextThemeWrapper(context, R.style.some_activity_theme))
Run Code Online (Sandbox Code Playgroud)

您可以在此处阅读有关此内容的更多信息