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