1、最简版EditText
在API 19版本下,拿一个最简单的EditText Demo 给大家看看效果:
从体验的角度,这里至少暴露出下面几个问题:
- EditText边框及样式
- EditText默认长宽不限定
EditText字数无及时提示
前面两个问题可以通过静态修改来实现,而第三个问题则需要实时监听EditText来实现,下面给出具体的修改步骤,来打造我们的万金油EditText。
2、改良版EditText
在对EditText进行样式大手术之前,让我们先来温习一下Android布局如何自定义控件background:
温习过后我们了解到,自定义background(即shape)中corners、gradient、padding、size、solid、stroke这几个属性比较重要。现在我们只考虑corners(圆角)、solid(填充色)、stroke(描边)、padding(内边距),其余的属性各位随用随查,不加赘述。
drawable下名为:background的文件
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<solid android:color="#FFFFFF" />
<corners android:radius="3dp"></corners>
<stroke android:color="#F2935B" android:width="1dp"></stroke>
<padding android:left="10dp"
android:right="10dp"
android:top="10dp"></padding>
</shape>
在布局文件中作出如下改动:
<?xml version="1.0" encoding="utf-8"?>
<!--增加EditText边距-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp"
tools:context="com.example.primexiao.mylimitededittext.MainActivity">
<!--修改长宽及输入内容位置gravity-->
<EditText
android:background="@drawable/background"
android:layout_width="match_parent"
android:layout_height="200dp"
android:gravity="start"
android:hint="请输入文字" />
</LinearLayout>
注意在外层Linearlayout布局设置padding和在内层EditText中设置layout_margin是拥有一个效果的,详情参考:
改良版效果如下:
相对于版本1来说,体验已经有了很大的进步,目前还缺少一个动态提示字数的功能,以及光标样式,我们接着改。
3、动态监听版
我们需要考虑下面几个事情:
- 何时改变状态(监听器)
- 在哪改变状态(代码)
- 在哪展示状态(布局)
查看Android系统文档,发现了一个这样的方法:
通过EditText类的addTextChangedListener方法监听该EditText,在继承TextWatcher:
我们可以在beforeTextChanged,onTextChanged,afterTextChanged的回调方法中进行重写,简答介绍一下这三个方法的区别和参数:
1、beforeTextChanged(CharSequence s, int start, int count, int after)
在EditText文本改变之前调用,并且传入四个参数。
CharSequence s参数表示当前文本内部的mText成员变量,实际上就是当前显示的文本;
int start参数表示需要改变的文字区域的起点,即选中的文本区域的起始点;
int count参数表示需要改变的文字的字符数目,即选中的文本区域的字符的数目;
int after参数表示替换的文字的字符数目。
特别的,当删除文本的时候,after的值为0,此时使用用空字符串代替需要改变的文字区域来达到删除文字的目的。
2、onTextChanged(CharSequence s, int start, int before, int count)
在EditText文本改变的时候调用,此时mText成员变量已经被修改为新的文本,并且也传入四个参数,其中多了一个before参数,少了一个after参数。
当直接输入文本(无替换)时,before的值为0。
3、afterTextChanged(Editable s)
方法是在调用完所有已注册的TextWatcher的onTextChanged方法之后回调的。此时mText成员变量已经被修改为新的文本,并且传入s,该参数s实际上就是mText。
实际上,动态监听字数这个功能只需用到afterTextChanged这个回调方法,具体我们来看代码实现:
@Override
public void afterTextChanged(Editable editable) {
//动态显示当前输入字数
int number = editable.length();
mTextView.setText(number + "/20");
//超过字数情况处理
selectionStart = mEditText.getSelectionStart();
selectionEnd = mEditText.getSelectionEnd();
if (number > num) {
//删除多余输入的字(不会显示出来)
editable.delete(selectionStart - 1, selectionEnd);
int tempSelection = selectionEnd;
mEditText.setText(editable);
Toast.makeText(this, "已超过" + num + "字", Toast.LENGTH_SHORT).show();
mEditText.setSelection(tempSelection);//设置光标在最后
}
}
下面部分是没超过限定字数之前(20)用来动态显示输入字数:
int number = editable.length();
mTextView.setText(number + "/20");
如果超过20,则删除多余输入的字
/*拿到多余输入的起止位置*/
selectionStart = mEditText.getSelectionStart();
selectionEnd = mEditText.getSelectionEnd();
if (number > num) {
/*删除多余输入的字(不会显示出来)*/
/*删除,(a,b]这样的参数取值方式*/
editable.delete(selectionStart - 1, selectionEnd);
mEditText.setText(editable);
Toast.makeText(this, "已超过" + num + "字", Toast.LENGTH_SHORT).show();
//动态设置光标
int tempSelection = selectionEnd;
mEditText.setSelection(tempSelection);
}
效果图如下:
4、锦上添花
改到这应该能满足大多数该死的需求了,但是在布局上还有一些小瑕疵,比如提示的那个框应该放在输入框里。
该怎么放呢?动态获取输入的字数,然后设置显示在最后一行?如果输入内容行数过多,需要分离输入框呢?
与其想这么多,不妨换种思考方式:
即用一个布局嵌套EditText和文本框,为布局设置相同效果的background从而达到效果,具体看布局代码实现:
<?xml version="1.0" encoding="utf-8"?>
<!--增加EditText边距-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp"
android:orientation="vertical"
tools:context="com.example.primexiao.mylimitededittext.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/background"
android:orientation="vertical">
<EditText
android:id="@+id/myEditText"
android:background="@null"
android:layout_width="match_parent"
android:layout_height="200dp"
android:gravity="start"
android:hint="请输入文字" />
<TextView
android:id="@+id/myTextView"
android:layout_margin="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="0"
android:gravity="right"
/>
</LinearLayout>
</LinearLayout>
最终演示图:
完。
本人水平有限,考虑不足的地方,欢迎大家留言交流!~