效果展示
从图中可以看出这次自定义View的效果。具体功能如下:
设置头部文字的字体大小、字体颜色、文字内容
设置输入框的字体大小、字体颜色、文字内容、提示文字
开始自定义
一、 第一步先新建一个类名为EditTextPlus(可自己命名)继承FrameLayout的文件,因为我们要实现在布局文件中能是用自己的属性,所以我们还要在values目录下新建attrs.xml文件(用于添加自定义的属性)
二、在 attrs.xml 文件中添加如下属性(其中除了字体的基本属性之外,还包括了输入框的输入类型,键盘的类型等)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="EditTextPlus">
<attr name="head_title_text" format="string" />
<attr name="head_titile_text_size" format="dimension" />
<attr name="head_title_text_color" format="color" />
<attr name="edit_hint_text" format="string" />
<attr name="edit_text_size" format="dimension" />
<attr name="edit_text_color" format="color" />
<attr name="edit_input_type" format="enum">
<enum name="Text" value="0" />
<enum name="Phone" value="1" />
<enum name="Password" value="2" />
<enum name="Number" value="3" />
</attr>
<!-- 键盘类型 -->
<attr name="edit_editor_option" format="enum">
<enum name="IME_ACTION_NONE" value="0" />
<enum name="IME_ACTION_DONE" value="1" />
<enum name="IME_ACTION_GO" value="2" />
<enum name="IME_ACTION_NEXT" value="3" />
<enum name="IME_ACTION_PREVIOUS" value="4" />
<enum name="IME_ACTION_SEARCH" value="5" />
<enum name="IME_ACTION_SEND" value="6" />
<enum name="IME_ACTION_UNSPECIFIED" value="7" />
</attr>
</declare-styleable>
</resources>
那么添加了这些属性之后要如何使用呢?如下图所示:
其中最重要的是要使用下面那句话,才能使用自定义的属性。(xmlns:app中的app命名可以任意)
xmlns:app="http://schemas.android.com/apk/res-auto"
三、在布局文件中已经使用了自定义的属性,那么我们现在要做的就是如何解析相关属性。所以我们回到EditTextPlus类中。
上图为类中声明的成员变量。
在解析的时候我们通过 AttributeSet 来获得 TypeArray(注意: 必须要调用 recycle 方法进行回收)
不同类型的属性使用不同的方法来获得,而且必须设置默认值,在用户没有设置属性的时候,使用默认值
其中通过 typedArray.getDimension 方法得到的参数单位为像素(px)。在使用的时候要注意单位的转化,所以在设置默认值得时候,将 sp 转化为 px
edit_editor_option 和 edit_input_type 为枚举类型,在 attrs.xml 文件中声明了每个枚举对应的 value
具体解析自定义属性的代码如下:
private void initAttr(AttributeSet attrs) {
Drawable background = getBackground();
//当没有设置background时使用默认的background
if (null == background) {
setBackgroundResource(R.drawable.drawable_default_edittext_plus);
}
TypedArray typedArray = mContext.obtainStyledAttributes(attrs, R.styleable.EditTextPlus);
//
mEditTextSize = typedArray.getDimension(R.styleable.EditTextPlus_edit_text_size, sp2px(mEditTextSize));
mEditHintText = typedArray.getString(R.styleable.EditTextPlus_edit_hint_text);
if (TextUtils.isEmpty(mEditHintText)) {
mEditHintText = "";
}
mEditTextColor = typedArray.getColor(R.styleable.EditTextPlus_edit_text_color,
ContextCompat.getColor(mContext, R.color.EditTextPlusDefaultTextColor));
mInputType = typedArray.getInt(R.styleable.EditTextPlus_edit_input_type, mInputType);
mEditorOption = typedArray.getInt(R.styleable.EditTextPlus_edit_editor_option, mEditorOption);
//
mHeadTextSize = typedArray.getDimension(R.styleable.EditTextPlus_head_titile_text_size, sp2px(mHeadTextSize));
mHeadText = typedArray.getString(R.styleable.EditTextPlus_head_title_text);
if (TextUtils.isEmpty(mHeadText)) {
mHeadText = "未设置";
}
mHeadTextColor = typedArray.getColor(R.styleable.EditTextPlus_head_title_text_color, mEditTextColor);
//
typedArray.recycle();
}
获取属性方法的调用顺序如下
在一个参数构造方法中调用两个参数的构造方法,在两个参数的构造方法中调用三个参数的构造方法。这样子所有的构造方法都会经过三个参数的构造方法
在构造方法中填充布局,调用 initAttr 得到各个属性的值,再调用 initView 设置对应属性的值。
四、既然设置自定义属性的值,并且属性都设置到相应的位置。最后一个问题,就是如何将自定义View中的事件传输出去,如:删除按钮的点击事件。
- 在类中声明接口
public interface OnDeleteListener {
void onDelete();
}
- 在类中声明成员变量 onDeleteListener
-
声明变量的 set 方法
public void setOnDeleteListener(OnDeleteListener onDeleteListener) { this.onDeleteListener = onDeleteListener; }
-
在 initView 中设置点击事件,并判断是否声明的 onDeleteListener 是否为空,不为空则调用接口中的方法
ivDelete.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { etInput.setText(""); if (mHasDeleteAnimator) { //为了实现在点击删除时,控件左右抖动的效果 EditTextPlus.this.animate().translationX(5).setInterpolator(new CycleInterpolator(3)).setDuration(500).start(); } if (null != onDeleteListener) { onDeleteListener.onDelete(); } } });
使用该接口的时候就相当于设置系统控件的点击事件一样,调用 setOnDeleteListener 方法。
GitHub地址: EditextDemo