例如,输入一组25位的序列号,希望分成5组,每组5个数字。效果如下图。
Android中没有发现类似的空间,只好自己动手了。
1.首先自定义控件继承EditText,实现相应方法。
2.在res/values下增加attrs.xml。
3.在布局文件中使用。
其中xmlns:fsms="http://schemas.android.com/apk/res/com.example.sequencenumber","com.example.sequencenumber"部分为R.java的包。其他部分是不变的。
Android中没有发现类似的空间,只好自己动手了。
1.首先自定义控件继承EditText,实现相应方法。
- package com.example.sequencenumber;
- import android.content.Context;
- import android.content.res.TypedArray;
- import android.text.Editable;
- import android.text.TextWatcher;
- import android.util.AttributeSet;
- import android.view.View;
- import android.widget.EditText;
- /**
- * 分割输入框
- *
- * @author Administrator
- *
- */
- public class DivisionEditText extends EditText {
- /* 内容数组 */
- private String[] text;
- /* 数组实际长度 (内容+分隔符) */
- private Integer length;
- /* 允许输入的长度 */
- private Integer totalLength;
- /* 每组的长度 */
- private Integer eachLength;
- /* 分隔符 */
- private String delimiter;
- /* 占位符 */
- private String placeHolder;
- public DivisionEditText(Context context) {
- super(context);
- }
- public DivisionEditText(Context context, AttributeSet attrs) {
- super(context, attrs);
- try {
- // 初始化属性
- TypedArray typedArray = context.obtainStyledAttributes(attrs,
- R.styleable.EditText);
- this.totalLength = typedArray.getInteger(
- R.styleable.EditText_totalLength, 0);
- this.eachLength = typedArray.getInteger(
- R.styleable.EditText_eachLength, 0);
- this.delimiter = typedArray
- .getString(R.styleable.EditText_delimiter);
- if (this.delimiter == null || this.delimiter.length() == 0) {
- this.delimiter = "-";
- }
- this.placeHolder = typedArray
- .getString(R.styleable.EditText_placeHolder);
- if (this.placeHolder == null || this.placeHolder.length() == 0) {
- this.placeHolder = " ";
- }
- typedArray.recycle();
- // 初始化
- init();
- // 内容变化监听
- this.addTextChangedListener(new DivisionTextWatcher());
- // 获取焦点监听
- this.setOnFocusChangeListener(new DivisionFocusChangeListener());
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- public DivisionEditText(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
- /**
- * 初始化
- */
- public void init() {
- // 总共分几组
- int groupNum = 0;
- // 如果每组长度(除数)不为0,计算
- if (this.eachLength != 0) {
- groupNum = this.totalLength / this.eachLength;
- }
- // 实际长度
- length = this.totalLength + this.eachLength != 0 ? this.totalLength
- + groupNum - 1 : 0;
- // 初始化数组
- text = new String[this.length];
- // 如果数组大小大于0,初始化里面内容
- // 空格占位,分隔符占位
- if (length > 0) {
- for (int i = 0; i < length; i++) {
- if (i != 0 && (i + 1) % (this.eachLength + 1) == 0) {
- text[i] = this.delimiter;
- } else {
- text[i] = placeHolder;
- }
- }
- // 设置文本
- mySetText();
- // 设置焦点
- mySetSelection();
- }
- }
- /**
- * 获取结果
- *
- * @return
- */
- public String getResult() {
- StringBuffer buffer = new StringBuffer();
- for (String item : text) {
- if (!placeHolder.equals(item) && !delimiter.equals(item)) {
- buffer.append(item);
- }
- }
- return buffer.toString();
- }
- /**
- * 文本监听
- *
- * @author Administrator
- *
- */
- private class DivisionTextWatcher implements TextWatcher {
- @Override
- public void afterTextChanged(Editable s) {
- }
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count,
- int after) {
- }
- @Override
- public void onTextChanged(CharSequence s, int start, int before,
- int count) {
- // 如果当前长度小于数组长度,认为使用退格
- if (s.length() < length) {
- // 光标所在位置
- int index = DivisionEditText.this.getSelectionStart();
- // 删除的字符
- String deleteStr = text[index];
- // 如果是分隔符,删除分隔符前一个
- if (delimiter.equals(deleteStr)) {
- index--;
- }
- // 置空
- text[index] = placeHolder;
- // 查看前一个是否为分隔符
- if (index - 1 >= 0) {
- if (delimiter.equals(text[index - 1])) {
- index--;
- }
- }
- // 设置文本
- mySetText();
- // 设置焦点
- mySetSelection(index);
- }
- // 只能一个一个字符输入
- if (count == 1) {
- // 从光标起始,是否还有空的位置
- int index = isBlank(DivisionEditText.this.getSelectionStart());
- // 如果还有
- if (index != -1) {
- // 输入框内的字符串
- String allStr = s.toString();
- // 输入的字符串
- String inputStr = allStr.substring(start, start + count);
- // 替换占位符
- text[index] = inputStr;
- }
- // 设置文本
- mySetText();
- // 设置焦点
- mySetSelection();
- }
- }
- }
- /**
- * 获取焦点监听
- *
- * @author Administrator
- *
- */
- private class DivisionFocusChangeListener implements OnFocusChangeListener {
- @Override
- public void onFocusChange(View v, boolean hasFocus) {
- if (hasFocus) {
- // 设置焦点
- mySetSelection(0);
- }
- }
- }
- /**
- * 设置文本
- *
- * @param text
- */
- private void mySetText() {
- StringBuffer buffer = new StringBuffer();
- for (String item : text) {
- buffer.append(item);
- }
- // 设置文本
- setText(buffer);
- }
- /**
- * 设置焦点
- *
- * @param text
- */
- private void mySetSelection() {
- mySetSelection(fullSelection());
- }
- /**
- * 设置焦点
- *
- * @param text
- */
- private void mySetSelection(int index) {
- DivisionEditText.this.setSelection(index);
- }
- /**
- * 从光标位置起始,检查后面是否还有空的占位符
- *
- * @param text
- * @param selection
- * @return
- */
- private int isBlank(int selection) {
- int index = -1;
- for (int i = selection - 1; i < length; i++) {
- if (placeHolder.equals(text[i])) {
- index = i;
- break;
- }
- }
- return index;
- }
- /**
- * 最后一个不空的字符后的光标位置
- *
- * @param text
- * @return
- */
- private int fullSelection() {
- int index = 0;
- for (int i = 0; i < length; i++) {
- if (!placeHolder.equals(text[i]) && !delimiter.equals(text[i])) {
- index = i + 1;
- }
- }
- return index;
- }
- public Integer getTotalLength() {
- return totalLength;
- }
- public void setTotalLength(Integer totalLength) {
- this.totalLength = totalLength;
- }
- public Integer getEachLength() {
- return eachLength;
- }
- public void setEachLength(Integer eachLength) {
- this.eachLength = eachLength;
- }
- public String getDelimiter() {
- return delimiter;
- }
- public void setDelimiter(String delimiter) {
- this.delimiter = delimiter;
- }
- public String getPlaceHolder() {
- return placeHolder;
- }
- public void setPlaceHolder(String placeHolder) {
- this.placeHolder = placeHolder;
- }
- }
2.在res/values下增加attrs.xml。
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <declare-styleable name="EditText">
- <!-- 总共输入长度 -->
- <attr name="totalLength" format="integer" />
- <!-- 每组的长度 -->
- <attr name="eachLength" format="integer" />
- <!-- 分隔符 -->
- <attr name="delimiter" format="string" />
- <!-- 占位符 -->
- <attr name="placeHolder" format="string" />
- </declare-styleable>
- </resources>
3.在布局文件中使用。
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- xmlns:fsms="http://schemas.android.com/apk/res/com.example.sequencenumber"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical" >
- <com.example.sequencenumber.DivisionEditText
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- fsms:delimiter="-"
- fsms:eachLength="5"
- fsms:placeHolder="0"
- fsms:totalLength="25" />
- </LinearLayout>
其中xmlns:fsms="http://schemas.android.com/apk/res/com.example.sequencenumber","com.example.sequencenumber"部分为R.java的包。其他部分是不变的。
fsms:delimiter(分隔符),fsms:eachLength(每组的长度),fsms:placeHolder(占位符),fsms:totalLength(总长度)为自定义的属性。
原文引自:http://renxin-327666062-qq-com.iteye.com/blog/1666694