2011-12-03 27 views
36

Điều này thật kỳ lạ.ListView: setItemChecked chỉ hoạt động với ArrayAdapter tiêu chuẩn - KHÔNG hoạt động khi sử dụng ArrayAdapter tùy chỉnh?

Khi tôi sử dụng ArrayAdapter tiêu chuẩn cho một ListView gọi setItemChecked hoạt động OK

Nhưng khi sử dụng một tùy chỉnh thực hiện ArrayAdapter nó không.

Điều gì sẽ là lý do? Đây có phải là một lỗi? Hay tôi đang thiếu một cái gì đó?

public class Test_Activity extends Activity { 

    /** Called when the activity is first created. */ 
    private List<Model> list; 
    private ListView lView; 

    public void onCreate(Bundle icicle) { 
    super.onCreate(icicle); 
    // Create an array of Strings, that will be put to our ListActivity 
    setContentView(R.layout.main); 
    lView = (ListView) findViewById(R.id.ListView01); 
    lView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); 

    list = getModel(); 

    //with this adapter setItemChecked works OK 
    lView.setAdapter(new ArrayAdapter<Model>(this, 
     android.R.layout.simple_list_item_multiple_choice, list)); 


    //************************** 
    //PROBLEM: with this adapter it does not check any items on the screen 
    // ArrayAdapter<Model> adapter = new Test_Class1(this, list); 
    // lView.setAdapter(adapter); 



    } 

    private List<Model> getModel() { 
     List<Model> list = new ArrayList<Model>(); 
     list.add(get("0")); 
     list.add(get("1")); 
     list.add(get("2")); 
     list.get(1).setSelected(true); 
     Model m = list.get(1); 
     list.add(get("3")); 
     list.add(get("4")); 
     list.add(get("5")); 
     list.add(get("6")); 
     list.add(get("7")); 
     // Initially select one of the items 
     return list; 
    } 

    private Model get(String s) { 
     return new Model(s); 
    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     MenuInflater inflater = getMenuInflater(); 
     inflater.inflate(R.menu.results_screen_option_menu, menu); 
     return true; 
    } 

    /** 
    * @category OptionsMenu 
    */ 
    @Override 
public boolean onOptionsItemSelected(MenuItem item) { 
    switch (item.getItemId()) { 
    case R.id.select_all: { 

     int size = lView.getAdapter().getCount(); 

     for (int i = 0; i <= size; i++) { 

      //************************** PROBLEM 
     lView.setItemChecked(i, true); // selects the item only for standard ArrayAdapter 

    Log.i("xxx", "looping " + i); 
     } 
    } 
     return true; 
    case R.id.select_none: 
     return true; 
    } 
    return false; 
    } 
} 

// ----------------------------------------- -------------------

public class Test_Class1 extends ArrayAdapter<Model> { 

    private final List<Model> list; 
    private final Activity context; 

public Test_Class1(Activity context, List<Model> list) { 
    super(context, R.layout.rowbuttonlayout2, list); 
    this.context = context; 
    this.list = list; 
    } 

    static class ViewHolder { 
    protected TextView text; 
    protected CheckBox checkbox; 
    } 

    @Override 
public View getView(int position, View convertView, ViewGroup parent) { 
    View view = null; 
    Log.i("xxx", "-> getView " + position); 
    if (convertView == null) { 
     LayoutInflater inflator = context.getLayoutInflater(); 
     view = inflator.inflate(R.layout.rowbuttonlayout, null); 
     final ViewHolder viewHolder = new ViewHolder(); 
     viewHolder.text = (TextView) view.findViewById(R.id.label); 
     viewHolder.checkbox = (CheckBox) view.findViewById(R.id.check); 
     viewHolder.checkbox 
      .setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 

      @Override 
      public void onCheckedChanged(CompoundButton buttonView, 
       boolean isChecked) { 
       Model element = (Model) viewHolder.checkbox 
        .getTag(); 
       Log.i("xxx", "-> onCheckedChanged"); 
       element.setSelected(buttonView.isChecked()); 
       Log.i("xxx", "<- onCheckedChanged"); 

      } 
      }); 
     view.setTag(viewHolder); 
     viewHolder.checkbox.setTag(list.get(position)); 
    } else { 
     view = convertView; 
     ((ViewHolder) view.getTag()).checkbox.setTag(list.get(position)); 
    } 
    ViewHolder holder = (ViewHolder) view.getTag(); 
    holder.text.setText(list.get(position).getName()); 
    Log.i("xxx", "holder.checkbox.setChecked: " + position); 

    holder.checkbox.setChecked(list.get(position).isSelected()); 
    Log.i("xxx", "<- getView " + position); 

    return view; 
    } 

} 

Trả lời

46

bố trí hàng của bạn cần phải được Checkable cho setItemChecked() để làm việc, trong trường hợp đó Android sẽ quản lý gọi setChecked() trên của bạn Checkable như người dùng nhấp vào hàng. Bạn sẽ không cần thiết lập OnCheckedChangeListener của riêng mình.

Để biết thêm, xem:

+27

Không thể tin được - tại sao điều này phức tạp và khó tìm? Tôi cũng làm lập trình iPhone, trong khi đến nay tôi thực sự thích Android, đây là một thiết lập thực sự trở lại. Cảm ơn rất nhiều ! – user387184

+3

Tôi đã xem chi tiết mã mẫu ngay bây giờ và quyết định không theo giải pháp này. Thay vào đó, tôi xây dựng một mảng các CheckBox trong ArrayAdapter của mình. Với điều này trong tầm tay tôi sau đó có thể dễ dàng làm những thứ tôi cần. Cảm ơn một lần nữa rất nhiều vì đã chỉ cho tôi theo hướng! – user387184

+0

liên kết cập nhật đến hướng dẫn marvinlabs http://blog.marvinlabs.com/2010/10/29/custom-listview-ability-check-items/ –

1

Checkable là một cur học Tôi không muốn nhận ngay bây giờ. Bạn có thể đặt và bỏ chọn Hộp kiểm theo cách thủ công trong các hoạt động 'OnItemClickListener'. Duy trì biến boolean isChecked tạm thời trong danh sách MyObject trong ArrayAdapter<MyObject>.

public void onItemClick(AdapterView<?> av, View v, int position, long arg3) { 
    final ListView listView = (ListView) findViewById(android.R.id.list); 
    MyObject item = (MyObject) listView.getItemAtPosition(position); 
    item.isChecked = !item.isChecked; 
    if(item.isChecked) 
     addItem(item); 
    else 
     removeItem(item); 
} 

Để tính cho người dùng, hãy nhấp vào CheckBox; sử dụng cùng một logic addItem (item)/removeItem (item) trong triển khai thực hiện getView của bộ điều hợp mảng tùy chỉnh của bạn, trong OnClickListener của CheckBox.

public View getView(int position, View convertView, ViewGroup viewGroup) { 
     CheckBox cb = null; 
     if (convertView == null) { 
      if(inflater == null) //cache to avoid reconstructing for each view 
      inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
      convertView =inflater.inflate(R.layout.list_item_text_right_checkmark, null); 

      CheckBox cb = (CheckBox) convertView.findViewById(R.id.check); 
      cb.setChecked((list.get(position).isChecked)); 
      cb.setTag(list.get(position); 
      public void onClick(View v) { 
       if(v instanceof CheckBox) { 
        CheckBox cb = (CheckBox) v; 
        if(cb.isChecked()) //verify boolean logic here!!! 
         activityRef.get().addItem(cb.getTag()); //WeakReference to activity 
        else 
         activityRef.get().removeItem(cb.getTag()); 

       } 
      }); 
    } else cb = (CheckBox) convertView.findViewById(R.id.check); 
    cb.setChecked((list.get(position).isChecked)); 
... 
} 

Hộp kiểm cuộc gọi :: setChecked() là khóa ở đây.
Điều này dường như làm các trick miễn là bộ điều hợp mảng của bạn có thể giả định cùng một hoạt động, và bộ điều hợp mảng của bạn có thể giả định cùng một mục danh sách xml định nghĩa trong res/layout /.

checkable danh mục XML:

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

    <TextView 
     android:id="@+id/text" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_toLeftOf="@+id/check" 
     android:gravity="center_vertical" 
     android:paddingLeft="8dp" 
     android:textAppearance="?android:attr/textAppearanceMedium" /> 

    <CheckBox 
    android:id="@+id/check" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:layout_alignParentRight="true" 
    android:focusable="false"/> 
</RelativeLayout> 

Nếu bạn cần kiểm tra một số CheckBoxs của bạn ban đầu, chỉ cần đặt các thành viên isChecked của bạn trong MyObject của bạn trước khi lạm phát.

9

Để chắc chắn bạn phải thiết lập các chế độ lựa chọn cho ListView của bạn, ví dụ:

list.setChoiceMode(ListView.CHOICE_MODE_SINGLE); 

Nhưng nếu bạn cũng đang sử dụng một cách bố trí tùy chỉnh cho mục danh sách của bạn (R.layout.drawing_list_item), sau đó bạn cần phải thực hiện chắc chắn bố trí của bạn cài đặt giao diện Checkable:

public class CheckableRelativeLayout extends RelativeLayout implements Checkable { 
    private boolean isChecked = false; 

    public CheckableRelativeLayout(Context context, AttributeSet attrs) { 
     super(context, attrs); 
    } 

    public boolean isChecked() { 
     return isChecked; 
    } 

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

    public void toggle() { 
     this.isChecked = !this.isChecked; 
     changeColor(this.isChecked); 
    } 

    private void changeColor(boolean isChecked){ 
     if (isChecked) { 
      setBackgroundColor(getResources().getColor(android.R.color.holo_blue_light)); 
     } else { 
      setBackgroundColor(getResources().getColor(android.R.color.transparent)); 
     } 
    } 
} 

sau đó bố trí checkable của bạn sẽ được xác định như ví dụ sau:

<?xml version="1.0" encoding="utf-8"?> 
<it.moondroid.banking.CheckableRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/drawer_item_layout" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:padding="10dp" > 

    <ImageView 
     android:id="@+id/agenzie_item_icon" 
     android:layout_width="30dp" 
     android:layout_height="30dp" 
     android:layout_alignParentLeft="true" 
     android:layout_centerVertical="true" 
     android:background="@android:color/darker_gray" 
     android:focusable="false" /> 

    <TextView 
     android:id="@+id/agenzie_item_name" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_centerVertical="true" 
     android:layout_toRightOf="@+id/agenzie_item_icon" 
     android:focusable="false" 
     android:paddingLeft="10dp" 
     android:text="item" 
     android:textAppearance="?android:attr/textAppearanceSmall" 
     android:textColor="#FFFFFF" /> 

</it.moondroid.banking.CheckableRelativeLayout> 
0

Không có câu trả lời nào phù hợp với tôi. Vấn đề của tôi là chỉ có các cuộc gọi ban đầu để ExpandableListView.setItemChecked từ OnCreate/OnStart/OnPause đã không hoạt động như thể chế độ xem chưa được khởi tạo đầy đủ. Để giải quyết vấn đề này, tôi phải làm như sau:

_expandableListView.Post(() => 
{ 
    _expandableListView.SetItemChecked(fragmentPosition, true); 
}); 
Các vấn đề liên quan