Các bước để tạo ra 1 class adapter của RecyclerView
B1. Tạo 1 class mới ví dụ RecyclerViewAdapter
B2. Cho class kế thừa như: RecyclerViewAdapter(val context: Context, val category: List<Category>) : RecyclerView.Adapter(){}
B3. Trong class tao tạo 1 inner class Holder : inner class Holder : RecyclerView.ViewHolder
B4. Để chuột vào class Holder nhấn alt+enter rồi chọn Add contructor parameter... sau đó sẽ được như sau : inner class Holder(itemView: View) : RecyclerView.ViewHolder(itemView)
B5. Ta sẽ truyền class Holder vào RecyclerView.Adapter() của class cha ta sẽ được
RecyclerViewAdapter : RecyclerView.Adapter<RecyclerViewAdapter.Holder>(){}
B6.Để trỏ chuột vào class RecyclerViewAdapter nhấn alt+enter chọn implement member để thêm các hàm thành phần : ta chọn 3 hàm trong cửa sổ hiện lên
B7. Khi ta thêm được 3 hàm thành viên như sau
+ onCreateViewHolder :
+getItemCount : Trả về số item có trong danh sách
+onBindViewHolder:
+ Holder : tao các biến liên kết đến các thành phần layout của item
B8. Ta sẽ thao viết code ở class Holder trước:
-Tại đây ta thực hiện các công việc như tạo biến liên kết đến các thành phần layout của item thông qua findViewById
Vd: val categoryName = itemView.findViewById<TextView>(R.id.)
-Ta tạo thêm 1 hàm bindCategory(context: Context, category: Category) : Hàm này thực hiện những câu lệnh truyền giá trị cho biến liên kết layout OR có thể chuyển text thành liên kết để truyền giá trị
B9. Hàm getItemCount : Hàm này trả về số Item sẽ hiển thị ra
overide fun getItemCount(): Int{ return categories.count()}
B10. Hàm onBindViewHolder : Item của RecyclerView lần lượt xuất hiện ở hàm này khi có parametter : position - trả về vị trí hiện tại của list Item
-Ta sẽ thực thi hàm bindCategory tại đây: holder.bindCategory(context, categories[position])
B11. Hàm onCreateViewHolder : Hàm này tạo ra biến view liên kết đến layout của Item
val view = LayoutInflater.from(context).inflate(R. layout.<> , parent, false)
return Holder(view)
Các thao tác với RecyclerView
1. Không thể thiếu đó là tạo 1 biến adapter:
private lateinit var adapter: <tên class adapter>
Tạo adapter: adapter = <tên class adapter>(truyền các parameter cho class)
p/s: Nếu parameter là context thì trên activity ta truyền this, còn trên fragment truyền this.requireActivity()
2. Các item hiện theo hàng ngang hoặc dọc:
Ta có 2 layout: LinearLayoutManager, GridLayoutManager
ví dụ: val layoutManager = LinearLayoutManager(this, LinearLayoutManager.HOZIRONTAL)
3. Tích chọn nhiều Item cùng 1 lúc:
1.Trước tiên ta sẽ tạo 1 list thay đổi được ( mutableListOf<>() ) để lưu vị trị (position) của item được click chọn
2. Trong fun bind của Holder tao viết thuật toán để xuất ra màn hình những thay đổi về layout để người dùng biết là item đã được click chọn hoặc không ( thay đổi màu toàn bộ item or có 1 thành phần nào đó làm điều này )
fun bindHolder (context: Context, product: Product, isSelected: Boolean, position: Int ){
if(isSelected) {
productToggle.setBackgroundResource(R.drawable.color_cllicked)
} else {
productToggle.setBackgroundResource(R.drawable.color_unclicked)
}
}
3. Trong hàm onBindViewHolder() : Ta sẽ thực hiện kiểm tra xem item cừa được click đã được chọn hay chưa bằng cách kiểm tra vị của item xem có trong mutableListOf ở bước 1 không.
Nếu có thì sẽ xoá vị trí đó khỏi list và biến layout trở về trạng thái ban đầu
Nếu không thì sẽ thêm vị trí đó vào list đồng thời thay đổi giao diện để người dùng nhận biết được
override fun onBindViewHolder(holder: Holder, position: Int) {
holder.productCardView.setOnClickListener {
if(selectedItems.contains(position)) {
holder.bindHolder(context, product[position], false, position)
selectedItems.remove(position)
} else {
holder.bindHolder(context, product[position], true, position)
selectedItems.add(position)
}
}
}
4.Bắt sự kiện click recyclerView
a. Tạo 1 interface trong adapter
interface OnItemClickListener {
fun onItemClick(position: Int)
}
b.Tạo đối tượng cho interface đó
private var listener : OnItemClickListener? = null
c. Tạo hàm để lấy ìnterface bên fragment:
fun setOnItemClickListener(listener: OnItemClickListener){
this.listener = listener
}
d. Bên fragment ta override fun onItemClick(position: Int)
recyclerViewAdapter.setOnItemClickListener(object : <tên class Adapter>.OnItemClickListener{
override fun onItemClick(position: Int) {
<code sử lý xử kiện bắt được>
}
})
Nhằm để thực thi bên adapter
e.Thực thi hàm bên adapter
override fun onBindViewHolder(holder: Holder, position: Int) {
holder.bindHolder(context, product[position], false, position)
holder.productCardView.setOnClickListener {
if(selectedItems.contains(position)) {
holder.bindHolder(context, product[position], false, position)
selectedItems.remove(position)
} else {
holder.bindHolder(context, product[position], true, position)
selectedItems.add(position)
}
listener?.onItemClick(position)
}
}
khi click vào item thì listener?.onItemClick(position) được thực thi
5. Load lại danh sách nếu người dùng có thêm, sửa, xoá item
Bên ngoài fragment và trong adapter chúng ta đều gọi 1 hàm đó là
fragment: adapter.notify<nhiều tuỳ chọn>
adapter : this.notify<nhiều tuỳ chọn>
5.1 Cập nhật danh sách một cách thông mình và hiệu quả hơn
* Sử dụng thư viên DiffUtil và AsyncListDiffer
private val differCallback = object : DiffUtil.ItemCallback<Article>(){ //
override fun areItemsTheSame(oldItem: Article, newItem: Article): Boolean {
return oldItem.url == newItem.url
}
override fun areContentsTheSame(oldItem: Article, newItem: Article): Boolean {
return oldItem == newItem
}
}
private val differ = AsyncListDiffer(this, differCallback)
differ.currentList sẽ trả về 1 list dữ liệu kiểu Article
override fun onBindViewHolder(holder: ArticleViewHolder, position: Int) {
val article = differ.currentList[position]
holder.itemView.apply {
Glide.with(this).load(article.urlToImage).into(findViewById(R.id.ivArticleImage))
findViewById<TextView>(R.id.tvSource).text = article.source.name
findViewById<TextView>(R.id.tvTitle).text = article.title
findViewById<TextView>(R.id.tvDescription).text = article.description
findViewById<TextView>(R.id.tvPublishedAt).text = article.publishedAt
setOnClickListener{
onItemClickListener?.let { it(article) }
}
}
}
Đây là 1 cách truyền dữ liệu vào recyclerView hiểu quả khác
6. Xử lý sự kiện vuốt lên-xuông, trái-phải của Item
val itemTouchHelperCallBack = object : ItemTouchHelper.SimpleCallback(
ItemTouchHelper.UP or ItemTouchHelper.DOWN,
ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
) {
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
return true
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
val position = viewHolder.layoutPosition
val article = articleAdapter.differ.currentList[position]
viewModel.deleteArticle(article)
Snackbar.make(view, "Delete successfully", Snackbar.LENGTH_LONG).apply {
setAction("Undo") {
viewModel.insertArticle(article)
}
}.show()
}
}
ItemTouchHelper(itemTouchHelperCallBack).apply {
attachToRecyclerView(binding.rvSavedNews)
}
+ các param là set phương hướng di chuyển cho item
+ Hàm onMove() cho phép or không cho phép item di chuyển
+ hàm onSwiped(). set sự kiện nếu như item bị vuốt sẽ thực thi hững câu lệnh trong hàm
ItemTouchHelper() sẽ liên kết với RecycleView nó sẽ bắt đầu theo dõi sự kiện vuột để trả về các hàm tương ứng trong itemTouchHelperCallBack
Nhận xét
Đăng nhận xét