#android #android_edittext
У меня есть несколько EditText,и мне нужно проверять на валидность когда фокус теряется. Вот сам код: public class ExpandableListAdapter extends BaseExpandableListAdapter { String[] countries; private Context _context; private List_listDataHeader; private HashMap > _listDataChild; String[] data; public static EditText etBookingName; public static EditText etBookingLastname; public static EditText etBookingBirthday; public static AutoCompleteTextView etBookingNationality; public static Spinner spinner; public static EditText etBookingPassport; public static EditText etExpiryDate; public ExpandableListAdapter(Context context, List listDataHeader, HashMap > listChildData) { this._context = context; this._listDataHeader = listDataHeader; this._listDataChild = listChildData; } @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, а мне нужно чтобы валидация срабатывала когда фокус теряется! Вопрос: Что я пропустил?
Ответы
Ответ 1
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); ArrayListgroups = new ArrayList<>(); groups.add("Group 1"); groups.add("Group 2"); Adapter adapter = new Adapter(this, groups); listView.setAdapter(adapter); } } Adapter: public class Adapter extends BaseExpandableListAdapter { private final Context mContext; private ArrayList groups = new ArrayList<>(); private ArrayList views = new ArrayList<>(); private ArrayList nameEditTexts = new ArrayList<>(); private ArrayList lastNameEditTexts = new ArrayList<>(); private ArrayList birthdayEditTexts = new ArrayList<>(); private ArrayList passportEditTexts = new ArrayList<>(); public Adapter(Context context, ArrayList groups) { mContext = context; for (int i = 0; i < groups.size(); i++) { initGroup(groups.get(i)); } addOnFocusChangeListeners(onFocusChangeListener); } 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 list, View v) { for (int i = 0; i < list.size(); i++) { if (list.get(i) == v) return true; } return false; } 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 я добавил очистку полей, чтобы при следующем открытии они были пустыми и не провалидированными, этого можно и не делать, в зависимости от необходимого поведения. Остальное должно быть понятно из названий функций. Если возникнут вопросы, отвечу на них в комментариях к ответу. Ответ 2
final EditText editText = (EditText) findViewById(R.id.edit); editText.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { if (v == editText && hasFocus == false) { .... } } });Ответ 3
в Manifest прописать android:windowSoftInputMode="adjustPan" для вашей активити в listview прописать android:descendantFocusability="afterDescendants" в editText прописать android:focusable="true", android:focusableInTouchMode="true"
Комментариев нет:
Отправить комментарий