扒android 样式的工具,Android开源:手把手教你做一款含一键删除&自定义样式的SuperEditText...

本文介绍了如何创建一个名为SuperEditText的自定义Android控件,该控件具备一键删除输入内容的功能,并允许自定义丰富的样式,包括左侧图标、删除图标、分割线和光标样式。通过详细的功能逻辑和源码分析,展示了其实现过程,同时提供了开源项目链接,便于开发者进行二次开发。
摘要由CSDN通过智能技术生成

99d9dc5bcffc

前言

Android开发中,EditText的使用 非常常见

本文将手把手教你做一款 附带一键删除功能 & 自定义样式丰富的 SuperEditText控件,希望你们会喜欢。

99d9dc5bcffc

效果图

已在Github开源:Super_EditText,欢迎 Star !

目录

99d9dc5bcffc

示意图

1. 简介

一款 附带一键删除功能 & 自定义样式丰富的 SuperEditText控件

已在Github开源:Super_EditText,欢迎 Star !

99d9dc5bcffc

效果图

2. 功能介绍

2.1 需求场景

对于 EditText来说,一般的需求有:

方便用户因出现输入错误而进行2次输入

标识用户正在填写项

根据具体场景增加一定的UI元素

2.2 功能需求

根据需求场景,得出EditText需要具备的功能如下:

一键删除

丰富的自定义样式:左侧图标、删除功能图标、分割线 & 光标 样式变化。具体如下图:

99d9dc5bcffc

示意图

注:该样式的设置是系统自带的 API 所不具备的

功能列表

99d9dc5bcffc

示意图

2.3 功能示意

99d9dc5bcffc

效果图

3. 特点

对比市面上EditText控件,该控件Super_EditText 的特点是:

3.1 功能实用

一键删除功能 在需求中非常常见,现将其封装后更加方便使用

可自定义样式程度高(比自带的强大 & 方便),不复杂却能满足一般的EditText使用需求

可自定义样式如下:(注:该样式的设置是系统自带的 API 所不具备的)

99d9dc5bcffc

示意图

3.2 使用简单

3.3 二次开发成本低

本项目已在 Github上开源:Super_EditText

具备详细的源码分析文档(即本文)

所以,在其上做二次开发 & 定制化成本非常低。

4. 功能详细设计

下面将给出详细的功能逻辑

4.1 一键清空输入字段

描述:将当前用户输入的字段清空

需求场景:方便用户因出现输入错误而进行2次输入

原型图

99d9dc5bcffc

示意图

源码分析

/*

* 步骤1:定义属性

* */

private int ic_deleteResID; // 删除图标 资源ID

private Drawable ic_delete; // 删除图标

private int delete_x,delete_y,delete_width,delete_height; // 删除图标起点(x,y)、删除图标宽、高(px)

/*

* 步骤2:初始化属性

* */

private void init(Context context, AttributeSet attrs) {

// 获取控件资源

TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.SuperEditText);

/**

* 初始化删除图标

*/

// 1. 获取资源ID

ic_deleteResID = typedArray.getResourceId(R.styleable.SuperEditText_ic_delete,R.drawable.delete);

// 2. 根据资源ID获取图标资源(转化成Drawable对象)

ic_delete = getResources().getDrawable(ic_deleteResID);

// 3. 设置图标大小

// 起点(x,y)、宽= left_width、高 = left_height

delete_x = typedArray.getInteger(R.styleable.SuperEditText_delete_x, 0);

delete_y = typedArray.getInteger(R.styleable.SuperEditText_delete_y, 0);

delete_width = typedArray.getInteger(R.styleable.SuperEditText_delete_width, 60);

delete_height = typedArray.getInteger(R.styleable.SuperEditText_delete_height, 60);

ic_delete.setBounds(delete_x, delete_y, delete_width, delete_height);

/**

* 步骤3:通过监听复写EditText本身的方法来确定是否显示删除图标

* 监听方法:onTextChanged() & onFocusChanged()

* 调用时刻:当输入框内容变化时 & 焦点发生变化时

*/

@Override

protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {

super.onTextChanged(text, start, lengthBefore, lengthAfter);

setDeleteIconVisible(hasFocus() && text.length() > 0,hasFocus());

// hasFocus()返回是否获得EditTEXT的焦点,即是否选中

// setDeleteIconVisible() = 根据传入的是否选中 & 是否有输入来判断是否显示删除图标->>关注1

}

@Override

protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {

super.onFocusChanged(focused, direction, previouslyFocusedRect);

setDeleteIconVisible(focused && length() > 0,focused);

// focused = 是否获得焦点

// 同样根据setDeleteIconVisible()判断是否要显示删除图标->>关注1

}

/**

* 关注1

* 作用:判断是否显示删除图标

*/

private void setDeleteIconVisible(boolean deleteVisible,boolean leftVisible) {

setCompoundDrawables(leftVisible ? ic_left_click : ic_left_unclick, null,

deleteVisible ? ic_delete: null, null);

// setCompoundDrawables(Drawable left, Drawable top, Drawable right, Drawable bottom)介绍

// 作用:在EditText上、下、左、右设置图标(相当于android:drawableLeft="" android:drawableRight="")

// 备注:传入的Drawable对象必须已经setBounds(x,y,width,height),即必须设置过初始位置、宽和高等信息

// x:组件在容器X轴上的起点 y:组件在容器Y轴上的起点 width:组件的长度 height:组件的高度

// 若不想在某个地方显示,则设置为null

// 另外一个相似的方法:setCompoundDrawablesWithIntrinsicBounds(Drawable left, Drawable top, Drawable right, Drawable bottom)

// 作用:在EditText上、下、左、右设置图标

// 与setCompoundDrawables的区别:setCompoundDrawablesWithIntrinsicBounds()传入的Drawable的宽高=固有宽高(自动通过getIntrinsicWidth()& getIntrinsicHeight()获取)

// 不需要设置setBounds(x,y,width,height)

}

/**

* 步骤4:对删除图标区域设置点击事件,即"点击 = 清空搜索框内容"

* 原理:当手指抬起的位置在删除图标的区域,即视为点击了删除图标 = 清空搜索框内容

*/

@Override

public boolean onTouchEvent(MotionEvent event) {

// 原理:当手指抬起的位置在删除图标的区域,即视为点击了删除图标 = 清空搜索框内容

switch (event.getAction()) {

// 判断动作 = 手指抬起时

case MotionEvent.ACTION_UP:

Drawable drawable = ic_delete;

if (drawable != null && event.getX() <= (getWidth() - getPaddingRight())

&& event.getX() >= (getWidth() - getPaddingRight() - drawable.getBounds().width())) {

// 判断条件说明

// event.getX() :抬起时的位置坐标

// getWidth():控件的宽度

// getPaddingRight():删除图标图标右边缘至EditText控件右边缘的距离

// 即:getWidth() - getPaddingRight() = 删除图标的右边缘坐标 = X1

// getWidth() - getPaddingRight() - drawable.getBounds().width() = 删除图标左边缘的坐标 = X2

// 所以X1与X2之间的区域 = 删除图标的区域

// 当手指抬起的位置在删除图标的区域(X2=

setText("");

}

break;

}

return super.onTouchEvent(event);

}

99d9dc5bcffc

示意图

4.2 选中样式

描述:通过增加UI元素 & 交互样式表示用户正在填写的项目

需求场景:标识用户正在填写项

样式说明

99d9dc5bcffc

示意图

原型图

99d9dc5bcffc

示意图

属性说明

99d9dc5bcffc

示意图

99d9dc5bcffc

示意图

源码分析

/*

* 步骤1:定义属性

* */

private Paint mPaint; // 画笔

private int ic_left_clickResID,ic_left_unclickResID; // 左侧图标 资源ID(点击 & 无点击)

private Drawable ic_left_click,ic_left_unclick; // 左侧图标(点击 & 未点击)

private int left_x,left_y,left_width,left_height; // 左侧图标起点(x,y)、左侧图标宽、高(px)

private int cursor; // 光标

// 分割线变量

private int lineColor_click,lineColor_unclick;// 点击时 & 未点击颜色

private int color;

private int linePosition; // 分割线位置

/*

* 步骤2:初始化属性

* */

private void init(Context context, AttributeSet attrs) {

// 获取控件资源

TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.SuperEditText);

/**

* 初始化左侧图标(点击 & 未点击)

*/

// a. 点击状态的左侧图标

// 1. 获取资源ID

ic_left_clickResID = typedArray.getResourceId(R.styleable.SuperEditText_ic_left_click, R.drawable.ic_left_click);

// 2. 根据资源ID获取图标资源(转化成Drawable对象)

ic_left_click = getResources().getDrawable(ic_left_clickResID);

// 3. 设置图标大小

// 起点(x,y)、宽= left_width、高 = left_height

left_x = typedArray.getInteger(R.styleable.SuperEditText_left_x, 0);

left_y = typedArray.getInteger(R.styleable.SuperEditText_left_y, 0);

left_width = typedArray.getInteger(R.styleable.SuperEditText_left_width, 60);

left_height = typedArray.getInteger(R.styleable.SuperEditText_left_height, 60);

ic_left_click.setBounds(left_x, left_y,left_width, left_height);

// Drawable.setBounds(x,y,width,height) = 设置Drawable的初始位置、宽和高等信息

// x = 组件在容器X轴上的起点、y = 组件在容器Y轴上的起点、width=组件的长度、height = 组件的高度

// b. 未点击状态的左侧图标

// 1. 获取资源ID

ic_left_unclickResID = typedArray.getResourceId(R.styleable.SuperEditText_ic_left_unclick, R.drawable.ic_left_unclick);

// 2. 根据资源ID获取图标资源(转化成Drawable对象)

// 3. 设置图标大小(此处默认左侧图标点解 & 未点击状态的大小相同)

ic_left_unclick = getResources().getDrawable(ic_left_unclickResID);

ic_left_unclick.setBounds(left_x, left_y,left_width, left_height);

/**

* 设置EditText左侧图片(初始状态仅有左侧图片))

*/

setCompoundDrawables( ic_left_unclick, null,

null, null);

// setCompoundDrawables(Drawable left, Drawable top, Drawable right, Drawable bottom)介绍

// 作用:在EditText上、下、左、右设置图标(相当于android:drawableLeft="" android:drawableRight="")

// 备注:传入的Drawable对象必须已经setBounds(x,y,width,height),即必须设置过初始位置、宽和高等信息

// x:组件在容器X轴上的起点 y:组件在容器Y轴上的起点 width:组件的长度 height:组件的高度

// 若不想在某个地方显示,则设置为null

// 另外一个相似的方法:setCompoundDrawablesWithIntrinsicBounds(Drawable left, Drawable top, Drawable right, Drawable bottom)

// 作用:在EditText上、下、左、右设置图标

// 与setCompoundDrawables的区别:setCompoundDrawablesWithIntrinsicBounds()传入的Drawable的宽高=固有宽高(自动通过getIntrinsicWidth()& getIntrinsicHeight()获取)

// 不需要设置setBounds(x,y,width,height)

/**

* 初始化光标(颜色 & 粗细)

*/

// 原理:通过 反射机制 动态设置光标

// 1. 获取资源ID

cursor = typedArray.getResourceId(R.styleable.SuperEditText_cursor, R.drawable.cursor);

try {

// 2. 通过反射 获取光标属性

Field f = TextView.class.getDeclaredField("mCursorDrawableRes");

f.setAccessible(true);

// 3. 传入资源ID

f.set(this, cursor);

} catch (Exception e) {

e.printStackTrace();

}

/**

* 初始化分割线(颜色、粗细、位置)

*/

// 1. 设置画笔

mPaint = new Paint();

mPaint.setStrokeWidth(2.0f); // 分割线粗细

// 2. 设置分割线颜色(使用十六进制代码,如#333、#8e8e8e)

int lineColorClick_default = context.getResources().getColor(R.color.lineColor_click); // 默认 = 蓝色#1296db

int lineColorunClick_default = context.getResources().getColor(R.color.lineColor_unclick); // 默认 = 灰色#9b9b9b

lineColor_click = typedArray.getColor(R.styleable.SuperEditText_lineColor_click, lineColorClick_default);

lineColor_unclick = typedArray.getColor(R.styleable.SuperEditText_lineColor_unclick, lineColorunClick_default);

color = lineColor_unclick;

mPaint.setColor(lineColor_unclick); // 分割线默认颜色 = 灰色

setTextColor(color); // 字体默认颜色 = 灰色

// 3. 分割线位置

linePosition = typedArray.getInteger(R.styleable.SuperEditText_linePosition, 5);

// 消除自带下划线

setBackground(null);

/**

* 步骤3:通过监听复写EditText本身的方法来设置所有样式

* 监听方法:onTextChanged() & onFocusChanged()

* 调用时刻:当输入框内容变化时 & 焦点发生变化时

*/

@Override

protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {

super.onTextChanged(text, start, lengthBefore, lengthAfter);

setDeleteIconVisible(hasFocus() && text.length() > 0,hasFocus());

// hasFocus()返回是否获得EditTEXT的焦点,即是否选中

// setDeleteIconVisible() = 根据传入的是否选中 & 是否有输入来判断是否显示删除图标->>关注1

}

@Override

protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {

super.onFocusChanged(focused, direction, previouslyFocusedRect);

setDeleteIconVisible(focused && length() > 0,focused);

// focused = 是否获得焦点

// 同样根据setDeleteIconVisible()判断是否要显示删除图标->>关注1

}

/**

* 关注1

* 作用:设置分割线颜色

*/

private void setDeleteIconVisible(boolean deleteVisible,boolean leftVisible) {

color = leftVisible ? lineColor_click : lineColor_unclick;

setTextColor(color);

invalidate();

}

/**

* 步骤4:绘制分割线

*/

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

mPaint.setColor(color);

setTextColor(color);

// 绘制分割线

// 需要考虑:当输入长度超过输入框时,所画的线需要跟随着延伸

// 解决方案:线的长度 = 控件长度 + 延伸后的长度

int x=this.getScrollX(); // 获取延伸后的长度

int w=this.getMeasuredWidth(); // 获取控件长度

// 传入参数时,线的长度 = 控件长度 + 延伸后的长度

canvas.drawLine(0, this.getMeasuredHeight()- linePosition, w+x,

this.getMeasuredHeight() - linePosition, mPaint);

}

}

attrs.xml

cursor.xml

android:shape="rectangle" >

5. 完整源码地址

6. 具体使用

7. 贡献代码

希望你们能和我一起完善这款简单 & 好用的SuperEditText控件,具体请看:贡献代码说明

关于该开源项目的意见 & 建议可在Issue上提出。欢迎 Star !

8. 总结

相信你一定会喜欢上 这款简单 & 好用的SuperEditText控件

已在Github上开源:Super_EditText,欢迎 Star !

99d9dc5bcffc

效果图

下一篇文章我将继续进行一些 简单 & 实用的自定义View实例讲解,感兴趣的同学可以继续关注本人运营的Wechat Public Account:

请点赞!因为你的鼓励是我写作的最大动力!

不定期分享关于安卓开发的干货,追求短、平、快,但却不缺深度。

99d9dc5bcffc

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值