安卓开发之自定义控件实现MaterialEditText
来源:互联网 发布:当量直径算法 编辑:程序博客网 时间:2024/05/01 16:05
按照常规先展示效果图并说明:
主要有以下几个效果:
- edittext中的内容为0时,标签不出现
- edittext中的内容不为0时,标签开始出现
- edittext获取焦点时,下划线的颜色/粗细会发生改变
- edittext失去焦点时,下划线同样发生改变,标签颜色也更改
- 当限制输入字符个数时,右下角计数文字会进行计数
- 超过个数后,下划线和计数文字颜色会发生变化
一、继承EditText
为保留EditText的一些独特属性,我们选择继承EditText来实现自定义MaterialEditText.
但在原生的EditText动手脚绘制一些文字/线,我们需要进行一些预处理:
原生EditText本身含有下划线,我们需要将原生下划线去掉,这里可以通过设置EditView背景为null来实现
// 设置edittext的背景为空,主要为了隐藏自带的下划线if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { setBackground(null);} else { setBackgroundDrawable(null);}
要绘制文字/下划线,我们需要获得坐标。而EditText的内部是可以滑动的,随着文字的增加,高度也会自动的增长。这里我们获取坐标时,使用getScrollX() 和 getScrollY() 这两个函数获取输入状态下,我们需要的不断变化的横坐标和纵坐标:
// 获取下划线的起点纵坐标ylineStartY = getScrollY()+getHeight()-getPaddingBottom()+dpToPix(5); // 获取下划线的起点横坐标x / 标签文字的横坐标xgetScrollX()...其他类似
在系统开始绘制MaterialEditText之前,我们需要重新设置原生EditText的padding值,为什么需要重新设置padding值呢?因为我们在原生EditText上绘制文字和下划线等,占用了输入框的高度。重新设置padding值后,我们可以在padding的地方绘制我们的文字和下划线。一般我们设置顶部和底部的padding值就好了
// 额外的顶部内边距private int extraTopPadding;// 额外的底部内边距private int extraBottomPadding;// 获取额外的顶部内边距:用于绘制文字和文字的marginextraTopPadding = (int) getTextHeight(textPaint) + dpToPix(4);// 获取额外的底部内边距:用于绘制底部的计数的文字和文字的marginextraBottomPadding = (int) getTextHeight(textPaint) + dpToPix(6);// 重新设置内边距// 因为我们需要绘制标签和下划线,因此需要重新设置padding值private void correctPaddings() { super.setPadding(getPaddingLeft(),getPaddingTop()+extraTopPadding,getPaddingRight(),getPaddingBottom()+extraBottomPadding+dpToPix(5)); // 最后底部加上5dp主要是为了包含绘制下划线的空间}
二、自定义属性
解决了上面的问题后,我们需要为MaterialEditText自定义一些常用的属性:
<declare-styleable name="MaterialEditText"> <attr name="preLineColor" format="color"/> <attr name="labelText" format="string"/> <attr name="labelColor" format="color"/> <attr name="maxLength" format="integer"/> <attr name="overlengthColor" format="color"/></declare-styleable>
preLineColor : 获取焦点后的下划线颜色
labelText :标签的文字
labelColor :标签文字的颜色
maxLength :最大的字数限制。-1是为不限制字数
overlengthColor :超过限制后的下划线和右下角计数文字的颜色
三、设置标签的动画
从上面的Gif动画可知,label有一个浮现和浮走的动画,这里主要使用了属性动画获取标签文字的透明度和移动的高度比例:
// 初始化标签动画 labelAnim = ValueAnimator.ofFloat(0, 255); labelAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { // 获取标签的透明度 textAlpha = (float) animation.getAnimatedValue(); // 获取文字的高度比例: // 当透明度为0时,高度比例为1.5,透明度为255时,高度为1 // 达到一种从底部浮现的效果 yFraction = (float) (-(5.0f / 2550.0f) * textAlpha + 1.5); // 重绘 invalidate(); } });
我们发现,浮出动画和浮走动画正是一对相互逆序播放的动画,所以我们只设置一个动画即可,之后再进行逆序播放达到浮走的效果
四、对EditText设置监听
因输入字符的个数不同/是否得到焦点的不同,设置了 下划线 / 标签文字 / 右下角计数文字 设置不同的颜色和对标签文字播放动画:
private void initListener() { /// 设置edittetx内容改变监听器 addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override public void afterTextChanged(Editable s) { // 当内容改变后,是否展示计数内、判断是否已经超过规定字符长度 if(maxCount!=-1) { // maxCount = -1时,不限制字数且不显示计数文字 // 添加计数字符串 countString.delete(0, countString.length()); presentCount = s.length(); countString.append(presentCount); countString.append(" / "); countString.append(maxCount); // 超过规定长度时,绘制的颜色发生变化 if (presentCount > maxCount) { paint.setColor(overLengthColor); countPaint.setColor(overLengthColor); } else { paint.setColor(preLineColor); countPaint.setColor(Color.LTGRAY); } } // 当内容长度为0并获得焦点时: if(s.length()==0&&isShow&&isFocused()){ // 将标签动画逆序播放,将标签隐藏 labelAnim.reverse(); isShow = false; }else if(s.length()!=0&&!isShow&&isFocused()){ // 当内容长度不为0时,播放标签浮出一次 labelAnim.start(); isShow = true; // 防止播放多次动画 } } }); // 添加焦点的获取通知 setOnFocusChangeListener(new OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { // 获取焦点时 if(hasFocus) { // 改变下划线的粗细 paint.setStrokeWidth(dpToPix(1.3f)); // 改变标签的颜色 textPaint.setColor(labelColor); if(presentCount>maxCount&&maxCount!=-1){ // 超出字符长度时,设置画笔颜色 paint.setColor(overLengthColor); countPaint.setColor(overLengthColor); }else { // 不超出字符长度/不设置规定长度时,设置画笔颜色 paint.setColor(preLineColor); countPaint.setColor(Color.LTGRAY); } }else { // 没有获取焦点时,改变下划线的颜色和粗细和标签颜色 textPaint.setColor(Color.LTGRAY); paint.setColor(Color.LTGRAY); paint.setStrokeWidth(dpToPix(0.35f)); } } });}
五、最后的onDraw()
对标签的绘制 + 对下划线的绘制 + (对右下角计数文字的绘制) + 原生EditTetx的绘制:
@Override protected void onDraw(Canvas canvas) { // 获取下划线的起点高度 lineStartY = getScrollY()+getHeight()-getPaddingBottom()+dpToPix(5); // 设置标签的透明度 textPaint.setAlpha((int) textAlpha); // 根据标签的高度比例绘制标签文字 canvas.drawText(labelText, getScrollX(),(getScrollY()-dpToPix(4)+extraTopPadding)*yFraction, textPaint); // 绘制下划线 canvas.drawRect(getScrollX(), lineStartY, getScrollX()+getWidth()-getPaddingRight(), lineStartY + dpToPix(0.8f), paint); // 根据是否有字符长度规定绘制右下角的计数 if(maxCount!=-1) { canvas.drawText(countString.toString(), getScrollX()+getWidth()-getPaddingRight() - getTextWidth(countString.toString(), countPaint), lineStartY + extraBottomPadding, countPaint); } // 开始edittext原生的绘制 super.onDraw(canvas); }
六、xml使用示例:
这里的MaterialEditText使用如上述效果图Gif:
<?xml version="1.0" encoding="utf-8"?><ScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_height="match_parent" android:layout_width="match_parent"> <LinearLayout android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="15dp" android:background="#ffffff" tools:context="com.cxmscb.cxm.newtest.MainActivity"> <com.cxmscb.cxm.newtest.MaterialEditText android:layout_width="match_parent" android:layout_height="wrap_content" app:maxLength = "12" app:labelText="用户名" app:labelColor="#18b4ed" app:preLineColor="#18b4ed" app:overlengthColor="@android:color/holo_red_light" android:hint="用户名" android:singleLine="true" android:layout_marginTop="10dp" android:paddingLeft="0dp" android:textSize="18sp"/> <com.cxmscb.cxm.newtest.MaterialEditText android:layout_width="match_parent" android:layout_height="wrap_content" app:maxLength = "12" app:labelText="密码" app:labelColor="#18b4ed" app:preLineColor="#18b4ed" app:overlengthColor="@android:color/holo_red_light" android:hint="密码" android:singleLine="true" android:password="true" android:layout_marginTop="10dp" android:paddingLeft="0dp" android:textSize="18sp"/> <com.cxmscb.cxm.newtest.MaterialEditText android:layout_width="match_parent" android:layout_height="wrap_content" app:maxLength = "-1" app:labelText="无限制输入" app:labelColor="#e2d66f" app:preLineColor="#e2d66f" android:hint="无限制输入" android:layout_marginTop="10dp" android:paddingLeft="0dp" android:textSize="18sp"/> <com.cxmscb.cxm.newtest.MaterialEditText android:layout_width="match_parent" android:layout_height="wrap_content" android:drawableLeft="@drawable/avatar" android:drawablePadding="4dp" app:maxLength = "12" app:labelText="用户名" app:labelColor="#18b4ed" app:preLineColor="#18b4ed" app:overlengthColor="@android:color/holo_red_light" android:hint="用户名" android:singleLine="true" android:layout_marginTop="10dp" android:paddingLeft="0dp" android:textSize="18sp"/> </LinearLayout></ScrollView>
七、完整源码和项目: Github
因本人太懒,没有做成库,需要的可以直接提取/学习。
http://blog.csdn.net/cxmscb/article/details/52808790
- 安卓开发之自定义控件实现MaterialEditText
- 安卓开发之自定义控件实现MaterialEditText
- 安卓开发之自定义控件实现画板
- 安卓开发之自定义粒子旋转动画加载控件
- 安卓开发之使用PathMeasure自定义加载动画控件
- 安卓自定义组合控件的实现
- 安卓自定义控件之饼图
- 安卓自定义控件之仪表盘
- 安卓自定义控件之折线图
- 安卓开发学习之017 自定义控件之属性获取
- 【安卓自定义控件系列】安卓自定义控件之组合控件
- 安卓开发笔记——自定义HorizontalScrollView控件(实现QQ5.0侧滑效果)
- 自定义安卓控件
- 安卓----自定义控件
- 安卓自定义控件
- 安卓自定义控件
- 安卓自定义控件
- 安卓自定义控件
- 谁家孩子跑的最慢-C语言
- 查询数据库中是否存在某张表
- 织梦教程:定时生成站点地图sitemap.xml
- Submitting Applications
- 第10篇 WebRTC-IOS之信令与RTCPeerConnection建立及SDP描述符 周三
- 安卓开发之自定义控件实现MaterialEditText
- 垂直行业网站destoon系统如何开启伪静态urlrewrite
- Ubuntu系统下安装AndroidStudio2.0 以及升级jdk的终端指令
- 可以滑动取消的消息指数
- 深入理解groupByKey、reduceByKey
- 事务的四个特性
- MySQL 正则表达式
- 【记事】
- 管程的思考