سلام خدمت شما همراهان سایت SmartDevelopers.ir .
فکر میکنم تا حالا بیشتر شما برنامه هایی رو دیدین که با کشیدن یا درگ کردن (swipe کردن ) آیتم های لیست موجود در برنامه اون آیتم حذف میشه یا کار دیگه ای انجام میشه . برای مثال لیست تماس ها وقتی آیتم ، ریکورد یا مخاطبی رو به سمت راست میکشید با مخاطب تماس میگیره و وقتی به سمت چپ میکشید اونو حذف میکنه یا اینکه به قسمت ارسال اس ام اس میره . تو این آموزش قصد دارم حذف کردن آیتم های RecyclerView با کشیدن به سمت چپ یا راست رو به شما آموزش بدم .
من تو این آموزش نمیخوام یک برنامه کامل درست کنم و فقط میخوام که نحوه ایجاد همچین عملکردی رو بهتون یاد بدم پس برنامه رو به ساده ترین شکل ایجاد میکنم .
ایجاد Layout ها:
یک پروژه جدید درست کنید و در فایل activity_main.xml یک RecyclerView قرار بدید :
1 2 3 4 5 6 7 8 9 10 11 |
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="wrap_content"/> </RelativeLayout> |
یک فایل جدید به اسم recycler_row در پوشه layout بسازید . این فایل قراره لایوت هرکدوم از آیتم های لیست ما بشه . کد های زیر رو درون فایل وارد کنید:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <RelativeLayout android:id="@+id/view_background" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#cf5f5f"> <TextView android:id="@+id/delete" android:layout_width="wrap_content" android:layout_height="40dp" android:text="DELETE" android:gravity="center_vertical" android:layout_alignParentEnd="true"/> </RelativeLayout> <RelativeLayout android:id="@+id/view_foreground" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#f9f0f0" > <TextView android:id="@+id/title" android:gravity="center_vertical" android:textSize="20sp" android:layout_width="wrap_content" android:layout_height="40dp" android:layout_centerHorizontal="true"/> </RelativeLayout> </FrameLayout> |
اینجا از FrameLayout استفاده کردم چون برای اینکه بتونیم اشیا یا ویجت هارو روی همدیگه قرار بدیم، این لایوت بهتر از بقیه لایوت ها عمل میکنه (البته به گفته خود گوگلی ها ) ولی در عمل با RelativeLayout هم میشه همچین کاری کرد ! توی این قسمت دوتا RelativeLayout داریم که یکیش با آیدی view_background و دومیش با آیدی view_foreground مشخص شدند . view_foreground همون لایوت اصلیه که قراره به کاربر نشون داده بشه وview_background که به رنگ قرمز هست قراره زیر view_foreground قرار بگیره که وقتی کاربر آیتم رو به سمت چپ یا راست کشید لایه زیریش یعنی view_background دیده میشه و نوشته DELETE رو نشون میده .
تعریف Adapter برای RecyclerView :
خب تا اینجای کار لایوت های RecyclerView خودمون رو درست کردیم حالا بریم سراغ Adapter برای RecyclerView . یک کلاس به اسم MyAdapter.java بسازید و کد های زیر رو درون فایل وارد کنید :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder>{ private ArrayList<String> models=new ArrayList<>(); public MyAdapter( ArrayList<String> models) { this.models = models; } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_row,parent,false); return new MyViewHolder(view); } @Override public void onBindViewHolder(MyViewHolder holder, int position) { String s=models.get(position); holder.title.setText(s); } @Override public int getItemCount() { return models.size(); } public class MyViewHolder extends RecyclerView.ViewHolder{ public TextView title; public RelativeLayout viewForeground,viewBackground; public MyViewHolder(View itemView) { super(itemView); title=itemView.findViewById(R.id.title); viewBackground=itemView.findViewById(R.id.view_background); viewForeground=itemView.findViewById(R.id.view_foreground); } } public void remove(int position){ models.remove(position); notifyItemRemoved(position); } } |
اگه قبلا با RecyclerView کارکرده باشید فکر نمیکنم تا اینجای کار با کد های بالا مشکلی داشته باشید . فقط در کلاس بالا یک متد با نام remove قرار دادم که قراره برای حذف آیتم استفاده بشه .
حالا به قسمت اصلی میرسیم که کلاس ItemTouchHelper هستش . با استفاده از این کلاس میتونیم swipe کردن (کشیدن) یا عمل (drag and drop ) رو به RecyclerView اضافه کنید .
کلاس دیگری که خاصیت های onSwipe ، onMove و … رو در اختیار ما میذاره کلاس ItemTouchHelper.SimpleCallback هستش . برای استفاده از این کلاس کلاسی به اسم RecyclerItemTouchHelper.java میسازیم و این کلاس از ItemTouchHelper.SimpleCallback ارث بری خواهد کرد .
کد های زیر مربوط به کلاس RecyclerItemTouchHelper.java ست :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
public class RecyclerItemTouchHelper extends ItemTouchHelper.SimpleCallback { // در آخر همین فایل این اینترفیس تعریف شده است و بهتر است اول این اینتر فیس را تعریف کنید private RecyclerItemTouchHelperListener listener; public RecyclerItemTouchHelper(int dragDirs, int swipeDirs,RecyclerItemTouchHelperListener listener) { super(dragDirs, swipeDirs); this.listener=listener; } @Override public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) { if (viewHolder !=null){ // ویو ای که قراره انتخاب بشه و به سمت چپ یا راست کشیده بشه final View foregroundView=((MyAdapter.MyViewHolder)viewHolder).viewForeground; getDefaultUIUtil().onSelected(forgroundView); } } @Override public void onChildDrawOver(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { final View foregroundView=((MyAdapter.MyViewHolder)viewHolder).viewForeground; getDefaultUIUtil().onDrawOver(c,recyclerView,forgroundView,dX,dY,actionState,isCurrentlyActive); } @Override public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { final View foregroundView=((MyAdapter.MyViewHolder)viewHolder).viewForeground; getDefaultUIUtil().clearView(forgroundView); } @Override public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { final View foregroundView=((MyAdapter.MyViewHolder)viewHolder).viewForeground; getDefaultUIUtil().onDraw(c,recyclerView,forgroundView,dX,dY,actionState,isCurrentlyActive); } @Override public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { return true; } @Override public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { listener.onSwiped(viewHolder,direction,viewHolder.getAdapterPosition()); } @Override public int convertToAbsoluteDirection(int flags, int layoutDirection) { return super.convertToAbsoluteDirection(flags, layoutDirection); } public interface RecyclerItemTouchHelperListener{ void onSwiped(RecyclerView.ViewHolder holder,int direction,int position); } } |
شاید براتون سوال باشه که اینترفیس RecyclerItemTouchHelperListener برای چیه ؟ خب ما برای اینکه به کلاس ItemTouchHelper.SimpleCallback بفهمونیم که قراره چه کاری انجام بشه وقتی که آیتم swipe شد به این اینترفیس نیاز داریم تا متدش رو در متد onSwiped مربوط به RecyclerItemTouchHelper فراخوانی کنیم که کاری که قراره انجام بشه رو اجرا کنه (در این آموزش حذف کردن آیتم) . در واقع برای اینکه ما بتونیم یک متد رو به عنوان آرگومان به یک متد دیگه ارسال کنیم باید از اینترفیس استفاده کنیم . کمی جلوتر با نحوه این چیزی که گفتم آشنا میشید .
بخش پایانی :
و در آخر کد های مربوط به MainActivity.java باقی موند که به صورت زیر نوشته میشن :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
public class MainActivity extends AppCompatActivity implements RecyclerItemTouchHelper.RecyclerItemTouchHelperListener{ private RecyclerView recyclerView; private ArrayList<String> models=new ArrayList<>(); private MyAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); recyclerView=findViewById(R.id.recyclerView); models.add("salam"); models.add("salam1"); models.add("salam2"); models.add("salam3"); models.add("salam4"); adapter=new MyAdapter(models); RecyclerView.LayoutManager manager=new LinearLayoutManager(this); recyclerView.setLayoutManager(manager); recyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL)); recyclerView.setItemAnimator(new DefaultItemAnimator()); recyclerView.setAdapter(adapter); //*********** ItemTouchHelper.SimpleCallback simpleCallback=new RecyclerItemTouchHelper(0,ItemTouchHelper.LEFT,this); new ItemTouchHelper(simpleCallback).attachToRecyclerView(recyclerView); } @Override public void onSwiped(RecyclerView.ViewHolder holder, int direction, int position) { adapter.remove(position); } } |
برای اینکه ItemTouchHelper.SimpleCallback رو به RecyclerView معرفی کنیم اول از این کلاس یک شی تولید میکنیم(خط اول زیر ستاره ها ) و با استفاده از متد attachToRecyclerView مربوط به ItemTouchHelper ، شی simpleCallback ی رو که تولید کردیم رو به RecyclerView نسبت میدیم (خط دوم زیر ستاره ها ).
اگر میخواین با کشیدن به هر دو سمت عمل حذف انجام بشه simpleCallback رو به صورت زیر تعریف کنید :
1 2 |
ItemTouchHelper.SimpleCallback simpleCallback= new RecyclerItemTouchHelper(0,ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT,this); |
دقت داشته باشید که MainActivity ما از کلاس RecyclerItemTouchHelper.RecyclerItemTouchHelperListener ایمپلیمنت شده . و در متد onSwiped هم عمل حذف آیتم swipe شده رو انجام میدیم و به متد simpleCallback ارسال میکنیم .
امیدوارم از این آموزش لذت برده باشید 🙂