如何继承EditText实现同外观的带标题自定义输入组件?
我来给你梳理两种可行的方案,帮你解决这个问题:
方案一:继承EditText,通过绘制实现标题和底部横线
因为EditText本身是TextView的子类,无法直接添加子View,但我们可以通过重写onDraw()方法,在EditText的上方绘制标题文本、下方绘制底部横线,这样既继承了EditText的所有原生属性,又能保留你需要的外观样式。
步骤与代码示例
- 定义少量自定义属性(可选,用于XML配置标题)
在res/values/attr.xml中添加:
<declare-styleable name="TitleEditText"> <attr name="titleText" format="string"/> <attr name="titleTextColor" format="color"/> <attr name="titleTextSize" format="dimension"/> <attr name="bottomLineColor" format="color"/> </declare-styleable>
- 创建自定义EditText子类
public class TitleEditText extends androidx.appcompat.widget.AppCompatEditText { private String mTitleText = ""; private int mTitleTextColor = Color.parseColor("#666666"); private float mTitleTextSize; private int mBottomLineColor = Color.parseColor("#eeeeee"); private Paint mTitlePaint; private Paint mLinePaint; // 标题与EditText的间距 private final int mTitleTopPadding = dpToPx(16); private final int mTitleBottomPadding = dpToPx(8); public TitleEditText(Context context) { super(context); init(null, 0); } public TitleEditText(Context context, AttributeSet attrs) { super(context, attrs); init(attrs, 0); } public TitleEditText(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(attrs, defStyleAttr); } private void init(AttributeSet attrs, int defStyleAttr) { // 初始化默认标题字号 mTitleTextSize = spToPx(12); // 解析自定义属性 if (attrs != null) { TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.TitleEditText, defStyleAttr, 0); mTitleText = ta.getString(R.styleable.TitleEditText_titleText); mTitleTextColor = ta.getColor(R.styleable.TitleEditText_titleTextColor, mTitleTextColor); mTitleTextSize = ta.getDimension(R.styleable.TitleEditText_titleTextSize, mTitleTextSize); mBottomLineColor = ta.getColor(R.styleable.TitleEditText_bottomLineColor, mBottomLineColor); ta.recycle(); } // 初始化画笔 mTitlePaint = new Paint(Paint.ANTI_ALIAS_FLAG); mTitlePaint.setColor(mTitleTextColor); mTitlePaint.setTextSize(mTitleTextSize); mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG); mLinePaint.setColor(mBottomLineColor); mLinePaint.setStrokeWidth(dpToPx(1)); // 调整EditText内边距,给标题和横线留出空间 int topPadding = getPaddingTop() + (int)mTitleTextSize + mTitleTopPadding + mTitleBottomPadding; int bottomPadding = getPaddingBottom() + dpToPx(1); setPadding(getPaddingLeft(), topPadding, getPaddingRight(), bottomPadding); } @Override protected void onDraw(Canvas canvas) { // 绘制标题文本 if (!TextUtils.isEmpty(mTitleText)) { float titleX = getPaddingLeft(); float titleY = mTitleTopPadding + mTitlePaint.getFontSpacing(); canvas.drawText(mTitleText, titleX, titleY, mTitlePaint); } // 绘制底部横线 float lineStartX = getPaddingLeft(); float lineEndX = getWidth() - getPaddingRight(); float lineY = getHeight() - getPaddingBottom(); canvas.drawLine(lineStartX, lineY, lineEndX, lineY, mLinePaint); // 绘制EditText原生内容 super.onDraw(canvas); } // 辅助转换方法 private float dpToPx(float dp) { return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics()); } private float spToPx(float sp) { return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, getResources().getDisplayMetrics()); } // 代码中设置标题的方法 public void setTitleText(String title) { mTitleText = title; invalidate(); } }
- XML中使用
<com.yourpackage.TitleEditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="예) 힌트 텍스트" android:inputType="text" android:singleLine="true" android:textSize="18sp" android:textColor="@color/textLightDark" app:titleText="필드 이름" app:titleTextColor="@color/textLightDark" app:bottomLineColor="@color/colorLight"/>
这样你就能直接使用EditText的所有原生属性,同时拥有标题和底部横线的样式。
方案二:保持ConstraintLayout结构,透传EditText属性
如果你想保留原来的ConstraintLayout布局结构,又不想在attr.xml中定义大量EditText属性,可以通过属性透传的方式,让XML中设置的EditText属性自动传递给内部的contentEditText。
修改后的自定义View代码
public class DefaultEditTextContainerView extends ConstraintLayout { @BindView(R.id.titleText) public TextView titleText; @BindView(R.id.contentEditText) public EditText contentEditText; private String mTitleText; public DefaultEditTextContainerView(Context context) { super(context); init(null, 0); } public DefaultEditTextContainerView(Context context, AttributeSet attrs) { super(context, attrs); init(attrs, 0); } public DefaultEditTextContainerView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(attrs, defStyleAttr); } private void init(AttributeSet attrs, int defStyle) { View view = inflate(getContext(), R.layout.view_default_edit_text_container_view, this); ButterKnife.bind(this, view); // 解析自定义标题属性 if (attrs != null) { TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.DefaultEditTextContainerView, defStyle, 0); mTitleText = ta.getString(R.styleable.DefaultEditTextContainerView_titleText); ta.recycle(); // 透传EditText核心属性 TypedArray editTextTa = getContext().obtainStyledAttributes(attrs, new int[]{ android.R.attr.hint, android.R.attr.inputType, android.R.attr.textColor, android.R.attr.textColorHint, android.R.attr.textSize, android.R.attr.singleLine }); contentEditText.setHint(editTextTa.getString(0)); contentEditText.setInputType(editTextTa.getInt(1, InputType.TYPE_CLASS_TEXT)); contentEditText.setTextColor(editTextTa.getColor(2, Color.parseColor("#666666"))); contentEditText.setHintTextColor(editTextTa.getColor(3, Color.parseColor("#eeeeee"))); contentEditText.setTextSize(TypedValue.COMPLEX_UNIT_PX, editTextTa.getDimension(4, spToPx(18))); contentEditText.setSingleLine(editTextTa.getBoolean(5, true)); editTextTa.recycle(); } titleText.setText(mTitleText); } private float spToPx(float sp) { return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, getResources().getDisplayMetrics()); } // 代理EditText的常用方法,方便代码调用 public String getInputText() { return contentEditText.getText().toString(); } public void setInputText(String text) { contentEditText.setText(text); } }
这种方式不需要额外自定义大量属性,XML中直接使用Android原生的EditText属性即可,会自动传递给内部的输入框。
内容的提问来源于stack exchange,提问作者softmarshmallow
相关产品推荐
相关产品推荐

