可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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.
edit.setInputType(InputType.TYPE_DATETIME_VARIATION_TIME)
Even android:text="time"
is also not working.
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.
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.
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
<?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 source
contains its previous character value.
回答1:
Try casting the chars to ints, then test if they are greater than 24 and 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.
回答2:
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
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
EDIT
If you wanted to implement like this
23:59 correct
24:05 incorrect
02:56 correct
02:79 incorrect
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 ?
EDIT 2
Now 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
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 });
}
}
回答3:
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:mm
only (no other character accepted)
回答4:
I found this library for time EditText
.
The code is easy to use. I add some explanations from the code owner:
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.
Here is the TimeEditText
Class:
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" />
回答5:
//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());
}
});