Summary
Steps to follow
1. Create ColorStateList
for boxStrokeColor
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?attr/colorSurface" android:state_focused="true" />
<item android:alpha="0.87" android:color="?attr/colorSurface" android:state_hovered="true" />
<item android:alpha="0.12" android:color="?attr/colorSurface" android:state_enabled="false" />
<item android:alpha="0.38" android:color="?attr/colorSurface" />
</selector>
2. Create ColorStateList
for android:textColorHint
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:alpha="0.38" android:color="?attr/colorSurface" android:state_enabled="false" />
<item android:alpha="0.6" android:color="?attr/colorSurface" />
</selector>
3. Set view attributes - There are 3 ways that you can do this.
I. Using attribute set
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Password"
android:textColorHint="@color/text_color_hint"
app:boxStrokeColor="@color/box_stroke_color"
app:hintTextColor="?attr/colorSurface">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
II. Using explicit style
Define custom style
<style name="CustomTextInputStyle" parent="Widget.MaterialComponents.TextInputLayout.OutlinedBox">
<item name="boxStrokeColor">@color/box_stroke_color</item>
<item name="hintTextColor">?attr/colorSurface</item>
<item name="android:textColorHint">@color/text_color_hint</item>
</style>
Set style
<com.google.android.material.textfield.TextInputLayout
style="@style/CustomTextInputStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Password">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
III. Using default style attribute - set global style for TextInputLayout
<!-- Base application theme. -->
<style name="Theme.TestApp" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
...
<!-- Status bar color. -->
...
<!-- Customize your theme here. -->
<item name="textInputStyle">@style/CustomTextInputStyle</item>
</style>
Explanation
There are various ways to change TextInputLayout
box stroke color and hint text color.
The responsible attribute for box outline color is boxStrokeColor
.
First let's create ColorStateList
in xml format. Create Android color
resource directory and create new resource file named box_stroke_color.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?attr/colorSurface" android:state_focused="true" />
<item android:alpha="0.87" android:color="?attr/colorSurface" android:state_hovered="true" />
<item android:alpha="0.12" android:color="?attr/colorSurface" android:state_enabled="false" />
<item android:alpha="0.38" android:color="?attr/colorSurface" />
</selector>
I referred resources of material design library. See how this is done in material design library https://github.com/material-components/material-components-android/blob/master/lib/java/com/google/android/material/textfield/res/color/mtrl_outlined_stroke_color.xml
To change hint text color, we have to set two attributes,
hintTextColor
(The color of the label when it is collapsed and the text field is active)
android:textColorHint
(The color of the label in all other text field states, such as resting and disabled)
How do I know which attributes are required to change? I checked attributes defined in theme Widget.MaterialComponents.TextInputLayout.OutlinedBox
. Look at parent theme if not defined in the child theme. https://github.com/material-components/material-components-android/blob/788866e4483621e2222f649e617ee95f7aa9caa6/lib/java/com/google/android/material/textfield/res/values/styles.xml#L88 (This may vary in master branch)
app:hintTextColor="?attr/colorSurface"
Note that hintTextColor
is not stateful.
But android:textColorHint
is stateful.
Let's create custom ColorStateList
for android:textColorHint
.
Referred this https://github.com/material-components/material-components-android/blob/master/lib/java/com/google/android/material/textfield/res/color/mtrl_indicator_text_color.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:alpha="0.38" android:color="?attr/colorSurface" android:state_enabled="false" />
<item android:alpha="0.6" android:color="?attr/colorSurface" />
</selector>
Note that I have used ?attr/colorSurface
, because generally it's value is white in light theme and black in dark theme. You could use @android:color/white
directly if you don't want dynamic color adjustments.
There are several ways that you can set box stroke color attribute value,
Attribute values are resolved using context.theme.obtainStyledAttributes()
.
If value is defined in multiple places, the following order determines which attribute value is ultimately applied.
- AttributeSet - Value defined in layout xml file.
- Style - Value defined in explicit style. (Retrieve it through
theme.getExplicitStyle(AttributeSet)
)
- defStyleAttr - Default style attribute, which is the third argument of view class constructor.
- defStyleRes - Default style resource, which is the fourth argument of view class constructor.
- Theme - If not defined in all of the above, theme attribute value is resolved.
Let's see them one by one
- Using AttributeSet
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Password"
android:textColorHint="@color/text_color_hint"
app:boxStrokeColor="@color/box_stroke_color"
app:hintTextColor="?attr/colorSurface">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
- Using explicit style
Define custom style in styles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="CustomTextInputStyle" parent="Widget.MaterialComponents.TextInputLayout.OutlinedBox">
<item name="boxStrokeColor">@color/box_stroke_color</item>
<item name="hintTextColor">?attr/colorSurface</item>
<item name="android:textColorHint">@color/text_color_hint</item>
</style>
</resources>
Define explicit style for the widget
<com.google.android.material.textfield.TextInputLayout
style="@style/CustomTextInputStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Password">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
- Using default style attribute - This is used to define global style for a view. How do you know which attribute is required to set? Just check default value of third argument of any view constructor. For material
TextInputLayout
this value is com.google.android.material.R.attr.textInputStyle
.
<!-- Base application theme. -->
<style name="Theme.TestApp" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
...
<!-- Status bar color. -->
...
<!-- Customize your theme here. -->
<item name="textInputStyle">@style/CustomTextInputStyle</item>
</style>
Using default style resource - This is only applicable when creating widgets programmatically. If you check fourth argument of the constructor of any view except material design views, you can see defStyleRes
parameter. If theme.obtainStyledAttributes()
cannot resolve from the above ways, then it looks for attribute in default style resource. This is not applicable in material design library widgets, because this value is hard coded in those widgets and not exposed to change programmatically. (It is internally applied through theme.applyStyle()
)
Using app theme - This is not possible in material design widgets, because defStyleRes
is hard coded in material design widgets and it takes precedence over app theme attributes.
<!-- Customize your theme here. -->
<item name="boxStrokeColor">@color/box_stroke_color</item>
<item name="hintTextColor">?attr/colorSurface</item>
<item name="android:textColorHint">@color/text_color_hint</item>
Above is only applicable in Android Sdk provided widgets.