Android обрабатывает множество полей EditText в ListView


Только основной вопрос: если у меня есть несколько десятков полей EditText, которые являются частью ListAdapter, как отдельные поля EditText могут знать, к какой строке они принадлежат?

В настоящее время я использую TextWatcher для прослушивания ввода текста. Я попытался расширить TextWatcher, чтобы я мог передать позицию EditText конструктору TextWatcher.

Однако, когда появляется мягкая клавиатура, позиции, соответствующие различным полям EditText, перемешиваются.

Как можно ли отследить правильное расположение полей EditText?

Я использую GridView, чтобы разложить все по полочкам. Макет каждого элемента представляет собой ImageView С полем TextView и EditText под ним.

Текст для каждого EditText хранится в глобальном строковом массиве, называемом strings. Он изначально пуст и обновляется моим классом TextWatcher.

public void initList()
    {
        ArrayAdapter<String> listAdapter = new ArrayAdapter<String>(this, R.layout.shape, strings)
        {
            @Override
            public View getView(final int position, View convertView, ViewGroup parent)  {
                if (convertView == null)  {
                    convertView = LayoutInflater.from(getContext()).inflate(R.layout.shape, null);
                }
                final String theData = getItem(position);
                final EditText editText = (EditText) convertView.findViewById(R.id.shape_edittext);
                editText.setText(theData);
                editText.addTextChangedListener(
                        new MyTextWatcher(position, editText)
                );

                ImageView image = (ImageView) convertView.findViewById(R.id.shape_image);
                image.setBackgroundResource(images[position]);

                TextView text = (TextView) convertView.findViewById(R.id.shape_text);
                if (gameType == SHAPES_ABSTRACT)
                    text.setText("Seq:");
                else
                    text.setVisibility(View.GONE);  

                return convertView;
            }

            @Override
            public String getItem(int position) {        return strings[position];       }
        };

        grid.setAdapter(listAdapter);
    }


private class MyTextWatcher implements TextWatcher {
    private int index;
    private EditText edittext;
    public MyTextWatcher(int index, EditText edittext) { 
               this.index = index; 
               this.edittext = edittext;    
        }
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
    public void onTextChanged(CharSequence s, int start, int before, int count) {}
    public void afterTextChanged(Editable s) {  strings[index] = s.toString();      }
    public void setIndex(int newindex) {  index = newindex;    }
}

Когда я нажимаю на первый редактируемый текст (см. рисунок), редактируемый текст перемещается на тот, который находится под смайликом.

Показывает, как расположены поля EditText

5 6

5 ответов:

Не принимая во внимание, если это хороший дизайн пользовательского интерфейса, вот как вы это сделаете:

public class TestList
{
    public void blah()
    {
        ArrayAdapter<DataBucket> listAdapter = new ArrayAdapter<DataBucket>()
        {

            @Override
            public View getView(int position, View convertView, ViewGroup parent)
            {
                if (convertView == null)
                {
                    convertView = LayoutInflater.from(getContext()).inflate(R.layout.testlayout, null);
                }

                final DataBucket dataBucket = getItem(position);
                final EditText editText = (EditText) convertView.findViewById(R.id.theText);
                editText.setText(dataBucket.getSomeData());
                editText.addTextChangedListener(new TextWatcher()
                {
                    public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2)
                    {

                    }

                    public void onTextChanged(CharSequence charSequence, int i, int i1, int i2)
                    {

                    }

                    public void afterTextChanged(Editable editable)
                    {
                        dataBucket.setSomeData(editable.toString());
                    }
                });

                return convertView;
            }
        };
    }

    public static class DataBucket
    {
        private String someData;

        public String getSomeData()
        {
            return someData;
        }

        public void setSomeData(String someData)
        {
            this.someData = someData;
        }
    }
}

"DataBucket" - это заполнитель. Вы должны использовать любой созданный вами класс для хранения данных, которые вводятся и редактируются в редактируемом тексте. TextWatcher будет иметь ссылку на объект данных, на который ссылается. По мере прокрутки текстовые поля редактирования должны обновляться текущими данными, а изменения текста должны сохраняться. Вы можете захотеть отследить, какие объекты были изменены пользователем на сделайте обновления данных / сети более эффективными.

* Edit *

Чтобы использовать позицию int вместо прямой ссылки на объект:

ArrayAdapter<DataBucket> listAdapter = new ArrayAdapter<DataBucket>()
{

    @Override
    public View getView(final int position, View convertView, ViewGroup parent)
    {
        if (convertView == null)
        {
            convertView = LayoutInflater.from(getContext()).inflate(R.layout.testlayout, null);
        }

        final DataBucket dataBucket = getItem(position);
        final EditText editText = (EditText) convertView.findViewById(R.id.theText);
        editText.setText(dataBucket.getSomeData());
        editText.addTextChangedListener(new TextWatcher()
        {
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2)
            {

            }

            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2)
            {

            }

            public void afterTextChanged(Editable editable)
            {
                getItem(position).setSomeData(editable.toString());
            }
        });

        return convertView;
    }
};

* Снова Редактировать *

Я чувствую себя обязанным сказать для потомков, что на самом деле я бы не стал кодировать его таким образом. Я бы предположил, что вы хотите немного более структурированные данные, чем строковый массив, и вы поддерживаете строковый массив снаружи, а также ArrayAdapter, так что это своего рода странная параллельная ситуация. Тем не менее, это будет работать отлично.

У меня есть данные в одном строковом массиве, а не в многомерном массиве. Причина в том, что модель данных, поддерживающая GridView, - это всего лишь простой список. Это может показаться нелогичным, но так оно и есть. GridView должен сделать макет сам, и если оставить его на свои собственные устройства, будет заполнять строку с переменным числом ячеек, в зависимости от того, сколько данных у вас есть и насколько широк ваш экран (AFAIK).

Хватит болтать. Код:

public class TestList extends Activity
{
    private String[] guess;

    //Other methods in here, onCreate, etc

    //Call me from somewhere else. Probably onCreate.
    public void initList()
    {
        ArrayAdapter<String> listAdapter = new ArrayAdapter<String>(this, /*some resourse id*/, guess)
        {

            @Override
            public View getView(final int position, View convertView, ViewGroup parent)
            {
                if (convertView == null)
                {
                    convertView = LayoutInflater.from(getContext()).inflate(R.layout.testlayout, null);
                }

                final String theData = getItem(position);
                final EditText editText = (EditText) convertView.findViewById(R.id.theText);
                editText.setText(theData);
                editText.addTextChangedListener(
                        new MyTextWatcher(position)
                );

                return convertView;
            }
        };

        gridView.setAdapter(listAdapter);
    }

    class MyTextWatcher extends TextWatcher {
         private int position;

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

         public void afterTextChanged(Editable s) {
                 guess[position] = s.toString();
         }

     // other methods are created, but empty
    }
}

Чтобы отслеживать номер строки, каждый слушатель в EditText должен сохранить ссылку на элемент в списке и использовать getPosition(item), чтобы получить позицию в ListView. В моем примере используется Button, но я думаю, что его можно применить к EditText.

class DoubleAdapter extends ArrayAdapter<Double> {
    public DoubleAdapter(Context context, List<Double> list) {
        super(context, android.R.layout.simple_list_item_1, list);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
            convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_row, null);
        }

        // keep a reference to an item in a list
        final Double d = getItem(position);

        TextView lblId = (TextView) convertView.findViewById(R.id.lblId);
        lblId.setText(d.toString());

        Button button1 = (Button) convertView.findViewById(R.id.button1);
        button1.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // the button listener has a reference to an item in the list
                // so it can know its position in the ListView
                int i = getPosition(d);
                Toast.makeText(getContext(), "" + i, Toast.LENGTH_LONG).show();
                remove(d);
            }
        });

        return convertView;
    }
}

Может быть, стоит подумать, Нужно ли сохранять редактируемые тексты в ячейках списка? Это кажется немного ненужным, когда пользователь будет редактировать только один за раз.

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

Я не уверен, что это хороший дизайн, так как у редактируемого текстового контента будет хороший шанс возникновения проблем (перетасовка содержимого, отсутствие текста) после прокрутки вашего listview. подумайте о том, чтобы попробовать идею m6tt.

Но если вы действительно хотите идти своим путем, можете ли вы опубликовать какой-то код, в частности, вашего TextWatcher?

Я попытался решить эту проблему, и, как вы можете видеть, есть простой метод - я публикую ответ здесь, поскольку он может быть полезен для кого-то.

Не удается получить позицию, когда вид списка - > редактировать текст имеет текстовый наблюдатель.

Это решение, которое сработало для меня:

В get view -

Когда я добавляю прослушиватель text watcher для редактирования текста, я также добавил нижеприведенную строку

edittext.setTag(R.id.position<any unique string identitiy>, position)

В вашем afterTextChanged -

 int position = edittext.getTag(R.id.position) 

Дает правильный номер позиции и вы можете вносить изменения в зависимости от номера позиции.