Страницы

Поиск по вопросам

четверг, 12 декабря 2019 г.

Действие на потерю фокуса в `EditText`

#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); ArrayList groups = 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"

Комментариев нет:

Отправить комментарий