今天没有时间看源码了。就写一篇今天的工作记录吧,为了解决一个小功能,就对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>
<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(); }在其构造方法中进行填充,为了省篇幅就不把所有的代码贴出来了,里面冗杂代码略多,讲主要的。
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背景图片,如果不设置就是我提供的原图片 * @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做的效果图哪来填充好了:
至此,今天的日志完毕。