Android Обработка многих полей EditText в ListView

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

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

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

Как я могу отслеживать поля EditText в их правильном положении?

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

Текст для каждого EditText хранится в глобальном массиве строк, называемом строками. Первоначально он пуст и обновляется моим классом 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 (см. Рисунок), EditText смещается на тот, что под смайликом.

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

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 будет иметь ссылку на объект данных, на который ссылаются. При прокрутке текстовые поля редактирования должны обновляться с текущими данными, а изменения текста должны сохраняться. Вы можете отслеживать, какие объекты были изменены пользователем, чтобы сделать обновления данных / сети более эффективными.

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

Чтобы использовать позицию 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;
    }
};

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

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

У меня есть данные в одном массиве String, а не в многомерном массиве. Причина в том, что модель данных, поддерживающая 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;
    }
}

Я не уверен, что у вас хороший дизайн, так как контент EditText будет иметь хорошие шансы на проблемы (перетасовывание контента, пропущенный текст) после прокрутки списка. попробуйте попробовать идею M6TT.

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

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

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

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

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

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

В обзоре -

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

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

в вашем afterTextChanged -

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

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

Другие вопросы по тегам