如何更改 TextInputLayout 中 EditText 提示的大小

How to change the size of the EditText hint in TextInputLayout

我正在尝试更改 TextInputLayout 中的提示大小,但它没有按预期工作。这就是我想要实现的目标:


styles.xml

<style name="TextLabel" parent="TextAppearance.Design.Hint">
    <item name="android:textSize">44sp</item>
</style>

fragment.xml

<android.support.design.widget.TextInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:hintTextAppearance="@style/TextLabel"
    android:hint="Password">

    <android.support.design.widget.TextInputEditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="24sp"/>

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

此代码仅适用于浮动标签,当 EditText 不为空时,但我想在 EditText 本身为空时更改提示大小。

在 inflation/initialization 期间添加到 TextInputLayout 时,常规提示文本的大小设置为 EditText 的文本大小。此值最终设置在 TextInputLayout 中的私有助手 class 上,并且没有公开公开的方法或字段来更改它。

但是,我们可以通过子classing TextInputLayout 来拦截 EditText 的添加,从而对文本大小进行一些调整。当添加 EditText 时,我们缓存它的文本大小,将所需的提示大小设置为其文本大小,允许超级 class 添加它并初始化提示,最后设置 EditText的文字大小恢复到原来的值。

例如:

public class CustomTextInputLayout extends TextInputLayout {

    private float mainHintTextSize;
    private float editTextSize;

    public CustomTextInputLayout(Context context) {
        this(context, null);
    }

    public CustomTextInputLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CustomTextInputLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        TypedArray a = context.obtainStyledAttributes(
            attrs, R.styleable.CustomTextInputLayout);

        mainHintTextSize = a.getDimensionPixelSize(
            R.styleable.CustomTextInputLayout_mainHintTextSize, 0);

        a.recycle();
    }

    @Override
    public void addView(View child, int index, ViewGroup.LayoutParams params) {
        final boolean b = child instanceof EditText && mainHintTextSize > 0;

        if (b) {
            final EditText e = (EditText) child;
            editTextSize = e.getTextSize();
            e.setTextSize(TypedValue.COMPLEX_UNIT_PX, mainHintTextSize);
        }

        super.addView(child, index, params);

        if (b) {
            getEditText().setTextSize(TypedValue.COMPLEX_UNIT_PX, editTextSize);
        }
    }

    // Units are pixels.

    public float getMainHintTextSize() {
        return mainHintTextSize;
    }

    // This optional method allows for dynamic instantiation of this class and
    // its EditText, but it cannot be used after the EditText has been added.
    // Units are scaled pixels.

    public void setMainHintTextSize(float size) {
        if (getEditText() != null) {
            throw new IllegalStateException(
                "Hint text size must be set before EditText is added");
        }

        mainHintTextSize = TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_SP, size, getResources().getDisplayMetrics());
    }
}

要使用自定义 mainHintTextSize 属性,我们需要在 <resources> 中添加以下内容,只需将以下文件粘贴到 res/values/ 文件夹中即可,或者添加到已经存在的那个。

attrs.xml

<resources>
    <declare-styleable name="CustomTextInputLayout" >
        <attr name="mainHintTextSize" format="dimension" />
    </declare-styleable>
</resources>

如果不想使用自定义属性,可以跳过这个文件,去掉上面第三个构造函数中的TypedArray处理

此自定义 class 是 TextInputLayout 的直接替代品,可以按原样使用。例如:

<com.mycompany.myapp.CustomTextInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="Password"
    app:hintTextAppearance="@style/TextLabel"
    app:mainHintTextSize="12sp">

    <android.support.design.widget.TextInputEditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="24sp"
        android:text="qwerty123" />

</com.mycompany.myapp.CustomTextInputLayout>


这种方法很好,因为它仅使用可公开访问的记录方法,但必须在添加 EditText 之前设置提示文本大小,无论是否在 inflation 期间发生,或者通过直接实例化。

如果您希望提示在展开和折叠状态下具有相同的大小。您可以编写自己的自定义 TextInputLayout

package android.support.design.widget

import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup
import android.widget.EditText

class ConstantHintSizeTextInputLayout : TextInputLayout {
    constructor(context: Context?) : super(context)
    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)

    @SuppressLint("RestrictedApi")
    override fun addView(child: View?, index: Int, params: ViewGroup.LayoutParams?) {
        super.addView(child, index, params)
        if (child is EditText) {
            collapsingTextHelper.expandedTextSize = collapsingTextHelper.collapsedTextSize
        }
    }
}

重要提示:包名应该完全等于android.support.design.widget,因为这个解决方案使用访问包私有字段,但不涉及反射,所以它很快