以编程方式设置TextInputLayout主题

10

在Android中,是否有一种方法可以通过编程方式更改TextInputLayout的主题。例如,如果我有以下的TextInputLayout:

<android.support.design.widget.TextInputLayout
    android:id="@+id/label"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom"
    android:paddingTop="16dp"
    android:theme="@style/TextInputLayoutTheme"
    app:errorTextAppearance="@style/Error">

    <android.support.v7.widget.AppCompatEditText
        android:id="@+id/edit_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingBottom="8dp"
        android:paddingTop="8dp"/>
</android.support.design.widget.TextInputLayout>

我能否通过编程的方式将这一行 android:theme="@style/TextInputLayoutTheme" 改为其他主题?


你可能想看一下这个链接:https://dev59.com/LWgt5IYBdhLWcg3w7BkE - Tolga Okur
2个回答

18

运行时没有办法改变任何视图或布局的主题,因为主题和样式是在创建视图时递归应用的(主题也适用于布局的子视图)。

但是,您可以在创建视图之前使用XML布局或编程方式更改该主题。

编程方式:

方法1 - 使用android.view.ContextThemeWrapper包装Context并以编程方式创建TextInputLayout并使用它。

TextInputLayout layout = new TextInputLayout(new ContextThemeWrapper(getContext(), R.style. TextInputLayoutTheme));

方法2 - 扩展TextInputLayout并使用自己的布局。将ContextThemeWrapper作为上下文传递。

public class MyTextInputLayout extends TextInputLayout {
    public MyTextInputLayout(Context context) {
        super(new ContextThemeWrapper(context, R.style.AppTheme));
    }

    public MyTextInputLayout(Context context, AttributeSet attrs) {
        super(new ContextThemeWrapper(context, R.style.AppTheme), attrs);
    }

    public MyTextInputLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(new ContextThemeWrapper(context, R.style.AppTheme), attrs, defStyleAttr);
    }
}

现在,您可以在XML布局中使用MyTextInputLayout

使用XML布局:

1)attrs.xml文件中,创建名为textInputLayoutTheme的新属性

<attr name="textInputLayoutTheme" format="reference"/>

2)styles.xml文件的AppTheme中,将@style/TextInputLayoutTheme设置为textInputLayoutTheme

<resources>
    <style name="AppTheme" parent="PARENT_THEME">
        <item name="textInputLayoutTheme">@style/TextInputLayoutTheme</item>
    </style>

    <style name="AppTheme.Secondary">
        <item name="textInputLayoutTheme">@style/TextInputLayoutTheme_Secondary</item>
    </style>
</resources>

3) 在你的layout.xml文件中,将?attr/textInputLayoutTheme设置为TextInputLayout主题。

<android.support.design.widget.TextInputLayout
    android:id="@+id/label"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom"
    android:paddingTop="16dp"
    android:theme="@?attr/textInputLayoutTheme"
    app:errorTextAppearance="@style/Error">

现在,当你将应用程序主题从 AppTheme 更改为 AppTheme.Secondary 时,TextInputLayoutTheme_Secondary 将用作您的 TextInputLayout 的主题,而不是 TextInputLayoutTheme


2
我已经尝试了编程的两种方法,但都没有起作用。 - Vaibhav Alone
你正在使用android.view.ContextThemeWrapper吗?支持库也有一个名为ContextThemeWrapper的类,但只限于支持库的内部使用。https://dev59.com/yFgQ5IYBdhLWcg3wazIi#42814273 - Tolga Okur
我正在使用androidx.appcompat.view.ContextThemeWrapper; - Vaibhav Alone
使用 XML 是可以工作的,但是当我尝试以编程方式完成时遇到了问题。 - Vaibhav Alone
好的,请尝试使用android.view.ContextThemeWrapper - Tolga Okur

0

很遗憾,被接受的答案对我来说不起作用。

我的解决方案是将TextInputLayout包装在自定义布局中。

view_input_layout_wrapper.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:theme="@style/AppThemeMaterial"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/til"
        style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

    <com.google.android.material.textfield.TextInputEditText
        android:id="@+id/edit_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    </com.google.android.material.textfield.TextInputLayout>
</FrameLayout>

TextInputLayoutWrapper

class TextInputLayoutWrapper(context: Context) : FrameLayout(context) {

    var inputLayout: TextInputLayout
        private set

    init {
        inflate(context, R.layout.view_input_layout_wrapper, this)
        inputLayout = findViewById(R.id.til)
    }
}

在视图中的实现(片段/活动):

private fun addNewField(fieldName: String) {
    val textInputLayoutWrapper = TextInputLayoutWrapper(
        requireContext()
    ).apply {
        inputLayout.hint = fieldName
    }

    fieldsContainerViewGroup.addView(textInputLayoutWrapper)       
}

注意:我的应用程序主题不是材料主题,因此我必须在TextInputLayout的根ViewGroup中添加theme="@style/AppThemeMaterial"

<style name="AppThemeMaterial" parent="Theme.MaterialComponents.Light">
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="android:windowBackground">@android:color/black</item>
</style>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接