TextInputLayout 错误右对齐

TextInputLayout Error right align

我有一个包含在 TextInputLayout 中的 EditText。我希望在 EditText 下显示错误,但对齐到屏幕的右端。

这是我目前拥有的:

错误显示如下:

我希望它看起来像什么:

我的XML是这样的:

        <android.support.design.widget.TextInputLayout
            android:id="@+id/text_input_email"
            style="@style/forgot_pass_text_inputlayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/tv_enter_email_message"
            android:layout_marginTop="@dimen/email_padding_top"
            android:hintTextAppearance="@{forgotPasswordVM.hintTextAppearance}"
            android:theme="@style/forgot_pass_til_state"
            app:error="@{forgotPasswordVM.email.textInputError}">

            <EditText
                android:id="@+id/actv_email"
                style="@style/forgot_pass_edit_text"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="@string/email_address"
                android:imeActionId="@+id/btn_submit"
                android:imeOptions="actionSend"
                android:inputType="textEmailAddress"
                android:maxLines="1"
                android:onEditorAction="@{forgotPasswordVM.onEditorAction}"
                android:singleLine="true"
                app:binding="@{forgotPasswordVM.email.text}" />
        </android.support.design.widget.TextInputLayout>

我正在使用数据绑定。

我已经尝试在 EditText 和 TextInputLayout 上设置 android:gravity="right"android:layout_gravity="right"。两者都不像我想要的那样工作。

我试过在主题和样式中设置正确的引力。两者都对错误没有任何影响。

我已经在 app:errorTextAppearance="@style/right_error" 中应用的样式上尝试了正确的引力。即使这样也行不通。

我尝试通过在 this link 之后使用带有 AlignmentSpan 的 SpannableStringBuilder 以编程方式将错误向右移动。即使那样对我也不起作用。

我不确定还能尝试什么。请提出建议。

感谢 Mike's answer 我找到了解决方案。

我创建了一个自定义 class:

public class CustomTextInputLayout extends TextInputLayout {

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

    @Override
    public void setErrorEnabled(boolean enabled) {
        super.setErrorEnabled(enabled);

        if (!enabled) {
            return;
        }

        try {
            Field errorViewField = TextInputLayout.class.getDeclaredField("mErrorView");
            errorViewField.setAccessible(true);
            TextView errorView = (TextView) errorViewField.get(this);
            if (errorView != null) {
                errorView.setGravity(Gravity.RIGHT);
                LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
                params.gravity = Gravity.END;
                errorView.setLayoutParams(params);
            }
        }
        catch (Exception e) {
            // At least log what went wrong
            e.printStackTrace();
        }
    }
}

现在我只是用 CustomTextInputLayout 替换了我的 TextInputLayout。 奇迹般有效。非常感谢Mike。我希望我能把这个答案更多地归功于你。

我的习惯 class 使用 Kotlin

class CustomTextInputLayout(context: Context, attrs: AttributeSet) :
    TextInputLayout(context, attrs) {

    override fun setErrorEnabled(enabled: Boolean) {
        super.setErrorEnabled(enabled)

        if (!enabled) {
            return
        }

        try {
            val layout = this
            val errorView : TextView = ((this.getChildAt(1) as ViewGroup).getChildAt(0) as ViewGroup).getChildAt(0) as TextView

            (layout.getChildAt(1) as ViewGroup).layoutParams.width = LayoutParams.MATCH_PARENT
            (layout.getChildAt(1) as ViewGroup).getChildAt(0).layoutParams.width = FrameLayout.LayoutParams.MATCH_PARENT

            errorView.gravity = Gravity.END

        } catch (e: Exception) {
            e.printStackTrace()
        }

    }
}

如果选择的答案无效。另一种解决方案如下:

创建自定义 class 如下:

public class CustomTextInputLayout extends TextInputLayout
{

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

@Override
public void setErrorEnabled(boolean enabled)
{
    super.setErrorEnabled(enabled);

    if (!enabled)
    {
        return;
    }

    try
    {
        TextView errorView = this.findViewById(R.id.textinput_error);
        FrameLayout errorViewParent = (FrameLayout) errorView.getParent();
        errorViewParent.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT));
        errorView.setGravity(Gravity.CENTER); // replace CENTER  with END or RIGHT
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }
}
}

然后将您的自定义 TextInputLayout 创建为:

 <CustomTextInputLayout
    android:id="@+id/til_first_name"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="@dimen/activity_horizontal_margin"
    app:layout_constraintBottom_toTopOf="@+id/til_last_name">

    <EditText
        android:id="@+id/et_first_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/first_name"
        android:gravity="right"
        />

</CustomTextInputLayout>

之后在您的代码中初始化为:

private CustomTextInputLayout tilFirstName;
tilFirstName = view.findViewById(R.id.til_first_name);

恭喜!你已经完成了你所要求的。

这是 Kotlin 中不依赖于视图层次结构的 hack:

class CustomTextInputLayout @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : TextInputLayout(context, attrs, defStyleAttr) {

    override fun setError(errorText: CharSequence?) {
        super.setError(errorText)
        with(findViewById<TextView>(R.id.textinput_error)) {
            // this will work as long as errorView's layout width is
            // MATCH_PARENT -- it is, at least now in material:1.2.0-alpha06
            textAlignment = TextView.TEXT_ALIGNMENT_VIEW_END
        }
    }
}

使用 material-componets 版本 1.2.0-rc01,您可以创建一个继承自 TextInputLayout 的 CustomTextInputLayout,以将 文本对齐方式 更改为末尾(或您想要的位置它是)像这样:

class CustomTextInputLayout : TextInputLayout {

    constructor(context: Context) : super(context)

    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)

    constructor(
        context: Context,
        attrs: AttributeSet?,
        defStyleAttrs: Int
    ) : super(context, attrs, defStyleAttrs)

    override fun setErrorEnabled(enabled: Boolean) {
        super.setErrorEnabled(enabled)
        if (!enabled) {
            return
        }
        try {
            changeTextAlignment(
                com.google.android.material.R.id.textinput_error,
                View.TEXT_ALIGNMENT_VIEW_END
            )
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

   
    private fun changeTextAlignment(textViewId: Int, alignment: Int) {
        val textView = findViewById<TextView>(textViewId)
        textView.textAlignment = alignment
    }
}

IndicatorViewController class 中指定的对齐始终为 View.TEXT_ALIGNMENT_VIEW_START。此 class 由 TextInputLayout 使用。

来自IndicatorViewControllerclass

  void setErrorEnabled(boolean enabled) {
    if (errorEnabled == enabled) {
      return;
    }

    cancelCaptionAnimator();

    if (enabled) {
      errorView = new AppCompatTextView(context);
      errorView.setId(R.id.textinput_error);
      if (VERSION.SDK_INT >= 17) {
        errorView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
      }
//More code...

基于@Emmanuel Guerra的回答。我也在 helperText 上应用了它:

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

    override fun setErrorEnabled(enabled: Boolean) {
        super.setErrorEnabled(enabled)
        if (!enabled) return
        centerMiniText(com.google.android.material.R.id.textinput_error)
    }

    override fun setHelperTextEnabled(enabled: Boolean) {
        super.setHelperTextEnabled(enabled)
        if (!enabled) return
        centerMiniText(com.google.android.material.R.id.textinput_helper_text)
    }

    private fun centerMiniText(textViewId: Int) {
        try {
            changeTextAlignment(textViewId, View.TEXT_ALIGNMENT_CENTER)
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    @Suppress("SameParameterValue")
    private fun changeTextAlignment(textViewId: Int, alignment: Int) {
        findViewById<TextView>(textViewId)?.textAlignment = alignment
    }

}