需求:项目中需要一个能截取到小数点后2位的edittext,且在输入的时候实时的监听输入变化,将金额内容转换成中文金额大写的内容;
参考:http://www.blogjava.net/fastunit/archive/2008/03/25/188537.html 大写金额
其中几点可能需要注意:
1. 不希望用自定义控件,那样耦合性会很大,个人觉得没必要;
2. 利用现有edittext控件的各种特性和方法为我们实现想要的效果服务:
a. android:inputType="numberDecimal" 在布局相应控件直接定义该属性,帮助我们限制该输入框只能输入数字(含小数)
b. android:maxLength="12" 设置可以接受的金额长度(包含小数点)
c. 监听edittext控件的addTextChangedListener方法,在afterTextChanged接口中处理即将显示到输入框中的值;而在这里添加一个回掉,方便主线程中处理相应的逻辑,比如上面需求中需要的,并行显示输入金额的中文大写(感谢参考链接中,哪位仁兄提供的一系列方法)。
效果:
项目代码:
布局:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
<TextView android:text="测试EditText,支持仅能输入小数点后两位"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/textView" />
<!-- android:maxLength="12" 连上小数点最多可以输入的字符-->
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:inputType="numberDecimal"
android:ems="12"
android:maxLength="12"
android:id="@+id/editText"
android:layout_below="@+id/textView"/>
<TextView
android:text="等待输入"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_below="@id/editText"
android:id="@+id/showTextView" />
</RelativeLayout>
主Activity:
package top.playinteractive.testapp;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.widget.EditText;
import android.widget.TextView;
import top.playinteractive.testapp.log.CommonLog;
import top.playinteractive.testapp.log.LogFactory;
import top.playinteractive.testapp.utils.MoneyUtil;
import top.playinteractive.testapp.utils.UIUtils;
public class MainActivity extends ActionBarActivity {
private static final CommonLog log;
static {
log = LogFactory.createLog();
}
private TextView showTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
showTextView = (TextView) findViewById(R.id.showTextView);
((EditText) findViewById(R.id.editText)).addTextChangedListener(UIUtils.getDecimalRestrictionsTextWatcher(3, new UIUtils.DecimalRestrictionsCallBack() {
@Override
public void afterTextChanged(String txt) {
log.e(MoneyUtil.toChinese(txt));
showTextView.setText(MoneyUtil.toChinese(txt));
}
}));
/*
* 以下为测试代码:
* 1、复写EditText继承自 android.widget.TextView 的addTextChangedListener方法;
* 方法定义:
* void addTextChangedListener(TextWatcher watcher)
Adds a TextWatcher to the list of those whose methods are called whenever this TextView's text changes.
2、该方法在textview的setText被调用时之后会被通知,在这里会被分为3个阶段调用该接口(TextWatcher)中的3个实现,在每个实现中都可以对文本进行处理;
* */
// ((EditText) findViewById(R.id.editText)).addTextChangedListener(new TextWatcher() {
//
// /*
// * This method is called to notify you that, within s, the count characters beginning at start are about
// * to be replaced by new text with length after. It is an error to attempt to make changes to s from this callback
// * */
// @Override
// public void beforeTextChanged(CharSequence s, int start, int count, int after) {
log.e("---beforeTextChanged---");
log.e(s);//上一次显示的文本
log.e(start);//准备插入的字符将以这个位置进行插入(0为起始位置)
log.e(count);//0输入的时候、1删除的时候
log.e(after);//输入的个数,始终为1
log.e("---...---");
// }
//
// @Override
// public void onTextChanged(CharSequence s, int start, int before, int count) {
log.e("---onTextChanged---");
log.e(s);//当前输入的文本
log.e(start);//准备插入的字符将以这个位置进行插入(0为起始位置)
log.e(count);//1输入的时候、0删除的时候
log.e("---...---");
// }
//
// @Override
// public void afterTextChanged(Editable s) {
log.e("---afterTextChanged---");
log.e(s);//最后将会显示到输入框的值
log.e("---...---");
// if (null != s) {
// String temp = s.toString();
// int posDot = temp.indexOf(".");
// if (posDot <= 0) return;
// //如果字符串的长度(加上小数点) - 小数点所在位置,再减去 1,得到小数点后的字符数量,如果大于2就标识用户试图输入2位以上的小数
// if (temp.length() - posDot - 1 > 2) {
// //用小数点后两位 替换 小数点后面的字符(后4位)
// s.delete(posDot + 3, posDot + 4);
// }
// }
// }
// });
}
}
工具类:
UIUtils:
package top.playinteractive.testapp.utils;
import android.text.Editable;
import android.text.TextWatcher;
/**
* Created by zhaojin on 15/3/3.
*/
public class UIUtils {
/**
* 保留几位小数
* @param digits 保留的小数位数
* */
public static TextWatcher getDecimalRestrictionsTextWatcher(final int digits) {
return new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
if (null != s || s.length() != 0) {
String temp = s.toString();
int posDot = temp.indexOf(".");
if (posDot <= 0) return;
//如果字符串的长度(加上小数点) - 小数点所在位置,再减去 1,得到小数点后的字符数量,如果大于2就标识用户试图输入2位以上的小数
if (temp.length() - posDot - 1 > digits) {
//用小数点后两位 替换 小数点后面的字符(后4位)
s.delete(posDot + digits + 1, posDot + digits + 2);
}
}
}
};
}
public interface DecimalRestrictionsCallBack{
void afterTextChanged(String txt);
}
/**
* 保留几位小数
* @param digits 保留的小数位数
* */
public static TextWatcher getDecimalRestrictionsTextWatcher(final int digits, final DecimalRestrictionsCallBack callback) {
return new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
if (null != s || s.length() != 0) {
if(s.length() == 1 && s.toString().equals(".")){
s.replace(0,s.length(),"0.");
}
String temp = s.toString();
int posDot = temp.indexOf(".");
if (posDot > 0) {
//如果字符串的长度(加上小数点) - 小数点所在位置,再减去 1,得到小数点后的字符数量,如果大于2就标识用户试图输入2位以上的小数
if (temp.length() - posDot - 1 > digits) {
//用小数点后两位 替换 小数点后面的字符(后4位)
s.delete(posDot + digits + 1, posDot + digits + 2);
}
}
}
callback.afterTextChanged(s.toString());
}
};
}
}
package top.playinteractive.testapp.utils;
/**
* Created by zhaojin on 15/3/4.
*/
public class MoneyUtil {
/**
* 大写数字
*/
private static final String[] NUMBERS = {"零", "壹", "贰", "叁", "肆", "伍", "陆",
"柒", "捌", "玖"};
/**
* 整数部分的单位
*/
private static final String[] IUNIT = {"元", "拾", "佰", "仟", "万", "拾", "佰",
"仟", "亿", "拾", "佰", "仟", "万", "拾", "佰", "仟"};
/**
* 小数部分的单位
*/
private static final String[] DUNIT = {"角", "分", "厘"};
/**
* 得到大写金额。
*/
public static String toChinese(String str) {
str = str.replaceAll(",", "");// 去掉","
String integerStr;// 整数部分数字
String decimalStr;// 小数部分数字
// 初始化:分离整数部分和小数部分
if (str.indexOf(".") > 0) {
integerStr = str.substring(0, str.indexOf("."));
decimalStr = str.substring(str.indexOf(".") + 1);
} else if (str.indexOf(".") == 0) {
integerStr = "";
decimalStr = str.substring(1);
} else {
integerStr = str;
decimalStr = "";
}
// integerStr去掉首0,不必去掉decimalStr的尾0(超出部分舍去)
if (!integerStr.equals("")) {
integerStr = Long.toString(Long.parseLong(integerStr));
if (integerStr.equals("0")) {
integerStr = "";
}
}
// overflow超出处理能力,直接返回
if (integerStr.length() > IUNIT.length) {
throw new RuntimeException("输入数字长度大于IUNIT.length"+IUNIT.length);
}
int[] integers = toArray(integerStr);// 整数部分数字
boolean isMust5 = isMust5(integerStr);// 设置万单位
int[] decimals = toArray(decimalStr);// 小数部分数字
return getChineseInteger(integers, isMust5) + getChineseDecimal(decimals);
}
/**
* 整数部分和小数部分转换为数组,从高位至低位
*/
private static int[] toArray(String number) {
int[] array = new int[number.length()];
for (int i = 0; i < number.length(); i++) {
array[i] = Integer.parseInt(number.substring(i, i + 1));
}
return array;
}
/**
* 得到中文金额的整数部分。
*/
private static String getChineseInteger(int[] integers, boolean isMust5) {
StringBuffer chineseInteger = new StringBuffer("");
int length = integers.length;
for (int i = 0; i < length; i++) {
// 0出现在关键位置:1234(万)5678(亿)9012(万)3456(元)
// 特殊情况:10(拾元、壹拾元、壹拾万元、拾万元)
String key = "";
if (integers[i] == 0) {
if ((length - i) == 13)// 万(亿)(必填)
key = IUNIT[4];
else if ((length - i) == 9)// 亿(必填)
key = IUNIT[8];
else if ((length - i) == 5 && isMust5)// 万(不必填)
key = IUNIT[4];
else if ((length - i) == 1)// 元(必填)
key = IUNIT[0];
// 0遇非0时补零,不包含最后一位
if ((length - i) > 1 && integers[i + 1] != 0)
key += NUMBERS[0];
}
chineseInteger.append(integers[i] == 0 ? key
: (NUMBERS[integers[i]] + IUNIT[length - i - 1]));
}
return chineseInteger.toString();
}
/**
* 得到中文金额的小数部分。
*/
private static String getChineseDecimal(int[] decimals) {
StringBuffer chineseDecimal = new StringBuffer("");
for (int i = 0; i < decimals.length; i++) {
// 舍去3位小数之后的
if (i == 3)
break;
chineseDecimal.append(decimals[i] == 0 ? ""
: (NUMBERS[decimals[i]] + DUNIT[i]));
}
return chineseDecimal.toString();
}
/**
* 判断第5位数字的单位"万"是否应加。
*/
private static boolean isMust5(String integerStr) {
int length = integerStr.length();
if (length > 4) {
String subInteger = "";
if (length > 8) {
// 取得从低位数,第5到第8位的字串
subInteger = integerStr.substring(length - 8, length - 4);
} else {
subInteger = integerStr.substring(0, length - 4);
}
return Integer.parseInt(subInteger) > 0;
} else {
return false;
}
}
public static void main(String[] args) {
String number = "1.23";
System.out.println(number + " " + MoneyUtil.toChinese(number));
number = "1234567890123456.123";
System.out.println(number + " " + MoneyUtil.toChinese(number));
number = "0.0798";
System.out.println(number + " " + MoneyUtil.toChinese(number));
number = "10,001,000.09";
System.out.println(number + " " + MoneyUtil.toChinese(number));
number = "01.107700";
System.out.println(number + " " + MoneyUtil.toChinese(number));
}
}
LogFactory:
package top.playinteractive.testapp.log;
public class LogFactory {
private static final String TAG = "playinteractive";
private static CommonLog log = null;
public static CommonLog createLog() {
if (log == null) {
log = new CommonLog();
}
log.setTag(TAG);
return log;
}
public static CommonLog createLog(String tag) {
if (log == null) {
log = new CommonLog();
}
if (tag == null || tag.length() < 1) {
log.setTag(TAG);
} else {
log.setTag(tag);
}
return log;
}
}
CommonLog:
package top.playinteractive.testapp.log;
import android.util.Log;
public class CommonLog {
private String tag = "CommonLog";
public static int logLevel = Log.VERBOSE;
public static boolean isDebug = true;
public CommonLog() {
}
public CommonLog(String tag) {
this.tag = tag;
}
public void setTag(String tag) {
this.tag = tag;
}
private String getFunctionName() {
StackTraceElement[] sts = Thread.currentThread().getStackTrace();
if (sts == null) {
return null;
}
for (StackTraceElement st : sts) {
if (st.isNativeMethod()) {
continue;
}
if (st.getClassName().equals(Thread.class.getName())) {
continue;
}
if (st.getClassName().equals(this.getClass().getName())) {
continue;
}
return "[" + Thread.currentThread().getId() + ": "
+ st.getFileName() + ":" + st.getLineNumber() + "]";
}
return null;
}
public void info(Object str) {
if (logLevel <= Log.INFO) {
String name = getFunctionName();
String ls = (name == null ? str.toString() : (name + " - " + str));
Log.i(tag, ls);
}
}
public void i(Object str) {
if (isDebug) {
info(str);
}
}
public void verbose(Object str) {
if (logLevel <= Log.VERBOSE) {
String name = getFunctionName();
String ls = (name == null ? str.toString() : (name + " - " + str));
Log.v(tag, ls);
}
}
public void v(Object str) {
if (isDebug) {
verbose(str);
}
}
public void warn(Object str) {
if (logLevel <= Log.WARN) {
String name = getFunctionName();
String ls = (name == null ? str.toString() : (name + " - " + str));
Log.w(tag, ls);
}
}
public void w(Object str) {
if (isDebug) {
warn(str);
}
}
public void error(Object str) {
if (logLevel <= Log.ERROR) {
String name = getFunctionName();
String ls = (name == null ? str.toString() : (name + " - " + str));
Log.e(tag, ls);
}
}
public void error(Exception ex) {
if (logLevel <= Log.ERROR) {
StringBuffer sb = new StringBuffer();
String name = getFunctionName();
StackTraceElement[] sts = ex.getStackTrace();
if (name != null) {
sb.append(name + " - " + ex + "\r\n");
} else {
sb.append(ex + "\r\n");
}
if (sts != null && sts.length > 0) {
for (StackTraceElement st : sts) {
if (st != null) {
sb.append("[ " + st.getFileName() + ":"
+ st.getLineNumber() + " ]\r\n");
}
}
}
Log.e(tag, sb.toString());
}
}
public void e(Object str) {
if (isDebug) {
error(str);
}
}
public void e(Exception ex) {
if (isDebug) {
error(ex);
}
}
public void debug(Object str) {
if (logLevel <= Log.DEBUG) {
String name = getFunctionName();
String ls = (name == null ? str.toString() : (name + " - " + str));
Log.d(tag, ls);
}
}
public void d(Object str) {
if (isDebug) {
debug(str);
}
}
}