在TextInputLayout中,如果将drawableLeft添加到EditText中,则会将提示向右移动。

13

在此输入图片描述我在TextInputLayout中创建了一个EditText。我在代码中运行时为EditText设置了drawableLeft,但是一旦添加了drawableLeft,TextInputLayout内的浮动提示就会向右移动,留下与drawable宽度相等的空间。但我不想在提示中留下那个空间,请帮助我解决这个问题!


请发布您的XML。 - Rahul Khurana
使用 _setCompoundDrawablePadding_。 - Piyush
3个回答

38

TextInputLayout 使用一个受限制的库辅助类 CollapsingTextHelper 来操作其提示文本。该辅助类的实例是私有的,与其布局相关的属性都没有暴露出来,因此我们需要使用一些反射技巧来访问它。此外,每次 TextInputLayout 布局时都会设置和重新计算其属性,因此最好继承 TextInputLayout,重写其 onLayout() 方法,并在那里进行调整。

import android.content.Context
import android.graphics.Rect
import android.util.AttributeSet
import com.google.android.material.textfield.TextInputLayout

class CustomTextInputLayout @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = com.google.android.material.R.attr.textInputStyle
) : TextInputLayout(context, attrs, defStyleAttr) {

    private val collapsingTextHelper = try {
        TextInputLayout::class.java.getDeclaredField("collapsingTextHelper")
            .apply { isAccessible = true }.get(this)
    } catch (e: Exception) {
        null
    }

    private val recalculateMethod = collapsingTextHelper?.let { helper ->
        try {
            helper.javaClass.getDeclaredMethod("recalculate")
        } catch (e: Exception) {
            null
        }
    }

    private val collapsedBounds = collapsingTextHelper?.let { helper ->
        try {
            helper.javaClass.getDeclaredField("collapsedBounds")
                .apply { isAccessible = true }.get(helper) as Rect
        } catch (e: Exception) {
            null
        }
    }

    override fun onLayout(
        changed: Boolean,
        left: Int,
        top: Int,
        right: Int,
        bottom: Int
    ) {
        super.onLayout(changed, left, top, right, bottom)

        val edit = editText ?: return
        val helper = collapsingTextHelper ?: return
        val recalculate = recalculateMethod ?: return
        val bounds = collapsedBounds ?: return

        bounds.left = edit.left + edit.paddingLeft
        try {
            recalculate.invoke(helper)
        } catch (e: Exception) {
            // fail silently
        }
    }
}

自定义类是常规TextInputLayout的即插即用替代品。例如:

<com.example.app.CustomTextInputLayout
    android:id="@+id/text_input_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="Model (Example i10, Swift, etc.)"
    app:hintTextAppearance="@style/TextLabel">

    <com.google.android.material.textfield.TextInputEditText
        android:id="@+id/edit_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:drawableLeft="@drawable/bmw"
        android:text="M Series" />

</com.example.app.CustomTextInputLayout>

Screenshot showing the adjusted hint alignment.


1
在支持库28中,他们更改了变量的名称,因此getDeclaredField反射不再起作用。 他们改变了所有变量的大小写,因此您必须将mCollapsingTextHelper更改为collapsingTextHelper。 - Adrian Blanco
1
请将以下行添加到Proguard规则中,以便在生产构建中仍然可以正常工作:-keep class android.support.design.widget.TextInputLayout{ *; } -keep class android.support.design.widget.CollapsingTextHelper{ *; } - Tim
1
对于 Android X 包,字段名称已更改。请使用 collapsingTextHelper 和 collapsedBounds。 - Victor
请问您能分享一下TextLabel的样式吗? - android_sh
如果反射或ProGuard等存在任何问题,此答案展示了一种略有不同的方法,将自定义类放置在库包中,从而直接访问相关字段和方法。可能会出现库限制错误,但可以抑制它。除此之外,唯一的缺点可能是Material Components的TextInputLayout因其所有新功能而以不同的方式计算边界,因此只使用所示的基本填充计算可能无法正确对齐。 - Mike M.
显示剩余2条评论

-1

是的,这是我最近遇到的一个常见问题。我用一行简单的代码解决了它: 通过使用 drawble padding 在提示和 drawbleleft 之间放置一个填充。 如果您正在运行时添加 drawble,只需提前在 xml 中添加 drawblepadding 或者您可以动态添加 drawble 填充。


-2
 editText.setCompoundDrawablePadding(your padding value);

试一下,然后告诉我。这在我这里有效。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接