android ListView與EditText共存錯位


在一個ListView中,如果里面有EditText會很麻煩,因為修改EditText里面的數據會發生錯位現象.
這時候,需要在適配器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_itemSPINNER_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.itemnull);
            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(listthis);
        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再也不會錯亂.
 








免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM