以编程方式设置 TextInputLayout 主题

Set TextInputLayout theme programmatically

有没有办法在 Android 中以编程方式更改 TextInputLayout 的主题。 如果我有以下 TextInputLayout for ex.:

<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" 以编程方式更改为另一个主题?

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

但是,您可以在创建视图之前使用 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 .

不幸的是,接受的答案对我不起作用。

我的解决方案是将 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)
    }
}

视图中的实现(fragment/activity):

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

    fieldsContainerViewGroup.addView(textInputLayoutWrapper)       
}

注意:我的应用主题不是material主题,所以我必须在[=]的根ViewGroup中添加theme="@style/AppThemeMaterial" 14=].

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