在TextInputLayout中垂直居中提示和EditText

问题描述 投票:8回答:4

我使用TextInputLayout来显示提示,但我无法垂直居中。我总是得到这个:

enter image description here

EditText / TextInputEditText中没有文字时,我想垂直提示中心。我尝试过基本的想法(重力,layout_gravity等)。到目前为止,唯一的方法是添加一些“魔术”填充,但我想以更清洁的方式做到这一点。我正在考虑测量顶部提示标签高度,并在它不可见时将其添加为底部边距,并在可见时删除相同的边距,但我还不太了解TextInputLayout源代码。有谁知道怎么做?

编辑:

我试过这个建议的答案:

<android.support.design.widget.TextInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="20dp"
    android:background="@color/grey_strong">

    <android.support.design.widget.TextInputEditText
        android:layout_width="match_parent"
        android:layout_height="90dp"
        android:background="@color/red_light"
        android:gravity="center_vertical"
        android:hint="Test"/>

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

我得到了这个:

enter image description here

“大”提示仍然没有垂直居中。它略低于中心,因为“小”提示(在灰色背景中,在顶部,仅在场聚焦时可见)在顶部占据一些空间并推动EditText

android android-edittext android-textinputlayout android-gravity
4个回答
6
投票

目前TextInputLayout的实现似乎无法做到这一点。但是你可以通过玩TextInputEditText的填充来实现你想要的。

假设你有这样的TextInputLayoutTextInputEditText

<android.support.design.widget.TextInputLayout
    android:id="@+id/text_input_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#FAA"
    android:hint="Text hint">

    <android.support.design.widget.TextInputEditText
        android:id="@+id/text_input_edit_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#AAF" />

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

enter image description here

enter image description here

正如您所看到的,TextInputLayout由一个顶部区域组成,用于保存小版本中的提示,一个底部区域用于保存大版本中的提示(以及输入内容)。当视图失去焦点且编辑文本为空时,提示将在蓝色空间内移动。另一方面,当视图获得焦点或编辑文本内部有一些文本时,提示将移动到红色空间。

所以我们想要做的是:

  • TextInputEditText内部没有焦点和文字时,在TextInputEditText的底部添加一个额外的填充,这个填充等于红色区域的高度;
  • enter image description here具有焦点或文本内部时删除此填充。

因此,视图看起来像这样,大提示垂直居中:private lateinit var textInputLayout: TextInputLayout private lateinit var textInputEditText: TextInputEditText override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { ... textInputLayout = view.findViewById(R.id.text_input_layout) textInputEditText = view.findViewById(R.id.text_input_edit_text) ... }

假设你检索你的观点如下:

private fun getTextInputLayoutTopSpace(): Int {
    var currentView: View = textInputEditText
    var space = 0
    do {
        space += currentView.top
        currentView = currentView.parent as View
    } while (currentView.id != textInputLayout.id)
    return space
}

以下是可用于计算顶部红色空间(以像素为单位)的实现示例。

private fun updateHintPosition(hasFocus: Boolean, hasText: Boolean) {
    if (hasFocus || hasText) {
        textInputEditText.setPadding(0, 0, 0, 0)
    } else {
        textInputEditText.setPadding(0, 0, 0, getTextInputLayoutTopSpace())
    }
}

然后你可以像这样更新填充:

textInputLayout.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
    override fun onPreDraw(): Boolean {
        if (textInputLayout.height > 0) {
            textInputLayout.viewTreeObserver.removeOnPreDrawListener(this)
            updateHintPosition(textInputEditText.hasFocus(), !textInputEditText.text.isNullOrEmpty())
            return false
        }
        return true
    }
})

textInputEditText.setOnFocusChangeListener { _, hasFocus ->
    updateHintPosition(hasFocus, !textInputEditText.text.isNullOrEmpty())
}

现在你必须在两个地方调用这个方法:创建视图时(实际上我们需要等待视图完全测量)和焦点改变时。

TextInputLayout

一个问题是TextInputLayout的高度正在变化,因此所有视图都在移动,并且它看起来并不真正居中。您可以通过将FrameLayout放在具有固定高度的TransitionManager中并将其垂直居中来解决此问题。

最后,你可以动画所有的东西。更改填充时,您只需使用支持库的https://streamable.com/la9uk

您可以在此链接中查看最终结果:<FrameLayout android:layout_width="match_parent" android:layout_height="60dp"> <-- Adapt the height for your needs --> <android.support.design.widget.TextInputLayout android:id="@+id/text_input_layout" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:background="#FAA" android:hint="Text hint"> <android.support.design.widget.TextInputEditText android:id="@+id/text_input_edit_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#AAF" /> </android.support.design.widget.TextInputLayout> </FrameLayout>

完整的代码如下所示:

布局:

private lateinit var textInputLayout: TextInputLayout
private lateinit var textInputEditText: TextInputEditText

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    super.onCreateView(inflater, container, savedInstanceState)
    val view = inflater.inflate(R.layout.your_layout, container, false)

    textInputLayout = view.findViewById(R.id.text_input_layout)
    textInputEditText = view.findViewById(R.id.text_input_edit_text)

    textInputLayout.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
        override fun onPreDraw(): Boolean {
            // Wait for the first draw to be sure the view is completely measured
            if (textInputLayout.height > 0) {
                textInputLayout.viewTreeObserver.removeOnPreDrawListener(this)
                updateHintPosition(textInputEditText.hasFocus(), !textInputEditText.text.isNullOrEmpty(), false)
                return false
            }
            return true
        }
    })

    textInputEditText.setOnFocusChangeListener { _, hasFocus ->
        updateHintPosition(hasFocus, !textInputEditText.text.isNullOrEmpty(), true)
    }

    return view
}

private fun updateHintPosition(hasFocus: Boolean, hasText: Boolean, animate: Boolean) {
    if (animate) {
        TransitionManager.beginDelayedTransition(textInputLayout)
    }
    if (hasFocus || hasText) {
        textInputEditText.setPadding(0, 0, 0, 0)
    } else {
        textInputEditText.setPadding(0, 0, 0, getTextInputLayoutTopSpace())
    }
}

private fun getTextInputLayoutTopSpace(): Int {
    var currentView: View = textInputEditText
    var space = 0
    do {
        space += currentView.top
        currentView = currentView.parent as View
    } while (currentView.id != textInputLayout.id)
    return space
}

代码:

<android.support.design.widget.TextInputLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:android="http://schemas.android.com/apk/res/android">

<android.support.design.widget.TextInputEditText
    android:layout_width="match_parent"
    android:layout_height="90dp"
    android:hint="Test"
    android:gravity="center" />

我希望这能解决你的问题。


1
投票

请使用此代码如果要在Center中显示EditText提示

<android.support.design.widget.TextInputLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:android="http://schemas.android.com/apk/res/android">

<android.support.design.widget.TextInputEditText
    android:layout_width="match_parent"
    android:layout_height="90dp"
    android:hint="Test"
    android:gravity="center_vertical" />

如果要在垂直居中显示EditText提示以及左对齐

<android.support.design.widget.TextInputLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:android="http://schemas.android.com/apk/res/android">

<android.support.design.widget.TextInputEditText
    android:layout_width="match_parent"
    android:layout_height="90dp"
    android:hint="Test"
    android:gravity="center|left" />

要么

"Widget.MaterialComponents.TextInputLayout.FilledBox.Dense"


1
投票

当我使用主题Before和密码可见性切换按钮时,我遇到了这个问题。

所以我最终根据这个问题的答案创建了自定义类。

之前:After之后:package com.mycompany import android.content.Context import android.util.AttributeSet import android.view.View import android.view.ViewTreeObserver import com.google.android.material.textfield.TextInputEditText import com.google.android.material.textfield.TextInputLayout import com.mycompany.R class CustomTextInputEditText : TextInputEditText { //region Constructors constructor(context: Context) : super(context) constructor(context: Context, attrs: AttributeSet) : super(context, attrs) constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) //endregion //region LifeCycle override fun onAttachedToWindow() { super.onAttachedToWindow() textInputEditText.setOnFocusChangeListener { _, hasFocus -> updateHintPosition(hasFocus, !textInputEditText.text.isNullOrEmpty()) } textInputEditText.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener { override fun onPreDraw(): Boolean { if ((textInputLayout?.height ?: 0) > 0) { textInputLayout?.viewTreeObserver?.removeOnPreDrawListener(this) updateHintPosition(textInputEditText.hasFocus(), !textInputEditText.text.isNullOrEmpty()) return false } return true } }) } //endregion //region Center hint private var paddingBottomBackup:Int? = null private var passwordToggleButtonPaddingBottomBackup:Float? = null private val textInputEditText: TextInputEditText get() { return this } private val textInputLayout:TextInputLayout? get(){ return if (parent is TextInputLayout) (parent as? TextInputLayout) else (parent?.parent as? TextInputLayout) } private val passwordToggleButton:View? get() { return (parent as? View)?.findViewById(R.id.text_input_password_toggle) } private fun updateHintPosition(hasFocus: Boolean, hasText: Boolean) { if (paddingBottomBackup == null) paddingBottomBackup = paddingBottom if (hasFocus || hasText) textInputEditText.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottomBackup!!) else textInputEditText.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottomBackup!! + getTextInputLayoutTopSpace()) val button = passwordToggleButton if (button != null){ if (passwordToggleButtonPaddingBottomBackup == null) passwordToggleButtonPaddingBottomBackup = button.translationY if (hasFocus || hasText) button.translationY = - getTextInputLayoutTopSpace().toFloat() * 0.50f else button.translationY = passwordToggleButtonPaddingBottomBackup!! } } private fun getTextInputLayoutTopSpace(): Int { var currentView: View = textInputEditText var space = 0 do { space += currentView.top currentView = currentView.parent as View } while (currentView !is TextInputLayout) return space } //endregion //region Internal classes data class Padding(val l: Int, val t: Int, val r: Int, val b: Int) //endregion }

自定义类:

        <com.google.android.material.textfield.TextInputLayout
            style="@style/Widget.MaterialComponents.TextInputLayout.FilledBox.Dense"
            android:layout_height="wrap_content"
            android:layout_width="match_parent"
            android:hint="Password"
            app:passwordToggleEnabled="true">

            <com.mycompany.CustomTextInputEditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:inputType="textPassword" />

        </com.google.android.material.textfield.TextInputLayout>

用法:

    <android.support.design.widget.TextInputLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

    <android.support.design.widget.TextInputEditText
        android:layout_width="200dp"
        android:layout_height="90dp"
        android:hint="Test"
        android:gravity="center_vertical" />

0
投票

找到了解决方案:

android:gravity="center_vertical"

高度为90dp就是一个例子。如果你能提供你的xml,我可以根据你的情况进行调整。你只需要设置TextInputLayoutwrap_content应该有class TextInputCenterHelper constructor(val textInputLayout: TextInputLayout, val textInputEditText: TextInputEditText){ init { textInputLayout.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener { override fun onPreDraw(): Boolean { if (textInputLayout.height > 0) { textInputLayout.viewTreeObserver.removeOnPreDrawListener(this) updateHintPosition(textInputEditText.hasFocus(), !textInputEditText.text.isNullOrEmpty(), false) return false } return true } }) textInputEditText.setOnFocusChangeListener { _, hasFocus -> updateHintPosition(hasFocus, !textInputEditText.text.isNullOrEmpty(), true) } } private fun updateHintPosition(hasFocus: Boolean, hasText: Boolean, animate: Boolean) { if (animate) { TransitionManager.beginDelayedTransition(textInputLayout) } if (hasFocus || hasText) { textInputEditText.setPadding(0, 0, 0, 0) } else { textInputEditText.setPadding(0, 0, 0, getTextInputLayoutTopSpace()) } } private fun getTextInputLayoutTopSpace(): Int { var currentView: View = textInputEditText var space = 0 do { space += currentView.top currentView = currentView.parent as View } while (currentView.id != textInputLayout.id) return space } 作为高度

希望能帮助到你 :)


0
投票

也许有点晚了但......基于@JFrite的回复......你可以创建一个类来改进代码:

 TextInputCenterHelper(your_text_input_layout, your_text_input_edit_text)

并使用它:

qazxswpoi

我希望这可以帮助别人!

© www.soinside.com 2019 - 2024. All rights reserved.