Looks like the TextInputLayout and TextInputEditTextLayout are defaulting the cursor (and cursor bubble) color to primary color. I tested it by switching the global primary color of the app and it works. However, when I try to create a theme for that specific view and override the primary color, it doesn't work.
<style name="Widget.AppTheme.TextInputEditText.Dense" parent="Widget.MaterialComponents.TextInputEditText.FilledBox.Dense">
<item name="colorPrimary">@color/orange</item>
</style>
<com.google.android.material.textfield.TextInputLayout
app:hintEnabled="false"
app:hintAnimationEnabled="false"
android:id="@+id/f_login_email_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_default"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/f_login_subheader">
<com.google.android.material.textfield.TextInputEditText
style="@style/Widget.AppTheme.TextInputEditText.Dense"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="12dp"
android:ems="10"
android:textSize="@dimen/text_size_text_entry"
android:hint="@string/login_email_hint"
android:inputType="textEmailAddress" />
</com.google.android.material.textfield.TextInputLayout>
Could somebody help with this?
UPDATE
If I create the style for the TextInputLayout and define the colorControlActivated like
<style name="Widget.AppTheme.TextInputLayout.FilledBox.Dense" parent="Widget.MaterialComponents.TextInputLayout.FilledBox.Dense">
<item name="errorIconDrawable">@null</item>
<item name="hintTextColor">@color/black</item>
<item name="boxBackgroundColor">@color/greyLight</item>
<item name="boxStrokeWidth">0dp</item>
<item name="errorTextColor">@color/orange</item>
<item name="colorControlActivated">@color/orange</item>
</style>
and use theming instead of styling on the TextInputLayout
<com.google.android.material.textfield.TextInputLayout
app:hintEnabled="false"
app:hintAnimationEnabled="false"
android:id="@+id/f_login_email_layout"
android:theme="@style/Widget.AppTheme.TextInputLayout.FilledBox.Dense"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_default"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/f_login_subheader">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/f_login_email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="12dp"
android:ems="10"
android:textSize="@dimen/text_size_text_entry"
android:hint="@string/login_email_hint"
android:inputType="textEmailAddress" />
</com.google.android.material.textfield.TextInputLayout>
It suddenly works perfectly. But I don't really want to use theming because I have to copy that line all over the place while using styling I can simply use <item name="editTextStyle">@style/Widget.AppTheme.TextInputEditText.Dense</item>
I agree this is a bug and I've been looking for a way around it for the past week. I was actually about to finally log a bug when I found your issue already logged. I'll give your workaround a try...but I completely agree that I shouldn't have to do it that way.
It might also be important to point out that if an app has existing EditText controls those will use colorAccent while TextInputLayout will use colorPrimary. An app could easily have a mixture of cursor colors. Basically, all legacy Android controls (that I know of) have always used colorAccent for the cursor color. I feel that should be the default for new controls as well.
The reason why using android:theme works is because colorControlActivated is a theme attribute, as opposed to a specific component attribute (e.g., hintTextColor).
One way you could customize a global theme attribute but only have that customization apply to a specific component is to use our materialThemeOverlay functionality. E.g.:
Create a theme overlay that customizes colorControlActivated:
<style name="ThemeOverlay.AppTheme.TextInputEditText.FilledBox.Dense" parent="ThemeOverlay.MaterialComponents.TextInputEditText.FilledBox.Dense">
<item name="colorControlActivated">@color/orange</item>
</style>
Create a TextInputLayout style that uses the theme overlay:
<style name="Widget.AppTheme.TextInputLayout" parent="Widget.MaterialComponents.TextInputLayout.FilledBox.Dense">
<item name="materialThemeOverlay">@style/ThemeOverlay.AppTheme.TextInputEditText.FilledBox.Dense</item>
</style>
Set the TextInputLayout style as the default in your app theme:
<item name="textInputStyle">@style/Widget.AppTheme.TextInputLayout</item>
@dsn5ft it doesn't seem to work
Apologies, there was a typo in my comment above. Make sure the materialThemeOverlay in the TextInputLayout style actually points to the AppTheme theme overlay.
Also, make sure to remove any android:themes and/or styles from your specific TextInputLayout instance.
ah thanks, I also figured out 😄
This was never an issue before in v1.0.0. Why this is changed in v1.1.0? It has made things very complicated now. For OutlinedBox, this has totally messed up the things. If I apply the style as a theme then it makes my box appear with bottom outline only with grey background.
How to apply fix for OutlinedBox?
@zishanj the solution given by @dsn5ft should also work for the outlined text field as long as you have the parents set to the OutlinedBox styles instead of the FilledBox styles. Does it not work for you?
My bad I missed one style but it has worked though. Btw. Is there a shorthand way to change colorPrimary of any component using colorPrimary attribute or something similar?
you mean you want to change colorPrimary for your entire app? You can set it on your own theme like:
<style name="Theme.YourTheme" parent="Theme.MaterialComponents.Light">
<item name="colorPrimary">@color/yourColor</item>
</style>
Not for entire app but for specific component like TextInputLayout in this case which I want to change to colorAccent.
@zishanj I think you can create a style and apply it to materialThemeOverlay as @dsn5ft pointed out above
Why couldn't leave colorAccent for this as before? Now we have to write this workaround to get what was originally expected of TextInputEditText.
I also confirm that the solution provided from @dsn5ft works for OutlinedBox, but like @akhbulatov has pointed - there is a lot of work to do for a simple styling ...
Hi everyone
I share my way of setting the OutlinedBox style.
First of all, I am using version 1.1.0
implementation 'com.google.android.material:material:1.1.0'
Just like you mentioned @dsn5ft , I create a style by referencing the style TextInputEditText.OutlinedBox
<style name="exampleCursor" parent="ThemeOverlay.MaterialComponents.TextInputEditText.OutlinedBox">
<item name="colorControlActivated">@color/green</item>
</style>
In my case I use a style for my TextInputLayout, I add android:theme with the created style
<style name="TextInputLayoutStyle" parent="Widget.MaterialComponents.TextInputLayout.OutlinedBox">
<item name="android:background">@android:color/transparent</item>
<item name="android:textColorHint">@color/colorAccent</item>
<item name="android:textColor">@color/colorAccent</item>
<item name="hintTextColor">@color/colorAccent</item>
<item name="boxStrokeColor">@color/silver</item>
<item name="boxStrokeWidth">1dp</item>
<item name="errorEnabled">true</item>
<item name="counterEnabled">false</item>
<item name="android:theme">@style/exampleCursor</item>
</style>
and I add the style in the component
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/TextInputLayoutStyle"
….
and that's it, the color change to the cursor works

regards.
Is there a way to color the selection? I'm really sorry but coming from iOS, I feel like Android styling is so much more convoluted.
@funct7 can you try using android:textColorHighlight?
https://stackoverflow.com/questions/20639594/how-to-change-highlight-color-on-edittext-field
Feature request:
<item name="cursorColor">>@color/colorAccent</item>
😂
I'm going to have to write my own component because setting the line color and the bubble color also changes the selection popup background color on some phones 😂 colorControlActivated drives literally everything
If anyone needs something like it (no error management cuz I was lazy):
view_custom_input.xml:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/textInputField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp"
android:background="@drawable/custom_input_edittext_background"
android:textCursorDrawable="@drawable/edittext_caret"
android:maxLines="3"
android:saveEnabled="false" />
<TextView
android:id="@+id/textHintLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:focusable="false"
android:padding="4dp"
android:textColor="@color/textCaption"
android:translationY="10dp"
tools:text="Comment" />
<TextView
android:id="@+id/textCharacterCountIndicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="8dp"
android:textColor="@color/textCharacterCount"
android:textSize="12sp"
tools:text="35/35" />
</merge>
CustomInputView.kt:
class CustomInputView : FrameLayout {
constructor(context: Context) : super(context) {
init(context, null)
}
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
init(context, attrs)
}
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
) {
init(context, attrs)
}
private var hintText: String = ""
private var maxCharacterCount: Int = 70
private lateinit var binding: ViewCustomInputBinding
private fun init(context: Context, attrs: AttributeSet?) {
LayoutInflater.from(context).inflate(R.layout.view_custom_input, this, true)
clipToPadding = false
updatePadding(left = dp(16), right = dp(16), top = dp(24))
binding = ViewCustomInputBinding.bind(this)
if (attrs != null) {
val a = context.obtainStyledAttributes(attrs, R.styleable.CustomInputView)
if (a.hasValue(R.styleable.CustomInputView_hintText)) {
hintText = a.getString(R.styleable.CustomInputView_hintText) ?: ""
binding.textHintLabel.text = hintText
}
if (a.hasValue(R.styleable.CustomInputView_maxCharacterCount)) {
maxCharacterCount = a.getInt(R.styleable.CustomInputView_maxCharacterCount, 0)
}
a.recycle()
}
}
val editText: EditText
get() = binding.textInputField
val text: String
get() = editText.text.toString()
private var isLabelOnTop = false
var onTextChanged: ((String) -> Unit)? = null
override fun onFinishInflate() {
super.onFinishInflate()
val textHint = binding.textHintLabel
val textInput = binding.textInputField
val textCharacterCountIndicator = binding.textCharacterCountIndicator
fun moveLabelToTop() {
textHint.objectAnimate()
.translationY(dp(-16).f)
.translationX(dp(-8).f)
.scales(0.825f)
.setDuration(100L)
.onAnimationEnd {
isLabelOnTop = true
}
.start()
}
fun moveLabelToBottom() {
textHint.objectAnimate()
.translationY(dp(10).f)
.translationX(0f)
.scales(1f)
.setDuration(100L)
.onAnimationEnd {
isLabelOnTop = false
}
.start()
}
textInput.onFocusChange { view, hasFocus ->
val text = view.text.toString()
if (text.isEmpty() && isLabelOnTop) {
moveLabelToBottom()
}
if ((hasFocus && !isLabelOnTop) || (text.isNotEmpty() && !isLabelOnTop)) {
moveLabelToTop()
}
}
textCharacterCountIndicator.text = "${text.length}/${maxCharacterCount}"
textInput.onTextChanged { text ->
textCharacterCountIndicator.text = "${text.length}/${maxCharacterCount}"
onTextChanged?.invoke(text)
}
}
override fun onSaveInstanceState(): Parcelable =
SavedState(super.onSaveInstanceState()).apply {
currentText = text
}
override fun onRestoreInstanceState(state: Parcelable) {
val savedState = state as SavedState
super.onRestoreInstanceState(savedState.superState)
editText.setText(state.currentText)
if (state.currentText.isNotEmpty()) {
isLabelOnTop = true
binding.textHintLabel.apply {
translationY = dp(-16).f
translationX = dp(-8).f
scaleX = 0.825f
scaleY = 0.825f
}
}
}
class SavedState : BaseSavedState {
var currentText: String = ""
constructor(superState: Parcelable?) : super(superState) {}
override fun writeToParcel(out: Parcel, flags: Int) {
super.writeToParcel(out, flags)
out.writeString(currentText)
}
private constructor(`in`: Parcel) : super(`in`) {
currentText = `in`.readString() ?: ""
}
companion object {
@JvmField
val CREATOR: Parcelable.Creator<SavedState> = object : Parcelable.Creator<SavedState> {
override fun createFromParcel(`in`: Parcel): SavedState {
return SavedState(`in`)
}
override fun newArray(size: Int): Array<SavedState?> {
return arrayOfNulls(size)
}
}
}
}
}
edittext_caret.xml (not sure if this even does anything tbh):
<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetTop="1dp"
android:insetBottom="1dp">
<shape android:shape="rectangle">
<size android:width="1dp" />
<solid android:color="@color/colorAccent" />
<padding
android:bottom="-1dp"
android:top="-1dp" />
</shape>
</inset>
custom_input_edittext_background.xml:
<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="4dp"
android:insetTop="10dp"
android:insetRight="4dp"
android:insetBottom="7dp">
<selector>
<item android:state_pressed="true">
<layer-list>
<item
android:bottom="1dp"
android:left="-6dp"
android:right="-6dp"
android:top="-12dp">
<shape android:shape="rectangle">
<stroke
android:width="1dp"
android:color="@color/customInputActiveLine" />
<solid android:color="#00FFFFFF" />
<padding
android:bottom="7dp"
android:left="3dp"
android:right="3dp"
android:top="8dp" />
</shape>
</item>
</layer-list>
</item>
<item android:state_focused="true">
<layer-list>
<item
android:bottom="1dp"
android:left="-6dp"
android:right="-6dp"
android:top="-12dp">
<shape android:shape="rectangle">
<stroke
android:width="1dp"
android:color="@color/customInputActiveLine" />
<solid android:color="#00FFFFFF" />
<padding
android:bottom="7dp"
android:left="3dp"
android:right="3dp"
android:top="8dp" />
</shape>
</item>
</layer-list>
</item>
<item>
<layer-list>
<item
android:bottom="1dp"
android:left="-6dp"
android:right="-6dp"
android:top="-12dp">
<shape android:shape="rectangle">
<stroke
android:width="1dp"
android:color="@color/customInputInactiveLine" />
<solid android:color="#00FFFFFF" />
<padding
android:bottom="7dp"
android:left="3dp"
android:right="3dp"
android:top="8dp" />
</shape>
</item>
</layer-list>
</item>
</selector>
</inset>
attrs.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CustomInputView">
<attr name="hintText" format="string" />
<attr name="maxCharacterCount" format="integer" />
</declare-styleable>
</resources>
I'm sure whoever needs more can fill in the blanks.
Most helpful comment
Hi everyone
I share my way of setting the OutlinedBox style.
First of all, I am using version 1.1.0
implementation 'com.google.android.material:material:1.1.0'Just like you mentioned @dsn5ft , I create a style by referencing the style TextInputEditText.OutlinedBox
In my case I use a style for my TextInputLayout, I add android:theme with the created style
and I add the style in the component
and that's it, the color change to the cursor works
regards.