Android如何创建类似谷歌登录样式的带边框EditText?
可以在Java中实现这类自定义EditText控件
完全可以通过继承EditText(推荐用AppCompatEditText兼容更多版本),自定义出带边框且提示文本显示在边框内部的浮动标签控件,以下是具体实现方案:
1. 定义自定义属性
在res/values/attrs.xml中添加自定义属性,方便在布局中配置样式:
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="FloatingBorderEditText"> <attr name="borderColor" format="color"/> <attr name="borderWidth" format="dimension"/> <attr name="floatingLabelColor" format="color"/> <attr name="floatingLabelSize" format="dimension"/> </declare-styleable> </resources>
2. 实现自定义EditText类
继承AppCompatEditText,重写绘制逻辑,处理边框绘制和浮动标签的显示:
import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; import android.util.AttributeSet; import androidx.appcompat.widget.AppCompatEditText; public class FloatingBorderEditText extends AppCompatEditText { private Paint borderPaint; private Paint labelPaint; private float borderWidth; private int borderColor; private int labelColor; private float labelSize; private String floatingLabel; private Rect labelBounds; private boolean hasFocus; public FloatingBorderEditText(Context context) { super(context); init(null); } public FloatingBorderEditText(Context context, AttributeSet attrs) { super(context, attrs); init(attrs); } public FloatingBorderEditText(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(attrs); } private void init(AttributeSet attrs) { // 读取自定义属性 TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.FloatingBorderEditText); borderWidth = ta.getDimension(R.styleable.FloatingBorderEditText_borderWidth, dpToPx(1)); borderColor = ta.getColor(R.styleable.FloatingBorderEditText_borderColor, getCurrentTextColor()); labelColor = ta.getColor(R.styleable.FloatingBorderEditText_floatingLabelColor, getCurrentTextColor()); labelSize = ta.getDimension(R.styleable.FloatingBorderEditText_floatingLabelSize, getTextSize() * 0.8f); floatingLabel = getHint().toString(); ta.recycle(); // 初始化画笔 borderPaint = new Paint(); borderPaint.setColor(borderColor); borderPaint.setStrokeWidth(borderWidth); borderPaint.setStyle(Paint.Style.STROKE); borderPaint.setAntiAlias(true); labelPaint = new Paint(); labelPaint.setColor(labelColor); labelPaint.setTextSize(labelSize); labelPaint.setAntiAlias(true); labelBounds = new Rect(); labelPaint.getTextBounds(floatingLabel, 0, floatingLabel.length(), labelBounds); // 设置内边距,避免文本与边框、标签重叠 int padding = (int) (borderWidth + dpToPx(8)); setPadding(padding, (int) (padding + labelBounds.height()), padding, padding); // 监听焦点变化,更新标签状态 setOnFocusChangeListener((v, hasFocus) -> { this.hasFocus = hasFocus; invalidate(); }); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 绘制矩形边框 canvas.drawRect(borderWidth/2, borderWidth/2, getWidth() - borderWidth/2, getHeight() - borderWidth/2, borderPaint); // 绘制浮动标签位置计算 float labelX = getPaddingLeft(); float labelY = getPaddingTop() - labelBounds.height()/2; // 当输入有内容或控件获取焦点时,显示边框内的浮动标签 if (getText().length() > 0 || hasFocus) { canvas.drawText(floatingLabel, labelX, labelY, labelPaint); } // 无内容且无焦点时,保留默认hint的显示逻辑 } @Override public void setHint(CharSequence hint) { super.setHint(hint); floatingLabel = hint.toString(); labelPaint.getTextBounds(floatingLabel, 0, floatingLabel.length(), labelBounds); invalidate(); } // dp转px工具方法 private float dpToPx(float dp) { return dp * getContext().getResources().getDisplayMetrics().density; } }
3. 在布局中使用自定义控件
直接在XML布局中引用,配置自定义属性:
<com.yourpackage.FloatingBorderEditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="请输入用户名" app:borderColor="#6200EE" app:borderWidth="2dp" app:floatingLabelColor="#6200EE" app:floatingLabelSize="12sp"/>
扩展优化
如果需要更流畅的动画效果(比如标签的缩放、位移动画),可以引入ValueAnimator,在焦点变化或文本内容改变时,动态调整标签的大小和位置。
内容的提问来源于stack exchange,提问作者Cripple Sd
相关产品推荐
相关产品推荐

