Trả lời

41

Vì vậy, đây là những gì tôi đã làm.

Chỉnh sửa: Sau một năm trôi qua kể từ khi tôi phát hiện ra câu trả lời trước đó có rất nhiều mã vô dụng (woops) và điều CAB có thể đạt được với nỗ lực ít hơn nhiều và mã sạch hơn, vì vậy tôi đã dành thời gian và cập nhật nó

Các LibraryFragment ListView cần được xác định với chế độ lựa chọn "none"

<ListView 
    android:id="@android:id/list" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:choiceMode="none"/> 

Các mục trong danh sách cần phải có một? attr/activatedBackgroundIndicator foreground để tự động vẽ nổi bật lớp phủ bán công khai trên list.setItemChecked (pos , true)

list_item_library.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:foreground="?attr/activatedBackgroundIndicator" 
    android:paddingBottom="5dp" 
    android:paddingTop="5dp" > 

.... 

Các ListFragment

import android.support.v4.app.DialogFragment; 
import com.actionbarsherlock.app.SherlockListFragment; 
import com.actionbarsherlock.view.ActionMode; 
import com.actionbarsherlock.view.Menu; 

public final class LibraryFragment 
     extends SherlockListFragment 
{ 

    private MyListAdapter adapter; 
    private ListView list; 

    // if ActoinMode is null - assume we are in normal mode 
    private ActionMode actionMode; 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
      Bundle savedInstanceState) 
    { 
     View v = inflater.inflate(R.layout.fragment_library, null); 
     this.list = (ListView) v.findViewById(android.R.id.list); 
     this.initListView(); 
     return v; 
    } 

    @Override 
    public void onPause() 
    { 
     super.onPause(); 
     if (this.actionMode != null) { 
      this.actionMode.finish(); 
     } 
    } 

    @Override 
    public void onResume() { 
     super.onResume(); 
     updateData(); 
    } 

    // update ListView 
    protected void updateData() 
    { 
     if (adapter == null) { 
      return; 
     } 
     adapter.clear(); 
     // my kinda stuff :) 
     File[] items = scan(); 
     if (items != null) { 
      adapter.updateData(items); 
      if (actionMode != null) { 
       actionMode.invalidate(); 
      } 
     } 
     // if empty - finish action mode. 
     if (actionMode != null && (files == null || files.length == 0)) { 
      actionMode.finish(); 
     } 
    } 

    private void initListView() 
    { 
     this.adapter = new MyAdapter(getActivity()); 
     this.list.setAdapter(adapter); 
     this.list.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() 
     { 

      @Override 
      public boolean onItemLongClick(AdapterView<?> arg0, 
        View arg1, int arg2, long arg3) 
      { 
       if (actionMode != null) { 
        // if already in action mode - do nothing 
        return false; 
       } 
       // set checked selected item and enter multi selection mode 
       list.setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE); 
       list.setItemChecked(arg2, true); 

       getSherlockActivity().startActionMode(
         new ActionModeCallback()); 
       return true; 
      } 
     }); 
     this.list.setOnItemClickListener(new AdapterView.OnItemClickListener() 
     { 
      @Override 
      public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, 
        long arg3) 
      { 
       if (actionMode != null) { 
        // the items are auomatically "checked" becaise we've set AbsListView.CHOICE_MODE_MULTIPLE before 
        // starting action mode, so the only thing we have to care about is invalidating the actionmode 
        actionMode.invalidate(); //invalidate title and menus. 
       } else { 
        // do whatever you should on item click 
       } 
      } 
     }); 
    } 


    // all our ActionMode stuff here :) 
    private final class ActionModeCallback 
      implements ActionMode.Callback 
    { 

     // " selected" string resource to update ActionBar text 
     private String selected = getActivity().getString(
       R.string.library_selected); 

     @Override 
     public boolean onCreateActionMode(ActionMode mode, Menu menu) 
     { 
      actionMode = mode; 
      return true; 
     } 

     @Override 
     public boolean onPrepareActionMode(ActionMode mode, Menu menu) 
     { 
      // remove previous items 
      menu.clear(); 
      final int checked = list.getCheckedItemCount(); 
      // update title with number of checked items 
      mode.setTitle(checked + this.selected); 
      switch (checked) { 
      case 0: 
       // if nothing checked - exit action mode 
       mode.finish(); 
       return true; 
      case 1: 
       // all items - rename + delete 
       getSherlockActivity().getSupportMenuInflater().inflate(
         R.menu.library_context, menu); 
       return true; 
      default: 
       getSherlockActivity().getSupportMenuInflater().inflate(
         R.menu.library_context, menu); 
       // remove rename option - because we have more than one selected 
       menu.removeItem(R.id.library_context_rename); 
       return true; 
      } 
     } 

     @Override 
     public boolean onActionItemClicked(ActionMode mode, 
       com.actionbarsherlock.view.MenuItem item) 
     { 
      SparseBooleanArray checked; 
      switch (item.getItemId()) { 
      case R.id.library_context_rename: 
       // the rename action is present only when only one item is selected. 
       // so when the first checked item found, show the dialog and break 
       checked = list.getCheckedItemPositions(); 
       for (int i = 0; i < checked.size(); i++) { 
        final int index = checked.keyAt(i); 
        if (checked.get(index)) { 
         final DialogFragment d = RenameDialog.instantiate(adapter.getItem(index).getFile(), LibraryFragment.this); 
         d.show(getActivity().getSupportFragmentManager(), "dialog"); 
         break; 
        } 
       } 
       return true; 

      case R.id.library_context_delete: 
       // delete every checked item 
       checked = list.getCheckedItemPositions(); 
       for (int i = 0; i < checked.size(); i++) { 
        final int index = checked.keyAt(i); 
        if (checked.get(index)) { 
         adapter.getItem(index).getFile().delete(); 
        } 
       } 
       updateData(); 
       return true; 
      default: 
       return false; 
      } 
     } 

     @Override 
     public void onDestroyActionMode(ActionMode mode) 
     { 
      list.clearChoices(); 

      //workaround for some items not being unchecked. 
      //see http://stackoverflow.com/a/10542628/1366471 
      for (int i = 0; i < list.getChildCount(); i++) { 
       (list.getChildAt(i).getBackground()).setState(new int[] { 0 }); 
      } 

      list.setChoiceMode(AbsListView.CHOICE_MODE_NONE); 
      actionMode = null; 
     } 

    } 
+0

Cảm ơn bạn đã chia sẻ. Tôi đã tìm kiếm chính xác điều này! – h4ck3d

+0

cảm ơn bài đăng tuyệt vời này, nhưng tôi gặp vấn đề về thay đổi định hướng. Giả sử, tôi đã chọn một vài mục trên actionmode, sau đó xoay thiết bị, tôi có thể khôi phục thanh tác vụ và thiết lập các mục đã chọn. Nhưng điểm nổi bật không hiển thị cho đến khi tôi cuộn danh sách ra khỏi màn hình và quay lại, điểm nổi bật cho thấy. Bất kỳ ý tưởng nào? – triston

+0

@triston làm cách nào để bạn khôi phục trạng thái? Hãy chắc chắn rằng bạn gọi setChecked() trên Adapter. Trong trường hợp này nó sẽ hoạt động. Nhưng nếu đó là những gì bạn đang làm và nó không hoạt động, tôi sợ tôi không thể giúp bạn vì tôi không có đủ thời gian rảnh để kiểm tra những điều này. –

0

giải pháp của bạn là giải pháp tốt nhất và dễ dàng nhất cho chủ đề này. Nhưng có một vấn đề nhỏ trong getView() - tham khảo lại các bình luận của tôi ở trên.

int version = android.os.Build.VERSION.SDK_INT;  
if(version < 11){ 
    if (checkedItems.contains(Integer.valueOf(position))) { 
     convertView.getBackground().setState(
       new int[] { android.R.attr.state_checked }); 
    } else { 
     convertView.getBackground().setState(
       new int[] { -android.R.attr.state_checked }); 
    } 
}else{ 

    if (checkedItems.contains(Integer.valueOf(position))) { 
     convertView.setActivated(true); 
    } else { 
     convertView.setActivated(false);   
    } 
} 

này sẽ cung cấp cho bạn hỗ trợ đầy đủ từ API8 để API18

+0

setActivated chỉ khả dụng bắt đầu từ cấp API 11. Nếu bạn sử dụng API 11 thì không cần ActionBarSherlock và giải pháp của tôi không tốt vì có cách dễ dàng hơn để thực hiện API bắt đầu này 11. http://developer.android.com/ hướng dẫn/chủ đề/ui/menus.html # CAB –

+0

Dự án của tôi là đặt API8 tối thiểu, vì vậy tôi phải sử dụng cả hai. Tôi cũng sẽ sửa đổi đề xuất của tôi ở trên. Cảm ơn. – triston

Các vấn đề liên quan