
في الجزء الأول ، نظرنا إلى ItemTouchHelper وتنفيذ ItemTouchHelper.Callback ، الذي يضيف وظائف السحب والإفلات الأساسية والسحب إلى الفصل إلى RecyclerView
. في هذه المقالة ، سنواصل ما تم فعله في المقالة السابقة بإضافة دعم لترتيب العناصر في شكل شبكة ، وسحب وحدات التحكم وإسقاطها ، واختيار عنصر قائمة ، ورسوم متحركة مخصصة للتمرير.

سحب وإسقاط وحدات التحكم
عند إنشاء قائمة تدعم السحب والإفلات ، عادةً ما تنفذ القدرة على سحب العناصر وإفلاتها عن طريق اللمس. يساهم هذا في وضوح القائمة وسهولة استخدامها في "وضع التحرير" ، كما يوصى به من خلال إرشادات المواد. إن إضافة وحدات تحكم بالسحب والإسقاط إلى مثالنا أمر سهل للغاية.

أولاً ، قم بتحديث layout
العنصر ( item_main.xml ).
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/item" android:layout_width="match_parent" android:layout_height="?listPreferredItemHeight" android:clickable="true" android:focusable="true" android:foreground="?selectableItemBackground"> <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_marginLeft="16dp" android:textAppearance="?android:attr/textAppearanceMedium" /> <ImageView android:id="@+id/handle" android:layout_width="?listPreferredItemHeight" android:layout_height="match_parent" android:layout_gravity="center_vertical|right" android:scaleType="center" android:src="@drawable/ic_reorder_grey_500_24dp" /> </FrameLayout>
يمكن العثور على الصورة المستخدمة لوحدة التحكم في السحب في أيقونات Material Design وإضافتها إلى المشروع باستخدام المكوّن الإضافي المناسب لإنشاء الرموز في Android Studio.
كما ذكرنا بإيجاز في مقال سابق ، يمكنك استخدام ItemTouchHelper.startDrag(ViewHolder)
لبدء السحب والإفلات برمجيًا. لذلك ، كل ما علينا فعله هو تحديث ViewHolder
عن طريق إضافة وحدة تحكم بالسحب ، وإعداد معالج لمس بسيط يستدعي startDrag()
.
سنحتاج إلى واجهة لنقل الأحداث على طول السلسلة:
public interface OnStartDragListener { void onStartDrag(RecyclerView.ViewHolder viewHolder); }
ثم قم بتحديد ImageView
لوحدة تحكم السحب في ItemViewHolder
:
public final ImageView handleView; public ItemViewHolder(View itemView) { super(itemView);
وتحديث RecyclerListAdapter
:
private final OnStartDragListener mDragStartListener; public RecyclerListAdapter(OnStartDragListener dragStartListener) { mDragStartListener = dragStartListener;
يجب أن يبدو RecyclerListAdapter
الآن شيء مثل هذا .
كل ما عليك فعله هو إضافة OnStartDragListener
إلى الجزء:
public class RecyclerListFragment extends Fragment implements OnStartDragListener {
يجب أن يبدو RecyclerListFragment
الآن مثل هذا . الآن ، عند تشغيل التطبيق ، يمكنك البدء في السحب والإسقاط بلمس وحدة التحكم.

تمييز عنصر قائمة
الآن في مثالنا لا يوجد مؤشر مرئي على العنصر الذي يتم سحبه. من الواضح أن هذا لا ينبغي أن يكون ، ولكن من السهل إصلاحه. باستخدام ItemTouchHelper
يمكنك استخدام تأثيرات تمييز العنصر القياسية. على Lollipop والإصدارات الأحدث من Android ، "تنتشر الإضاءة الخلفية" فوق العنصر في عملية التفاعل معه ؛ في الإصدارات السابقة ، يغير العنصر لونه ببساطة إلى اللون الداكن.
لتنفيذ ذلك في مثالنا ، ما FrameLayout
سوى إضافة خلفية (خاصية background
) إلى الجذر FrameLayout
للعنصر FrameLayout
أو تعيينه في مُنشئ RecyclerListAdapter.ItemViewHolder . سيبدو شيء من هذا القبيل:

يبدو رائعًا ، ولكن قد ترغب في التحكم في المزيد. إحدى الطرق للقيام بذلك هي السماح لـ ViewHolder
بمعالجة تغييرات الحالة لعنصر. لهذا ، يوفر ItemTouchHelper.Callback
إضافيتين:
onSelectedChanged(ViewHolder, int)
كل مرة تتغير فيها حالة العنصر لسحبه ( ACTION_STATE_DRAG ) أو السحب ( ACTION_STATE_SWIPE ). يعد هذا مكانًا مثاليًا لتغيير حالة مكون view
إلى نشط .clearView(RecyclerView, ViewHolder)
عند اكتمال مكون view
السحب والإفلات ، وكذلك عند اكتمال التمرير السريع ( ACTION_STATE_IDLE ). هنا ، عادة ما يتم استعادة الحالة الأولية لمكون view
الخاص بك.
الآن ، دعنا نجمع كل شيء معًا.
أولاً ، قم بإنشاء واجهة سيقوم ViewHolders
بتنفيذها:
public interface ItemTouchHelperViewHolder { void onItemSelected(); void onItemClear(); }
بعد ذلك ، في SimpleItemTouchHelperCallback
نفذ الأساليب المناسبة:
@Override public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
كل ما تبقى الآن هو لـ RecyclerListAdapter.ItemViewHolder
لتطبيق ItemTouchHelperViewHolder
:
public class ItemViewHolder extends RecyclerView.ViewHolder implements ItemTouchHelperViewHolder {
في هذا المثال ، نضيف ببساطة خلفية رمادية أثناء تنشيط العنصر ، ثم نزيله. إذا كان ItemTouchHelper
والمحول متصلين بشكل وثيق ، يمكنك بسهولة التخلي عن هذا الإعداد وتبديل حالة مكون view
مباشرة في ItemTouchHelper.Callback
.
شبكات
إذا حاولت الآن استخدام GridLayoutManager
، فسترى أنه لا يعمل بشكل صحيح. السبب والحل بسيط: يجب أن نخبر ItemTouchHelper
بأننا نريد دعم سحب العناصر إلى اليسار واليمين. سابقًا في SimpleItemTouchHelperCallback
الذي SimpleItemTouchHelperCallback
بالفعل:
@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); }
التغيير الوحيد المطلوب لدعم الشبكات هو إضافة العلامات المناسبة:
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
ومع ذلك ، فإن التمرير السريع swipeFlags
ليس سلوكًا طبيعيًا للغاية لعناصر الشبكة ، لذلك swipeFlags
المرجح أن يتم swipeFlags
:
@Override public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT; int swipeFlags = 0; return makeMovementFlags(dragFlags, swipeFlags); }
لمشاهدة مثال GridLayoutManager
، راجع RecyclerGridFragment . إليك ما يبدو عليه عند بدء التشغيل:

انتقاد الرسوم المتحركة المخصصة
يوفر ItemTouchHelper.Callback
طريقة مريحة حقًا للتحكم الكامل في الرسوم المتحركة أثناء السحب أو المسح. نظرًا لأن ItemTouchHelper
عبارة عن RecyclerView.ItemDecoration ، يمكننا التدخل في عملية view
مكون view
بطريقة مماثلة. في الجزء التالي ، سنفحص هذا السؤال بمزيد من التفصيل ، ولكن في الوقت الحالي ، لنلق نظرة على مثال بسيط لتجاوز الرسوم المتحركة الافتراضية للتمرير السريع لإظهار الاختفاء الخطي.
@Override public void onChildDraw(Canvas c, RecyclerView recyclerView, ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) { float width = (float) viewHolder.itemView.getWidth(); float alpha = 1.0f - Math.abs(dX) / width; viewHolder.itemView.setAlpha(alpha); viewHolder.itemView.setTranslationX(dX); } else { super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); } }
dY
و dY
هي التحول الحالي بالنسبة لمكون view
المحدد ، حيث:
- -1.0f عبارة عن تمريرة كاملة من اليمين إلى اليسار (من
ItemTouchHelper.END
إلى ItemTouchHelper.START
) - 1.0f هو التمرير الكامل من اليسار إلى اليمين (من
ItemTouchHelper.START
إلى ItemTouchHelper.END
)
من المهم استدعاء super
لأي حالة actionState
لا تقوم actionState
من أجل تشغيل الرسوم المتحركة الافتراضية.
في الجزء التالي ، سننظر في مثال سنقوم فيه بالتحكم في رسم عنصر في لحظة السحب والإفلات.
الخلاصة
في الواقع ، يعد إعداد ItemTouchHelper أمرًا ممتعًا للغاية. من أجل عدم زيادة حجم هذه المقالة ، قسمتها إلى عدة.
كود المصدر
راجع الرمز الكامل لسلسلة المقالات هذه على مستودعات Android-ItemTouchHelper-Demo GitHub. تتناول هذه المقالة الالتزامات من ef8f149 إلى d164fba .
← اسحب وانتقد في RecyclerView. الجزء 1: ItemTouchHelper