You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android中如何在EditText右侧同时显示清除图标与密码切换图标

我之前也遇到过类似的图标重叠问题,核心是要把两个图标分配到不同的区域/控件上,避免互相抢占位置。这里有几种靠谱的解决方法,推荐第一种最省心的实现方式:

方法一:利用TextInputLayout内置endIcon做密码切换,EditText自身drawableEnd做清除图标

这种方式借助TextInputLayout的原生能力处理密码切换,把清除图标交给EditText负责,两者位置自然分离,不需要复杂的自定义逻辑。

1. 布局代码

<!-- 你的自定义LoginInputLayout(继承自TextInputLayout) -->
<com.yourpackage.LoginInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    <!-- 开启密码切换图标,用原生属性控制 -->
    app:passwordToggleEnabled="true"
    app:passwordToggleDrawable="@drawable/your_password_toggle_selector"
    app:endIconPadding="8dp">

    <com.google.android.material.textfield.TextInputEditText
        android:id="@+id/et_password"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="textPassword"
        <!-- 设置清除图标 -->
        android:drawableEnd="@drawable/ic_clear"
        android:drawablePadding="8dp"
        <!-- 给右侧的密码切换图标留出空间,避免重叠 -->
        android:paddingEnd="48dp"/>

</com.yourpackage.LoginInputLayout>

2. 处理清除图标点击事件

在代码里给EditText添加触摸监听,判断点击区域是否在清除图标上:

val etPassword = findViewById<TextInputEditText>(R.id.et_password)
etPassword.setOnTouchListener { v, event ->
    val drawableEndIndex = 2 // 对应EditText的END方向Drawable
    val clearDrawable = (v as EditText).compoundDrawables[drawableEndIndex] ?: return@setOnTouchListener false
    
    if (event.action == MotionEvent.ACTION_UP) {
        // 判断点击位置是否在清除图标范围内
        if (event.rawX >= v.right - clearDrawable.bounds.width()) {
            v.setText("")
            return@setOnTouchListener true
        }
    }
    false
}
方法二:组合两个Drawable为一个(适合必须把图标都放在EditText内的场景)

如果一定要把两个图标都作为EditText的drawableEnd,可以创建一个组合Drawable,手动控制两个图标的位置:

1. 创建组合Drawable文件 combined_end_drawables.xml

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 清除图标在左侧,给右侧密码图标留位置 -->
    <item
        android:drawable="@drawable/ic_clear"
        android:right="40dp"/>
    <!-- 密码图标在右侧,和清除图标保持间距 -->
    <item
        android:drawable="@drawable/your_password_toggle_selector"
        android:left="24dp"/>
</layer-list>

2. 布局中使用组合Drawable

<com.google.android.material.textfield.TextInputEditText
    android:id="@+id/et_password"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:inputType="textPassword"
    android:drawableEnd="@drawable/combined_end_drawables"/>

3. 处理两个图标的点击事件

需要计算每个图标的点击区域,区分清除和密码切换操作:

etPassword.setOnTouchListener { v, event ->
    if (event.action == MotionEvent.ACTION_UP) {
        val combinedDrawable = (v as EditText).compoundDrawables[2] ?: return@setOnTouchListener false
        val clearIconWidth = resources.getDrawable(R.drawable.ic_clear).bounds.width()
        val passwordIconWidth = resources.getDrawable(R.drawable.your_password_toggle_selector).bounds.width()
        val totalDrawableWidth = combinedDrawable.bounds.width()
        
        val clickX = event.rawX - v.right + totalDrawableWidth
        when {
            // 点击清除图标区域
            clickX <= clearIconWidth -> {
                v.setText("")
                return@setOnTouchListener true
            }
            // 点击密码切换图标区域
            clickX >= totalDrawableWidth - passwordIconWidth -> {
                // 切换密码可见性
                val newInputType = if (v.inputType == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) {
                    InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
                } else {
                    InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
                }
                v.inputType = newInputType
                // 保持光标在文本末尾
                v.setSelection(v.text?.length ?: 0)
                return@setOnTouchListener true
            }
        }
    }
    false
}
方法三:封装到自定义LoginInputLayout(复用性更高)

如果你的项目里多个页面需要这个效果,可以把逻辑封装到自定义的LoginInputLayout中,对外暴露简单的属性控制:

class LoginInputLayout @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = R.attr.textInputLayoutStyle
) : TextInputLayout(context, attrs, defStyleAttr) {

    private lateinit var editText: TextInputEditText

    init {
        editText = TextInputEditText(context).apply {
            layoutParams = LayoutParams(MATCH_PARENT, WRAP_CONTENT)
            // 预设右侧padding,给密码图标留空间
            setPadding(paddingLeft, paddingTop, 48.dpToPx(context), paddingBottom)
            setOnTouchListener { v, event -> handleClearIconClick(v as EditText, event) }
        }
        addView(editText)

        // 读取自定义属性,判断是否启用密码模式
        attrs?.let {
            val typedArray = context.obtainStyledAttributes(it, R.styleable.LoginInputLayout)
            val isPassword = typedArray.getBoolean(R.styleable.LoginInputLayout_isPassword, false)
            if (isPassword) {
                isPasswordToggleEnabled = true
                passwordToggleDrawable = ContextCompat.getDrawable(context, R.drawable.password_toggle_selector)
                editText.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
            }
            typedArray.recycle()
        }
    }

    private fun handleClearIconClick(editText: EditText, event: MotionEvent): Boolean {
        val clearDrawable = editText.compoundDrawables[2] ?: return false
        if (event.action == MotionEvent.ACTION_UP && event.rawX >= editText.right - clearDrawable.bounds.width()) {
            editText.setText("")
            return true
        }
        return false
    }

    private fun Int.dpToPx(context: Context): Int {
        return (this * context.resources.displayMetrics.density).toInt()
    }

    // 对外暴露EditText,方便获取文本等操作
    fun getEditText(): TextInputEditText = editText
}

然后在attrs.xml中添加自定义属性:

<declare-styleable name="LoginInputLayout">
    <attr name="isPassword" format="boolean"/>
</declare-styleable>

使用时只需要在布局里写:

<com.yourpackage.LoginInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:isPassword="true"
    app:endIconPadding="8dp"/>

内容的提问来源于stack exchange,提问作者Rafa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 11:08:25