Tắt tính năng Vuốt cho vị trí trong RecyclerView bằng ItemTouchHelper.SimpleCallback


92

Tôi đang sử dụng tái chế 22.2.0 và lớp trợ giúp ItemTouchHelper.SimpleCallback để bật tùy chọn vuốt để loại bỏ cho danh sách của tôi. Nhưng vì tôi có một loại tiêu đề trên đó, tôi cần phải tắt hành vi vuốt cho vị trí đầu tiên của bộ điều hợp. Vì RecyclerView.Adapter không có phương thức isEnabled () , tôi đã cố gắng vô hiệu hóa tương tác chế độ xem thông qua các phương thức isEnabled ()isFocusable () trong chính quá trình tạo ViewHolder, nhưng không thành công. Tôi đã cố gắng điều chỉnh ngưỡng vuốt thành giá trị đầy đủ, chẳng hạn như 0f ot 1f trong phương pháp của SimpleCallback getSwipeThreshold () SimpleCallback , nhưng cũng không thành công.

Mấy đoạn code của mình mong các bạn giúp mình với.

Hoạt động của tôi:

@Override
protected void onCreate(Bundle bundle) {
    //... initialization
    ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0,
            ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {

        @Override
        public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
                          RecyclerView.ViewHolder target) {
            return false;
        }

        @Override
        public float getSwipeThreshold(RecyclerView.ViewHolder viewHolder) {
            if (viewHolder instanceof CartAdapter.MyViewHolder) return 1f;
            return super.getSwipeThreshold(viewHolder);
        }

        @Override
        public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {

        }
    };

    ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchCallback);
    itemTouchHelper.attachToRecyclerView(recyclerView);
}

Và tôi có một bộ điều hợp chung với hai loại chế độ xem. Trong ViewHolder mà tôi muốn tắt vuốt, tôi đã làm:

public static class MyViewHolder extends RecyclerView.ViewHolder {
    public ViewGroup mContainer;

    public MyViewHolder(View v) {
        super(v);
        v.setFocusable(false);
        v.setEnabled(false);
        mContainer = (ViewGroup) v.findViewById(R.id.container);      
    }
}

Câu trả lời:


204

Sau khi chơi một chút, tôi thấy rằng SimpleCallback có một phương thức gọi là getSwipeDirs () . Vì tôi có một ViewHolder cụ thể cho vị trí không thể vuốt , tôi có thể sử dụng instanceof để tránh thao tác vuốt. Nếu đó không phải là trường hợp của bạn, bạn có thể thực hiện điều khiển này bằng cách sử dụng vị trí của ViewHolder trong Bộ điều hợp.

Java

@Override
public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
    if (viewHolder instanceof CartAdapter.MyViewHolder) return 0;
    return super.getSwipeDirs(recyclerView, viewHolder);
}

Kotlin

override fun getSwipeDirs (recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
    if (viewHolder is CartAdapter.MyViewHolder) return 0
    return super.getSwipeDirs(recyclerView, viewHolder)
}

1
Chính xác những gì tôi đang tìm kiếm! Đặc biệt là khi phương pháp này không xuất hiện trên các tài liệu chính thức ...
ptitvinou

1
@ptitvinou, nó có mặt trên SimpleCallback developer.android.com/intl/pt-br/reference/android/support/v7/…
Rafael Toledo

2
Đáng nói: nếu bạn muốn chỉ cho phép một hướng trên các mục nhất định thì hãy sử dụng return position == 0 ? ItemTouchHelper.LEFT : super.getSwipeDirs(recyclerView, viewHolder);- điều này tức là chỉ cho phép vuốt sang trái.
jean d'arme

Hoàn hảo. Làm việc như một sự quyến rũ
King of Masses

Cái này hoạt động ra sao? Tôi phải làm gì nếu tôi muốn vô hiệu hóa thao tác vuốt sang phải chẳng hạn?
Ab

66

Nếu ai đó đang sử dụng ItemTouchHelper.Callback . Sau đó, bạn có thể loại bỏ bất kỳ cờ liên quan nào trong hàm getMovementFlags (..) .

@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
    int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
    int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
    return makeMovementFlags(dragFlags, swipeFlags);
}

Ở đây thay vì dragFlagsswapFlags Bạn có thể chuyển 0 để tắt tính năng tương ứng.

ItemTouchHelper.START có nghĩa là vuốt từ trái sang phải trong trường hợp ngôn ngữ từ trái sang phải (Hỗ trợ ứng dụng LTR), nhưng ngược lại với ngôn ngữ từ phải sang trái (Hỗ trợ ứng dụng RTL). ItemTouchHelper.END có nghĩa là vuốt theo hướng ngược lại START.

vì vậy bạn có thể loại bỏ bất kỳ cờ nào theo yêu cầu của bạn.


Cảm ơn !, Tôi sử dụng mã: @Override public int getMovementFlags (RecyclerView RecyclerView, RecyclerView.ViewHolder viewHolder) {int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; // chuyển động kéo trả về makeFlag (ItemTouchHelper.ACTION_STATE_DRAG, dragFlags); // as tham số, action drag and flags drag}
Do Xuan Nguyen

Đây là câu trả lời ưa thích nếu (không giống như OP) bạn đang mở rộng ItemTouchHelper.Callbacktrực tiếp.
tir38

23

Đây là một cách đơn giản để thực hiện việc này chỉ phụ thuộc vào vị trí của mục đang được vuốt:

@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder holder) {
    int position = holder.getAdapterPosition();
    int dragFlags = 0; // whatever your dragFlags need to be
    int swipeFlags = createSwipeFlags(position)

    return makeMovementFlags(dragFlags, swipeFlags);
}

private int createSwipeFlags(int position) {
  return position == 0 ? 0 : ItemTouchHelper.START | ItemTouchHelper.END;
}

Điều này cũng sẽ hoạt động nếu bạn đang sử dụng SimpleCallback:

@Override
public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder holder) {
    int position = holder.getAdapterPosition();
    return createSwipeFlags(position);
}

private int createSwipeFlags(int position) {
  return position == 0 ? 0 : super.getSwipeDirs(recyclerView, viewHolder);
}

Nếu bạn muốn vô hiệu hóa thao tác vuốt có điều kiện đối với dữ liệu trong mục, hãy sử dụng position giá trị để lấy dữ liệu từ bộ điều hợp cho mục đang được vuốt và tắt tương ứng.

Nếu bạn đã có các loại chủ sở hữu cụ thể không cần vuốt, câu trả lời được chấp nhận sẽ hoạt động. Tuy nhiên, việc tạo các loại chủ sở hữu làm đại diện cho vị trí là một điều không tốt và nên tránh.


6

Có một số cách để giải quyết vấn đề này, nhưng nếu bạn chỉ có một ViewHolder, nhưng có nhiều bố cục, bạn có thể thực hiện phương pháp này.

Ghi đè getItemViewType và cung cấp cho nó một số logic để xác định kiểu xem dựa trên vị trí hoặc kiểu dữ liệu trong đối tượng (Tôi có một hàm getType trong đối tượng của mình)

@Override
public int getItemViewType(int position) {
    return data.get(position).getType;
}

Trả lại bố cục phù hợp trong onCreateView dựa trên ViewType (Đảm bảo chuyển loại chế độ xem cho lớp ViewHolder.

@Override
public AppListItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    mContext = parent.getContext();

    if (viewType == 0){
        return new AppListItemHolder(LayoutInflater.from(mContext).inflate(R.layout.layout, parent, false), viewType);
    else
        return new AppListItemHolder(LayoutInflater.from(mContext).inflate(R.layout.header, parent, false), viewType);
    }
}

Nhận các chế độ xem nội dung của các bố cục khác nhau dựa trên loại chế độ xem public static class AppListItemHolder mở rộng RecyclerView.ViewHolder {

    public AppListItemHolder (View v, int viewType) {
        super(v);

        if (viewType == 0)
            ... get your views contents
        else
            ... get other views contents
        }
    }
}

Và sau đó trong ItemTouchHelper của bạn thay đổi các hành động dựa trên ViewType. Đối với tôi, điều này vô hiệu hóa việc vuốt tiêu đề phần RecyclerView

@Override
public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
    if (viewHolder.getItemViewType() == 1) return 0;
        return super.getSwipeDirs(recyclerView, viewHolder);
    }
}

Ý tưởng tốt đẹp nhưng getItemViewType là cuối cùng
tim

3

Đầu tiên trong phương thức RecyclerView tại onCreateViewHolder, hãy đặt thẻ cho từng loại viewHolder, như mã dưới đây:

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
    if(ITEM_TYPE_NORMAL == viewType) {
        View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.deposite_card_view, viewGroup, false);
        ItemViewHolder holder = new ItemViewHolder(context, v);
        holder.itemView.setTag("normal");
        return holder;
    } else {
        View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.card_header, viewGroup, false);
        HeaderViewHolder holder = new HeaderViewHolder(context, v);
        holder.itemView.setTag("header");
        return holder;
    }
} 

sau đó trong triển khai ItemTouchHelper.Callback, cập nhật phương thức getMovementFlags, như bên dưới:

public class SwipeController extends ItemTouchHelper.Callback {

@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
    if("normal".equalsIgnoreCase((String) viewHolder.itemView.getTag())) {
        return makeMovementFlags(0, LEFT | RIGHT);
    } else {
        return 0;
    }
}

ở cuối đính kèm vào bộ tái chế

final SwipeController swipeController = new SwipeController();

    ItemTouchHelper itemTouchHelper = new ItemTouchHelper(swipeController);
    itemTouchHelper.attachToRecyclerView(recyclerView);

2

Ngoài câu trả lời @Rafael Toledo, Nếu bạn muốn loại bỏ cử chỉ vuốt cụ thể như vuốt TRÁI hoặc vuốt PHẢI dựa trên vị trí hoặc loại dữ liệu trong đối tượng trong Bộ điều hợp, thì bạn có thể làm như thế này.

@Override
  public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder)
       {
          int position = viewHolder.getAdapterPosition();
          ConversationDataModel conversationModel = null;
          conversationModel = mHomeAdapter.getItems().get(position);
          boolean activeChat = true;
          if(conversationModel!=null && !conversationModel.isActive())
           {
             activeChat = false;
           }
  return activeChat ? super.getSwipeDirs(recyclerView, viewHolder): ItemTouchHelper.RIGHT;
        }

Đây là trường hợp của tôi, Trong Bản xem lại của tôi, tôi đang tải các cuộc trò chuyện trò chuyện và nó có các cử chỉ vuốt RIGHT (đối với ARCHIVE) & LEFT (đối với EXIT) trên mỗi mục. Nhưng trong trường hợp nếu cuộc trò chuyện không hoạt động, thì tôi cần tắt vuốt PHẢI cho mục cụ thể trong chế độ xem Trình tái chế.

Vì vậy, tôi đang kiểm tra activeChatvà phù hợp và đã tắt tính năng vuốt RIGHT.


2

Nó có thể bị vô hiệu hóa bằng cách sử dụng ItemTouchHelper.ACTION_STATE_IDLE

ItemTouchHelper.SimpleCallback(
    ItemTouchHelper.UP or ItemTouchHelper.DOWN, //drag directions
    ItemTouchHelper.ACTION_STATE_IDLE //swipe directions
)
val touchHelperCallback = object : ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP or ItemTouchHelper.DOWN, ItemTouchHelper.ACTION_STATE_IDLE) {
    override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
        (recyclerView.adapter as MyAdapter).onItemMove(viewHolder.adapterPosition, target.adapterPosition)
        return true
    }

    override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
        return
    }

}
val touchHelper = ItemTouchHelper(touchHelperCallback)
touchHelper.attachToRecyclerView(recyclerViewX)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.