今天没有时间看源码了。就写一篇今天的工作记录吧,为了解决一个小功能,就对Android的EditText作了功能上的拓展。
首先说下遇到的需求,在EditText中对用户输入的内容进行一次“重新排版”,即没四个字符串分为一组,每一组用空格隔开:核心源码如下:
<span style="font-size:18px;">/**
* 文本改变监听
* @author sunny
*
*/
private class DidaTextWatcher implements TextWatcher{
//定义一个变量用于记录字符串的变化,
int tempCount;
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
}
@Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
//统计个数
int len = s.length();
//设置输入最大长度,后期按需增加此功能
if(len >= textMaxLength){
// return;
}
//如果包含空格,就清除
char[] chars = s.toString().trim().replace(" ", "").toCharArray();
len = chars.length;
//每4个分组,加上空格合成新的字符串
StringBuffer sb = new StringBuffer();
//注意,一定要加上这一个判断,否则会陷入死循环,因为我们在这里改变了字符串s,这个事件会一直被监听到
//所以,只有当我们输入的字符串不在改变的时候就不在监听到了
if(len != tempCount){
for(int i=0;i<len;i++){
//如果是密码状态就替换字符串
if(isPassword){
if(chars[i]+"" != " "){
chars[i] = '*';
}
}
//如果分割的话,每次遍历到4的倍数就添加一个空格
if(i % maxLength == 0 && i !=0){
sb.append(delimiter);
sb.append(chars[i]);
}else{
sb.append(chars[i]);
}
//改变需求,将所有字符替换成*号,表示输入的是密码
}
text = sb.toString();
//获取改变之后字符串的长度
tempCount = text.trim().replace(" ","").length();
//设置新的字符串到文本
editText.setText(sb.toString());
}
//设置光标的位置
if(text !=null){
editText.setSelection(text.length());
}
}</span>
正如上面代码所示最关键的代码在于对EditText中用户输入的内容变化作出相应的处理,此处为了良好的通用性,我也开放了一些其他属性供用户自主选择,如下方法:
<span style="font-size:18px;"> /**
* 设置是否密码
* @param isPassword
*/
public void setIsPassword(boolean isPassword){
this.isPassword = isPassword;
}
/**
* 设置允许输入的最大长度
* @param textMaxLength
*/
public void setTextMaxLength(Integer textMaxLength){
this.textMaxLength = textMaxLength;
}
/**
* 设置分割符号,是空格还是"-"还是其他符号,默认的是空格
* @param delimiter
*/
public void setDelimiter(String delimiter) {
this.delimiter = delimiter;
}
/**
* 设置分割时每组的字符数,默认的是4个
* @param maxLength
*/
public void setMaxLength(Integer maxLength){
this.maxLength = maxLength;
}
/**
* 一次性设置分割
* @param isDivision 是否分割
* @param maxLength 分割的每组数目
* @param delimiter 分割符号
*/
public void setDivision(Integer maxLength,String delimiter){
this.maxLength = maxLength;
this.delimiter = delimiter;
}</span>
上面的代码正如大家所见,我提供了几个开放的属性让用户拥有更多的自主权,比如用户是否要将其输入的文本隐藏,即密码框,但是和EditText的密码框不一样哈!而且提供了分割的字符串数目。如果不需要分割,调用方法时传入一个“”参数就可以了。虽然如此,还不够完善,因为此类控件是直接继承EditText完成的,没有实现定制一个个性化的编辑框。还有点时间可以顺便写一个复合控件。接下来就将此类改变下让其继承LinearLayout类来定制个性化的EditText,还是另外开一个类来写吧。
首先要明确一个概念,即复合控件和自定义视图是不一样的,前者是我们不需要去重写那些onMeasure()、onLayout()、onDraw()方法的。我们只需要继承一个写一个xml布局文件将已有的控件组合起来,然后编写一个类继承LinearLayou或其他容器类,进行填充即可,然后在该类里面也可以处理相应的想要拓展的功能。而后者是需要我们重写一系列方法,完全重绘一个视图的。下面我们基于复合视图来写一个个性化的EditText,首先是其xml布局文件:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TextView
android:id="@+id/text_edit"
android:layout_width="50dip"
android:layout_height="wrap_content"
android:background="@drawable/text_edit"/>
<EditText
android:id="@+id/dida_edit_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/text_edit"
android:background="@drawable/dida_edit_text"
android:imeOptions="actionDone"
android:hint="呵呵.."
/>
</RelativeLayout>
布局很简单,TextView就用来提供文字和图片,EditText是我们的编辑框,然后相应的类代码:
public DidaEditTextfromLinearLayout(Context context,AttributeSet attrs){
super(context,attrs);
View v = LayoutInflater.from(getContext()).inflate(R.layout.dida_edittext, this,true);
init();
}
在其构造方法中进行填充,为了省篇幅就不把所有的代码贴出来了,里面冗杂代码略多,讲主要的。
其次提供一个init()方法如下:
public void init(){
watcher = new DidaTextWatcher();
editText = (EditText) findViewById(R.id.dida_edit_text);
textView = (TextView) findViewById(R.id.text_edit);
//设置为密码输入,不过达不到我想要的结果,还是自己写一个了
// DidaEditText.this.setInputType(0x81);
//文本改变监听
editText.addTextChangedListener(watcher);
//焦点监听
editText.setOnFocusChangeListener(new DivisionFocusChangeListener());
}
此外,我还提供了一个更换TextView背景图片的方法:
/**
* 设置TextView背景图片,如果不设置就是我提供的原图片
* @param tempdrable 图片资源,参数形式为:R.drable.image_name
*/
public void setTextViewImage(int tempdrable){
Resources resource = getResources();
Drawable drable = resource.getDrawable(tempdrable);
textView.setBackgroundDrawable(drable);
}
其实该方法就是将系统的方法封装了一下,如果还需要对EditText的背景图片进行设置也可以提供一个封装的方法。最后就是使用该控件了,使用者的布局文件如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dip" >
<TextView
android:id="@+id/linear_textv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16.6dip"
android:height="30dip"
android:text="用户名:"/>
<com.dida.widget.DidaEditTextfromLinearLayout
android:id="@+id/et_linear"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/linear_textv"
/>
</RelativeLayout>
</LinearLayout>
没啥好说的,要把布局彻底搞熟练才行,这里需要注意的就是引用复合控件类时,要写类全名,不然在反射创建该对象会出错。
哦、忘记上效果图了啊。。用手机模拟的,怎么上效果图啊!鄙人愚昧,直接将我用PS做的效果图哪来填充好了:
至此,今天的日志完毕。