簡體   English   中英

listView中checkBox的奇怪行為

[英]Strange behaviour of checkBox in the listView

我有一個帶listView的片段,該listview布局包含(TextView,checkBox和ImageView如下)

t1........CB.......IV
t2........CB.......IV
t3........CB.......IV
t4........CB.......IV
t5........CB.......IV
t6........CB.......IV
      SaveButton

在getView()方法中,我檢查該復選框是否已選中,如果已選中,則將選中的項目添加到列表中。

問題是,最初我將所有復選框都設置為未選中,但是當我選中第一項時,令人驚訝的是,下面的第三項被自動選中,如果我選中了上面的第二項,那么下面的第二項是檢查,如果我從上面檢查了第三項,那么最后一項會自動檢查?

請看一下getView()方法,讓我知道我錯過了什么:

getView()

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    // TODO Auto-generated method stub

    if (convertView == null) {
        LayoutInflater layoutinflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        convertView = layoutinflater.inflate(R.layout.list_items_layout, null);
    }

    if (this.checkedItemsList == null) {
        this.checkedItemsList = new ArrayList<String>();
    }

    final TextView tv = (TextView) convertView.findViewById(R.id.tvlist_topic);
    final CheckBox cb = (CheckBox) convertView.findViewById(R.id.cbList_hook);
    final ImageView iv = (ImageView) convertView.findViewById(R.id.ivList_delete);

    tv.setText(this.topicsList.get(position));

    cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {

        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            // TODO Auto-generated method stub
            if (isChecked) {
                checkedItemsList.add(topicsList.get(position));
                setCheckedItemsList(checkedItemsList);
                Log.d(TAG, "size: " + checkedItemsList.size());
            }
        }
    });

    iv.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            if (cb.isChecked())
                cb.setChecked(false);

            topicsList.remove(position);
            notifyDataSetChanged();
        }
    });

    return convertView;
}

xml

<RelativeLayout 
    android:id="@+id/rl2_List"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_toEndOf="@id/rl1_List"
    android:layout_centerInParent="true">
    <CheckBox
        android:id="@+id/cbList_hook"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:focusable="false"
        android:focusableInTouchMode="false"
        android:checked="false"/>
</RelativeLayout>

<RelativeLayout 
    android:id="@+id/rl3_List"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_toEndOf="@id/rl2_List"
    android:layout_alignParentEnd="true"
    android:layout_marginStart="100dp">
    <ImageView 
        android:id="@+id/ivList_delete"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:focusable="false"
        android:focusableInTouchMode="false"
        android:clickable="true"
        android:src="@drawable/delete_icon"
        android:contentDescription="icon to delete item from the Listview"/>
</RelativeLayout>

您必須保持對象檢查狀態。

我將在您的對象中(在topicList中)實現一個實例變量,該變量指示是否選中了該變量。

就像是

public class Topic{

public boolean isChecked;

... //Other instance variables

public boolean isChecked() {
    return isChecked;
}

public void setChecked(boolean isChecked) {
    this.isChecked = isChecked;
}

...
//other getters and setters

}

然后在您的listAdapter getView方法中,檢查此值並相應地設置復選框。

final CheckBox cb = (CheckBox) convertView.findViewById(R.id.cbList_hook);

boolean isChecked = topicsList.get(position).isChecked();

cb.setChecked(isChecked);

//Set a tag on the cb, to know which object it corresponds with
cb.setTag(topicsList.get(position));

另外,單擊對象時必須更改其檢查值。

cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {

    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        // TODO Auto-generated method stub
        if (isChecked) {
            checkedItemsList.add(topicsList.get(position));
            setCheckedItemsList(checkedItemsList);
            Log.d(TAG, "size: " + checkedItemsList.size());
        }
        CheckBox cb = (CheckBox) buttonView;
        Object yourObject = (Object) buttonView.getTag();
        yourObject.setChecked(isChecked);
    }
});

您需要了解convertView ,對於初學者而言,這通常會更加令人困惑。

例如,如果您在一個巨大的列表中有100個Checkbox,但是一次只能在屏幕上看到5個,那么天真的方法是為Checkbox創建100個對象(實際上,這是在早期版本的Android中的工作方式)。 但是,創建新對象不僅會在創建過程中消耗CPU資源,而且還會在垃圾回收過程中消耗CPU資源。 這就是為什么要使用convertView的原因。 Android系統將僅創建5個對象,並在用戶滾動時重復使用相同的對象。 就您而言,我認為屏幕上只有3個對象。 因此,從技術上講,滾動出屏幕的第一個對象和顯示在屏幕上的第四個對象是相同的。

您的解決方案是將View對象視為可視元素,然后將狀態保存在其他位置。 我認為另一個答案是建議代碼,因此,我將避免建議代碼,並鼓勵您理解概念並自己找到解決方案。

你必須做這樣的事情

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub

if (convertView == null) {
    LayoutInflater layoutinflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
    convertView = layoutinflater.inflate(R.layout.list_items_layout, null);
}

if (this.checkedItemsList == null) {
    this.checkedItemsList = new ArrayList<String>();
}

final TextView tv = (TextView) convertView.findViewById(R.id.tvlist_topic);
final CheckBox cb = (CheckBox) convertView.findViewById(R.id.cbList_hook);
final ImageView iv = (ImageView) convertView.findViewById(R.id.ivList_delete);

tv.setText(this.topicsList.get(position));
cb.setTag(position);
cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {

    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        // TODO Auto-generated method stub
        if (isChecked) {
            checkedItemsList.add(topicsList.get(Integer.parseInt(buttonView.getTag().toString())));
            setCheckedItemsList(checkedItemsList);
            Log.d(TAG, "size: " + checkedItemsList.size());
        }
    }
});



return convertView;
}

如果使用ViewHolder模式會更好。 這樣可以防止每次用戶滾動列表時都增加視圖的開銷。 另外,數據源(您要用來填充ListView的數據結構;在本例中為topicList)中是否應該存在一個復選框。 假設數據結構的模型類名為Model:

public class Model {
 private boolean mChecked = false;

 public boolean isChecked() {
  return this.mChecked;
 }
 public void setChecked(boolean checked) {
  this.mChecked = checked;
 }
}

現在在ListView的適配器類中

public class SomeAdapter extends BaseAdapter {

 private ArrayList<Model> topicsList; //assuming this is filled with data
 static class ViewHolder { //the view holder's class
  TextView text;
  CheckBox checkBox;
  ImageView imageView;
 }


 @Override
 public View getView(final int position, View convertView, ViewGroup parent) {
    // TODO Auto-generated method stub
    ViewHolder holder;
    if (convertView == null) {
        LayoutInflater layoutinflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        convertView = layoutinflater.inflate(R.layout.list_items_layout, null);
        TextView tv = (TextView) convertView.findViewById(R.id.tvlist_topic);
        CheckBox cb = (CheckBox) convertView.findViewById(R.id.cbList_hook);
        ImageView iv = (ImageView) convertView.findViewById(R.id.ivList_delete);
        holder = new ViewHolder(); 
        holder.textView = tv;
        holder.checkBox = cb;
        holder.imageView = iv;
        convertView.setTag(viewHolder);
    } else {
        viewHolder = (ViewHolder) converView.getTag();
    }

    if (this.checkedItemsList == null) {
        this.checkedItemsList = new ArrayList<String>();
    }


    TextView textView = viewHolder.textView;
    CheckBox checkBox = viewHolder.checkBox;
    ImageView imageView = viewHolder.imageView;    

    textView.setText(this.topicsList.get(position));
    if (this.topicsList.get(position).isChecked()) {
     checkBox.setChecked(true);
    } else {
     checkBox.setChecked(false);
    }

    checkBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {

        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            // TODO Auto-generated method stub
            if (isChecked) {
                SomeAdapter.this.topicsList.get(position).setChecked(isChecked);
              checkedItemsList.add(SomeAdapter.this.topicsList.get(position));
                setCheckedItemsList(checkedItemsList);
                Log.d(TAG, "size: " + checkedItemsList.size());
            }
        }
    });

    imageView.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            if (checkBox.isChecked()) {
                checkBox.setChecked(false);
                SomeAdapter.this.topicsList.get(position).setChecked(false);
                topicsList.remove(position);
                notifyDataSetChanged();
            } else { //if needed
                checkBox.setChecked(true); 
                SomeAdapter.this.topicsList.get(position).setChecked(true);
                //perform other operations here
            }

        }
    });

    return convertView;
 }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM