首页 文章

如何屏蔽EditText以显示dd / mm / yyyy日期格式

提问于
浏览
40

如何格式化 EditText 以遵循“ dd/mm/yyyy ”格式,就像我们可以使用 TextWatcher 格式化来屏蔽用户输入看起来像"0.05€"一样 . 我不是在谈论限制字符,或者验证日期,只是掩盖了以前的格式 .

5 回答

  • 94

    我为一个项目写了这个 TextWatcher ,希望它对某人有帮助 . 请注意,它确认 not 验证用户输入的日期,并且您应该在焦点更改时处理该日期,因为用户可能尚未完成输入日期 .

    Update 25/06 制作一个wiki,看看我们是否达到了更好的最终代码 .

    Update 07/06 我终于为观察者本身添加了某种验证 . 它将执行以下无效日期:

    • 如果月份大于12,则为12(12月)

    • 如果日期大于所选月份的日期,请将其作为该月份的最大值 .

    • 如果年份不在 1900-2100 范围内,请将其更改为在范围内

    这个验证符合我的需要,但有些人可能想稍微更改一下,范围很容易更改,你可以将这个验证挂钩到例如 Toast 消息,以通知用户我们已经修改了他/她的日期,因为它无效 .

    在这段代码中,我将假设我们有一个名为 dateEditText 的引用,它附加了 TextWatcher ,这可以这样做:

    EditText date;
    date = (EditText)findViewById(R.id.whichdate);
    date.addTextChangedListener(tw);
    

    TextWatcher tw = new TextWatcher() {
        private String current = "";
        private String ddmmyyyy = "DDMMYYYY";
        private Calendar cal = Calendar.getInstance();
    

    当用户更改 EditText 的文本时

    @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            if (!s.toString().equals(current)) {
                String clean = s.toString().replaceAll("[^\\d.]|\\.", "");
                String cleanC = current.replaceAll("[^\\d.]|\\.", "");
    
                int cl = clean.length();
                int sel = cl;
                for (int i = 2; i <= cl && i < 6; i += 2) {
                    sel++;
                }
                //Fix for pressing delete next to a forward slash
                if (clean.equals(cleanC)) sel--;
    
                if (clean.length() < 8){
                   clean = clean + ddmmyyyy.substring(clean.length());
                }else{
                   //This part makes sure that when we finish entering numbers
                   //the date is correct, fixing it otherwise
                   int day  = Integer.parseInt(clean.substring(0,2));
                   int mon  = Integer.parseInt(clean.substring(2,4));
                   int year = Integer.parseInt(clean.substring(4,8));
    
                   mon = mon < 1 ? 1 : mon > 12 ? 12 : mon;
                   cal.set(Calendar.MONTH, mon-1);
                   year = (year<1900)?1900:(year>2100)?2100:year;
                   cal.set(Calendar.YEAR, year); 
                   // ^ first set year for the line below to work correctly
                   //with leap years - otherwise, date e.g. 29/02/2012
                   //would be automatically corrected to 28/02/2012 
    
                   day = (day > cal.getActualMaximum(Calendar.DATE))? cal.getActualMaximum(Calendar.DATE):day;
                   clean = String.format("%02d%02d%02d",day, mon, year);
                }
    
                clean = String.format("%s/%s/%s", clean.substring(0, 2),
                    clean.substring(2, 4),
                    clean.substring(4, 8));
    
                sel = sel < 0 ? 0 : sel;
                current = clean;
                date.setText(current);
                date.setSelection(sel < current.length() ? sel : current.length());
            }
        }
    

    我们还实现了其他两个功能,因为我们必须这样做

    @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
    
        @Override
        public void afterTextChanged(Editable s) {}
    };
    

    这会产生以下效果,删除或插入字符将显示或隐藏 dd/mm/yyyy 掩码 . 因为我试图让代码尽可能简单,所以应该很容易修改以适应其他格式的掩码 .

    enter image description here

  • 0

    此答案不会对剩余的无类型数字应用完整掩码 . 但是,它是相关的,是我需要的解决方案 . 它的工作方式与 PhoneNumberFormattingTextWatcher 的工作方式类似 .

    在您键入时,它会添加斜杠以分隔格式为 mm/dd/yyyy 的日期 . 它没有做任何验证 - 只是格式化 .

    不需要 EditText 参考 . 只需设置监听器即可 . myEditText.addTextChangedListener(new DateTextWatcher());

    import android.text.Editable;
    import android.text.TextWatcher;
    
    import java.util.Locale;
    
    /**
     * Adds slashes to a date so that it matches mm/dd/yyyy.
     *
     * Created by Mark Miller on 12/4/17.
     */
    public class DateTextWatcher implements TextWatcher {
    
        public static final int MAX_FORMAT_LENGTH = 8;
        public static final int MIN_FORMAT_LENGTH = 3;
    
        private String updatedText;
        private boolean editing;
    
    
        @Override
        public void beforeTextChanged(CharSequence charSequence, int start, int before, int count) {
    
        }
    
        @Override
        public void onTextChanged(CharSequence text, int start, int before, int count) {
            if (text.toString().equals(updatedText) || editing) return;
    
            String digitsOnly = text.toString().replaceAll("\\D", "");
            int digitLen = digitsOnly.length();
    
            if (digitLen < MIN_FORMAT_LENGTH || digitLen > MAX_FORMAT_LENGTH) {
                updatedText = digitsOnly;
                return;
            }
    
            if (digitLen <= 4) {
                String month = digitsOnly.substring(0, 2);
                String day = digitsOnly.substring(2);
    
                updatedText = String.format(Locale.US, "%s/%s", month, day);
            }
            else {
                String month = digitsOnly.substring(0, 2);
                String day = digitsOnly.substring(2, 4);
                String year = digitsOnly.substring(4);
    
                updatedText = String.format(Locale.US, "%s/%s/%s", month, day, year);
            }
        }
    
        @Override
        public void afterTextChanged(Editable editable) {
    
            if (editing) return;
    
            editing = true;
    
            editable.clear();
            editable.insert(0, updatedText);
    
            editing = false;
        }
    }
    
  • 4

    使用JuanCortés代码的更简洁的方法是将它放在一个类中:

    public class DateInputMask implements TextWatcher {
    
    private String current = "";
    private String ddmmyyyy = "DDMMYYYY";
    private Calendar cal = Calendar.getInstance();
    private EditText input;
    
    public DateInputMask(EditText input) {
        this.input = input;
        this.input.addTextChangedListener(this);
    }
    
    @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.toString().equals(current)) {
            return;
        }
    
        String clean = s.toString().replaceAll("[^\\d.]|\\.", "");
        String cleanC = current.replaceAll("[^\\d.]|\\.", "");
    
        int cl = clean.length();
        int sel = cl;
        for (int i = 2; i <= cl && i < 6; i += 2) {
            sel++;
        }
        //Fix for pressing delete next to a forward slash
        if (clean.equals(cleanC)) sel--;
    
        if (clean.length() < 8){
            clean = clean + ddmmyyyy.substring(clean.length());
        }else{
            //This part makes sure that when we finish entering numbers
            //the date is correct, fixing it otherwise
            int day  = Integer.parseInt(clean.substring(0,2));
            int mon  = Integer.parseInt(clean.substring(2,4));
            int year = Integer.parseInt(clean.substring(4,8));
    
            mon = mon < 1 ? 1 : mon > 12 ? 12 : mon;
            cal.set(Calendar.MONTH, mon-1);
            year = (year<1900)?1900:(year>2100)?2100:year;
            cal.set(Calendar.YEAR, year);
            // ^ first set year for the line below to work correctly
            //with leap years - otherwise, date e.g. 29/02/2012
            //would be automatically corrected to 28/02/2012
    
            day = (day > cal.getActualMaximum(Calendar.DATE))? cal.getActualMaximum(Calendar.DATE):day;
            clean = String.format("%02d%02d%02d",day, mon, year);
        }
    
        clean = String.format("%s/%s/%s", clean.substring(0, 2),
                clean.substring(2, 4),
                clean.substring(4, 8));
    
        sel = sel < 0 ? 0 : sel;
        current = clean;
        input.setText(current);
        input.setSelection(sel < current.length() ? sel : current.length());
    }
    
    @Override
    public void afterTextChanged(Editable s) {
    
    }
    }
    

    然后你可以重复使用它

    new DateInputMask(myEditTextInstance);
    
  • -1

    目前的答案非常好,并帮助指导我自己的解决方案 . 我决定发布自己的解决方案有几个原因,即使这个问题已经有一个有效的答案:

    • 我在Kotlin工作,而不是Java . 发现自己遇到同样问题的人将不得不翻译当前的解决方案 .

    • 我想写一个更清晰的答案,以便人们可以更容易地适应他们自己的问题 .

    • 正如dengue8830所建议的,我在一个类中封装了这个问题的解决方案,所以任何人都可以使用,甚至不用担心实现 .

    要使用它,只需执行以下操作:

    • DateInputMask(mEditText).listen()

    解决方案如下所示:

    class DateInputMask(val input : EditText) {
    
        fun listen() {
            input.addTextChangedListener(mDateEntryWatcher)
        }
    
        private val mDateEntryWatcher = object : TextWatcher {
    
            var edited = false
            val dividerCharacter = "/"
    
            override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
                if (edited) {
                    edited = false
                    return
                }
    
                var working = getEditText()
    
                working = manageDateDivider(working, 2, start, before)
                working = manageDateDivider(working, 5, start, before)
    
                edited = true
                input.setText(working)
                input.setSelection(input.text.length)
            }
    
            private fun manageDateDivider(working: String, position : Int, start: Int, before: Int) : String{
                if (working.length == position) {
                    return if (before <= position && start < position)
                        working + dividerCharacter
                    else
                        working.dropLast(1)
                }
                return working
            }
    
            private fun getEditText() : String {
                return if (input.text.length >= 10)
                    input.text.toString().substring(0,10)
                else
                    input.text.toString()
            }
    
            override fun afterTextChanged(s: Editable) {}
            override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
        }
    }
    
  • 5

    尝试使用可以解决此问题的库,因为屏蔽它不是开箱即用的 . 有很多极端情况(比如在已经屏蔽的文本中间添加/删除字符)并正确处理这个问题,你最终会得到很多代码(和bug) .

    以下是一些可用的库:
    https://github.com/egslava/edittext-mask
    https://github.com/dimitar-zabaznoski/MaskedEditText
    https://github.com/pinball83/Masked-Edittext
    https://github.com/RedMadRobot/input-mask-android
    https://github.com/santalu/mask-edittext

    **请注意,在编写这些库时并非没有问题,因此您有责任选择最适合您的库并测试代码 .

相关问题