ปิดใช้งานการปัดสำหรับตำแหน่งใน RecyclerView โดยใช้ ItemTouchHelper.SimpleCallback


92

ฉันใช้ Recyclerview 22.2.0 และคลาสผู้ช่วย ItemTouchHelper.SimpleCallback เพื่อเปิดใช้งานตัวเลือกปัดเพื่อปิดในรายการของฉัน แต่เนื่องจากฉันมีส่วนหัวประเภทหนึ่งอยู่ฉันจึงต้องปิดใช้งานพฤติกรรมการปัดสำหรับตำแหน่งแรกของอะแดปเตอร์ เนื่องจากRecyclerView.Adapterไม่มีเมธอด isEnabled ()ฉันจึงพยายามปิดใช้งานการโต้ตอบมุมมองผ่านเมธอดisEnabled ()และisFocusable ()ในการสร้าง ViewHolder แต่ไม่ประสบความสำเร็จ ฉันพยายามปรับเกณฑ์การปัดเป็นค่าเต็มเช่น0f ot 1fในเมธอดgetSwipeThreshold ()ของSimpleCallbackแต่ก็ไม่ประสบความสำเร็จเช่นกัน

รหัสบางส่วนของฉันเพื่อช่วยให้คุณช่วยฉันได้

กิจกรรมของฉัน:

@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);
}

และฉันมีอะแดปเตอร์ทั่วไปที่มีมุมมองสองประเภท ในViewHolderที่ฉันต้องการปิดใช้งานการปัดฉันทำ:

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);      
    }
}

คำตอบ:


204

หลังจากที่เล่นบิตฉันจัดการที่SimpleCallbackมีวิธีการที่เรียกว่าgetSwipeDirs () เนื่องจากฉันมี ViewHolder เฉพาะสำหรับตำแหน่งที่ไม่สามารถเลื่อนได้ฉันจึงสามารถใช้อินสแตนซ์ของเพื่อหลีกเลี่ยงการปัดได้ หากไม่ใช่กรณีของคุณคุณสามารถดำเนินการควบคุมนี้โดยใช้ตำแหน่งของ ViewHolder ในอะแดปเตอร์

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
สิ่งที่ฉันกำลังมองหา! โดยเฉพาะอย่างยิ่งเมื่อวิธีนี้ไม่ปรากฏในเอกสารอย่างเป็นทางการ ...
ptitvinou

1
@ptitvinou มีอยู่ในSimpleCallback developer.android.com/intl/pt-br/reference/android/support/v7/…
Rafael Toledo

2
มูลค่าการกล่าวขวัญ: หากคุณต้องการเพียงแค่อนุญาตให้ใช้ทิศทางเดียวในบางรายการให้ใช้ return position == 0 ? ItemTouchHelper.LEFT : super.getSwipeDirs(recyclerView, viewHolder);- อันนี้อนุญาตให้ปัดไปทางซ้ายเท่านั้น
jean d'arme

สมบูรณ์แบบ. ทำงานอย่างมีเสน่ห์
King of Masses

วิธีนี้ทำงานอย่างไร? ฉันต้องทำอย่างไรหากต้องการปิดการใช้งานการปัดขวา
Ali Bdeir

66

หากมีใครใช้ItemTouchHelper.Callback จากนั้นคุณสามารถนำธงใด ๆ ที่เกี่ยวข้อง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);
}

ที่นี่แทนdragFlagsและSwipeFlagsคุณสามารถส่ง 0 เพื่อปิดใช้งานคุณสมบัติที่เกี่ยวข้อง

ItemTouchHelper.STARTหมายถึงการปัดจากซ้ายไปขวาในกรณีที่ตำแหน่งจากซ้ายไปขวา (การสนับสนุนแอปพลิเคชัน LTR) แต่ในอีกทางหนึ่งจะอยู่ในตำแหน่งจากขวาไปซ้าย (การสนับสนุนแอปพลิเคชัน RTL) ItemTouchHelper.ENDSTARTหมายถึงการรูดในทิศทางตรงข้ามของ

เพื่อให้คุณสามารถลบแฟล็กใดก็ได้ตามความต้องการของคุณ


ขอบคุณ! ฉันใช้รหัส: @Override public int getMovementFlags (RecyclerView RecyclerView, RecyclerView.ViewHolder viewHolder) {int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; // การเคลื่อนไหวลากกลับ makeFlag (ItemTouchHelper.ACTION_STATE_DRAG, dragFlags); // เป็นพารามิเตอร์การลากการกระทำและการลากธง}
Do Xuan Nguyen

นี่คือคำตอบที่ต้องการหาก (ไม่เหมือน OP) คุณกำลังขยายItemTouchHelper.Callbackโดยตรง
tir38

23

นี่เป็นวิธีง่ายๆในการทำสิ่งนี้ซึ่งขึ้นอยู่กับตำแหน่งของรายการที่กำลังปัด:

@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;
}

สิ่งนี้ควรใช้งานได้หากคุณใช้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);
}

หากคุณต้องการปิดใช้งานการปัดตามเงื่อนไขกับข้อมูลในรายการให้ใช้positionค่าเพื่อรับข้อมูลจากอะแดปเตอร์สำหรับรายการที่กำลังปัดและปิดใช้

หากคุณมีผู้ถือบางประเภทที่ไม่จำเป็นต้องปัดคำตอบที่ยอมรับจะใช้ได้ อย่างไรก็ตามการสร้างประเภทผู้ถือเป็นพร็อกซีสำหรับตำแหน่งเป็นสิ่งที่ควรหลีกเลี่ยง


6

มีสองสามวิธีในการดำเนินการนี้ แต่ถ้าคุณมี ViewHolder เพียงอันเดียว แต่มีเลย์เอาต์มากกว่าหนึ่งแบบคุณสามารถใช้แนวทางนี้ได้

แทนที่ getItemViewType และให้ตรรกะบางอย่างเพื่อกำหนดประเภทมุมมองตามตำแหน่งหรือประเภทของข้อมูลในวัตถุ (ฉันมีฟังก์ชัน getType ในวัตถุของฉัน)

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

ส่งคืนรูปแบบที่เหมาะสมใน onCreateView ตาม ViewType (ตรวจสอบให้แน่ใจว่าได้ส่งประเภทมุมมองไปยังคลาส 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);
    }
}

รับมุมมองเนื้อหาของเลย์เอาต์ที่แตกต่างกันตามประเภทมุมมองคลาสสแตติกสาธารณะ AppListItemHolder ขยาย RecyclerView.ViewHolder {

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

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

จากนั้นใน ItemTouchHelper ของคุณจะเปลี่ยนการกระทำตาม ViewType สำหรับฉันสิ่งนี้ปิดใช้งานการปัดส่วนหัวของส่วน RecyclerView

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

เป็นความคิดที่ดี แต่ getItemViewType ถือเป็นที่สิ้นสุด
ทิม

3

อันดับแรกใน RecyclerView ที่เมธอด onCreateViewHolder ตั้งค่าแท็กสำหรับแต่ละประเภท viewHolder เช่นโค้ดด้านล่าง

@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;
    }
} 

จากนั้นในการใช้งาน ItemTouchHelper.Callback อัปเดตเมธอด getMovementFlags ดังต่อไปนี้:

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;
    }
}

ในตอนท้ายแนบกับรีไซเคิลดู:

final SwipeController swipeController = new SwipeController();

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

2

นอกจากคำตอบของ @Rafael Toledo แล้วหากคุณต้องการลบท่าทางการปัดเฉพาะเช่นการปัดซ้ายหรือการปัดขวาตามตำแหน่งหรือประเภทของข้อมูลในออบเจ็กต์ในอะแดปเตอร์คุณสามารถทำได้เช่นนี้

@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;
        }

ในกรณีของฉันใน Recyclerview ของฉันฉันกำลังโหลดการสนทนาทางแชทและมีท่าทางการปัดขวา (สำหรับ ARCHIVE) & ซ้าย (สำหรับ EXIT) ในแต่ละรายการ แต่ในกรณีที่การสนทนาไม่ทำงานฉันจำเป็นต้องปิดการใช้งานการปัดขวาสำหรับรายการเฉพาะในมุมมอง Recycler

ดังนั้นฉันกำลังตรวจสอบactiveChatและตามและปิดใช้งานการปัดขวา


2

สามารถปิดใช้งานได้โดยใช้ 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)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.