buellas
buellas

Reputation: 331

Set TextInputLayout theme programmatically

Is there a way to change the theme of a TextInputLayout programmatically in Android. If I have the following 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>

Could I somehow change this line android:theme="@style/TextInputLayoutTheme" to another theme programmatically?

Upvotes: 10

Views: 8857

Answers (2)

Pavel Poley
Pavel Poley

Reputation: 5587

Unfortunately the accepted answer is not working for me.

My solution was to wrap TextInputLayout in a custom layout.

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

Implementation in the view (fragment/activity):

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

    fieldsContainerViewGroup.addView(textInputLayoutWrapper)       
}

NOTE: My app theme is not material theme, so I must add theme="@style/AppThemeMaterial" in the root ViewGroup of the TextInputLayout.

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

Upvotes: 0

Tolga Okur
Tolga Okur

Reputation: 7113

There is no way to change theme of any view or any layout at runtime. Because of themes and styles are applied during creation of view, recursively. (Themes also applies child views of layouts)

But, you can change that theme before creation of view using XML layout or programmatically.

Programmatically:

Method 1 - Create TextInputLayout programmatically with wrapping Context with android.view.ContextThemeWrapper and use.

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

Method 2 - Extend TextInputLayout and use your own layout. Pass ContextThemeWrapper as context.

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);
    }
}

Now, you can use MyTextInputLayout in your XML layout

With XML Layout:

1) In attrs.xml file, create new attribute named textInputLayoutTheme

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

2) In your AppTheme in styles.xml file set your @style/TextInputLayoutTheme as 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) In your layout.xml file, set ?attr/textInputLayoutTheme as a TextInputLayout theme

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

Now, when you change your application theme from AppTheme to AppTheme.Secondary TextInputLayoutTheme_Secondary will be used as a theme of your TextInputLayout instead of TextInputLayoutTheme.

Upvotes: 18

Related Questions