There are two Recyclerview in same activity rv1 and rv2. Selected item of rv1 will show in rv2
rv1:
Here I select multiple items
rv2:
it should shows like this
Adapter class of rv1:
class ServiceJobAdapter(val context: Context, var list:ArrayList<JobRespo>,var listener:OnItemClick):
RecyclerView.Adapter<ServiceJobAdapter.ItemsCarrier>(){
var currentSelectedIndex= -1
var selectedItem = SparseBooleanArray()
var animationItemsIndex = SparseBooleanArray()
private val reverseAllAnimations = false
var holder:ItemsCarrier? =null
class ItemsCarrier(itemView: View) : RecyclerView.ViewHolder(itemView)
{
var jobName = itemView.findViewById<TextView>(R.id.job_name)
var jobPrice = itemView.findViewById<TextView>(R.id.job_price)
var iconBack = itemView.findViewById(R.id.icon_back) as RelativeLayout
var iconFront = itemView.findViewById(R.id.icon_front) as RelativeLayout
var iconContainer = itemView.findViewById(R.id.icon_container) as CardView
fun binde(jobRespo: JobRespo) {
jobName.text = jobRespo.repDesc
jobPrice.text="₹"+jobRespo.repRice
if (iconFront.visibility == View.VISIBLE)
{
jobRespo.setChecked(false)
}else{
jobRespo.setChecked(true)
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemsCarrier {
val view = LayoutInflater.from(context).inflate(R.layout.job_row,parent,false)
return ItemsCarrier(view)
}
override fun getItemCount(): Int {
return list.size
}
override fun onBindViewHolder(holder: ItemsCarrier, position: Int) {
this.holder = holder
holder.itemView.isActivated = selectedItem[position,false]
holder.binde(list[position])
applyIconAnimation(holder, position)
// apply click events
applyClickEvents(holder, position)
}
private fun applyClickEvents(holder: ItemsCarrier, position: Int) {
holder.iconContainer.setOnClickListener {
listener.onIconClicked(position)
listener.AllItem(list[position]) }
}
private fun applyIconAnimation(holder: ItemsCarrier, position: Int)
{
if (selectedItem.get(position, false)) {
holder.iconFront!!.visibility = View.GONE
resetIconYAxis(holder.iconBack)
holder.iconBack.visibility = View.VISIBLE
holder.iconBack.alpha = 1f
if (currentSelectedIndex == position) {
FlipAnimator.flipView(context, holder.iconBack, holder.iconFront, true)
resetCurrentIndex()
}
} else {
holder.iconBack.visibility = View.GONE
resetIconYAxis(holder.iconFront)
holder.iconFront.visibility = View.VISIBLE
holder.iconFront.alpha = 1f
if (reverseAllAnimations && animationItemsIndex.get(
position,
false
) || currentSelectedIndex == position
) {
FlipAnimator.flipView(context, holder.iconBack, holder.iconFront, false)
resetCurrentIndex() } } }
private fun resetIconYAxis(view: RelativeLayout?)
{
if (view!!.rotationY != 0f) {
view.rotationY = 0f
}
}
private fun resetCurrentIndex() {
currentSelectedIndex = -1
}
fun toggleSelection(pos: Int) {
currentSelectedIndex = pos
if (selectedItem.get(pos, false)) {
selectedItem.delete(pos)
animationItemsIndex.delete(pos)
} else {
selectedItem.put(pos, true)
animationItemsIndex.put(pos, true)
}
notifyItemChanged(pos)
}
fun getSelectedItems(): ArrayList<JobRespo>
{
val selectItems = ArrayList<JobRespo>()
for(item in list)
{
if (!item.isChecked())
{
selectItems.add(item)
}
}
return selectItems}}
Using Interface
interface OnItemClick{
fun onIconClicked(position: Int)
fun AllItem(jobs:JobRespo)}
Implement interface in Activity
override fun onIconClicked(position: Int) {
mAdapter!!.toggleSelection(position)
}
override fun AllItem(jobs: JobRespo) {
val selectedItems:ArrayList<JobRespo>
=mAdapter!!.getSelectedItems()
selectIte.addAll(selectedItems)
}
Adapter class of 2nd Recyclerview:
lass SelectItemAdapter(val context: Context, var list:List<JobRespo>): RecyclerView.Adapter<SelectItemAdapter.ItemsCarriers>(){
class ItemsCarriers(itemView: View) : RecyclerView.ViewHolder(itemView) {
var itemName = itemView.findViewById<TextView>(R.id.item_name)
var itemPrice= itemView.findViewById<TextView>(R.id.item_peice)
var itmDelet =itemView.findViewById<LinearLayout>(R.id.item_delete)
fun bind(job: JobRespo) {
itemName.text = job.repDesc
itemPrice.text = job.repRice }
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemsCarriers {
val root = LayoutInflater.from(context).inflate(R.layout.select_item_row,parent,false)
return ItemsCarriers(root)
}
override fun getItemCount(): Int {
return list.size
}
override fun onBindViewHolder(holder: ItemsCarriers, position: Int) {
holder.bind(list[position])}}
Now how can i pass multiselected data from one recyclerview to anathor recyclerview of same activity?
Thanks your consideration and guidded to me :)
You can create a method in a second adapter to update the selected value like below and use it when you getting selected items.
fun setSelectedData(data:ArrayList<JobRespo>){
this.list.clear()
this.list.addAll(data)
notifyDataSetChanged ();
}
Related
In my application I want use checkbox in recyclerview.
I want when users click on item check/unchecked checkbox and when click on Select All or clear, checked/unchecked all of items.
I write below codes, when click on select all checked all of checkboxes but after click on one of checkbox not unchecked!
I should click twice on checkbox after unchecked!
My UI is :
My Adapter codes :
class DataListAdapter #Inject constructor() : RecyclerView.Adapter<DataListAdapter.ViewHolder>() {
private lateinit var binding: ItemWithCheckboxBinding
private lateinit var context: Context
private var moviesList = emptyList<String>()
private var isSelectedAll = false
private var checkBoxState = SparseBooleanArray()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
binding = ItemWithCheckboxBinding.inflate(LayoutInflater.from(parent.context), parent, false)
context = parent.context
return ViewHolder()
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(moviesList[position])
holder.checkBox.isChecked = checkBoxState.get(position, false)
var state: String
if (!isSelectedAll) {
holder.checkBox.isChecked = false
state = LIST_STATE_REMOVE
onItemClickListener?.let { it(moviesList[position], state) }
} else {
holder.checkBox.isChecked = true
state = LIST_STATE_ADD
onItemClickListener?.let { it(moviesList[position], state) }
}
}
override fun getItemCount() = moviesList.size
inner class ViewHolder : RecyclerView.ViewHolder(binding.root) {
val checkBox = binding.itemCheck
#SuppressLint("SetTextI18n")
fun bind(item: String) {
binding.apply {
//Views
itemTitle.text = item
//Click
var state: String
binding.root.setOnClickListener {
if (!checkBoxState.get(adapterPosition, false)) {
checkBox.isChecked = true
checkBoxState.put(adapterPosition, true)
state = LIST_STATE_ADD
} else {
checkBox.isChecked = false
checkBoxState.put(adapterPosition, false)
state = LIST_STATE_REMOVE
}
onItemClickListener?.let { it(item, state) }
}
}
}
}
#SuppressLint("NotifyDataSetChanged")
fun selectAll() {
isSelectedAll = true
notifyDataSetChanged()
}
#SuppressLint("NotifyDataSetChanged")
fun unSelectAll() {
isSelectedAll = false
notifyDataSetChanged()
}
private var onItemClickListener: ((String, String) -> Unit)? = null
fun setOnItemClickListener(listener: (String, String) -> Unit) {
onItemClickListener = listener
}
fun setData(data: List<String>) {
val moviesDiffUtil = NotesDiffUtils(moviesList, data)
val diffUtils = DiffUtil.calculateDiff(moviesDiffUtil)
moviesList = data
diffUtils.dispatchUpdatesTo(this)
}
class NotesDiffUtils(private val oldItem: List<String>, private val newItem: List<String>) : DiffUtil.Callback() {
override fun getOldListSize(): Int {
return oldItem.size
}
override fun getNewListSize(): Int {
return newItem.size
}
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldItem[oldItemPosition] === newItem[newItemPosition]
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldItem[oldItemPosition] === newItem[newItemPosition]
}
}
}
For control select all and clear checkboxes I write codes in Fragment:
selectAllTxt.setOnClickListener { dataListAdapter.selectAll() }
clearTxt.setOnClickListener { dataListAdapter.unSelectAll() }
How can I fix it?
Try to use the !checkBox.isChecked instead of !checkBoxState.get(adapterPosition, false) when clicking:
binding.root.setOnClickListener {
if (!checkBox.isChecked) {
checkBox.isChecked = true
checkBoxState.put(adapterPosition, true)
state = LIST_STATE_ADD
} else {
checkBox.isChecked = false
checkBoxState.put(adapterPosition, false)
state = LIST_STATE_REMOVE
}
onItemClickListener?.let { it(item, state) }
}
I am trying to show multiple type of views in a recyclerview with a header and 5 rows followed by another header and 5 rows but only 4 rows are appearing.
Here is the log output from the adapter in the onBindViewHolder
Here is the code from the adapter
class DailyFragAdapter(
private val activityData: (DetailActivityData) -> Unit,
private val dates: List<Date>,
private val list : ArrayList<TabType1>
) : RecyclerView.Adapter<RecyclerView.ViewHolder>()
/*
ListAdapter<TabType1, RecyclerView.ViewHolder>(Diff())*/ {
private lateinit var context: Context
private val HEADER = 1
private val ROW = 2
/*private class Diff : DiffUtil.ItemCallback<TabType1>() {
override fun areItemsTheSame(oldItem: TabType1, newItem: TabType1): Boolean {
return oldItem.header == newItem.header && oldItem.cps.cps[0].id == newItem.cps.cps[0].id
}
override fun areContentsTheSame(
oldItem: TabType1,
newItem: TabType1
): Boolean {
return oldItem.hashCode() == newItem.hashCode()
}
}*/
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
context = parent.context
val layoutInflater = LayoutInflater.from(context)
return if (viewType == 2) {
DVH(DailyFragRecyclerItemBinding.inflate(layoutInflater, parent, false))
} else {
TitleHolder(DailyTableHeaderBinding.inflate(layoutInflater, parent, false))
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val data: TabType1 = list[position]
if (holder is DVH) {
data.cps.cps.forEach {
Timber.i("is: a row")
holder.bind(it)
}
}else{
Timber.i("is: header")
holder as TitleHolder
holder.bind(data.header)
}
}
override fun getItemViewType(position: Int): Int {
val tabType1 = list[position]
return if (tabType1.header.title == "") {
ROW
} else {
HEADER
}
}
inner class TitleHolder(binding: DailyTableHeaderBinding) :
RecyclerView.ViewHolder(binding.root) {
private val groupHeader: TextView = binding.title
fun bind(title: Header) {
groupHeader.text = title.title
}
}
inner class DVH(binding: DailyFragRecyclerItemBinding) : RecyclerView.ViewHolder(binding.root) {
private var cpname: TextView = binding.cpName
private var day1: FrameLayout = binding.frameLayout
private var day2: FrameLayout = binding.frameLayout2
private var day3: FrameLayout = binding.frameLayout3
private var day4: FrameLayout = binding.frameLayout4
private var dayContainer: ArrayList<FrameLayout> = ArrayList()
fun bind(cpVo: CheckingPointVo) {
dayContainer.addAll(arrayListOf(day1, day2, day3, day4))
cpname.apply {
text = cpVo.name
setOnClickListener {
activityData.invoke(DetailActivityData(cpVo.id, cpVo.pcID))
}
}
val map = cpVo.chartEntriesMap
for (i in dates.indices) {
val dateID = BkpDateUtil.getDateId(dates[i])
Timber.i("dateID $dateID")
var ceVo: List<ChartEntryVo>? = map[dateID]
if (ceVo == null) {
ceVo = ArrayList<ChartEntryVo>()
ceVo.add(ChartEntryVo(0, dateID, 0L, 0L, "", false))
}
val entryValue = ceVo[0].value
when (cpVo.cpType) {
CheckingPointType.YES_NO -> {
val fl: FrameLayout = dayContainer[i]
fl.setOnClickListener {
openYesNoDialog(cpVo, ceVo[0])
}
if (entryValue == 1L) {
setIconInChartEntry(fl, R.drawable.ic_tick, cpVo)
} else {
setIconInChartEntry(fl, R.drawable.ic_no_entry, cpVo)
}
}
CheckingPointType.QUANTIFIABLE -> {
}
CheckingPointType.COUNTABLE -> {
}
CheckingPointType.CATEGORY -> {
}
CheckingPointType.TEXT -> {
}
}
}
dayContainer.clear()
}
}
private fun setIconInChartEntry(fl: FrameLayout, resID: Int, cpVo: CheckingPointVo) {
fl.getChildAt(0).visibility = GONE
val image: ImageView = fl.getChildAt(1) as ImageView
image.visibility = VISIBLE
image.setImageResource(resID)
/*image.setOnClickListener {
activityData.invoke(DetailActivityData(cpVo.id, cpVo.pcID))
}*/
}
private fun openYesNoDialog(cpVo: CheckingPointVo, ce: ChartEntryVo) {
val builder = AlertDialog.Builder(context)
val dataSourceArray = BkpUiUtil.getYesNoArray()
val date = getDateFromId(ce.dateKey)
val title: String = getDayText(date, 1) + " - " + cpVo.name
builder.setTitle(title)
builder.setSingleChoiceItems(
dataSourceArray, BkpUiUtil.getYesNoIndex(ce.value.toString())
) { dialog, which ->
ce.value = BkpUiUtil.getYesNoId(which)
activityData.invoke(
DetailActivityData(
cpvo = cpVo,
cevo = ce,updateChart = true
))
dialog.dismiss()
}
val d = builder.create()
d.show()
}
override fun getItemCount() = list.size
}
data class DetailActivityData(var cpID: Long = 0, var pcID: Long = 0, var cpvo:CheckingPointVo = CheckingPointVo(), var cevo:ChartEntryVo= ChartEntryVo(), var updateChart : Boolean = false)
data class TabType1(
val header: Header = Header(""), val cps: CheckingPointVoList = CheckingPointVoList(
cps = listOf(
CheckingPointVo()
)
)
)
This is how the adapter is given the data.
val data: ArrayList<TabType1> = arrayListOf(
TabType1(
header = Header("Group One")
),
TabType1(
cps = CheckingPointVoList(it)
),
TabType1(
header = Header("Group Two")
),
TabType1(
cps = CheckingPointVoList(it)
)
)
if(it1.updateChart){
vm.updateChartEntry(it1.cpvo,it1.cevo)
}else{
Intent(requireContext(), CpDetailActivity::class.java).apply {
putExtra("cprId", it1.cpID)
putExtra("pcId", it1.pcID)
requireActivity().startActivity(this)
}
}
}, arraylist,dayslist)
This is the output that I get.
What am I missing?
An Adapter should adapt ONE list of data, not multiple lists nested within others. Meaning you need an Adapter and RecyclerView for each list.
If you want to do that you need to add an Adapter/RecyclerView to DVH and display your CheckingPoint list in there.
look here ->
override fun getItemCount() = list.size
Its only going to bind 4 times because you only gave it 4 items.
And here you are just rebinding the same ViewHolder, you need to pass in the data to the ViewHolder and have it display the list of "cps"
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val data: TabType1 = list[position]
if (holder is DVH) {
holder.bind(data) //HERE
}else{
Timber.i("is: header")
holder as TitleHolder
holder.bind(data.header)
}
}
inner class DVH(binding: DailyFragRecyclerItemBinding) : RecyclerView.ViewHolder(binding.root) {
private var checkingPointVoRecyclerView: RecyclerView = binding.recyclerVew
private var checkingPointVoAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder> = CheckingPointVoAdapter(dates)
checkingPointVoRecyclerView.adapter = checkingPointVoAdapter
fun bind(data: TabType1) {
checkingPointVoAdapter.list = data.cps
checkingPointVoAdapter.notifyDataSetChanged()
}
}
class CheckingPointVoAdapter(
private val dates: List<Date>,
) : RecyclerView.Adapter<RecyclerView.ViewHolder>(){
public var list: List<CheckingPointVo> = ArrayList()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
context = parent.context
val layoutInflater = LayoutInflater.from(context)
return ViewHolder(CheckingPointRecyclerItemBinding.inflate(layoutInflater, parent, false))
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val cpv: CheckingPointVo = list[position]
holder as ViewHolder
holder.bind(cpv)
}
inner class ViewHolder(binding: CheckingPointRecyclerItemBinding) : RecyclerView.ViewHolder(binding.root) {
private var cpname: TextView = binding.cpName
private var day1: FrameLayout = binding.frameLayout
private var day2: FrameLayout = binding.frameLayout2
private var day3: FrameLayout = binding.frameLayout3
private var day4: FrameLayout = binding.frameLayout4
private var dayContainer: ArrayList<FrameLayout> = ArrayList()
fun bind(cpVo: CheckingPointVo) {
dayContainer.addAll(arrayListOf(day1, day2, day3, day4))
cpname.apply {
text = cpVo.name
setOnClickListener {
activityData.invoke(DetailActivityData(cpVo.id, cpVo.pcID))
}
}
val map = cpVo.chartEntriesMap
for (i in dates.indices) {
val dateID = BkpDateUtil.getDateId(dates[i])
Timber.i("dateID $dateID")
var ceVo: List<ChartEntryVo>? = map[dateID]
if (ceVo == null) {
ceVo = ArrayList<ChartEntryVo>()
ceVo.add(ChartEntryVo(0, dateID, 0L, 0L, "", false))
}
val entryValue = ceVo[0].value
when (cpVo.cpType) {
CheckingPointType.YES_NO -> {
val fl: FrameLayout = dayContainer[i]
fl.setOnClickListener {
openYesNoDialog(cpVo, ceVo[0])
}
if (entryValue == 1L) {
setIconInChartEntry(fl, R.drawable.ic_tick, cpVo)
} else {
setIconInChartEntry(fl, R.drawable.ic_no_entry, cpVo)
}
}
CheckingPointType.QUANTIFIABLE -> {
}
CheckingPointType.COUNTABLE -> {
}
CheckingPointType.CATEGORY -> {
}
CheckingPointType.TEXT -> {
}
}
}
dayContainer.clear()
}
}
}
I did not test this but this is like 90% of what you need.
OnBindViewHolder gives you a view or you can imagine it as a row
, then you bind data to that row (setting text, etc..)
let's look at what you actually did in OnBindViewHolder
data.cps.cps.forEach { // you bind the data to the same row multiple times
Timber.i("is: a row")
holder.bind(it)
}
But there is only one row.
To solve this you need to pass a list of header items and row items only
sealed class DataItem {
abstract val id: Long
data class RowItem(val row: Row) : DataItem() {
override val id = row.id
}
data class HeaderItem(val header: Header) : DataItem() {
override val id = header.id
}
}
The Transform your row and header data to the DataItem Like this
val rowItems: List<DataItem> = rowList.map { DataItem.RowItem(it) }
val headertems: List<DataItem> = headerList.map { DataItem.BankItem(it) }
val items = rowItems+ headertems
//then pass the items to the adapter
So your adapter now will create a new ViewHoler to each item in the list and you can check for it as
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
ITEM_VIEW_TYPE_ITEM_ROW -> DVH(DailyFragRecyclerItemBinding.inflate(layoutInflater, parent, false))
ITEM_VIEW_TYPE_ITEM_HEADER -> TitleHolder(DailyTableHeaderBinding.inflate(layoutInflater, parent, false))
else -> throw ClassCastException("Unknown viewType $viewType")
}
}
then bind data to each view as
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is DVH-> {
val item = getItem(position) as DataItem.RowItem
holder.bind(item)
}
is TitleHolder -> holder.bind(item)
}
}
Finally you need to adjust getItemViewType
override fun getItemViewType(position: Int): Int {
return when (getItem(position)) {
is DataItem.RowItem -> ITEM_VIEW_TYPE_ITEM_ROW
is DataItem.HeaderItem -> ITEM_VIEW_TYPE_ITEM_HEADER
}
}
I have set up a fragment with a recyclerView in it and I fetch data from firestore successfully. What I want to know is that if it is possible to add items at a certain position in recyclerView. Suppose, I want to add an item (from a different collection in Firestore) after every 5 items in a recyclervView. Is it possible to do it in Android using Kotlin?
Thank you.
Edit:
DashboardFragment.kt
class DashboardFragment : BaseFragment() {
var srchProductsList: ArrayList<Product> = ArrayList()
var adList: ArrayList<Ads> = ArrayList()
var srchTempProductsList: ArrayList<Product> = ArrayList()
var newView: String = "ListView"
private lateinit var binding: FragmentDashboardBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentDashboardBinding.inflate(inflater, container, false)
binding.fbDashboard.setImageResource(R.drawable.ic_grid_view)
binding.fbDashboard.setOnClickListener {
if (newView=="ListView"){
newView="GridView"
fb_dashboard.setImageResource(R.drawable.ic_list_view)
}else{
newView="ListView"
fb_dashboard.setImageResource(R.drawable.ic_grid_view)
}
onResume()
}
return binding.root
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val id = item.itemId
when (id) {
R.id.action_settings -> {
startActivity(Intent(activity, SettingsActivity::class.java))
return true
}
R.id.action_cart -> {
startActivity(Intent(activity, CartListActivity::class.java))
return true
}
}
return super.onOptionsItemSelected(item)
}
override fun onResume() {
super.onResume()
srchProductsList.clear()
srchTempProductsList.clear()
getDashboardItemsList()
}
private fun getDashboardItemsList() {
showProgressDialog(resources.getString(R.string.please_wait))
getDashboardItemsList2()
}
fun successDashboardItemsList(dashboardItemsList: ArrayList<Product>) {
val adsLists =getListOfAds()
hideProgressDialog()
if (dashboardItemsList.size > 0) {
Toast.makeText(
context,
"Total " + dashboardItemsList.size + " products loaded",
Toast.LENGTH_LONG
).show()
rv_dashboard_items.visibility = View.VISIBLE
tv_no_dashboard_items_found.visibility = View.GONE
rv_dashboard_items.layoutManager =
StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
rv_dashboard_items.setHasFixedSize(true)
val adapter = DashboardItemsListAdapterTest(requireActivity(), dashboardItemsList,adsLists)
rv_dashboard_items.adapter = adapter
//////// I HAVE PROBLEM WITH THE FOLLOWING BLOCK OF CODE WHICH IS WHY I HAVE COMMENTED IT OUT ONLY TO CHECK IF OTHER PART OF THE CODE IS WORKING. I NEED TO FIX THE ERROR FOR THE BELOW BLOCK OF CODE ALSO
/* adapter.setOnClickListener(object :
DashboardItemsListAdapter.OnClickListener {
override fun onClick(position: Int, product: Product) {
val intent = Intent(context, ProductDetailsActivity::class.java)
intent.putExtra(Constants.EXTRA_PRODUCT_ID, product.product_id)
intent.putExtra(Constants.EXTRA_PRODUCT_OWNER_ID, product.user_id)
startActivity(intent)
}
})*/
} else {
rv_dashboard_items.visibility = View.GONE
tv_no_dashboard_items_found.visibility = View.VISIBLE
}
}
fun successDashboardItemsListListView(dashboardItemsList: ArrayList<Product>) {
val adsLists =getListOfAds()
hideProgressDialog()
if (dashboardItemsList.size > 0) {
Toast.makeText(
context,
"Total " + dashboardItemsList.size + " products loaded",
Toast.LENGTH_LONG
).show()
rv_dashboard_items.visibility = View.VISIBLE
tv_no_dashboard_items_found.visibility = View.GONE
rv_dashboard_items.layoutManager =
LinearLayoutManager(context)
rv_dashboard_items.setHasFixedSize(true)
val adapter = DashboardItemsListAdapterTest(requireActivity(), dashboardItemsList,adsLists)
rv_dashboard_items.adapter = adapter
//////// I HAVE PROBLEM WITH THE FOLLOWING BLOCK OF CODE WHICH IS WHY I HAVE COMMENTED IT OUT ONLY TO CHECK IF OTHER PART OF THE CODE IS WORKING. I NEED TO FIX THE ERROR FOR THE BELOW BLOCK OF CODE ALSO
/* adapter.setOnClickListener(object :
DashboardItemsListAdapter.OnClickListener {
override fun onClick(position: Int, product: Product) {
val intent = Intent(context, ProductDetailsActivity::class.java)
intent.putExtra(Constants.EXTRA_PRODUCT_ID, product.product_id)
intent.putExtra(Constants.EXTRA_PRODUCT_OWNER_ID, product.user_id)
startActivity(intent)
}
})*/
} else {
rv_dashboard_items.visibility = View.GONE
tv_no_dashboard_items_found.visibility = View.VISIBLE
}
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.dashboard_menu, menu)
super.onCreateOptionsMenu(menu, inflater)
val item = menu.findItem(R.id.my_search_bar)
val searchView = item?.actionView as SearchView
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?): Boolean {
srchTempProductsList.clear()
val searchKey = query
if (searchKey != null) {
if (searchKey.isNotEmpty()) {
srchProductsList.forEach {
if (it.description.toLowerCase(Locale.getDefault())
.contains(searchKey)
) {
srchTempProductsList.add(it)
}
}
rv_dashboard_items.adapter!!.notifyDataSetChanged()
} else {
srchTempProductsList.clear()
srchTempProductsList.addAll(srchProductsList)
rv_dashboard_items.adapter!!.notifyDataSetChanged()
}
}
return false
}
override fun onQueryTextChange(newText: String?): Boolean {
srchTempProductsList.clear()
val searchText = newText!!.toLowerCase(Locale.getDefault())
if (searchText.isNotEmpty()) {
srchProductsList.forEach {
if (it.description.toLowerCase(Locale.getDefault()).contains(searchText)) {
srchTempProductsList.add(it)
}
}
rv_dashboard_items.adapter!!.notifyDataSetChanged()
} else {
srchTempProductsList.clear()
srchTempProductsList.addAll(srchProductsList)
rv_dashboard_items.adapter!!.notifyDataSetChanged()
}
return false
}
})
}
private fun getDashboardItemsList2() {
val mFireStore = FirebaseFirestore.getInstance()
mFireStore.collection(Constants.PRODUCTS)
.get()
.addOnSuccessListener { document ->
for (i in document.documents) {
val product = i.toObject(Product::class.java)!!
product.product_id = i.id
srchProductsList.add(product)
}
srchTempProductsList.addAll(srchProductsList)
if (newView == "ListView") {
successDashboardItemsListListView(srchTempProductsList)
} else {
successDashboardItemsList(srchTempProductsList)
}
}
.addOnFailureListener {
}
}
private fun getListOfAds() : ArrayList<Ads>{
val mFireStore = FirebaseFirestore.getInstance()
mFireStore.collection("ads")
.get()
.addOnSuccessListener { document ->
for (i in document.documents) {
val ad = i.toObject(Ads::class.java)!!
ad.ad_id = i.id
adList.add(ad)
}
}
.addOnFailureListener {
}
return adList
}
}
DashboardItemListAdapterTest.kt
open class DashboardItemsListAdapterTest(
private val context: Context,
private var prodlist: ArrayList<Product>,
private var adslist: ArrayList<Ads>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
companion object {
const val produc= 1
const val ads= 2
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return if (viewType == produc) {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_dashboard_list_view_layout, parent, false)
Collection1Holder(view)
} else {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_dashboard_ad_view_layout, parent, false)
Collection2Holder(view)
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val promodel = prodlist[position]
val adsmodel = adslist[position]
if(getItemViewType(position) == produc) {
holder.itemView.tv_item_name.text = promodel.title
}else{
holder.itemView.tv_item_name.text = adsmodel.title
}
}
override fun getItemCount(): Int {
return prodlist.size + adslist.size
}
override fun getItemViewType(position: Int): Int {
return if(position%5 == 0) ads else produc
}
inner class Collection1Holder(itemView: View) : RecyclerView.ViewHolder(itemView) {
}
inner class Collection2Holder(itemView: View) : RecyclerView.ViewHolder(itemView) {
}
}
Model class
Ads.kt
data class Ads(
val title: String = "",
var ad_id: String = ""
)
You can use two viewholder for two different collections of data.
Change your adapter class like this.
class YourAdapter() : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
companion object {
const val COLLCTION1= 1
const val COLLCTION2= 2
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return if (viewType == COLLCTION1) {
val view = LayoutInflater.from(viewGroup.context)
.inflate(R.layout.collection1, viewGroup, false)
Collection1Holder(view)
} else {
val view = LayoutInflater.from(viewGroup.context)
.inflate(R.layout.collection2, viewGroup, false)
Collection2Holder(view)
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if(getItemViewType(position) == COLLCTION1) {
holder.name.text = collection1.text
}else{
holder.name.text = collection2.text
}
}
override fun getItemCount(): Int {
return collection1.size + collection2.size
}
override fun getItemViewType(position: Int): Int {
return if(position%5 == 0) COLLCTION2 else COLLCTION1
}
inner class Collection1Holder(itemView: View) : RecyclerView.ViewHolder(itemView) {
}
inner class Collection2Holder(itemView: View) : RecyclerView.ViewHolder(itemView) {
}
}
I try to make a RecyclerView smooth scrolling. I only load 10 items, with a ProgressBar while loading that disappears once loaded. Yet my RecyclerView gets stuck at the first element.
I used:
recyclerView.setNestedScrollingEnabled(false);
Without success.
class SummeryRecyclerViewAdapter(
var context: Context, val resultList: ArrayList<Result>
) : RecyclerView.Adapter<SummeryRecyclerViewAdapter.ViewHolder>() {
lateinit var onloadMoreListener: OnLoadMoreListener
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): SummeryRecyclerViewAdapter.ViewHolder {
return ViewHolder(LayoutInflater.from(parent?.context).inflate(R.layout.sigle_row_for_summery, parent, false))
}
override fun onBindViewHolder(holder: ViewHolder?, position: Int) {
// MY CODE IS HERE (ITS LONG LIME CODE)}
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getItemViewType(position: Int): Int {
return position
}
override fun getItemCount(): Int {
return resultList.size
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
// MY VIEW ITEMS HERE ...
}
fun setLoadMoreListener(onLoadMoreListener: OnLoadMoreListener) {
this.onloadMoreListener = onLoadMoreListener
}
interface OnLoadMoreListener {
fun onLoadMore()
}
fun addMoreData(articleLists: MutableList<Result>) {
resultList.addAll(articleLists)
notifyItemRangeInserted(resultList.size + 1, articleLists.size)
}
}
My Activity Code:
class SummeryActivity : AppCompatActivity(), SummeryRecyclerViewAdapter.OnLoadMoreListener {
private lateinit var summeryRecyclerViewAdapter: SummeryRecyclerViewAdapter
var last_no: Int = 0
var isLoading: Boolean = false
var countLoad: Int = 1
val resultHandler = ResultHandler(this)
var exam_id: Int = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_summery)
window.statusBarColor = resources.getColor(R.color.colorPrimaryDark)
summery_btnCloseActivity.setOnClickListener { finish() }
exam_id = intent.getIntExtra("examId", 0)
val myData = resultHandler.getResultData(exam_id)
Log.e("myData", "${myData}")
summeryRecyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
summeryRecyclerViewAdapter = SummeryRecyclerViewAdapter(this, getItems())
summeryRecyclerView.setNestedScrollingEnabled(false);
summeryRecyclerView.adapter = summeryRecyclerViewAdapter
summeryRecyclerViewAdapter.setLoadMoreListener(this)
}
fun getItems(): ArrayList<Result> {
val userList: ArrayList<Result>
userList = resultHandler.getResultData(exam_id, "10", last_no)
last_no = userList.size
return userList
}
override fun onLoadMore() {
if (resultHandler.getResultData(exam_id).size != last_no) {
if (!isLoading) {
isLoading = true
Handler().postDelayed({
load_progress_summery.visibility = View.VISIBLE
summeryRecyclerView.smoothScrollToPosition(summeryRecyclerViewAdapter.itemCount)
}, 100)
}
Handler().postDelayed({
isLoading = false
load_progress_summery.visibility = View.GONE
val userList: ArrayList<Result>
userList = resultHandler.getResultData(exam_id, "10", last_no)
last_no += userList.size
countLoad += 1
summeryRecyclerViewAdapter.addMoreData(userList)
}, 10 * 100)
} else {
load_progress_summery.visibility = View.GONE
}
}
}
I have a recycler view with two different items.
The first position should show a set of buttons while the rest of the items show details about a specific contact.
This is the adapter code
class CustomersAdapter(private val context: Context, private val customersListener: CustomerListener) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private val contacts: ArrayList<Contact> = ArrayList()
private var lastPosition = -1
private val colorGenerator = ColorGenerator.MATERIAL
companion object {
const val ITEM_TYPE_CONTACT = 1
const val ITEM_TYPE_BUTTONS = 2
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return if (viewType == ITEM_TYPE_BUTTONS) {
val v = LayoutInflater.from(context).inflate(R.layout.item_group_buttons, parent, false)
GroupViewHolder(v)
} else {
val v = LayoutInflater.from(context).inflate(R.layout.item_customer, parent, false)
ViewHolderContact(v)
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder.itemViewType == ITEM_TYPE_CONTACT) {
val contact = contacts[position - 1]
(holder as ViewHolderContact).bind(contact)
}
showAnimation(holder.itemView, position)
}
override fun getItemCount(): Int {
return contacts.size + 1
}
override fun getItemViewType(position: Int): Int {
return if (position == 0) ITEM_TYPE_BUTTONS
else ITEM_TYPE_CONTACT
}
private fun showAnimation(viewToAnimate: View, position: Int) {
if (position > lastPosition) {
val animation = AnimationUtils.loadAnimation(context, android.R.anim.slide_in_left)
viewToAnimate.animation = animation
lastPosition = position
}
}
interface CustomerListener {
fun onCustomerClicked(contact: Contact)
}
inner class ViewHolderContact(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(contact: Contact) {
itemView.icon_image.visibility = View.GONE
itemView.icon_text.visibility = View.VISIBLE
itemView.tv_text.text = contact.name.firstChar()
itemView.tv_customer_name.text = contact.name
itemView.tv_customer_progress.text = "${contact.profileCompleteness}% completed"
itemView.progress_customer.progress = contact.profileCompleteness
val icon = itemView.icon_profile.background as GradientDrawable
icon.setColor(colorGenerator.getColor(contact.name ?: ""))
itemView.setOnClickListener { customersListener.onCustomerClicked(contacts[adapterPosition]) }
}
}
inner class GroupViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
fun setContacts(contacts: ArrayList<Contact>) {
val callback = DiffUtilCallback(this.contacts, contacts)
val diffResult = DiffUtil.calculateDiff(callback)
diffResult.dispatchUpdatesTo(this)
this.contacts.clear()
this.contacts.addAll(contacts)
}
}
But when the adapter is set, the recycler views shows the last item and I have to add something like recyclerView.smoothScrollTo(0); but it becomes a problem when there are more than 1000. Why does this happen? This didn't happen when I just had the contacts item and not a heterogenous recycler view.
try with this
if (mRecyclerView != null) {
getHandler().post(new Runnable() {
#Override
public void run() {
mRecyclerView.scrollToPosition(0);
if (position == 0) {
LinearLayoutManager layoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
layoutManager.scrollToPositionWithOffset(0, 0);
}
}
});
}