material-components / material-components-android

Modular and customizable Material Design UI components for Android
Apache License 2.0
16.32k stars 3.06k forks source link

[TextInputLayout] End Clear Icon visibility not backward compatible #2266

Open foodpoison opened 3 years ago

foodpoison commented 3 years ago

Description:

I have TextInputLayout+TextInputEditText combo; TextInputLayout styled to @style/Widget.MaterialComponents.TextInputLayout.OutlinedBox and app:endIconMode="clear_text", while TextInputEditText has:

android:background="@null"
android:cursorVisible="false"
android:inputType="textNoSuggestions"
android:clickable="true"
android:focusable="false"
android:focusableInTouchMode="false"

The control is setup so that users can't directly entry text, the editText has a click listener that opens a drop-down or date-picker, that populates the editText once user have selected something. The end clear button should be visible to allow for clearing the data. This worked in material-1.3.0, the clear button is showing up even if the field is not focusable, but not longer shows up in material-1.4.0-x. There's a certain weirdness in 1.4.0-x as well, in that if the focusable=false then the clear button doesn't exist, but if focusable=true then it's clickable but alpha=0f, so not really visible to the human eye, even if it participates in the measure pass.

Expected behavior:

Would like the clear button to be visible and useable when the TextInputEditText is customised to work like a dropdown button. Would prefer not to use an actual button for this because the UX is weird, especially if user wants to clear the data, clear button is the obvious UX.

Android API version: 29

Material Library version: Reproducible on material-1.4.0-rc01 and material-1.4.0-beta01, worked as normal in material-1.3.0.

Device: tested and shows up on API 25 onwards

jdepypere commented 3 years ago

Can confirm that this is still an issue with material-1.4.0.

rogovalex commented 3 years ago

Is it possible to make focus dependent behavior configurable?

Ayagikei commented 2 years ago

We're facing the same issue.

It seems that it's related to the https://github.com/material-components/material-components-android/issues/2024 and https://github.com/material-components/material-components-android/pull/2025.

A reflect workaround: define two top level functions firstly

with 'com.google.android.material:material:1.10.0:

/**
 * top level function to get end icon view
 */
  fun getEndIconView(textInputLayout: TextInputLayout): CheckableImageButton? {
      return try {
          val field = TextInputLayout::class.java.getDeclaredField("endLayout")
          field.isAccessible = true
          val endLayout = field.get(textInputLayout)
          val field2 = endLayout::class.java.getDeclaredField("endIconView")
          field2.isAccessible = true
          val endIconView = field2.get(endLayout) as CheckableImageButton
          endIconView
      } catch (e: Exception) {
          logE(e)
          null
      }
  }

/**
 * top level function to force show end icon view
 */
fun TextInputLayout.forceShowEndIconView() {
    this.post {
        if (!this.isEndIconVisible) {
            this.isEndIconVisible = true
            this.getEndIconViewByReflect()?.apply {
                // or improve this by using the animation same as the ClearTextEndIconDelegate.java instead
                alpha = 1f
                scaleX = 1f
                scaleY = 1f
            }
        }
    }
}

with 'com.google.android.material:material:1.6.0-rc01':

/**
 * top level function to get end icon view
 */
fun TextInputLayout.getEndIconViewByReflect(): CheckableImageButton? {
    return try {
        val field = TextInputLayout::class.java.getDeclaredField("endIconView")
        field.isAccessible = true
        val endIconView = field.get(this) as CheckableImageButton
        endIconView
    } catch (e: Exception) {
        e.printStackTrace()
        null
    }
}

/**
 * top level function to force show end icon view
 */
fun TextInputLayout.forceShowEndIconView() {
    this.post {
        if (!this.isEndIconVisible) {
            this.isEndIconVisible = true
            this.getEndIconViewByReflect()?.apply {
                // or improve this by using the animation same as the ClearTextEndIconDelegate.java instead
                alpha = 1f
                scaleX = 1f
                scaleY = 1f
            }
        }
    }
}

And then using it in code:

fun setTextByCodeFunction() {
    ...
    textInputLayout.text = "xxx"
    // after set text, force show end icon
    textInputLayout.forceShowEndIconView()
    ...
}
ericsu111 commented 6 months ago

Can we also get an option to make the endIcon visible regardless of the focus?