در این مقاله ی آموزشی قصد داریم به شما یاد بدیم چطور روی آیتم های یک recyclerview عمل swipe به چپ یا راست را انجام دهید و بعد از swipe کردن کاربر آنرا حذف کنید . درست مثل اپلیکیشن اندرویدی GMail .
در این مقاله یاد میگیرید چطور یک آیتم را هنگام swipe پاک کنید و بعد از پاکسازی Undo هم برای لغو حذف نمایش دهید .
از نظر UX برای کاربران اپلیکیشن ها ، swipe کردن روی آیتم ها برای حذف کردن آنها بسیار راحت و دلچسب تر خواهد بود .
شما میتوانید از این آموزش برای تغییرات شخصی خودتان نیز به سادگی استفاده کنید .
خب بیایید شروع کنیم
قدم ۱ - پروژه جدید کاتلین بسازید :
در محیط اندروید استودیو خودتان یک پروژه جدید بسازید و یک اکتیویتی empty جدیدی بسازید . و یادتون نره موقع ساختن پروژه کاتلین رو بعنوان زبان برنامه نویسی انتخاب کنید .
حالا فایل build.gradle(Module: app) را باز کنید و کدهای زیر را بهش اضافه کنید
implementation 'com.android.support:recyclerview-v7:28.0.0'
implementation 'com.android.support:cardview-v7:28.0.0'
implementation 'com.android.support:design:28.0.0'
البته اگر قصد دارید از کتابخانه جدیدتر اینها استفاده کنید از AndroidX استفاده کنید که نحوه ی افزودن کتابخانه ها با androidx را به راحتی میتونید گوگل کنید .
خب برای اضافه کردن recyclerview و cardview و material desing به پروژمون ما نیاز داریم سه کتابخانه بالا را به گردل اضافه کنیم بعد اتصال به اینترنت با دور زدن ip ایران بخاطر تحریم ها نیاز است و سپس sync کنید تا کتابخانه های بالا دانلود و به پروژتون اضافه بشن .
قدم ۲ - اضافه کردن تصویر حذف :
خب یک فایل png تصویری پیدا کنید که تصویر سطل آشغال باشه برای پیدا کردن چنین تصویری مستقیما میتوانید در گوگل عبارت زیر را کپی و سرچ کنید ( البته بخش تصاویر ) :
trash icon filetype:png
و بعد از پیدا کردن تصویر آنرا در مسیر app->res->drawable کپی کنید .
قدم ۳ - اضافه کردن فایل XML و کلاس مدل :
خب در مسیر app->res->layout یک فایل xml جدید بسازید و نام آنرا rv_item.xml قرار دهید .
فایل rv_item.xml باید محتوای زیر را داشته باشد :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="5dp"
android:paddingLeft="5dp"
android:paddingRight="5dp"
tools:context=".MainActivity"
tools:ignore="NamespaceTypo">
<android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/card_view"
android:layout_width="match_parent"
android:layout_height="90dp"
android:layout_gravity="center"
app:cardBackgroundColor="#ffffff"
android:layout_marginTop="0dp"
card_view:cardCornerRadius="1dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/tv"
android:height="90dp"
android:gravity="center"
android:paddingLeft="10dp"
android:text="Image"
android:textColor="#000"
android:textStyle="bold"
android:textSize="18sp" />
</LinearLayout>
</android.support.v7.widget.CardView>
</RelativeLayout>
خب همانطور که در کدهای بالا میبینید این کدها یک textview را داخل یک cardview میسازد پس هر ردیف recyclerview یک عدد cardview خواهد داشت که درونش یک textview وجود دارد .
حالا یک فایل کاتلین جدید بسازید و اسمش رو SwipeModel.kt بزارید .
محتویات SwipeModel.kt باید به شکل زیر باشه :
class Model {
var name: String? = null
fun getNames(): String {
return name.toString()
}
fun setNames(name: String) {
this.name = name
}
}
در کدهای بالا یک متغیر از نوع رشته ای یا string تعریف کردیم که قراره نام ماشین را نگهداری بکنه و روی recyclerview به نمایش بذاره
برای این متغیر دو متد کمک کننده ی Setter و Getter نوشتیم که دریافت و ارسال اطلاعات را راحت میکنه .
قدم ۴ - آداپتر برای swipe :
یک فایل کلاس از نوع کاتلین بسازید و اسم انرا SwipeAdapter.kt انتخاب کنید .
محتویات SwipeAdapter.kt باید به شکل زیر باشد :
import android.content.Context
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import java.util.ArrayList
/**
* Created by avasam.ir in 2019
*/
class SwipeAdapter(ctx: Context, private val imageModelArrayList: ArrayList<Model>) :
RecyclerView.Adapter<SwipeAdapter.MyViewHolder>() {
private val inflater: LayoutInflater
init {
inflater = LayoutInflater.from(ctx)
}
fun removeItem(position: Int) {
imageModelArrayList.removeAt(position)
notifyItemRemoved(position)
notifyItemRangeChanged(position, imageModelArrayList.size)
}
fun restoreItem(model: Model, position: Int) {
imageModelArrayList.add(position, model)
// notify item added by position
notifyItemInserted(position)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val view = inflater.inflate(R.layout.rv_item, parent, false)
return MyViewHolder(view)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.time.setText(imageModelArrayList[position].getNames())
}
override fun getItemCount(): Int {
return imageModelArrayList.size
}
inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var time: TextView
init {
time = itemView.findViewById(R.id.tv) as TextView
}
}
}
در تابع onCreateViewHolder() ما rv_item.xml را پر میکنیم تا ویو مربوط به هر ردیف ساخته شود .
سپس در تابع onBindViewHolder() نام ماشین را در textview ست میکنیم ، برای این از imageModelArrayList بعنوان منبع دیتا استفاده کرده ایم .
imageModelArrayList یک arraylist است که درونش از آبجکت های SwipeModel پر میشود که آداپتر آنرا از پارامترها میگیرد .
خب حالا به کد زیر نگاه کنید :
fun removeItem(position: Int) {
imageModelArrayList.removeAt(position)
notifyItemRemoved(position)
notifyItemRangeChanged(position, imageModelArrayList.size)
}
این تابع زمانی اجرا میشود که کاربر به سمت راست یا چپ عمل swipe را انجام دهد و سپس دکمه ی undo را نزند .
کامپایلر آیتمی که روی آن عمل swipe اتفاق افتاده است را پاکسازی خواهد کرد .
سپس متد notifyItemRemoved() فراخوانی میشود و سپس متد notifyItemRangeChanged() ریسایکلر ویو را ریفرش میکند .
حالا به تابع زیر نگاه کنید :
fun restoreItem(model: Model, position: Int) {
imageModelArrayList.add(position, model)
// notify item added by position
notifyItemInserted(position)
}
اگر کاربر دکمه ی undo را کلیک کند قبل از اینکه آیتم حذف شود کامپایلر متد زیر را فراخوانی میکند .
ابتدا آیتم حذف شده را دوباره به سرجایش برمیگرداند و سپس متد notifyItemInserted() را فراخوانی میکند تا ریسایکلر ویو ریفرش شود .
قدم ۵ - تغییرات اکتیویتی اصلی برنامه :
خب ما دو فایل در اکتیویتی اصلی داریم یکی فایل کاتلین و یکی فایل لیوت آن بنام activity_main.xml که کدش در زیر است :
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/linear"
android:background="#e4e0e0"
tools:context=".MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="10dp"/>
</android.support.design.widget.CoordinatorLayout>
خب همانطور که میبینید چیز خاصی ندارد و فقط یک recyclerview به آن اضافه شده است
کد های زیر هم برای MainActivity.kt است :
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Color
import android.graphics.Paint
import android.graphics.RectF
import android.support.design.widget.Snackbar
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.graphics.Canvas
import java.util.ArrayList
import android.support.v7.widget.helper.ItemTouchHelper
class MainActivity : AppCompatActivity() {
private var recyclerView: RecyclerView? = null
private var imageModelArrayList: ArrayList<Model>? = null
private var adapter: SwipeAdapter? = null
private val p = Paint()
private val myImageNameList = arrayOf("Benz", "Bike", "Car", "Carrera", "Ferrari", "Harly", "Lamborghini", "Silver")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
recyclerView = findViewById(R.id.recycler) as RecyclerView
imageModelArrayList = populateList()
adapter = SwipeAdapter(this, imageModelArrayList!!)
recyclerView!!.adapter = adapter
recyclerView!!.layoutManager = LinearLayoutManager(applicationContext, LinearLayoutManager.VERTICAL, false)
enableSwipe()
}
private fun enableSwipe() {
val simpleItemTouchCallback =
object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) {
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
return false
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
val position = viewHolder.adapterPosition
if (direction == ItemTouchHelper.LEFT) {
val deletedModel = imageModelArrayList!![position]
adapter!!.removeItem(position)
// showing snack bar with Undo option
val snackbar = Snackbar.make(
window.decorView.rootView,
" removed from Recyclerview!",
Snackbar.LENGTH_LONG
)
snackbar.setAction("UNDO") {
// undo is selected, restore the deleted item
adapter!!.restoreItem(deletedModel, position)
}
snackbar.setActionTextColor(Color.YELLOW)
snackbar.show()
} else {
val deletedModel = imageModelArrayList!![position]
adapter!!.removeItem(position)
// showing snack bar with Undo option
val snackbar = Snackbar.make(
window.decorView.rootView,
" removed from Recyclerview!",
Snackbar.LENGTH_LONG
)
snackbar.setAction("UNDO") {
// undo is selected, restore the deleted item
adapter!!.restoreItem(deletedModel, position)
}
snackbar.setActionTextColor(Color.YELLOW)
snackbar.show()
}
}
override fun onChildDraw(
c: Canvas,
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
dX: Float,
dY: Float,
actionState: Int,
isCurrentlyActive: Boolean
) {
val icon: Bitmap
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
val itemView = viewHolder.itemView
val height = itemView.bottom.toFloat() - itemView.top.toFloat()
val width = height / 3
if (dX > 0) {
p.color = Color.parseColor("#388E3C")
val background =
RectF(itemView.left.toFloat(), itemView.top.toFloat(), dX, itemView.bottom.toFloat())
c.drawRect(background, p)
icon = BitmapFactory.decodeResource(resources, R.drawable.delete)
val icon_dest = RectF(
itemView.left.toFloat() + width,
itemView.top.toFloat() + width,
itemView.left.toFloat() + 2 * width,
itemView.bottom.toFloat() - width
)
c.drawBitmap(icon, null, icon_dest, p)
} else {
p.color = Color.parseColor("#D32F2F")
val background = RectF(
itemView.right.toFloat() + dX,
itemView.top.toFloat(),
itemView.right.toFloat(),
itemView.bottom.toFloat()
)
c.drawRect(background, p)
icon = BitmapFactory.decodeResource(resources, R.drawable.delete)
val icon_dest = RectF(
itemView.right.toFloat() - 2 * width,
itemView.top.toFloat() + width,
itemView.right.toFloat() - width,
itemView.bottom.toFloat() - width
)
c.drawBitmap(icon, null, icon_dest, p)
}
}
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
}
}
val itemTouchHelper = ItemTouchHelper(simpleItemTouchCallback)
itemTouchHelper.attachToRecyclerView(recyclerView)
}
private fun populateList(): ArrayList<Model> {
val list = ArrayList<Model>()
for (i in 0..7) {
val imageModel = Model()
imageModel.setNames(myImageNameList[i])
list.add(imageModel)
}
return list
}
}
خب بیایید اکتیویتی اصلی را بررسی کنیم .
ابتدا کدهای زیر را میبینید :
private var recyclerView: RecyclerView? = null
private var imageModelArrayList: ArrayList<Model>? = null
private var adapter: SwipeAdapter? = null
private val p = Paint()
private val myImageNameList = arrayOf("Benz", "Bike", "Car", "Carre
خب در ابتدا یک ابجکت از Recyclerview ساختیم و سپس یک SwipeAdapter و بعد هم کلاس های مورد نیازمان
یک آرایه با ابجکت های مدلی که بالاتر ساختیم و اسمش imageModelArrayList است
و یک آرایه ی از نوع string دیگر که نام وسایل نقلیه را نگهداری میکند مانند Benz Bike Car و ...
حالا کدهای زیر را ببینید :
imageModelArrayList = populateList()
adapter = SwipeAdapter(this, imageModelArrayList!!)
recyclerView!!.adapter = adapter
recyclerView!!.layoutManager = LinearLayoutManager(applicationContext, LinearLayoutManager.VERTICAL, false)
enableSwipe()
کامپایلر populateList() را استفاده خواهد کرد که دیتا را داخل imageModelArrayList قرار دهد .
سپس adapter را به recyclerview معرفی و bind خواهد کرد .
کامپایلر متد enableSwipe() را صدا میزند .
در زیر کدهای متد enableSwipe() میبینید :
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
val position = viewHolder.adapterPosition
if (direction == ItemTouchHelper.LEFT) {
val deletedModel = imageModelArrayList!![position]
adapter!!.removeItem(position)
// showing snack bar with Undo option
val snackbar = Snackbar.make(
window.decorView.rootView,
" removed from Recyclerview!",
Snackbar.LENGTH_LONG
)
snackbar.setAction("UNDO") {
// undo is selected, restore the deleted item
adapter!!.restoreItem(deletedModel, position)
}
snackbar.setActionTextColor(Color.YELLOW)
snackbar.show()
} else {
val deletedModel = imageModelArrayList!![position]
adapter!!.removeItem(position)
// showing snack bar with Undo option
val snackbar = Snackbar.make(
window.decorView.rootView,
" removed from Recyclerview!",
Snackbar.LENGTH_LONG
)
snackbar.setAction("UNDO") {
// undo is selected, restore the deleted item
adapter!!.restoreItem(deletedModel, position)
}
snackbar.setActionTextColor(Color.YELLOW)
snackbar.show()
}
}
کامپایلر متد onSwiped() را زمانی صدا میزند که کاربر به سمت راست یا چپ swipe بکند .
سپس یک شرط if گذاشتیم تا بررسی کند عمل swipe به کدام سمت بوده است .
سپس کامپایلر آبجکتی که میخواهد پاک شود را انتخاب میکند .
سپس متد removeItem() را صدا میزند که درون کلاس آداپتر است
سپس یک snack bar نمایش داده میشود .
زمانی که کاربر دکمه ی UNDO را روی snack bar کلیک میکند کامپایلر متد restoreItem() را صدا خواهد زد .
و کار ما با پیاده سازی این سیستم تمام شد .
مطالب زیر ممکن است برای شما مفید باشد
تحلیل دوره ی پروژه محور ساخت سایت و اپ مارکت بازار با سورس کامل تگ های header را در سئو سایت دست کم نگیرید رادیو صفر و یک - پادکست شماره ی 9 ام - اینترنت بی اینترنت رادیو صفر و یک - پادکست شماره ی 3 ام - شرکت جت برینز و محصولاتش برای برنامه نویسان رادیو صفر و یک - پادکست شماره ی 5 ام - دیپ فیک چیست ؟ آخرین مرز میان حقیقت و دروغ
محصولات برگزیده مناسب شما
دوره ی آموزش برنامه نویسی اندروید با جاوا و android studio کارگاه آموزش طراحی سایت با BULMA دوره آموزش برنامه نویسی اندروید با کاتلین kotlin بصورت پروژه محور دوره آموزش برنامه نویسی کار با سخت افزار اندروید
پایان 👍
- ۰ نظر
- ۲۵ بهمن ۹۸ ، ۰۲:۲۳