List Adapter中的EditText,如何保存值?

时间:2013-10-29 18:50:29

标签: java android listview android-arrayadapter

所以,我有一个自定义适配器,每行都有两个EditText字段。

除了将值保存在ArrayList中之外,我已经让大部分内容正常工作。

这是我到目前为止所做的代码:

private void holderTitleSavedOnScroll(final int position, IZUICartViewHolder holder) {
    if (!(position == (variantArrayList.size() - 1)) && holder.title != null) {
        holder.title.setText(variantArrayList.get(position).getVariantTitle());
        final int finalPosition = position;
        holder.title.setOnFocusChangeListener(new OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                    final EditText newVariant = (EditText) v;
                    variantArrayList.get(finalPosition).setVariantTitle(newVariant.getText().toString());
            }
        });
    }
}

所以这实际上做了我想要的,它在焦点改变时保存了值。除了一个问题,它只在焦点改变时保存值。

大多数情况下这是很棒的,除非用户实际按下使整个视图消失的按钮。焦点永远不会改变,并且值不会被设置。

所以我猜你们都在想,是的,我们只需调用addOnTextChangedListener并附加一个TextWatcher,添加如下内容:

        holder.title.setText(variantArrayList.get(position).getVariantTitle());
        final int finalPosition = position;
        final EditText holderTitle = (EditText) holder.title;

        if (holderTitle.getTag() != null) {
            final TextWatcher textWatcher = new TextWatcher() {
                @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {

                }

                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
                        variantArrayList.get(finalPosition).setVariantTitle(s.toString());
                }

                @Override
                public void afterTextChanged(Editable s) {

                }
            };


            holder.title.addTextChangedListener(textWatcher);
            holder.title.setTag(true);
        }

不,那也行不通。 当然它实际上保存了值,但是当你滚动时它也会混乱,因为listview重用了它认为来自一个单元格的值在另一个单元格中的单元格,然后从ArrayList中设置值。

我尝试过不同的方法,例如在更改值和内容时检查焦点,但它不起作用(原因或多或少)。

有什么创意解决方案可以解决这个问题吗?

更新(使用更多代码):

建议的TextWatcher方法:

我的getView方法(这里有很多其他无关的问题代码):

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View v = convertView;
    IZUICartViewHolder holder;
    LayoutInflater inflater = ((Activity) context).getLayoutInflater();

    if (v == null) {

        holder = new IZUICartViewHolder();
        int type = getItemViewType(position);

        switch (type) {
            case TYPE_EDIT:
                v = inflater.inflate(R.layout.iz_ui_modify_product_cell, parent, false);
                holder.title = (EditText) v.findViewById(R.id.iz_prod_modify_variant_title);
                holder.title.setHint(addVariantPlaceholder);
                holder.deleteButton = v.findViewById(R.id.click_remove);
                holder.price = (EditText) v.findViewById(R.id.iz_prod_modify_price);
                holder.price.setHint(pricePlaceholder);
                holder.price.setText(String.valueOf(0.0));
                break;

        }

        v.setTag(holder);

    } else {
        holder = (IZUICartViewHolder) v.getTag();
    }

    hideDeleteButton(holder, position);
    holderTitleSavedOnScroll(position, holder);
    holderPriceSavedOnScroll(position, holder);

    v.setTag(holder);
    return v;
}

holderTitleSavedOnScroll方法

private void holderTitleSavedOnScroll(final int position, IZUICartViewHolder holder) {
    if (!(position == (variantArrayList.size() - 1)) && holder.title != null) {

        holder.title.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                v.requestFocus();
            }
        });


        final int finalPosition = position;
        final EditText holderTitle = (EditText) holder.title;

        if (holderTitle != null) {
            holder.title.setText(variantArrayList.get(position).getVariantTitle());
        }

        holderTitle.addTextChangedListener(new EditVariantTextWatcher(variantArrayList.get(finalPosition)));

    }
}

TextWatcher类:

public class EditVariantTextWatcher implements TextWatcher {

private IZUIProductVariantContainer variantContainer;

protected EditVariantTextWatcher(IZUIProductVariantContainer variantContainer) {
    this.variantContainer = variantContainer;
}

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

}

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

}

@Override
public void afterTextChanged(Editable s) {
    variantContainer.setVariantTitle(s.toString());
}
}

2 个答案:

答案 0 :(得分:6)

这可以通过仔细使用TextWatchers来完成。

在ViewHolder中包含对当前TextWatcher的引用。当视图被回收时,删除现有的TextWatcher并添加一个新的,键入当前位置。

这是一个完整的工作示例,包括状态保存以允许测试导航:

public class EditTextListActivity extends ListActivity {

    private static final String SAVED_STATE_KEY = "saved_state_key";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        EditTextAdapter editTextAdapter = new EditTextAdapter(this, R.layout.main);
        setListAdapter(editTextAdapter);

        // Restore our state, if there is any
        if (savedInstanceState != null) {
            List<String> savedStrings = savedInstanceState.getStringArrayList(SAVED_STATE_KEY);
            for (String savedString : savedStrings)
                editTextAdapter.add(new ListItem(savedString));
        } else {
            // Add some empty items so that we can see it in action
            for (int i = 0; i < 30; i++)
                editTextAdapter.add(new ListItem(""));
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        ArrayList<String> arrayList = new ArrayList<String>();
        EditTextAdapter editTextAdapter = (EditTextAdapter) getListAdapter();
        for (int i = 0; i < editTextAdapter.getCount(); i++)
            arrayList.add(editTextAdapter.getItem(i).string1);
        outState.putStringArrayList(SAVED_STATE_KEY, arrayList);
    }

    /**
     * The object we have a list of, probably more complex in your app
     */
    static class ListItem {
        public String string1;

        ListItem(String string1) {
            this.string1 = string1;
        }
    }

    /**
     * ViewHolder which also tracks the TextWatcher for an EditText
     */
    static class ViewHolder {
        public TextView textView;
        public EditText editText;
        public TextWatcher textWatcher;
    }

    class EditTextAdapter extends ArrayAdapter<ListItem> {
        EditTextAdapter(Context context, int resource) {
            super(context, android.R.layout.simple_list_item_single_choice);
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View rowView = convertView;
            if (rowView == null) {
                // Not recycled, inflate a new view
                rowView = getLayoutInflater().inflate(R.layout.main, null);
                ViewHolder viewHolder = new ViewHolder();
                viewHolder.textView = (TextView) rowView.findViewById(R.id.textview);
                viewHolder.editText = (EditText) rowView.findViewById(R.id.edittext1);
                rowView.setTag(viewHolder);
            }

            ViewHolder holder = (ViewHolder) rowView.getTag();
            // Remove any existing TextWatcher that will be keyed to the wrong ListItem
            if (holder.textWatcher != null)
                holder.editText.removeTextChangedListener(holder.textWatcher);

            final ListItem listItem = getItem(position);

            // Keep a reference to the TextWatcher so that we can remove it later
            holder.textWatcher = new TextWatcher() {
                @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                }

                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
                    listItem.string1 = s.toString();
                }

                @Override
                public void afterTextChanged(Editable s) {
                }
            };
            holder.editText.addTextChangedListener(holder.textWatcher);

            holder.editText.setText(listItem.string1);
            holder.textView.setText(Integer.toString(position));

            return rowView;
        }
    }
}

layout/main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/textview"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content" />

    <EditText
        android:id="@+id/edittext1"
        android:layout_width="0dp"
        android:layout_height="?android:attr/listPreferredItemHeightSmall"
        android:layout_weight="2"
        android:inputType="text" />

    <!-- This EditText is included to demonstrate problems with a naive approach. -->
    <EditText
        android:inputType="text"
        android:layout_width="0dp"
        android:layout_height="?android:attr/listPreferredItemHeightSmall"
        android:layout_weight="2" />
</LinearLayout>

已知错误:当键盘出现时,EditText将失去初始焦点,请参阅this answer以了解该问题。

答案 1 :(得分:0)

我们可以借助TextWatcher

来节省价值

最好使用模型来存储和检索EditText的值。

public class RowData {

    private String value;

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
} 

接下来是TextWatcher侦听器

public class EditTextWatcher implements TextWatcher {

    private RowData data;

    public EditTextWatcher(RowData data) {
        this.data = data;
    }

    @Override
    public void afterTextChanged(Editable s) {
        data.setValue(s.toString());
    }

    @Override
    public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
            int arg3) {

    }

    @Override
    public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {

    }

}

您的适配器类

         public class YourAdapter extends ArrayAdapter<RowData> {
                private ArrayList<RowData> data;
                private Context context;
            public YourAdapter(Context context, ArrayList<RowData> data) {
                    super(context, 0, data);
                    this.data = data;
                }
            @Override
            public View getView(final int position, View convertView, ViewGroup parent) {
                View v = convertView;
                final RowData row = data.get(position);
                final EditText edittext = (EditText) v.findViewById(R.id.edittext);
                if (edittext != null)
                   edittext.setText(row.getValue());
                edittext.addTextChangedListener(new EditTextWatcher(row));


                ///////Your Code
                /////
        }
}

// edittext.addTextChangedListener(new EditTextWatcher(row)); 此行将存储 每个EditText的数据,即使您在创建单元格时滚动ListView 它将从Model(RowData)

设置值

试试这样,希望这会对你有帮助。