這時候,需要在適配器BaseAdapter的getView中設置setTag(),將position緩存起來.
下面來解決這個問題.
1.打開activity_main.xml .
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.listviewdemo1.MainActivity" >
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/btn_addRow"
android:text="增加一行"
/>
<ListView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/lv"
android:cacheColorHint="@android:color/transparent"
></ListView>
</LinearLayout>
在這個布局中,只有一個簡單的Button和一個ListView,Button是用來動態添加 一行記錄的.
2.新建一個item.xml,作為listView的子布局.
<?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:descendantFocusability="beforeDescendants"
android:orientation="horizontal" >
<TextView
android:layout_width="10dp"
android:layout_height="wrap_content"
android:id="@+id/tv_position"
/>
<Spinner
android:layout_width="100dp"
android:layout_height="wrap_content"
android:id="@+id/sp_type"
/>
<EditText
android:layout_width="100dp"
android:layout_height="wrap_content"
android:id="@+id/et_number"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btn_delete"
android:text="刪除"
/>
</LinearLayout>
子布局元素也只有四個, 一個TextView用來放索引位置, Spinner用來顯示一個下拉窗口 , 還有一個EditText和一個Button.
3.新建一個NumberInfo.java,用來存儲數據的javaBean.
public class NumberInfo {
private String type;
private String number;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
}
只有簡單的兩個屬性
4.新建一個MyAdapter.java 適配器, 用來展示ListView的數據, 解決混亂的重點.
public class MyAdapter extends BaseAdapter {
private List<NumberInfo> list=new ArrayList<NumberInfo>();
private Context context;
private OnListRemovedListener mListener;
//下拉列表的適配器
private ArrayAdapter<String> arrayAdapter;
//下拉列表的選項
private static final String[] SPINNER_TIME = {"手機","住宅","其他"};
public void setOnListRemovedListener(OnListRemovedListener listener){
this.mListener=listener;
}
public MyAdapter(List<NumberInfo> list,Context context) {
this.context=context;
this.list=list;
arrayAdapter=new ArrayAdapter<String>(context, android.R.layout.simple_spinner_item, SPINNER_TIME);
arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int arg0) {
return null;
}
@Override
public long getItemId(int arg0) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup arg2) {
ViewHolder holder=null;
if(convertView==null){
convertView=LayoutInflater.from(context).inflate(R.layout.item, null);
holder=new ViewHolder();
holder.tv_position=(TextView) convertView.findViewById(R.id.tv_position);
holder.sp_type=(Spinner) convertView.findViewById(R.id.sp_type);
holder.sp_type.setOnItemSelectedListener(new MySpinnerListener(holder) {
@Override
public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2,
long arg3, ViewHolder holder) {
TextView tv=(TextView) arg1;
int position=(Integer) holder.et_number.getTag();
NumberInfo n=list.get(position);
n.setType(tv.getText().toString());
list.set(position, n);
}
});
holder.et_number=(EditText) convertView.findViewById(R.id.et_number);
holder.et_number.setTag(position);
holder.et_number.addTextChangedListener(new MyTextWatcher(holder) {
@Override
public void afterTextChanged(Editable s, ViewHolder holder) {
int position=(Integer) holder.et_number.getTag();
NumberInfo n=list.get(position);
n.setNumber(s.toString());
list.set(position, n);
}
});
holder.btn_delete=(Button) convertView.findViewById(R.id.btn_delete);
holder.btn_delete.setOnClickListener(new MyOnClickListener(holder) {
@Override
public void onClick(View v, ViewHolder holder) {
if(mListener!=null){
int position=(Integer) holder.et_number.getTag();
list.remove(position);
mListener.onRemoved(); //通知主線程更新Adapter
}
}
});
convertView.setTag(holder);
}
else{
holder=(ViewHolder) convertView.getTag();
holder.et_number.setTag(position);
}
NumberInfo n=list.get(position);
holder.tv_position.setText(position+1+"");
holder.sp_type.setAdapter(arrayAdapter);
holder.et_number.setText(n.getNumber());
int p=getPositionForAdapter(position);
holder.sp_type.setSelection(p,true);
return convertView;
}
private int getPositionForAdapter(int po){
NumberInfo t = list.get(po);
int p = 0;
for(int i=0;i<SPINNER_TIME.length;i++){
if(t.getType().equals(SPINNER_TIME[i])){
p = i;
}
}
return p;
}
//動態添加List里面數據
public void addItem(NumberInfo n){
list.add(n);
}
private abstract class MySpinnerListener implements OnItemSelectedListener{
private ViewHolder holder;
public MySpinnerListener(ViewHolder holder) {
this.holder=holder;
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
@Override
public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
onItemSelected(arg0, arg1, arg2, arg3, holder);
}
public abstract void onItemSelected(AdapterView<?> arg0, View arg1, int arg2,long arg3,ViewHolder holder);
}
private abstract class MyTextWatcher implements TextWatcher{
private ViewHolder mHolder;
public MyTextWatcher(ViewHolder holder) {
this.mHolder=holder;
}
@Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
int arg3) {
}
@Override
public void onTextChanged(CharSequence arg0, int arg1, int arg2,
int arg3) {
}
@Override
public void afterTextChanged(Editable s) {
afterTextChanged(s, mHolder);
}
public abstract void afterTextChanged(Editable s,ViewHolder holder);
}
private abstract class MyOnClickListener implements OnClickListener{
private ViewHolder mHolder;
public MyOnClickListener(ViewHolder holder) {
this.mHolder=holder;
}
@Override
public void onClick(View v) {
onClick(v, mHolder);
}
public abstract void onClick(View v,ViewHolder holder);
}
private class ViewHolder{
TextView tv_position;
Spinner sp_type;
EditText et_number;
Button btn_delete;
}
//刪除操作回調
public interface OnListRemovedListener{
public void onRemoved();
}
}
仔細看,其實只是對每一個可點擊的事件重寫了一遍,與原來不同的是,這里多了一個ViewHolder,為什么需要這個,因為這里面存儲了每一個Item的Position信息.這樣,就可以對item進行准確操作.從而不會發生錯亂.
5.打開MainActivity.java
public class MainActivity extends ActionBarActivity implements OnClickListener,OnItemSelectedListener,OnListRemovedListener {
private List<NumberInfo> list=new ArrayList<NumberInfo>();
ListView lv;
Button btn_addRow;
MyAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_addRow=(Button) findViewById(R.id.btn_addRow);
btn_addRow.setOnClickListener(this);
lv=(ListView) findViewById(R.id.lv);
NumberInfo n=new NumberInfo();
n.setNumber("1");
n.setType("其他");
list.add(n);
mAdapter=new MyAdapter(list, this);
lv.setAdapter(mAdapter);
mAdapter.setOnListRemovedListener(this);
}
@Override
public void onClick(View v) {
if(v.getId()==R.id.btn_addRow){
NumberInfo n=new NumberInfo();
n.setNumber("");
n.setType("手機");
mAdapter.addItem(n);
mAdapter.notifyDataSetChanged();
}
}
@Override
public void onRemoved() {
mAdapter.notifyDataSetChanged();
}
@Override
public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
}
運行結果:
從此ListView再也不會錯亂.
