| app/src/main/java/com/xw/yunwei/ui/user/login/LoginActivity.kt | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| app/src/main/java/com/xw/yunwei/ui/widget/ClearEditText.kt | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| app/src/main/res/layout/activity_car_manage.xml | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| app/src/main/res/layout/activity_find_psw.xml | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| app/src/main/res/layout/activity_login.xml | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| app/src/main/res/layout/activity_select_car.xml | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| app/src/main/res/layout/activity_site_nav.xml | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| app/src/main/res/layout/fragment_task.xml | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| app/src/main/res/values/attrs.xml | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
app/src/main/java/com/xw/yunwei/ui/user/login/LoginActivity.kt
@@ -160,7 +160,7 @@ binding.psw.visibility=View.VISIBLE binding.eye2.visibility=View.VISIBLE binding.vPswLine.visibility=View.VISIBLE binding.forgetPsw.visibility=View.VISIBLE binding.forgetPsw.visibility=View.GONE } } } app/src/main/java/com/xw/yunwei/ui/widget/ClearEditText.kt
New file @@ -0,0 +1,200 @@ package com.xw.yunwei.ui.widget import android.annotation.SuppressLint import android.content.Context import android.content.res.ColorStateList import android.graphics.Canvas import android.graphics.Rect import android.graphics.RectF import android.graphics.drawable.Drawable import android.text.Editable import android.text.TextWatcher import android.util.AttributeSet import android.view.MotionEvent import androidx.appcompat.widget.AppCompatEditText import androidx.core.content.ContextCompat import androidx.core.graphics.drawable.DrawableCompat import androidx.core.graphics.withClip import com.xw.yunwei.R /** * 自定义 EditText,右侧带有可自定义大小和位置的清除按钮(Canvas 绘制) */ class ClearEditText @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = androidx.appcompat.R.attr.editTextStyle ) : AppCompatEditText(context, attrs, defStyleAttr) { // 清除按钮相关 private var clearIcon: Drawable? = null private var iconWidth: Int = 0 private var iconHeight: Int = 0 private var iconMarginRight: Int = 0 private var iconMarginTop: Int = 0 private var showClearIcon: Boolean = true private var iconTint: ColorStateList? = null // 图标绘制区域 private var iconRect = RectF() // 图标绘制区域 private var iconRectBound = Rect() private var isIconVisible = false // 默认清除图标资源 private val defaultClearIconRes = android.R.drawable.ic_menu_close_clear_cancel init { // 解析自定义属性 val typedArray = context.obtainStyledAttributes(attrs, R.styleable.ClearEditText, defStyleAttr, 0) val clearIconRes = typedArray.getResourceId(R.styleable.ClearEditText_clearIcon, defaultClearIconRes) iconWidth = typedArray.getDimensionPixelSize(R.styleable.ClearEditText_iconWidth, iconWidth) iconHeight = typedArray.getDimensionPixelSize(R.styleable.ClearEditText_iconHeight, iconHeight) iconMarginRight = typedArray.getDimensionPixelSize( R.styleable.ClearEditText_iconMarginRight, iconMarginRight ) iconMarginTop = typedArray.getDimensionPixelSize(R.styleable.ClearEditText_iconMarginTop, iconMarginTop) showClearIcon = typedArray.getBoolean(R.styleable.ClearEditText_showClearIcon, showClearIcon) iconTint = typedArray.getColorStateList(R.styleable.ClearEditText_iconTint) typedArray.recycle() // 加载图标 val drawable = ContextCompat.getDrawable(context, clearIconRes) clearIcon = drawable?.let { val wrapped = DrawableCompat.wrap(it) if (iconTint != null) { DrawableCompat.setTintList(wrapped, iconTint) } else { // 默认使用 hint 文字颜色 DrawableCompat.setTintList(wrapped, hintTextColors) } wrapped } // 添加文本变化监听 addTextChangedListener(object : TextWatcher { override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { updateIconVisibility() } override fun afterTextChanged(s: Editable?) {} }) // 焦点变化监听 setOnFocusChangeListener { _, _ -> updateIconVisibility() } // 初始更新可见性 post { updateIconVisibility() } } /** * 更新图标可见性 */ private fun updateIconVisibility() { val shouldShow = showClearIcon && hasFocus() && text?.isNotEmpty() == true if (isIconVisible != shouldShow) { isIconVisible = shouldShow invalidate() } } /** * 计算图标绘制区域 */ private fun calculateIconRect() { if (clearIcon == null) return val paddingRight = paddingEnd val availableHeight = height - paddingTop - paddingBottom // 图标右边位置 = 控件右边 - paddingRight - iconMarginRight val right = width - paddingRight - iconMarginRight val left = right - iconWidth // 垂直居中,加上 marginTop 微调 val centerY = paddingTop + availableHeight / 2f + iconMarginTop val top = centerY - iconHeight / 2f val bottom = centerY + iconHeight / 2f iconRect.set(left.toFloat(), top, right.toFloat(), bottom) } override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { super.onSizeChanged(w, h, oldw, oldh) calculateIconRect() } override fun onDraw(canvas: Canvas) { super.onDraw(canvas) // 绘制清除图标 if (isIconVisible && clearIcon != null) { canvas.withClip(iconRect) { // 剪切到图标区域(可选,防止绘制超出) iconRectBound.apply { left = iconRect.left.toInt() top = iconRect.top.toInt() right = iconRect.right.toInt() bottom = iconRect.bottom.toInt() } // 设置图标的边界 clearIcon?.bounds = iconRectBound clearIcon?.draw(this) } } } @SuppressLint("ClickableViewAccessibility") override fun onTouchEvent(event: MotionEvent): Boolean { if (event.action == MotionEvent.ACTION_UP) { val x = event.x val y = event.y // 检查点击是否在图标区域内 if (isIconVisible && iconRect.contains(x, y)) { text?.clear() // 清除后保持焦点 requestFocus() performClick() // 辅助功能 return true } } return super.onTouchEvent(event) } /** * 设置清除按钮是否可见 */ fun setShowClearIcon(show: Boolean) { showClearIcon = show updateIconVisibility() } /** * 设置清除图标资源 */ fun setClearIconRes(@androidx.annotation.DrawableRes resId: Int) { val drawable = ContextCompat.getDrawable(context, resId) clearIcon = drawable?.let { val wrapped = DrawableCompat.wrap(it) if (iconTint != null) { DrawableCompat.setTintList(wrapped, iconTint) } else { DrawableCompat.setTintList(wrapped, hintTextColors) } wrapped } invalidate() } } app/src/main/res/layout/activity_car_manage.xml
@@ -60,7 +60,7 @@ android:paddingHorizontal="@dimen/dp_10" app:layout_constraintTop_toTopOf="parent"> <androidx.appcompat.widget.AppCompatEditText <com.xw.yunwei.ui.widget.ClearEditText android:id="@+id/searchEt" android:layout_width="0dp" android:layout_height="@dimen/dp_34" @@ -70,6 +70,9 @@ android:drawableStart="@drawable/svg_search" android:drawablePadding="@dimen/dp_10" android:hint="请输入车牌号" app:iconHeight="@dimen/dp_15" app:iconWidth="@dimen/dp_15" app:clearIcon="@mipmap/ic_close_black2" android:imeOptions="actionSearch" android:paddingHorizontal="@dimen/dp_10" android:singleLine="true" app/src/main/res/layout/activity_find_psw.xml
@@ -40,7 +40,7 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <androidx.appcompat.widget.AppCompatEditText <com.xw.yunwei.ui.widget.ClearEditText android:id="@+id/phone" android:layout_width="match_parent" android:layout_height="@dimen/dp_56" @@ -49,6 +49,10 @@ android:background="@null" android:gravity="center_vertical" android:hint="手机号" app:iconHeight="@dimen/dp_15" app:iconWidth="@dimen/dp_15" app:iconMarginRight="@dimen/dp_10" app:clearIcon="@mipmap/ic_close_black2" android:inputType="phone" android:text="@={viewModel.phone}" android:textColor="@color/gray_10" app/src/main/res/layout/activity_login.xml
@@ -58,7 +58,7 @@ app:tabTextAppearance="@style/TabTextStyle" app:tabTextColor="@color/gray_7" /> <androidx.appcompat.widget.AppCompatEditText <com.xw.yunwei.ui.widget.ClearEditText android:id="@+id/phone" android:layout_width="match_parent" android:layout_height="@dimen/dp_56" @@ -67,6 +67,10 @@ android:background="@null" android:gravity="center_vertical" android:hint="手机号" app:iconHeight="@dimen/dp_15" app:iconWidth="@dimen/dp_15" app:iconMarginRight="@dimen/dp_10" app:clearIcon="@mipmap/ic_close_black2" android:inputType="phone" android:text="@={viewModel.phone}" android:textColor="@color/gray_10" @@ -157,6 +161,7 @@ android:layout_marginTop="@dimen/dp_12" android:onClick="@{viewModel.onClick}" android:text="忘记密码" android:visibility="gone" android:textColor="@color/gray_6" android:textSize="@dimen/sp_12" app:layout_constraintEnd_toEndOf="@+id/psw" app/src/main/res/layout/activity_select_car.xml
@@ -59,7 +59,7 @@ app:layout_constraintTop_toBottomOf="@+id/rlTitleBar" tools:ignore="MissingConstraints"> <androidx.appcompat.widget.AppCompatEditText <com.xw.yunwei.ui.widget.ClearEditText android:id="@+id/searchEt" android:layout_width="0dp" android:layout_height="@dimen/dp_34" @@ -69,6 +69,9 @@ android:drawablePadding="@dimen/dp_10" android:hint="请输入车牌号" android:maxLength="8" app:iconHeight="@dimen/dp_15" app:iconWidth="@dimen/dp_15" app:clearIcon="@mipmap/ic_close_black2" android:imeOptions="actionSearch" android:paddingHorizontal="@dimen/dp_10" android:singleLine="true" app/src/main/res/layout/activity_site_nav.xml
@@ -79,7 +79,7 @@ android:paddingHorizontal="@dimen/dp_10" app:layout_constraintTop_toTopOf="parent"> <androidx.appcompat.widget.AppCompatEditText <com.xw.yunwei.ui.widget.ClearEditText android:id="@+id/searchEt" android:layout_width="0dp" android:layout_height="@dimen/dp_34" @@ -89,6 +89,9 @@ android:drawableStart="@drawable/svg_search" android:drawablePadding="@dimen/dp_10" android:hint="请输入站点名称" app:iconHeight="@dimen/dp_15" app:iconWidth="@dimen/dp_15" app:clearIcon="@mipmap/ic_close_black2" android:imeOptions="actionSearch" android:paddingHorizontal="@dimen/dp_10" android:singleLine="true" app/src/main/res/layout/fragment_task.xml
@@ -73,11 +73,14 @@ app:layout_constraintTop_toBottomOf="@+id/rlTitleBar" tools:ignore="MissingConstraints"> <androidx.appcompat.widget.AppCompatEditText <com.xw.yunwei.ui.widget.ClearEditText android:id="@+id/searchEt" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" app:iconHeight="@dimen/dp_15" app:iconWidth="@dimen/dp_15" app:clearIcon="@mipmap/ic_close_black2" android:background="@drawable/shape_white_bg_4" android:drawableStart="@mipmap/ic_search_task" android:drawablePadding="@dimen/dp_6" app/src/main/res/values/attrs.xml
@@ -40,4 +40,20 @@ <attr name="spacingY" format="dimension" /> <attr name="isStaggered" format="boolean" /> </declare-styleable> <declare-styleable name="ClearEditText"> <!-- 清除按钮图标 --> <attr name="clearIcon" format="reference" /> <!-- 图标宽度 --> <attr name="iconWidth" format="dimension" /> <!-- 图标高度 --> <attr name="iconHeight" format="dimension" /> <!-- 图标距离右边的距离 --> <attr name="iconMarginRight" format="dimension" /> <!-- 图标距离顶部的偏移(用于垂直居中微调) --> <attr name="iconMarginTop" format="dimension" /> <!-- 是否显示清除按钮(默认true) --> <attr name="showClearIcon" format="boolean" /> <!-- 图标着色(可选) --> <attr name="iconTint" format="color|reference" /> </declare-styleable> </resources>