Reputation: 643
I want the RecyclerView to dynamically change when the list is altered.
The view is recomposed based on the AndroidView.update expression. However nothing I have tried works. I am not familiar with RecyclerViews and I think that is the issue.
Any ideas?
AndroidView(
factory = {
// Logic for inflating a RecyclerView in a normal Android View System
val view = LayoutInflater.from(it)
.inflate(R.layout.edit_list_xml_screen_layout, null, false)
val recyclerView = view.findViewById<RecyclerView>(R.id.taskListRV)
recyclerView.layoutManager = LinearLayoutManager(it)
val adapter = TaskRecyclerViewAdaptor(it, taskList)
// adapter.setClickListener()
recyclerView.adapter = adapter
recyclerView.addItemDecoration(
DividerItemDecoration(
it,
DividerItemDecoration.VERTICAL
)
)
recyclerView // Return recyclerView
},
update = {
/* TODO dynamically update recycler view */
}
Bonus points if someone can tell me what argument to add to adapter.setClickListener()
Upvotes: 2
Views: 2821
Reputation: 1268
In our case:
ViewBinding
in our Fragment
, therefore we need to remove the parent group first (cmiiw in this part), we use this ViewBindingDelegate hereonItemClick
OurFragment
instead of inside Compose screen, so the compose screen only receive the recyclerView: (Context) -> View
lambda to inflate the view inside Compose screen OurComposeScreen.kt
Our Fragment
// OurFragment.kt
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initBanner()
}
private fun initBanner() {
binding.banner.setContent {
BannerListScreen(
recyclerView = { context ->
recyclerViewSetup(
context = context,
onItemClick = ::recyclerViewClick,
)
},
)
}
}
// ...
private fun recyclerViewSetup(
context: Context,
// modify this to your usecase, as we use RecyclerView.OnItemTouchListener, but this is also possible to use a simple lambda () -> Unit
onItemClick: (Context, MyAdapter) -> RecyclerView.OnItemTouchListener,
): RecyclerView = with(LayoutInflater.from(context).inflate(R.layout.your_custom_xml, null, false)) {
val recyclerView = RecyclerView(context).apply {
if (parent != null) (parent as ViewGroup).removeView(this) // we need to remove the parent group as it'll inflate the view twice if added in compose
layoutManager = LinearLayoutManager(context).apply {
orientation = LinearLayoutManager.HORIZONTAL
}
adapter = MyAdapter(...)
adapter.notifyDataSetChanged()
addOnItemTouchListener(onItemClick(context, adapter))
}
recyclerView
}
private fun recyclerViewClick(
context: Context,
adapter: MyAdapter,
) = RecyclerItemClickListener(
context,
RecyclerItemClickListener.OnItemClickListener { view, position ->
val b = adapter.getItem(position) // todo something with the click listener
}
)
Our Compose screen:
// OurComposeScreen.kt
@Composable
internal fun BannerReminder(
// .....
recyclerView: (Context) -> View,
) {
Column(
// omitted....
) {
AndroidView(
modifier = /* ... */,
factory = { context -> recyclerView(context) }
)
}
}
Upvotes: 3
Reputation: 61
Here, the update block gets called whenever there is change in list "size". Like an item add, remove or clearing list. Considering "taskList" - initially the recycler view is populated on given list and both factory and update block are called for first time.
First update list:
taskList.addAll(itemsToBeAdded)
Notify adapter:
update = {
(it.adapter as TaskRecyclerViewAdaptor).notifyDataSetChanged()
}
To be specific on add or remove item, you can notify it like
UpdateList as:
taskList.add(item)
itemposition = position
or
taskList.remove(item)
itemposition = position
Then in update:
update = {
(it.adapter as TaskRecyclerViewAdaptor).notifyItemRemoved(itemposition)
}
Every time on change in list size, the update method gets called.
Upvotes: 2