android - TextInputLayout 中的错误文本被键盘覆盖

标签 android android-layout android-design-library androiddesignsupport android-textinputlayout

TextInputLayout 包含一个 EditText,它反过来接收来自用户的输入。使用 Android 设计支持库引入的 TextInputLayout,我们应该将错误设置为保存 EditText 而不是 EditText 本身的 TextInputLayout。编写 UI 时,将只关注 EditText 而不是整个 TextInputLayout,这可能导致键盘覆盖错误。在下面的 GIF 中,请注意用户必须先移除键盘才能看到错误消息。这与设置 IME 操作以继续使用键盘相结合会导致非常困惑的结果。

example error

布局xml代码:

<android.support.design.widget.TextInputLayout
    android:id="@+id/uid_text_input_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:errorEnabled="true"
    android:layout_marginTop="8dp">

    <EditText
        android:id="@+id/uid_edit_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:singleLine="true"
        android:hint="Cardnumber"
        android:imeOptions="actionDone"/>

</android.support.design.widget.TextInputLayout>

将错误设置为 TextInputLayout 的 Java 代码:

uidTextInputLayout.setError("Incorrect cardnumber");

如何确保错误消息在用户不采取行动的情况下可见?是否可以移动焦点?

最佳答案

更新: 看起来这可能已在 1.2.0-alpha03 中得到修复库的版本。


为了确保错误消息在用户不采取行动的情况下可见,我将 TextInputLayout 子类化并将其放置在 ScrollView 中。这让我可以在需要时向下滚动以显示错误消息,在每次设置错误消息时。使用它的 Activity/fragment 类无需更改。

enter image description here

import androidx.core.view.postDelayed

/**
 * [TextInputLayout] subclass that handles error messages properly.
 */
class SmartTextInputLayout @JvmOverloads constructor(
        context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : TextInputLayout(context, attrs, defStyleAttr) {

    private val scrollView by lazy(LazyThreadSafetyMode.NONE) {
        findParentOfType<ScrollView>() ?: findParentOfType<NestedScrollView>()
    }

    private fun scrollIfNeeded() {
        // Wait a bit (like 10 frames) for other UI changes to happen
        scrollView?.postDelayed(160) {
            scrollView?.scrollDownTo(this)
        }
    }

    override fun setError(value: CharSequence?) {
        val changed = error != value

        super.setError(value)

        // work around https://stackoverflow.com/q/34242902/1916449
        if (value == null) isErrorEnabled = false

        // work around https://stackoverflow.com/q/31047449/1916449
        if (changed) scrollIfNeeded()
    }
}

这里是辅助方法:

/**
 * Find the closest ancestor of the given type.
 */
inline fun <reified T> View.findParentOfType(): T? {
    var p = parent
    while (p != null && p !is T) p = p.parent
    return p as T?
}

/**
 * Scroll down the minimum needed amount to show [descendant] in full. More
 * precisely, reveal its bottom.
 */
fun ViewGroup.scrollDownTo(descendant: View) {
    // Could use smoothScrollBy, but it sometimes over-scrolled a lot
    howFarDownIs(descendant)?.let { scrollBy(0, it) }
}

/**
 * Calculate how many pixels below the visible portion of this [ViewGroup] is the
 * bottom of [descendant].
 *
 * In other words, how much you need to scroll down, to make [descendant]'s bottom
 * visible.
 */
fun ViewGroup.howFarDownIs(descendant: View): Int? {
    val bottom = Rect().also {
        // See https://stackoverflow.com/a/36740277/1916449
        descendant.getDrawingRect(it)
        offsetDescendantRectToMyCoords(descendant, it)
    }.bottom
    return (bottom - height - scrollY).takeIf { it > 0 }
}

我还修复了 TextInputLayout.setError() leaves empty space after clearing the error同类。

关于android - TextInputLayout 中的错误文本被键盘覆盖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31047449/

相关文章:

android - 自定义 NavigationView - 添加动态 headerView,Android 支持设计库

android - 如何改变TextInputLayout的 float 标签颜色

android - findViewById 与 setId

Android Realm 插入冲突忽略

android - 如何在 Android View 中的圆角矩形内插入文本?

android - TextView 宽度跟随 ImageView 的曲线

java - 在进度对话框中嵌套警报对话框

java - 创建时的 Android 方法

Android Volley JsonRequest

android - 带有两个 float 操作按钮的 CoordinatorLayout