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

发布于 2024-08-18 15:13:29 字数 3564 浏览 4 评论 0原文

我的主题将 TextView 的 textColor 指定为红色。

我正在使用 LayoutInflater 实例化 TextView。问题是,当使用 ApplicationContext 创建 inflater 时,样式不会应用于 TextView - 颜色不是红色。当使用 Activity 创建 LayoutInflater 时,一切正常。

为什么会发生这种情况,如何解决?

/res/values/styles.xml:AndroidManifest.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>

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

I have theme that specifies textColor for TextView as red.

I am using LayoutInflater to instantiate TextView. The problem is that styles are not applied to TextView when inflater created using ApplicationContext - the color is not red. All works fine when LayoutInflater created using activity.

Why this happens, and how can be fixed?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

蹲在坟头点根烟 2024-08-25 15:13:29

解决方案#1

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

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

如果我们有值作为“root”参数传递,那么我们可以使用它来获取“活动上下文”,从中我们可以获取正确的 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

只是尝试以编程方式设置应用程序上下文主题,并且它有效

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

我认为期望此标记是合乎逻辑的

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

:自动设置它,但它没有。

Solution # 1

The inflate method accepts optional 'ViewGroup root' argument:

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

If we have value to pass as 'root' parameter, than hence we can use it to get 'activity context' from where we can get correct LayoutInflater:

ViewGroup root > activity context > LayoutInflater

So my code could be:

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

Solution # 2

Just tried to set Application Context theme programmatically, and it works:

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

I think it was logical to expect this markup:

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

to set it automatically, but it does not.

一指流沙 2024-08-25 15:13:29

切勿使用应用程序上下文来扩充视图,因为样式不适用于此上下文。使用视图时始终使用 Activity 的上下文。唯一的例外是当您需要从服务创建 RemoteView 时。

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

Never use an Application Context to inflate views, because styling doesn't work with this context. Always use an Activity's context when playing with views. The only exception is when you need to create RemoteViews from a Service.

More info about the different types of Contexts and their capabilities can be found in this excellent article.

优雅的叶子 2024-08-25 15:13:29

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

要解决此问题,请使用以下内容:

val inflater= LayoutInflater.from(context).cloneInContext(ContextThemeWrapper(context, R.style.some_activity_theme))

您可以阅读有关此内容的更多信息 这里

You probably use a context that isn't one that has a theme.

To solve it, use something as such:

val inflater= LayoutInflater.from(context).cloneInContext(ContextThemeWrapper(context, R.style.some_activity_theme))

You can read more about this here

浪菊怪哟 2024-08-25 15:13:29

我通常在膨胀自定义视图时遇到这个问题。这是我个人在 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       
}   
}

I usually come across this issue on inflating a custom view. Here is what I personally do to keep the same theme of the activity in the 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       
}   
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文