使用TextWatcher实现EditView的度分秒控制输入。

项目中有个需求要求在EditView内只能进行度分秒的控制输入,看到参考其他软件的实现效果,自己实现了一下。
这里写图片描述
输入的时候会自动限定在经纬度数值范围之内,当光标在引号位置时输入无效并自动跳过。

这个效果需要使用TextWatcher。

TextWatcher接口有三个方法,在输入框内容修改的时候会依次执行

beforeTextChanged(CharSequences, int start, int count, int after);

s是修改之前输入框的内容
start是新内容插入的位置
count是对影响原有内容的长度,插入操作的时候通常为0
after是插入新内容的长度

onTextChanged(CharSequences, int start, int before, int count);

start是改变内容的开始位置
before是改变前的内容数量
count是改变内容的长度

afterTextChanged(Editables);

s是改变后的内容

根据这三个方法我们可以在内容插入的时候对内容进行修改,然后再次调用setText来实现输入框的限制输入,但是需要注意在调用setText后会重新执行这三个方法,可能导致死循环,因此在满足条件的时候就不要再调用setText了。

我们的要求是限制输入为度分秒,不多说,直接上代码

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import android.text.Editable;
import android.text.TextWatcher;
import android.widget.EditText;

/**
 * 度分秒输入控制器,可以将输入控制在经度、纬度、角度范围之内。
 * @author Wkkyo
 * @date 2016-4-19
 * @version 1.0.0
 * @code
 * <code>
 * EditView editView = findViewById(R.id.editView);
 * editView.addTextChangedListener(new DMSTextWatcher(editView,0));
 * </code>
 * 
 */
public final class DMSTextWatcher implements TextWatcher{

    private String oldText;

    private boolean backspace = true;

    private int watchType = 0;

    private final String MAX_VALUE_N = "90:00:00.00000";

    private final String MAX_VALUE_E = "180:00:00.00000";

    private final String MAX_VALUE_A = "360:00:00.00000";

    private final String DEFAULT_VALUE_N = "00:00:00.00000N";

    private final String DEFAULT_VALUE_E = "000:00:00.00000E";

    private final String DEFAULT_VALUE_A = "000:00:00.00000";

    private EditText mEditText;

    private Pattern mPattern;

    //纬度正则
    private final static String regExNE  = "(^([0-8][0-9]):([0-5][0-9]):([0-5][0-9])(\\.{1})([0-9]{5})" +
            "(N|S)$)|(^([0-8][0-9]):([6][0]):([0-5][0-9])(\\.{1})([0-9]{5})(N|S)$)|(^([0-8]" +
            "[0-9]):([0-5][0-9]):(60)(\\.{1})([0]{5})(N|S)$)|(^([0-8][0-9]):([6][0]):([6]" +
            "[0])(\\.{1})([0]{5})(N|S)$)|(^90:00:00.00000(N|S)$)";

    //经度正则
    private final static String regExEW = "(^([0][0-9][0-9]):([0-5][0-9]):([0-5][0-9])(\\.{1})([0-9]{5})(E|W)$)|(^(0[0-9]" +
            "[0-9]):([6][0]):([0-5][0-9])(\\.{1})([0-9]{5})(E|W)$)|(^(0[0-9][0-9]):([0-5][0-9]):(60)(\\.{1})" +
            "([0]{5})(E|W)$)|(^(0[0-9][0-9]):([6][0]):([6][0])(\\.{1})([0]{5})(E|W)$)|(^([1][0-7][0-9]):" +
            "([0-5][0-9]|60):([0-5][0-9])(\\.{1})([0-9]{5})(E|W)$)|(^([1][0-7][0-9]):([0-5][0-9]|60):" +
            "(60)(\\.{1})(0{5})(E|W)$)|(^180:00:00.00000(E|W)$)";

    //角度正则
    private final static String regEx = "(^(([0-2][0-9][0-9])|([0-3][0-5][0-9])):([0-5][0-9]|60):([0-5][0-9])(\\.{1})" +
            "([0-9]{5})$)|(^(([0-2][0-9][0-9])|([0-3][0-5][0-9])):([0-5][0-9]|60):(60)(\\.{1})(0{5})$)" +
            "|(^([0-3][0-5][0-9]):([6][0]):([0-5][0-9])(\\.{1})([0-9]{5})$)|(^([0-3][0-5][0-9]):(60):(60)" +
            "(\\.{1})([0]{5})$)|(^([0-3][0-5][0-9]):([0-5][0-9]):(60)(\\.{1})([0]{5})$)|(^([0-3][0-5][0-9])" +
            ":([0-5][0-9]):([0-5][0-9])(\\.{1})([0-9]{5})$)|(^360:00:00.00000$)";

    /**
     * 构造方法。
     * @param editText 需要控制的输入框。默认采用纬度控制,纬度最大值90:00:00.00000。
     */
    public DMSTextWatcher(EditText editText) {
        this(editText,0,null);
    }

    /**
     * 构造方法。
     * @param editText 需要控制的输入框。
     * @param type 控制方式,经度-1、纬度-0、角度-2。
     * <li>0-纬度控制,纬度最大值90:00:00.00000</li>
     * <li>1-经度控制,经度最大值180:00:00.00000</li>
     * <li>2-角度控制,经度最大值360:00:00.00000</li>
     */
    public DMSTextWatcher(EditText editText,int type) {
        this(editText,type,null);
    }

    /**
     * 构造方法。
     * @param editText 需要控制的输入框。默认采用纬度控制,纬度最大值90:00:00.00000。
     * @param defaultValue 默认值。
     */
    public DMSTextWatcher(EditText editText,String defaultValue) {
        this(editText,0,defaultValue);
    }

    /**
     * 构造方法。
     * @param editText 需要控制的输入框。
     * @param type 控制方式,经度-1、纬度-0、角度-2。
     * <li>0-纬度控制,纬度最大值90:00:00.00000</li>
     * <li>1-经度控制,经度最大值180:00:00.00000</li>
     * <li>2-角度控制,经度最大值360:00:00.00000</li>
     * @param defaultValue 默认值。
     */
    public DMSTextWatcher(EditText editText,int type,String defaultValue) {
        this.mEditText = editText;
        watchType = type;
        if(watchType == 0){
            this.mPattern = Pattern.compile(regExNE);
            if(defaultValue != null){
                Matcher matcher = mPattern.matcher(defaultValue);
                if(matcher.find()){
                    this.mEditText.setText(defaultValue);
                }else{
                    this.mEditText.setText(DEFAULT_VALUE_N);
                }
            }else{
                this.mEditText.setText(DEFAULT_VALUE_N);
            }
        }else if(watchType == 1){
            this.mPattern = Pattern.compile(regExEW);
            if(defaultValue != null){
                Matcher matcher = mPattern.matcher(defaultValue);
                if(matcher.find()){
                    this.mEditText.setText(defaultValue);
                }else{
                    this.mEditText.setText(DEFAULT_VALUE_E);
                }
            }else{
                this.mEditText.setText(DEFAULT_VALUE_E);
            }
        }else if(watchType == 2){
            this.mPattern = Pattern.compile(regEx);
            if(defaultValue != null){
                Matcher matcher = mPattern.matcher(defaultValue);
                if(matcher.find()){
                    this.mEditText.setText(defaultValue);
                }else{
                    this.mEditText.setText(DEFAULT_VALUE_A);
                }
            }else{
                this.mEditText.setText(DEFAULT_VALUE_A);
            }
        }
    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
//      KLog.d("onTextChanged :"+s+"    "+start+"---"+before+"---"+count);
        if(watchType == 0){
            onNSTextChanged(s,start,before,count);
        }else if(watchType == 1){
            onEWTextChanged(s,start,before,count);
        }else if(watchType == 2){
            onAngleTextChanged(s,start,before,count);
        }
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count,int after) {
//      KLog.d("beforeTextChanged :"+s+"    "+start+"---"+after+"---"+count);
        if(backspace){
            oldText = new String(s.toString());
        }else{
            backspace = true;
        }
    }

    @Override
    public void afterTextChanged(Editable s) {
//      KLog.d("afterTextChanged :"+s);
    }

    private void onNSTextChanged(CharSequence s, int start, int before, int count){
        StringBuilder str = new StringBuilder(s.toString());
        if(oldText != null && str.length() < oldText.length()){
            if(start == 2 || start == 5 || start == 8 || start == 14){
                str = new StringBuilder(oldText);
            }else{
                str.insert(start, "0");
            }
            mEditText.setTextKeepState(str);
            oldText = null;
        }else{
            Matcher m = mPattern.matcher(str);
            if(!m.find()){
                StringBuilder oldStr = new StringBuilder(str.toString().substring(0,start)+str.substring(start+1));
                if(count > 1){
                    str = new StringBuilder(MAX_VALUE_N);
                    str.append(oldStr.charAt(14) == 'N'?"N":"S");
                }else{
                    if(start == 2 || start == 5 || start == 8){
                        str = oldStr;
                    }else if(start == 14 || start == 15){
                        start = 14;
                        if(oldStr.charAt(14) == 'N'){
                            oldStr.replace(start, start+1, "S");
                        }else{
                            oldStr.replace(start, start+1, "N");
                        }
                        str = oldStr;
                        mEditText.setSelection(start);
                    }else{
                        String ch = str.substring(start, start+1);
                        str = new StringBuilder(oldStr);
                        str = str.replace(start, start+1, ch);
                        if(start == 0){
                            if(ch.equals("9")){
                                str = new StringBuilder(MAX_VALUE_N);
                                str.append(oldStr.charAt(14) == 'N'?"N":"S");
                            }
                        }else if(start == 3 || start == 6){
                            if("6789".indexOf(ch) > -1){
                                str = str.replace(start, start+1, "6");
                                str = str.replace(start+1, start+2, "0");
                                if(start == 6){
                                    str = str.replace(start+3, start+8, "00000");
                                }
                            }
                        }
                        m = mPattern.matcher(str);
                        m.reset();
                        if(!m.find()){
                            str = oldStr;
                        }
                    }
                }
                backspace = false;
                oldText = null;
                mEditText.setTextKeepState(str);
            }
        }
    }

    private void onEWTextChanged(CharSequence s, int start, int before, int count){
        StringBuilder str = new StringBuilder(s.toString());
        if(oldText != null && str.length() < oldText.length()){
            if(start == 3 || start == 6 || start == 9 || start == 15){
                str = new StringBuilder(oldText);
            }else{
                str.insert(start, "0");
            }
            mEditText.setTextKeepState(str);
            oldText = null;
        }else{          
            Matcher m = mPattern.matcher(str);
            if(!m.find()){
                StringBuilder oldStr = new StringBuilder(str.toString().substring(0,start)+str.substring(start+1));
                if(count > 1){
                    str = new StringBuilder(MAX_VALUE_E);
                    str.append(oldStr.charAt(15) == 'W'?"W":"E");
                }else{
                    if(start == 3 || start == 6 || start == 9){
                        str = oldStr;
                    }else if(start == 15 || start == 16){
                        start = 15;
                        if(oldStr.charAt(15) == 'E'){
                            oldStr.replace(start, start+1, "W");
                        }else{
                            oldStr.replace(start, start+1, "E");
                        }
                        str = oldStr;
                        mEditText.setSelection(start);
                    }else{
                        String ch = str.substring(start, start+1);
                        str = new StringBuilder(oldStr);
                        str = str.replace(start, start+1, ch);
                        if(start == 0){
                            if("23456789".indexOf(ch) > -1){
                                str = new StringBuilder(MAX_VALUE_E);
                                str.append(oldStr.charAt(15) == 'W'?"W":"E");
                            }
                            if("1".indexOf(ch) > -1 && (str.charAt(1) == '9' || str.charAt(1) == '8')){
                                str = new StringBuilder(MAX_VALUE_E);
                                str.append(oldStr.charAt(15) == 'W'?"W":"E");
                            }
                        }else if(start == 1){
                            if(("89").indexOf(ch) > -1 && str.charAt(0) == '1'){
                                str = new StringBuilder(MAX_VALUE_E);
                                str.append(oldStr.charAt(15) == 'W'?"W":"E");
                            }
                        }else if(start == 4 || start == 7){
                            if("6789".indexOf(ch) > -1){
                                str = str.replace(start, start+1, "6");
                                str = str.replace(start+1, start+2, "0");
                                if(start == 7){
                                    str = str.replace(start+3, start+8, "00000");
                                }
                            }
                        }
                        m = mPattern.matcher(str);
                        m.reset();
                        if(!m.find()){
                            str = oldStr;
                        }
                    }
                }
                backspace = false;
                oldText = null;
                mEditText.setTextKeepState(str);
            }
        }
    }

    private void onAngleTextChanged(CharSequence s, int start, int before, int count){
        StringBuilder str = new StringBuilder(s.toString());
        if(oldText != null && str.length() < oldText.length()){
            if(start == 3 || start == 6 || start == 9 || start == 15){
                str = new StringBuilder(oldText);
            }else{
                str.insert(start, "0");
            }
            mEditText.setTextKeepState(str);
            oldText = null;
        }else{          
            Matcher m = mPattern.matcher(str);
            if(!m.find()){
                StringBuilder oldStr = new StringBuilder(str.toString().substring(0,start)+str.substring(start+1));
                if(count > 1){
                    str = new StringBuilder(MAX_VALUE_A);
                }else{
                    if(start == 3 || start == 6 || start == 9){
                        str = oldStr;
                    }else if(start == 15){
                        start = 15;
                        str = oldStr;
                        mEditText.setSelection(start);
                    }else{
                        String ch = str.substring(start, start+1);
                        str = new StringBuilder(oldStr);
                        str = str.replace(start, start+1, ch);
                        if(start == 0){
                            if("456789".indexOf(ch) > -1){
                                str = new StringBuilder(MAX_VALUE_A);
                            }
                            if("3".indexOf(ch) > -1 && ("6789".indexOf(str.charAt(1)) > -1)){
                                str = new StringBuilder(MAX_VALUE_A);
                            }
                        }else if(start == 1){
                            if(("6789").indexOf(ch) > -1 && str.charAt(0) == '3'){
                                str = new StringBuilder(MAX_VALUE_A);
                            }
                        }else if(start == 4 || start == 7){
                            if("6789".indexOf(ch) > -1){
                                str = str.replace(start, start+1, "6");
                                str = str.replace(start+1, start+2, "0");
                                if(start == 7){
                                    str = str.replace(start+3, start+8, "00000");
                                }
                            }
                        }
                        m = mPattern.matcher(str);
                        m.reset();
                        if(!m.find()){
                            str = oldStr;
                        }
                    }
                }
                backspace = false;
                oldText = null;
                mEditText.setTextKeepState(str);
            }
        }
    }
}

我实现了三种类型的现在,分别对应纬度、经度和角度,在构造方法里通过参数判断,使用也很简单

EditView editView = findViewById(R.id.editView);
editView.addTextChangedListener(new DMSTextWatcher(editView,0));

后来发现有个InputFilter接口似乎也能实现这个效果,时间有限,以后有空再研究。

在于GIS相关的软件中经常要输入经纬数值,而基于MFC Edit控件的经纬输入控件需 要创建三个Edit编辑框,来分别输入、分、秒数值,并且需要分别进行输入范围和有效 性的检验。该基于BCGControlBar的经纬输入控件实现了在一个输入窗口中分别按照 、分、秒三个值域来输入经纬数值,并同时进行了输入分有效性和输入范围的检验。经 纬中的、分、秒字段均通过数字键盘直接输入数值,也可通过微调按钮或者键盘的上 下键进行数字的增减,你可以通过左右键进行、分、秒输入域的切换。该控件可以设置 输入范围,默认的范围是0~89。该1.1版本修复了键盘直接输入数值的逻辑问题。 In the GIS-related software often have to enter the latitude and longitude values, and MFC Edit control based on the latitude and longitude input controls need to create three Edit edit box to enter the degrees, minutes and seconds values, and the need for input range and validity of the test. The BCGControlBar-based latitude and longitude input control realizes the input of the latitude and longitude values in degrees,minutes,and seconds in one input window, and simultaneously verifies the validity of the input points and the input range.The degrees, minutes, and seconds fields can be entered directly through the numeric keypad, also can be fine-tuning button or the keyboard up and down keys to increase or decrease the number, you can use left and right keys for degrees, minutes and seconds to switch the input field. The control can set the input range of degree, the default range is 0 ~ 89.The 1.1 version fixes the logic of keyboard input values directly.
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值