У меня есть несколько EditText,и мне нужно проверять на валидность когда фокус теряется.
Вот сам код:
public class ExpandableListAdapter extends BaseExpandableListAdapter {
String[] countries;
private Context _context;
private List
public ExpandableListAdapter(Context context, List
@Override
public Object getChild(int groupPosition, int childPosititon) {
return this._listDataChild.get(this._listDataHeader.get(groupPosition))
.get(childPosititon);
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
@Override
public View getChildView(int groupPosition, final int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater infalInflater = (LayoutInflater) this._context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = infalInflater.inflate(R.layout.booking_list_items, null);
convertView.findViewById(R.id.etBookingNationality);
etBookingName = (EditText) convertView.findViewById(R.id.etBookingName);
etBookingLastname = (EditText) convertView.findViewById(R.id.etBookingLastname);
etBookingBirthday = (EditText) convertView.findViewById(R.id.etBookingBirthday);
etBookingPassport = (EditText) convertView.findViewById(R.id.etBookingPassport);
rgBookingGender = (RadioGroup) convertView.findViewById(R.id.rgBookingGender);
etExpiryDate = (EditText) convertView.findViewById(R.id.etDocumentExpiryDate);
etBookingNationality.setAdapter(nationAdapter);
etBookingBirthday.addTextChangedListener(Mask.insert("##.##.####", etBookingBirthday));
etExpiryDate.addTextChangedListener(Mask.insert("##.##.####", etExpiryDate));
}
});
@Override
public void onNothingSelected(AdapterView parent) {
}
});
etBookingName.setOnFocusChangeListener(validate);
etBookingLastname.setOnFocusChangeListener(validate);
etBookingBirthday.setOnFocusChangeListener(validate);
etBookingPassport.setOnFocusChangeListener(validate);
etExpiryDate.setOnFocusChangeListener(validate);
etBookingNationality.setOnFocusChangeListener(validate);
}
return convertView;
}
View.OnFocusChangeListener validate = new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if(v == etBookingName && !hasFocus) {
validation_name(etBookingName);
}
else if(v == etBookingLastname && !hasFocus) {
validation_last_name(etBookingLastname);
}
else if (v == etBookingBirthday && !hasFocus) {
validation_birthday(etBookingBirthday);
}
else if (v == etBookingPassport && !hasFocus) {
validation_passport(etBookingPassport);
}
else if (v == etExpiryDate && !hasFocus) {
validation_expiry(etExpiryDate);
}
else if(v == etBookingNationality && !hasFocus) {
validation_nation(etBookingNationality);
}
}
};
А Валидации типа этого:
static void validation_name(EditText edit) throws NumberFormatException {
String name = edit.getText().toString();
if (name.length() == 0) {
edit.setError("Введите имя");
} else if (!name.matches("[a-zA-Z ]+")) {
edit.setError("Введите имя латинскими буквами");
}
}
static void validation_last_name(EditText edit) throws NumberFormatException {
String lastName = edit.getText().toString();
if (lastName.length() == 0) ........
Не работает, точнее валидация срабатывает когда просто кликаешь на EditText, а мне нужно чтобы валидация срабатывала когда фокус теряется!
Вопрос: Что я пропустил?
Ответ
UPD_1 (дабы не засорять ответ лишней информацией удалил все не относящееся к решению проблемы)
После некоторых экспериментов выяснилось, что при клике на EditText находящийся внутри группы в ExpandableListView фокус скачет несколько раз подряд, то появляется, то пропадает. Внутри других компонентов такого поведения замечено не было.
У меня не получилось решить эту проблему стандартными средствами андроид, поэтому я написал небольшой костыль, работающий как часы и решающий данную проблему.
На словах решение выглядит так:
Проинициализировать все части компонента в конструкторе адаптера, в переопределенных методах из BaseExpandableListAdapter (таких как getGroupView, getChildView и т.п.) возвращать проинициализированные ранее части компонента
При изменении фокуса на 200 миллисекунд отписываться от события смены фокуса, потом опять подписываться
Вот полностью работоспособный пример с двумя группами:
MainActivity:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ExpandableListView listView = (ExpandableListView)findViewById(R.id.listView);
listView.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
ArrayList
Adapter:
public class Adapter extends BaseExpandableListAdapter {
private final Context mContext;
private ArrayList
public Adapter(Context context, ArrayList
private void initGroup(String groupTitle) {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ViewGroup group = (ViewGroup) inflater.inflate(R.layout.group, null);
TextView textGroup = (TextView) group.findViewById(R.id.textGroup);
textGroup.setText(groupTitle);
groups.add(group);
initGroupContent();
}
private void initGroupContent() {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View groupContent = inflater.inflate(R.layout.item, null);
views.add(groupContent);
nameEditTexts.add((EditText) groupContent.findViewById(R.id.nameEditText));
lastNameEditTexts.add((EditText) groupContent.findViewById(R.id.lastNameEditText));
birthdayEditTexts.add((EditText) groupContent.findViewById(R.id.birthdayEditText));
passportEditTexts.add((EditText) groupContent.findViewById(R.id.passportEditText));
}
private void addOnFocusChangeListeners(View.OnFocusChangeListener listener) {
for (int i = 0; i < groups.size(); i++) {
nameEditTexts.get(i).setOnFocusChangeListener(listener);
lastNameEditTexts.get(i).setOnFocusChangeListener(listener);
birthdayEditTexts.get(i).setOnFocusChangeListener(listener);
passportEditTexts.get(i).setOnFocusChangeListener(listener);
}
}
View.OnFocusChangeListener onFocusChangeListener = new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
addOnFocusChangeListeners(null);
startTimer();
return;
}
EditText edit = (EditText) v;
if (hasEditText(nameEditTexts, v)) validateName(edit);
else if (hasEditText(lastNameEditTexts, v)) validateLastName(edit);
else if (hasEditText(birthdayEditTexts, v)) validateBirthday(edit);
else if (hasEditText(passportEditTexts, v)) validatePassport(edit);
}
};
private boolean hasEditText(ArrayList
private void startTimer() {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
addOnFocusChangeListeners(onFocusChangeListener);
}
}, 200);
}
static void validateName(EditText edit) {
String text = edit.getText().toString();
if (text.length() == 0) edit.setError("Name error text");
else edit.setError(null);
}
static void validateLastName(EditText edit) {
String text = edit.getText().toString();
if (text.length() == 0) edit.setError("LastName error text");
else edit.setError(null);
}
static void validateBirthday(EditText edit) {
String text = edit.getText().toString();
if (text.length() == 0) edit.setError("Birthday error text");
else edit.setError(null);
}
static void validatePassport(EditText edit) {
String text = edit.getText().toString();
if (text.length() == 0) edit.setError("Passport error text");
else edit.setError(null);
}
@Override
public void onGroupCollapsed(int groupPosition) {
nameEditTexts.get(groupPosition).setError(null);
lastNameEditTexts.get(groupPosition).setError(null);
birthdayEditTexts.get(groupPosition).setError(null);
passportEditTexts.get(groupPosition).setError(null);
nameEditTexts.get(groupPosition).setText("");
lastNameEditTexts.get(groupPosition).setText("");
birthdayEditTexts.get(groupPosition).setText("");
passportEditTexts.get(groupPosition).setText("");
}
@Override
public void onGroupExpanded(int groupPosition) {
nameEditTexts.get(groupPosition).setError(null);
lastNameEditTexts.get(groupPosition).setError(null);
birthdayEditTexts.get(groupPosition).setError(null);
passportEditTexts.get(groupPosition).setError(null);
}
@Override
public int getGroupCount() {
return groups.size();
}
@Override
public int getChildrenCount(int groupPosition) {
return 1;
}
@Override
public Object getGroup(int groupPosition) {
return groups.get(groupPosition);
}
@Override
public Object getChild(int groupPosition, int childPosition) {
return views.get(groupPosition);
}
@Override
public long getGroupId(int groupPosition) {
return 1;
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return 1;
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
return groups.get(groupPosition);
}
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
return views.get(groupPosition);
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return false;
}
}
group.xml:
item.xml:
Примечание: в классе Adapter в функциях onGroupCollapsed и onGroupExpanded я добавил очистку полей, чтобы при следующем открытии они были пустыми и не провалидированными, этого можно и не делать, в зависимости от необходимого поведения.
Остальное должно быть понятно из названий функций. Если возникнут вопросы, отвечу на них в комментариях к ответу.
Комментариев нет:
Отправить комментарий