0

В CustomDialog создан CustomAdapter

Кастом адаптер создаёт поля с элементами EditText и Button.

Поля EditText заполняются из arrayAdapter.

Когда по нажатию на кнопку создаёшь несколько едиттекстов в листвью и прокручиваешь список вниз, те элементы, которые ушли за экран, очищаются от данных.

Исходный экран

первое

Создали парочку едитТекстов по нажатию на "+"

второе

Прокрутили вниз списка и вернулись наверх

третье

Код с адаптера:

public class CustomDialogAdapter extends ArrayAdapter<ItemNotify> {

private Context context;
ArrayList<ItemNotify> arrayList;
long id_pray;
InputFilter timeFilter;
private boolean doneOnce = false;

public CustomDialogAdapter(Context context, ArrayList<ItemNotify> arrayList, long id_pray) {
    super(context, R.layout.activity_custom_dialog, arrayList);
    this.context = context;
    this.arrayList = arrayList;
    this.id_pray = id_pray;
}

static class ViewHolder {
    public EditText editText;
    public Button delete;
    public Button add;
    public LinearLayout lay;
    public TextView txposition;
}

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    final ViewHolder holder;
    View rowView = convertView;
    if (rowView == null) {
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        rowView = inflater.inflate(R.layout.item_for_customdialog_adapter, null, true);
        holder = new ViewHolder();
        holder.txposition = (TextView) rowView.findViewById(R.id.textViewItem2);

        holder.editText = (EditText) rowView.findViewById(R.id.editTextItem2);
        holder.delete = (Button) rowView.findViewById(R.id.button);
        holder.add = (Button) rowView.findViewById(R.id.button2);
        holder.lay = (LinearLayout) rowView.findViewById(R.id.lay);

        rowView.setTag(holder);
    } else {
        holder = (ViewHolder) rowView.getTag();
    }

    holder.txposition.setText((position + 1)+"");
    holder.editText.setText(getItem(position).time);
    holder.editText.addTextChangedListener(new MyTextWatcher(position));

    return rowView;
}


private class MyTextWatcher implements TextWatcher {
    private int position;

    public MyTextWatcher(int position) {
        this.position = position;
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {

    }

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

    }

    public void afterTextChanged(Editable s) {
        Log.e("edit", "edit " + s);
        arrayList.get(position).time = s.toString();

        if (arrayList.get(position).en != StatusNotifi.NEW) {
            arrayList.get(position).en = StatusNotifi.EDIT;
        }
    }
}
}

Спасибо за совет, pavlofff

UPD: сделал. Это уже рабочий код класса

public class CustomDialogAdapter extends ArrayAdapter<ItemNotify> {

private Context context;
ArrayList<ItemNotify> arrayList;
long id_pray;
InputFilter timeFilter;
private boolean doneOnce = false;

public CustomDialogAdapter(Context context, ArrayList<ItemNotify> arrayList, long id_pray) {
    super(context, R.layout.activity_custom_dialog, arrayList);
    this.context = context;
    this.arrayList = arrayList;
    this.id_pray = id_pray;
}

static class ViewHolder { // класс для кеширования вьюшек, чтоб они каждый раз не пересоздавались
    public EditText editText;// поле ввода
    public Button delete;    // удаление поля ввода
    public Button add;  // добавление поля ввода
    public LinearLayout lay; // слой, нужен чтоб при удалении поля удалялся весь слой
    public TextView txposition; //нумерация полей
}

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    final ViewHolder holder;
    View rowView = convertView;
    if (rowView == null) {
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        rowView = inflater.inflate(R.layout.item_for_customdialog_adapter, null, true);

        holder = new ViewHolder();
        holder.txposition = (TextView) rowView.findViewById(R.id.textViewItem2);
        holder.editText = (EditText) rowView.findViewById(R.id.editTextItem2);
        holder.delete = (Button) rowView.findViewById(R.id.button);
        holder.add = (Button) rowView.findViewById(R.id.button2);
        holder.lay = (LinearLayout) rowView.findViewById(R.id.lay);

        rowView.setTag(holder); // установили тэг на элемент
    } else {
        holder = (ViewHolder) rowView.getTag(); // получили нужный элемент по тэгу
    }

    holder.txposition.setText((position < 9 ? "0" : "") + (position + 1)+".");// для выравнивания размера добавляем 0, позиция идёт с 0

    if (position == 0) { // на 0-й позиции кнопку удаления скрываем, чтоб нельзя было удалить все поля
        holder.delete.setVisibility(View.INVISIBLE);
    }else{
        holder.delete.setVisibility(View.VISIBLE);
    }

    timeFilter = new InputFilter() { // фильтр ввода. позволяет вводить от 00:00 до 23:59
        @Override
        public CharSequence filter(CharSequence source, int start, int end, Spanned dest,
                                   int dstart, int dend) {

            if (source.length() > 1 && !doneOnce) {
                source = source.subSequence(source.length() - 1, source.length());
                if (source.charAt(0) >= '0' && source.charAt(0) <= '2') { // первый символ может быть 0,1,2
                    doneOnce = true; //флаг первого символа в editText
                    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) { // если в поле 5 символов( 1 2 : 4 5 )
                return "";// не разрешать добавлять символы
            }
            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 : "";
        }
    };

    holder.editText.clearFocus(); // снимаем фокусировку(выполнится, когда мы начнём прокручивать список и отрисуется новый элемент)
    holder.editText.setText(getItem(position).time); //установка времени с массива arrayList

    if (arrayList.get(position).editDisabled == 1) { //если поле = 1 ("не удаляемое")
        holder.editText.setFocusable(false); //не фокусить
        holder.editText.setClickable(false); //не кликать
        holder.editText.setFocusableInTouchMode(false);
        holder.delete.setVisibility(View.INVISIBLE); //кнопку Х убрать
    } else { //если поле удаляемое
        holder.editText.setFilters(new InputFilter[]{timeFilter}); // установили наш фильтр полю
        holder.editText.setOnFocusChangeListener(new View.OnFocusChangeListener() { // слушатель смены фокуса на полях
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                Log.e("edit", "edit: " + hasFocus);
                if(hasFocus) return; // пока есть фокус на поле, которое заполняем, делаем прерывание

                EditText ed = (EditText) v; // находим адрес поля(берём с принимаемых аргументов)
                arrayList.get(position).time = ed.getText().toString(); // вносим данные с текущего поля

                if (arrayList.get(position).en != StatusNotifi.NEW) { // метка статуса поля массива
                    arrayList.get(position).en = StatusNotifi.EDIT; //(новое или изменённое)
                }
            }
        });
    }

    holder.delete.setOnClickListener(new View.OnClickListener() {  //реализация удаления поля
        @Override
        public void onClick(View v) {
            holder.lay.setVisibility(View.GONE);  //спрятали наш слой
            arrayList.get(position).en = StatusNotifi.DELETED; //дали статус поля "удалённое"
        }
    });

    holder.add.setOnClickListener(new View.OnClickListener() { //реализация добавления поля
        @Override
        public void onClick(View v) {
            arrayList.add(new ItemNotify(StatusNotifi.NEW, id_pray)); //добавили объект в массив
            CustomDialogAdapter.this.notifyDataSetChanged(); // и уведомили адаптер об этом
        }
    });

    return rowView;
}
}
zayn1991
  • 857

1 Answers1

1

Элементы списка, уходящие за экран - уничтожаются и затем пересоздаются если вернуться. getView перевызывается при скролле заново для каждого элемента, у вас он, видимо, неправильно наполняет view. Проверьте логом или дебагом что во время скролла на моменте holder.editText.setText(getItem(position).time) массив с данными не пустой.
И совсем не обязательно хранить контекст и arrayList у себя, они есть в родителе.

Nakrul
  • 76
  • 2
    Вышедшие за пределы экрана айтемы как раз не уничтожаются, а используются повторно для отображения айтемов на экране. Всего создается, к примеру 8 экземпляров (объектов) View и именно эти и только эти 8 экземпляров, многократно переиспользуются для спика хоть из 1000 позиций. Никакой речи о уничтожении старого и создании нового View здесь не идет, иначе такой список очень быстро упал бы по OoME,а до этого времени тормозил бы жутко. – pavlofff May 15 '16 at 03:09
  • @Nakrul дополнил код – zayn1991 May 16 '16 at 07:31