如何在EditText末尾添加带有叉(x)的按钮?

245

是否有类似于EditText的小部件,其中包含一个带叉号的按钮,或者是否有EditText的属性可以自动创建它?我希望在EditText中编写任何文本后,都能使用叉号按钮删除文本。


2
似乎没有标准的小部件可用。但是,您可以通过在Google中搜索“android edittext clear button x”来找到一些不同的方法。所以我猜“清除按钮”就是他们称之为的东西。此外,请参阅与相关问题的答案:https://dev59.com/sG855IYBdhLWcg3wuG-W#6235602 - HostileFork says dont trust SE
你可以在这里下载源代码:https://github.com/GhOsTTT/editTextXbutton 祝你有美好的一天。 - Gökhan Musapaşaoğlu ヅ
另一个本质上是重复的问题是 *在Android中实现UITextfield属性*。 - Alex Cohn
18个回答

177

2020年的解决方案:使用Material Design Components for Android:

将Material Components添加到您的gradle设置中:

从此处查找最新版本:https://maven.google.com/

implementation 'com.google.android.material:material:1.3.0'

或者如果您还没有更新为使用AndroidX库,可以按照以下方式添加:

implementation 'com.android.support:design:28.0.0'

然后

<com.google.android.material.textfield.TextInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="@string/hint_text"
    app:endIconMode="clear_text">

  <com.google.android.material.textfield.TextInputEditText
      android:layout_width="match_parent"
      android:layout_height="wrap_content"/>

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

注意: app:endIconMode="clear_text"

Material design docs中所述


20
这应该成为新的被接受答案。在我的情况下,如果不更新到AndroidX库,我就无法实现。 - Ben
请务必仔细阅读文档,因为并非所有的xml属性都得到支持。有时候您可能需要查看源代码或提交信息,因为这些地方通常包含了确切的实现细节。我曾经遇到过自定义endIcon的类似问题。一条提交信息揭示了该xml属性尚未得到支持。在实现完成之前,将不得不采用其他方法。 - M. Smith
2020年最佳答案。 - Sam Chen
@kevoroid 当我使用implementation 'com.google.android.material:material:1.1.0'时,会出现一些错误,我也使用了它的最新版本,但所有版本都会导致一些AAPT2错误。该怎么办? - KJEjava48
为什么这个输入框这么厚(几乎比常规的EditText高了一倍)? - Damn Vegetables
显示剩余6条评论

171

使用以下布局:

<FrameLayout
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="9dp"
    android:padding="5dp">

    <EditText
        android:id="@+id/calc_txt_Prise"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:inputType="numberDecimal"  
        android:layout_marginTop="20dp"
        android:textSize="25dp"
        android:textColor="@color/gray"
        android:textStyle="bold"
        android:hint="@string/calc_txt_Prise"
        android:singleLine="true" />

    <Button
        android:id="@+id/calc_clear_txt_Prise"      
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginRight="10dp"
        android:layout_gravity="right|center_vertical"
        android:background="@drawable/delete" />

</FrameLayout>

你也可以使用按钮的id,在其onClickListner方法中执行任何想要的操作。


8
这是一种低效的做法。Yanchenko的回答是使用复合可绘制对象的正确方法。 - numan salati
4
如果你选择了这个解决方案并发现图片被拉伸得太多了,那么你应该使用一个ImageButton而不是一个常规的Button。 - personne3000
5
虽然这种解决方案“效率低下”,但对于盲人用户来说更加易用。使用可绘制对象会迫使用户执行非常复杂的操作以清除文本,而视觉用户可以通过点击 “X” 按钮快速完成此操作。 - Daniel Monteiro
2
这有什么低效的问题吗? - Denny

121

如果你使用DroidParts,我刚刚添加了ClearableEditText

这是它使用自定义背景和清除图标设置为abs__ic_clear_holo_light来自ActionBarSherlock的样子:

enter image description here


12
最佳解决方案是因为该类继承自“EditText”。谢谢@yanchenko。 - tbruyelle
2
@stephanek。我已经在develop分支中修复了这个问题,它将成为1.4.3版本的一部分。 - yanchenko
4
谢谢!如果你能在DroidParts中加入一个ClearableAutoCompleteTextView就太好了。对于其他试图实现这个功能的用户,可以使用DroidParts库,从ClearableEditText复制代码并仅扩展AutoCompleteTextView即可。 - RobinDeCroon
2
这太棒了!您还可以使用它作为独立项,将TextWatcherAdapter依赖项更改为普通的TextWatcher。 - Pimentoso
1
@yanchenko 看了你的实现。似乎在接受触摸区域相当小和具有比默认高度更大的编辑文本的情况下,沿着编辑文本的y轴接受触摸事件存在一些权衡。你的实现是前者,而我的实现是后者。在类似的情况下,你会推荐做同样的事情吗?即选择一个较小的命中框,可能会误按,或者选择一个较大的命中框,在扩展或更大的编辑文本中,按压可能会远远超出可绘制区域的范围。 - Jack.Ramsden
显示剩余8条评论

38

这是一个 Kotlin 解决方案。将此辅助方法放入某个 Kotlin 文件中-

fun EditText.setupClearButtonWithAction() {

    addTextChangedListener(object : TextWatcher {
        override fun afterTextChanged(editable: Editable?) {
            val clearIcon = if (editable?.isNotEmpty() == true) R.drawable.ic_clear else 0
            setCompoundDrawablesWithIntrinsicBounds(0, 0, clearIcon, 0)
        }

        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit
        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) = Unit
    })

    setOnTouchListener(View.OnTouchListener { _, event ->
        if (event.action == MotionEvent.ACTION_UP) {
            if (event.rawX >= (this.right - this.compoundPaddingRight)) {
                this.setText("")
                return@OnTouchListener true
            }
        }
        return@OnTouchListener false
    })
}

然后在onCreate方法中使用它,你就可以开始了——

yourEditText.setupClearButtonWithAction()

顺便提一下,您需要首先添加 R.drawable.ic_clear 或清除图标。这个来自谷歌 - https://fonts.google.com/icons?selected=Material%20Icons%20Outlined%3Aclear%3A


如果你在 return true 语句前插入 this.clearFocus(),你可以使用 onFocusChange 监听器,在 EditText 调用者上监听这个事件。 - Joost Schepel
很好,它正在工作, 唯一的问题是我在AppCompatEditText中设置了可绘制的左侧图标,但当我调用此函数时,它会被删除,请问问题出在哪里? - Arbaz.in
是因为调用了方法 setCompoundDrawablesWithIntrinsicBounds(0, 0, clearIcon, 0)。您可以将左侧的可绘制图标 ID 作为新参数传递给此函数并放入调用中。 - Gulshan
@Gulshan 我已经做了相同的事情,但仍然无法删除那个可绘制对象。 - Arbaz.in

24

Android的支持库有一个SearchView类可以实现这一功能。(虽然不是从EditText派生而来,但仍需使用SearchView.OnQueryTextListener而非TextWatcher)

没有文本的搜索视图(带有提示文字“搜索”)

输入图像说明

在XML中使用如下:

  <android.support.v7.widget.SearchView
            android:id="@+id/searchView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:iconifiedByDefault="false"
            android:queryHint="@string/SearchHint"
            app:iconifiedByDefault="false"
            app:queryHint="@string/SearchHint" />

15
Drawable x = getResources().getDrawable(R.drawable.x);
x.setBounds(0, 0, x.getIntrinsicWidth(), x.getIntrinsicHeight());
mEditText.setCompoundDrawables(null, null, x, null);

其中,x为:

enter image description here


9
我们仍需要分配一个 onClickListener,对吧?快速搜索给了我这个链接 [https://dev59.com/V3A65IYBdhLWcg3w7Taa]。猜测更好的解决方案是使用 Framelayout。不过还是感谢你! - VenoM

13

1
顺便说一句,链接的域名已经失效并被抢注了。这是最后一次更新它的样子,显示4.1-7.1。非常好 :) https://web.archive.org/web/20171127224252/http://www.androiddrawables.com/Menu.html - i336_

7
如果您不想使用自定义视图或特殊布局,您可以使用9-patch 来制作(X)按钮。
例如: http://postimg.org/image/tssjmt97p/ (我没有足够的积分在StackOverflow上发布图片)
右下角黑色像素的交叉点表示内容区域。超出该区域的任何内容均为填充区域。因此,您可以设置OnTouchListener来检测用户是否单击了x:
editText.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        if (motionEvent.getAction() == MotionEvent.ACTION_UP){
            if (motionEvent.getX()>(view.getWidth()-view.getPaddingRight())){
                ((EditText)view).setText("");
            }
        }
        return false;
    }
});

根据您的需求,在某些情况下,此解决方案可以更好地工作。我更喜欢让我的xml尽可能简单。这也有助于如果您想在左侧放置图标,因为您可以将其简单地包含在9 patch中。

使用 motionEvent.getRawX() - CoolMind
@CoolMind motionEvent.getRawX() 不是返回相对于屏幕的绝对坐标吗?这个解决方案需要相对于视图的坐标,而 motionEvent.getX() 则可以实现。 - Andrei Tudor Diaconu
也许你是对的,但在我的情况下 getRawX() 有帮助。此页面上还有两个解决方案使用了 rawX()。但我同意你的观点,这取决于具体情况。 - CoolMind

7

只需在你的EditText中添加类似于drawableEnd的关闭交叉图标:

<EditText
     ...
    android:drawableEnd="@drawable/ic_close"
    android:drawablePadding="8dp"
     ... />

并使用扩展程序处理点击(或直接在EditText上使用OnTouchListener):

fun EditText.onDrawableEndClick(action: () -> Unit) {
    setOnTouchListener { v, event ->
        if (event.action == MotionEvent.ACTION_UP) {
            v as EditText
            val end = if (v.resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL)
                v.left else v.right
            if (event.rawX >= (end - v.compoundPaddingEnd)) {
                action.invoke()
                return@setOnTouchListener true
            }
        }
        return@setOnTouchListener false
    }
}

扩展使用:

editText.onDrawableEndClick {
    // TODO clear action
    etSearch.setText("")
}

6

清晰的文本:

"带有清除文本尾随图标的文本字段。"

如果设置,当文本存在时,会显示一个图标,按下它可以清除输入的文本。

    ...
    app:endIconMode="clear_text">
​
    ...
​
</com.google.android.material.textfield.TextInputLayout>

我放在这里: material.io 示例
示例

1
谢谢!你救了我的一天!这对API 24+有效。 - Black_Zerg
就是这样做的。不起作用。图标没有显示出来。 - TheRealChx101

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