`
小鑫。
  • 浏览: 135079 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Android自定义EditText,实现分割输入内容效果

 
阅读更多
例如,输入一组25位的序列号,希望分成5组,每组5个数字。效果如下图。


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://kandy0619.blog.163.com/blog/static/64344345201012325939280/
分享到:
评论

相关推荐

    Android的edittext在弹出框中实现输入自动千分位分隔和金额限制

    这个自定义控件"Android的edittext在弹出框中实现输入自动千分位分隔和金额限制"就解决了这样的问题。 首先,我们需要理解的是`EditText`的基本用法。`EditText`是继承自`TextView`的,它添加了文本编辑功能。我们...

    Android EditText 手机号码分段显示

    综上所述,通过结合`EditText`的属性设置、`TextWatcher`监听和自定义格式化方法,我们可以在Android应用中实现手机号码的分段显示功能,为用户提供更好的交互体验。在实际开发中,可以根据具体需求进行定制和扩展,...

    安卓EditText输入框相关-EditText输入电话号码银行卡号自动添加空格分割.zip

    在实际应用中,我们还可能遇到一些额外的需求,例如限制输入长度、不允许输入非数字字符等,这些都可以通过自定义EditText的过滤器(InputFilter)来实现。同时,为了提高用户体验,可以设置监听器监听输入状态,如...

    Android 自定义编辑框

    本示例将探讨如何使用Drawable资源来自定义编辑框(EditText),以实现更个性化的UI效果。 首先,编辑框(EditText)是Android中用于用户输入文本的基本控件,它的外观和行为可以通过XML属性或代码进行定制。在这里...

    android 前面部分可以编辑后面部分不可编辑的EditText Demo.zip

    这在显示预设信息并允许用户在其后添加自定义内容时非常有用,例如电话号码格式化或日期输入。 标题“android 前面部分可以编辑后面部分不可编辑的EditText Demo”所指向的就是这样一个定制的EditText实现。在这样...

    安卓EditText输入框相关-EditText内容分不同块显示支持校验删除块添加块得到块代表的字符串集合.rar

    7. **学习与参考**:尽管这个实现可能无法直接运行,但其代码结构和逻辑对于学习如何自定义EditText的功能是很有价值的。开发者可以通过阅读源码来理解如何扩展EditText的默认行为,以及如何实现复杂的文本处理逻辑...

    android edittext 添加表情

    在Android开发中,EditText是用于用户输入文本的基本控件,但在一些社交应用或者聊天界面中,我们常常需要在EditText中实现表情输入功能,以增强用户的交互体验。本篇将详细介绍如何在Android的EditText中添加表情...

    Android自定义Dialog带分隔的8位输入框按钮回调输入值部分代码

    在Android开发中,自定义Dialog是一种常见的需求,用于提供一种特殊的用户交互方式。在这个场景下,我们想要创建一个带有分隔符的8位输入框的自定义Dialog,并且当用户点击按钮时,能够通过回调方法将输入的值传递到...

    Android应用源码之前面部分可以编辑后面部分不可编辑的EditText.rar

    总的来说,实现"Android应用源码之前面部分可以编辑后面部分不可编辑的EditText"的核心在于自定义EditText控件,通过重写`onTouchEvent()`方法并结合`InputFilter`等手段,控制用户输入的范围和格式。这个压缩包中的...

    Android 手机号自动分割

    在Android开发中,手机号自动分割是一项常见的需求,尤其是在处理用户输入或者进行数据验证时。这个话题涉及到字符串处理、正则表达式以及用户界面设计等多个方面。以下是对这一知识点的详细阐述: 1. **字符串处理...

    Android高级应用源码-前面部分可以编辑后面部分不可编辑的EditText.zip

    1. **创建自定义EditText类**:创建一个新的Java类,继承自EditText,并添加必要的成员变量,如可编辑部分的起始位置、长度等。 2. **重写onDraw()方法**:在这个方法中,你需要根据自定义的需求进行绘制。首先调用...

    android 自定义控件

    本篇文章将深入探讨Android自定义控件的创建过程及其相关知识点。 首先,自定义控件主要分为两类:扩展已有的Android控件(如TextView、Button等)和完全自定义的View。对于扩展已有的控件,我们通常通过继承相应的...

    Android 自定义AlertDialog对话框样式

    在dialog_layout.xml文件中,我们可以定义一个TextView显示wifi名称,一条分割线,一个EditText用于密码输入,以及两个Button用于取消与连接。自定义AlertDialog对话框样式可以满足各种实际的需求。

    Android高级应用源码-前面部分可以编辑后面部分不可编辑的EditText.rar

    1. **自定义EditText子类**: 首先,创建一个新的Java类,继承自EditText。在这个类中,我们需要覆盖`onKey`或`onTextContextMenuItem`等与文本输入相关的事件处理方法,以便对用户的输入行为进行拦截和控制。 2. ...

    EditText输入电话号码、银行卡号自动添加空格分割

    在Android开发中,`EditText` 是一个非常常见的组件,用于接收用户输入文本。在实际应用中,特别是金融或电信类应用,我们常常需要用户输入电话号码或银行卡号。为了提高用户体验和可读性,通常会要求在特定位置(如...

    Android金额输入控件

    在Android中,我们通常使用`EditText`作为用户输入的基础组件。为了限制用户输入,我们可以重写`EditText`的`addTextChangedListener`方法,添加一个监听器来捕获用户输入的每一个字符。在监听器内部,我们可以通过`...

    前面部分可以编辑后面部分不可编辑的EditText

    要实现"前面部分可以编辑后面部分不可编辑"的效果,我们需要对EditText进行扩展,创建一个新的自定义View类。这个类会继承自EditText,并覆盖或扩展其默认行为。 1. **自定义View类**:在Java代码中,我们需要创建...

Global site tag (gtag.js) - Google Analytics