TextInputLayout标签如何放置在EditText左侧绘图上方?

9

当用户在EditText中聚焦或输入时,是否可以使TextInputLayout标签垂直显示在EditText左侧绘图上方。

这是EditText的XML:

 <android.support.design.widget.TextInputLayout
                android:id="@+id/completion_date_layout2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="5dp"
                android:layout_marginRight="5dp"
                android:layout_weight="1"
                android:orientation="horizontal">

                <EditText
                    android:id="@+id/etTaskDate"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:hint="@string/title_completion_date"
                    android:inputType="text"
                    android:drawableLeft="@drawable/ic_date"
                    android:paddingBottom="15dp"
                    android:drawablePadding="5dp"
                    android:textSize="@dimen/fields_text_size"/>
            </android.support.design.widget.TextInputLayout>

这是期望的输出结果:

enter image description here

这是我得到的输出结果:

enter image description here

(注意:保留了HTML标签,未做解释)

2
你找到解决方案了吗?我也遇到了同样的问题。 - Raymond
@RaymonddelaCroix 很抱歉,我的朋友上个月以来就不在了。我在下面发布了我所做的解决方法。 :) - icaneatclouds
4个回答

8
由于Java的成员访问模型和谷歌开发人员留下的一个小漏洞,可以通过简单的子类化来实现,这样可以重复最少量的原始代码。
package android.support.design.widget;

import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;

public final class TextInputLayoutEx extends TextInputLayout {

    private final int mDefaultPadding = __4DP__;
    private final Rect mTmpRect = new Rect();

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

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        if (isHintEnabled() && mEditText != null) {
            final Rect rect = mTmpRect;
            ViewGroupUtils.getDescendantRect(this, mEditText, rect);
            mCollapsingTextHelper.setCollapsedBounds(
                rect.left + mDefaultPadding, getPaddingTop(),
                rect.right - mDefaultPadding, bottom - top - getPaddingBottom());
            mCollapsingTextHelper.recalculate();
        }
    }

}

在这里,我们将一个新类放入相同的包中,该类使用包级别可见性打开对的访问,然后重复来自原始方法的一部分代码,该方法管理字段名称位置。 <__4DP__>值是转换为像素的4dp值,我非常确定每个人都有一个实用程序方法来完成此操作。
在您的xml布局中,只需从切换到,以便您的布局看起来像这样:
<android.support.design.widget.TextInputLayoutEx
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="Mobile">
    <android.support.design.widget.TextInputEditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:drawableLeft="@drawable/ic_phone_black_24dp"
        android:drawablePadding="4dp"/>
</android.support.design.widget.TextInputLayoutEx>

结论如下:

Collapsed and expanded state

目前仅适用于 com.android.support:design:25.3.1


这个我会在另一个项目上尝试一下。谢谢。 - icaneatclouds
EPIC,运行得非常顺畅。@icaneatclouds 考虑将此代码标记为“答案”。 - MiguelCatalan
非常聪明的解决方案!唯一的问题是,在某些情况下,裁剪不正确。例如,如果标签处于正确位置,然后我们打开键盘进行另一个edittext的编辑。解决方法是在onLayout方法的第一行添加以下内容:“if(!changed)return”,但显然这会产生后果。 - Vaios
以上示例中,mCollapsingTextHelper和mEditText是什么? - Auxano Services
2
@AuxanoServices 这些是基类中的包私有字段。随着迁移到AndroidX,它们的名称已更改为collapsingTextHelpereditText - Mikhail

0

您可以使用动画和frame_layout来为左侧图标添加动画效果,尝试一下this链接,可能对您有所帮助。


0

我已经针对这个问题做了一个解决方法。它可能有点不可靠,但在我的端上可以运行。 这是代码:

String spacer="        ";
EditText myEditText= (EditText)findViewById(R.id.myEditText);
myEditText.setText(spacer + "Today");
myEditText.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_calendar, 0, 0, 0);

我在这里做的是在editText内的文本前插入一个占位符,然后以编程方式添加左侧drawable。但确保在获取editText内容之前删除那些空格:
String title = myEditText.getText().toString().substring(8);

这意味着我在单词“今天”之前裁剪了8个空格。


你能解释一下为什么会有人踩我的帖子吗?因为我的问题没有得到有效的回答,所以我做了一个快速解决方案。 - icaneatclouds

0
你可以尝试使用这个自定义类:在这里找到它。
然后只需要在XML中进行更改即可。

com.mycompany.myapp.CustomTextInputLayout

import android.content.Context;
import android.graphics.Rect;
import android.support.design.widget.TextInputLayout;

import android.util.AttributeSet;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class CustomTextInputLayout extends TextInputLayout {
    private Object collapsingTextHelper;
    private Rect bounds;
    private Method recalculateMethod;

    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);

        init();
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);

        adjustBounds();
    }

    private void init() {
        try {
            Field cthField = TextInputLayout.class.getDeclaredField("mCollapsingTextHelper");
            cthField.setAccessible(true);
            collapsingTextHelper = cthField.get(this);

            Field boundsField = collapsingTextHelper.getClass().getDeclaredField("mCollapsedBounds");
            boundsField.setAccessible(true);
            bounds = (Rect) boundsField.get(collapsingTextHelper);

            recalculateMethod = collapsingTextHelper.getClass().getDeclaredMethod("recalculate");
        }
        catch (NoSuchFieldException | IllegalAccessException | NoSuchMethodException e) {
            collapsingTextHelper = null;
            bounds = null;
            recalculateMethod = null;
            e.printStackTrace();
        }
    }

    private void adjustBounds() {
        if (collapsingTextHelper == null) {
            return;
        }

        try {
            bounds.left = getEditText().getLeft() + getEditText().getPaddingLeft();
            recalculateMethod.invoke(collapsingTextHelper);
        }
        catch (InvocationTargetException | IllegalAccessException | IllegalArgumentException e) {
            e.printStackTrace();
        }
    }
}

这个可以工作,但只有在没有启用 Proguard 的情况下才能正常运行。有什么关于如何从 Proguard 中排除它的想法吗? - Tim
2
请不要只是复制别人的答案。如果您认为另一篇帖子已经解决了该问题,请标记当前问题为重复,或在评论中留下链接。 - Mike M.

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