java 如何限制android中edittext的输入时间

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13120947/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 11:34:24  来源:igfitidea点击:

How to restrict to input time for edittext in android

javaandroidvalidationandroid-edittext

提问by sam_k

I have to allow user to input only time in ##:## format in edit text on the fly, is there any way to achieve it? I have used below code but it doest not working.

我必须允许用户在动态编辑文本中只输入 ##:## 格式的时间,有什么办法可以实现吗?我使用了下面的代码,但它不起作用。

I able to enter number more than 24 value like 45623:5689.

我可以输入超过 24 个值的数字,例如 45623:5689。

edit.setInputType(InputType.TYPE_DATETIME_VARIATION_TIME)

Even android:text="time"is also not working.

甚至android:text="time"也不工作。

how can i achieve this thing. Can anybody suggest me how can i do this thing.

我怎样才能做到这一点。任何人都可以建议我如何做这件事。

I want to allow user to enter in first 2 places up to 23 value and then compulasary : and then user can allow up to 59 value.

我想允许用户在前 2 个位置输入最多 23 个值,然后是 compulasary : 然后用户最多可以允许 59 个值。

for example

例如

23:59 correct
24:05 incorrect
02:56 correct
02:79 incorrect

I used this customize filter also but its not working

我也使用了这个自定义过滤器,但它不起作用

I got this code from some where else in SO.

我从 SO 的其他地方得到了这个代码。

Code:

代码:

    InputFilter timeFilter = new InputFilter() {
        public CharSequence filter(CharSequence source, int start, int end, Spanned dest,
                int dstart, int dend) {
            if (source.length() == 0) {
                return null;// deleting, keep original editing
            }
            String result = "";
            result += dest.toString().substring(0, dstart);
            result += source.toString().substring(start, end);
            result += dest.toString().substring(dend, dest.length());

            if (result.length() > 5) {
                return "";// do not allow this edit
            }
            boolean allowEdit = true;
            char c;
            if (result.length() > 0) {
                c = result.charAt(0);
                allowEdit &= (c >= '0' && c <= '2');
            }
            if (result.length() > 1) {
                c = result.charAt(1);
                allowEdit &= (c >= '0' && c <= '9');
            }
            if (result.length() > 2) {
                c = result.charAt(2);
                allowEdit &= (c == ':');
            }
            if (result.length() > 3) {
                c = result.charAt(3);
                allowEdit &= (c >= '0' && c <= '5');
            }
            if (result.length() > 4) {
                c = result.charAt(4);
                allowEdit &= (c >= '0' && c <= '9');
            }
            return allowEdit ? null : "";
        }
    };

Edited Question : main.xml file code

编辑问题:main.xml 文件代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:gravity="center"
    android:orientation="vertical"
    android:padding="10dp" >

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:gravity="center"
        android:orientation="horizontal" >

        <TextView
            android:id="@+id/txtRecipientName"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingRight="20dp"
            android:text="@string/recipient_name" />

        <EditText
            android:id="@+id/edTxtRecipient"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:ems="10"
            android:paddingLeft="20dp" >

            <requestFocus />
        </EditText>
    </LinearLayout>

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:gravity="center"
        android:orientation="horizontal" >

        <TextView
            android:id="@+id/txtParcelDeliverTime"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingRight="20dp"
            android:text="@string/delivered_time" />

        <EditText
            android:id="@+id/edTxtParcelDeliverTime"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:ems="10"
            android:paddingLeft="20dp" >
        </EditText>
    </LinearLayout>

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:gravity="center"
        android:orientation="horizontal" >

        <Button
            android:id="@+id/btnRecipient_OK"
            android:layout_width="100dp"
            android:layout_height="wrap_content"
            android:text="@android:string/ok" />
    </LinearLayout>

</LinearLayout>

This code is working but if i insert first alphabet and insert proper value then its not working because sourcecontains its previous character value.

此代码有效,但如果我插入第一个字母并插入正确的值,则它不起作用,因为source包含其先前的字符值。

回答by Adude11

Try casting the chars to ints, then test if they are greater than 24 and 60.

尝试将字符转换为整数,然后测试它们是否大于 24 和 60。

int a = ((int) result.charAt(0)) - 48;
int b = ((int) result.charAt(1)) - 48;
int c = ((int) result.charAt(3)) - 48;
if(a < 0 || b < 0 || c < 0) {
    Not right.
}

if((a > 2 || (a == 2 && b > 3)) || c > 59) {
    Neither is this.
}

Minus 48 because numbers 0 is 48th in the ascii table. The test has to be ascii.

减去 48,因为数字 0 在 ascii 表中是第 48 位。测试必须是ascii。

回答by Girish Nair

Instead of char why dont you use string, Because char can also be used for comparsion as it can return numbers

为什么不使用字符串而不是字符,因为字符也可以用于比较,因为它可以返回数字

char c ='a';
    if(c>10)
    //do something

    //OR
int x = c;

So why dont you use String instead of char

那么为什么不使用 String 而不是 char

or what you can do is, take 1st two chars using substring or something like that and use Integer.parse() method to parse it, if it successfully parsed then its a valid number else it is not so you can validate it and similarly do it for next two chars

或者你可以做的是,使用子字符串或类似的东西取第一个两个字符,并使用 Integer.parse() 方法来解析它,如果它成功解析,那么它是一个有效的数字,否则它不是这样你可以验证它并类似地做它用于接下来的两个字符

EDIT

编辑

If you wanted to implement like this 23:59 correct 24:05 incorrect 02:56 correct 02:79 incorrect

如果你想这样实现 23:59 正确 24:05 错误 02:56 正确 02:79 错误

Then here is the code that worked from my side

然后这是从我这边工作的代码

public class MainActivity extends Activity {
 InputFilter timeFilter;
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    timeFilter  = new InputFilter() {
        @Override
        public CharSequence filter(CharSequence source, int start, int end, Spanned dest,
                int dstart, int dend) {
            if (source.length() == 0) {
                return null;// deleting, keep original editing
            }
            String result = "";
            result += dest.toString().substring(0, dstart);
            result += source.toString().substring(start, end);
            result += dest.toString().substring(dend, dest.length());

            if (result.length() > 5) {
                return "";// do not allow this edit
            }
            boolean allowEdit = true;
            char c;
            if (result.length() > 0) {
                c = result.charAt(0);
                allowEdit &= (c >= '0' && c <= '2');
            }
            if (result.length() > 1) {
                c = result.charAt(1);
                if(result.charAt(0) == '0' || result.charAt(0) == '1')
                    allowEdit &= (c >= '0' && c <= '9');
                else
                    allowEdit &= (c >= '0' && c <= '3');
            }
            if (result.length() > 2) {
                c = result.charAt(2);
                allowEdit &= (c == ':');
            }
            if (result.length() > 3) {
                c = result.charAt(3);
                allowEdit &= (c >= '0' && c <= '5');
            }
            if (result.length() > 4) {
                c = result.charAt(4);
                allowEdit &= (c >= '0' && c <= '9');
            }
            return allowEdit ? null : "";
        }

    };

    EditText txt1 = (EditText) findViewById(R.id.edTxtParcelDeliverTime);
    txt1.setFilters(new InputFilter[]{timeFilter});
}
}

I have just taken your XML and placed as my mains layout AND there are no changes to XML Now try this and tell ?

我刚刚采用了您的 XML 并作为我的主要布局放置并且 XML 没有任何更改 现在试试这个并告诉 ?

EDIT 2Now here i have added a validtion for firs char check using doneOnce boolean value This works now, tell me if you have any other problem from this code now

编辑 2现在,我在这里使用 doneOnce 布尔值添加了对 firs 字符检查的验证 这现在有效,告诉我您现在是否有任何其他问题来自此代码

public class MainActivity extends Activity {
EditText edt1;
InputFilter timeFilter;
private String LOG_TAG = "MainActivity";
private boolean doneOnce = false;
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    timeFilter  = new InputFilter() {
        @Override
        public CharSequence filter(CharSequence source, int start, int end, Spanned dest,
                int dstart, int dend) {

            if(source.length() > 1 && doneOnce == false){
                source = source.subSequence(source.length()-1, source.length());
                if(source.charAt(0)  >= '0' && source.charAt(0) <= '2'){
                    doneOnce = true;
                    return source;
                }else{
                    return "";
                }
            }


            if (source.length() == 0) {
                return null;// deleting, keep original editing
            }
            String result = "";
            result += dest.toString().substring(0, dstart);
            result += source.toString().substring(start, end);
            result += dest.toString().substring(dend, dest.length());

            if (result.length() > 5) {
                return "";// do not allow this edit
            }
            boolean allowEdit = true;
            char c;
            if (result.length() > 0) {
                c = result.charAt(0);
                allowEdit &= (c >= '0' && c <= '2');
            }
            if (result.length() > 1) {
                c = result.charAt(1);
                if(result.charAt(0) == '0' || result.charAt(0) == '1')
                    allowEdit &= (c >= '0' && c <= '9');
                else
                    allowEdit &= (c >= '0' && c <= '3');
            }
            if (result.length() > 2) {
                c = result.charAt(2);
                allowEdit &= (c == ':');
            }
            if (result.length() > 3) {
                c = result.charAt(3);
                allowEdit &= (c >= '0' && c <= '5');
            }
            if (result.length() > 4) {
                c = result.charAt(4);
                allowEdit &= (c >= '0' && c <= '9');
            }
            return allowEdit ? null : "";
        }

    };


    edt1 = (EditText) findViewById(R.id.edTxtParcelDeliverTime);
    edt1.setFilters(new InputFilter[] { timeFilter });

}
}

回答by Ruchika

Try this, I simply edited the code you provided....

试试这个,我只是编辑了你提供的代码......

InputFilter[] timeFilter = new InputFilter[1];

timeFilter[0] = new InputFilter() {
    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {

        if (source.length() == 0) {
            return null;// deleting, keep original editing
        }

        String result = "";
        result += dest.toString().substring(0, dstart);
        result += source.toString().substring(start, end);
        result += dest.toString().substring(dend, dest.length());

        if (result.length() > 5) {
            return "";// do not allow this edit
        }

        boolean allowEdit = true;
        char c;
        if (result.length() > 0) {
            c = result.charAt(0);
            allowEdit &= (c >= '0' && c <= '2' && !(Character.isLetter(c)));
        }

        if (result.length() > 1) {
            c = result.charAt(1);
            allowEdit &= (c >= '0' && c <= '9' && !(Character.isLetter(c)));
        }

        if (result.length() > 2) {
            c = result.charAt(2);
            allowEdit &= (c == ':'&&!(Character.isLetter(c)));
        }

        if (result.length() > 3) {
            c = result.charAt(3);
            allowEdit &= (c >= '0' && c <= '5' && !(Character.isLetter(c)));
        }

        if (result.length() > 4) {
            c = result.charAt(4);
            allowEdit &= (c >= '0' && c <= '9'&& !(Character.isLetter(c)));
        }

        return allowEdit ? null : "";
    }
};

This works absolutely fine for me. Accepts time in format hh:mmonly (no other character accepted)

这对我来说绝对没问题。hh:mm仅接受格式中的时间(不接受其他字符)

回答by Milad Faridnia

I found this libraryfor time EditText. The code is easy to use. I add some explanations from the code owner:

我找到了这个图书馆的时间EditText。该代码易于使用。我添加了代码所有者的一些解释:

A custom EditText (actually derived from TextView) to input time in 24h format. Features:
- It always shows the currently set time, so it's never empty.

  • Both virtual and physical keyboards can be used.

  • The current digit is highlighted;

  • when a number on the keyboard is pressed, the digit is replaced.

  • Back key moves the cursor backward.

  • Space key moves the cursor forward.

一个自定义的 EditText(实际上是从 TextView 派生的)以 24 小时格式输入时间。特点:
- 它总是显示当前设置的时间,所以它永远不会为空。

  • 可以使用虚拟键盘和物理键盘。

  • 当前数字高亮显示;

  • 当按下键盘上的数字时,该数字将被替换。

  • 后退键将光标向后移动。

  • 空格键向前移动光标。

Here is the TimeEditTextClass:

这是TimeEditText类:

public class TimeEditText extends TextView {

private static final int POSITION_NONE = -1;

private int[] digits = new int[4];
private int currentPosition = POSITION_NONE;
private int mImeOptions;

public TimeEditText(Context context) {
    this(context, null, 0);
}

public TimeEditText(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
}

public TimeEditText(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    setFocusableInTouchMode(true);

    if (attrs != null && !isInEditMode()) {
        mImeOptions = attrs.getAttributeIntValue("http://schemas.android.com/apk/res/android", "imeOptions", 0);
    }

    updateText();       
}

/**
 * @return the current hour (from 0 to 23)
 */
public int getHour() {
    return digits[0]*10+digits[1];
}

/**
 * @return the current minute
 */
public int getMinutes() {
    return digits[2]*10+digits[3];
}

/**
 * Set the current hour
 * @param hour hour (from 0 to 23)
 */
public void setHour(int hour) {
    hour = hour % 24;
    digits[0] = hour/10;
    digits[1] = hour%10;
    updateText();
}

/**
 * Set the current minute
 * @param min minutes (from 0 to 59)
 */
public void setMinutes(int min) {
    min = min % 60;
    digits[2] = min/10;
    digits[3] = min%10;
    updateText();
}

@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
    // hide cursor if not focused
    currentPosition = focused ? 0 : POSITION_NONE;
    updateText();
    super.onFocusChanged(focused, direction, previouslyFocusedRect);
}   

private void updateText() {
    int bold = currentPosition > 1 ? currentPosition+1 : currentPosition;   
    int color = getTextColors().getDefaultColor();
    Spannable text = new SpannableString(String.format("%02d:%02d", getHour(), getMinutes()));
    if (bold >= 0) {
        text.setSpan(new ForegroundColorSpan(color & 0xFFFFFF | 0xA0000000), 0, 5, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        text.setSpan(new StyleSpan(Typeface.BOLD), bold, bold+1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        text.setSpan(new ForegroundColorSpan(Color.BLACK), bold, bold+1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        text.setSpan(new BackgroundColorSpan(0x40808080), bold, bold+1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    }
    setText(text);  
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_UP) {
        requestFocusFromTouch();
        InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.showSoftInput(this,0);
        if (currentPosition == POSITION_NONE) {
            currentPosition = 0;
            updateText();
        }
    }
    return true;
}   

private boolean onKeyEvent(int keyCode, KeyEvent event) {
    if (event != null && event.getAction() != KeyEvent.ACTION_DOWN)
        return false;

    if (keyCode == KeyEvent.KEYCODE_DEL) {  
        // moves cursor backward
        currentPosition = currentPosition >= 0 ? (currentPosition+3)%4 : 3;
        updateText();
        return true;
    }

    if (keyCode == KeyEvent.KEYCODE_SPACE) {
        // moves cursor forward
        currentPosition = (currentPosition+1)%4;
        updateText();
        return true;
    }

    if (keyCode == KeyEvent.KEYCODE_ENTER) {
        View v = focusSearch(FOCUS_DOWN);
        boolean next = v!=null;
        if (next) {
            next = v.requestFocus(FOCUS_DOWN);
        }         
        if (!next) {
            hideKeyboard();
            currentPosition = POSITION_NONE;
            updateText();
        }
        return true;
    }       

    char c = (char) event.getUnicodeChar();  
    if (c >= '0' && c <= '9') {
        currentPosition = currentPosition == POSITION_NONE ? 0 : currentPosition;
        int n = c - '0';
        boolean valid = false;

        switch (currentPosition) {
            case 0: // first hour digit must be 0-2
                valid = n <= 2;
                break;
            case 1: // second hour digit must be 0-3 if first digit is 2
                valid = digits[0] < 2 || n <= 3;
                break;
            case 2: // first minute digit must be 0-6
                valid = n < 6;
                break;
            case 3: // second minuti digit always valid (0-9)
                valid = true;
                break;
        }

        if (valid) {
            if (currentPosition == 0 && n == 2 && digits[1] > 3) { // clip to 23 hours max
                digits[1] = 3;
            }

            digits[currentPosition] = n;
            currentPosition = currentPosition < 3 ? currentPosition+1 : POSITION_NONE;  // if it is the last digit, hide cursor
            updateText();
        }

        return true;
    }

    return false;
}

private void hideKeyboard() {
    InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
    imm.hideSoftInputFromWindow(getWindowToken(), 0);        
}


@Override
public boolean onKeyDown(int keyCode, KeyEvent event) { 
    // events from physical keyboard
    return onKeyEvent(keyCode, event);
}

@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
    // manage events from the virtual keyboard
    outAttrs.actionLabel = null;
    outAttrs.label = "time";
    outAttrs.inputType = InputType.TYPE_CLASS_NUMBER;
    outAttrs.imeOptions = mImeOptions | EditorInfo.IME_FLAG_NO_EXTRACT_UI;

    if ((outAttrs.imeOptions & EditorInfo.IME_MASK_ACTION) == EditorInfo.IME_ACTION_UNSPECIFIED) {
        if (focusSearch(FOCUS_DOWN) != null) {
            outAttrs.imeOptions |= EditorInfo.IME_ACTION_NEXT;
        } else {
            outAttrs.imeOptions |= EditorInfo.IME_ACTION_DONE;
        }
    }

    return new BaseInputConnection(this, false) {
        @Override
        public boolean performEditorAction(int actionCode) {
            if (actionCode == EditorInfo.IME_ACTION_DONE) {
                hideKeyboard();
                currentPosition = POSITION_NONE;
                updateText();
            } else if (actionCode == EditorInfo.IME_ACTION_NEXT){
                View v = focusSearch(FOCUS_DOWN);
                if (v!=null) {
                    v.requestFocus(FOCUS_DOWN);
                }
            }
            return true;
        }

        @Override
        public boolean deleteSurroundingText(int beforeLength, int afterLength) {
            onKeyEvent(KeyEvent.KEYCODE_DEL, null); 
            return true;
        }

        @Override
        public boolean sendKeyEvent(KeyEvent event) {
            onKeyEvent(event.getKeyCode(), event);
            return true;
        }           
     };
 }
}

You must add this lines to your view:

您必须将此行添加到您的视图中:

<YourPackageName.TimeEditText
            android:id="@+id/satOpenEditText"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:layout_marginRight="10dp"
            android:layout_weight="1"
            android:ems="10"
            android:inputType="time"
            android:textSize="16sp" />

回答by Prason Ghimire

//THis handles the input for the date and time at the runtime and all the //invalid atttempt are automatically consumed
//this is an alternative to regex expression that you can implement

//这在运行时处理日期和时间的输入,所有 //无效的尝试都会自动消耗
//这是您可以实现的正则表达式的替代方案

//using the input regulation for the time data
    timeField.addTextChangedListener(new TextWatcher() {
        String beforeTXT;
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                Log.i("before TEXT TEXXT", " this : "+s+" and "+start+" and "+count+"and "+after);
                beforeTXT= ""+s;
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            int input ;

            //first determine whether user is at hrs side or min side
            if (s.toString().equals("")){
                return;
            }
            if(s.toString().length()>2 && start<=2){ //means the user is at hour side
                input = Integer.parseInt(s.toString().substring(0,1)) % 10;

            }
            else if(s.toString().length()>2 && start>=3) {//means that user is at min side
                input = Integer.parseInt("0"+s.toString().substring(3))%10;

            }
            else if(s.toString().indexOf(":")==1){ // if we have for eg 1: or 0: then we take first character for parsing
                input = Integer.parseInt(s.toString().charAt(0)+"");
            }
            else{ //else it is default where the user is at first position
                input = Integer.parseInt(s.toString()) % 10;
            }

            //Special case where 00: is autommatically converted to 12: in 12hr time format
            if(s.toString().contains("00:")){
                Log.i("INsisde )))","i am called ");
                timeField.setText("12:");
               return;
            }

            //Now we manipulate the input and its formattin and cursor movement
            if(input<=1 && start ==0){ //thiis is for first input value to check .... time shouldnt exceed 12 hr
                //do nothing
            }
            else if (input>1 && start==0){ //if at hour >1 is press then automaticc set the time as 02: or 05: etc
             timeField.setText("0"+s+":");
            }
            else if(input>2 && start==1 && !s.toString().startsWith("0")){ //whe dont have greater than 12 hrs so second postionn shouldn't exceed value 2
                timeField.setText(beforeTXT);
            }
            else if(start==1 && !beforeTXT.contains(":")){  //if valid input 10 or 11 or 12 is given then convert it to 10: 11: or 12:
                timeField.setText(s.toString()+":");

                if(s.toString().length()==1 && s.toString().startsWith("0")){
                timeField.setText("");
                }
                if(s.toString().startsWith("1")&& s.toString().length()==1){ //on back space convert 1: to 01:
                    timeField.setText("0"+timeField.getText().toString());
                }

           }
            else if(start == 3 && input >5 ){ //min fig shouldn't exceed 59 so ...if at first digit of min input >5 then do nothing or codpy the earlier text
                timeField.setText(beforeTXT);
            }
           else if (start>4 && s.toString().length()>5){ // the total string lenght shouldn't excced 5
                timeField.setText(beforeTXT);
            }
            else if(start<2 && beforeTXT.length()>2){
                timeField.setText(beforeTXT);

            }


        }

        @Override
        public void afterTextChanged(Editable s) {

            Log.i("after  TEXT TEXXT", " this : "+s);
            timeField.setSelection(timeField.getText().toString().length());

        }
    });