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; }
}
Когда я нажимаю на первый редактируемый текст (см. рисунок), редактируемый текст перемещается на тот, который находится под смайликом.
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)
Дает правильный номер позиции и вы можете вносить изменения в зависимости от номера позиции.