给EditText添加一个工具方法,使其支持仅保留到第N位小数

来源:互联网 发布:专业视频制作软件 编辑:程序博客网 时间:2024/04/30 20:14

需求:项目中需要一个能截取到小数点后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方法;        *   方法定义:        *   voidaddTextChangedListener(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());            }        };    }}



MoneyUtil:


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);}}}






0 0