Wrongly run onBindViewHolder in Recyclerview - Kotlin - android

I'am trying to handle my recyclerview put there is a problem
when i scroll down (onBindView function) works fine
but when scroll back to the first items in recyclerview everything becomes wrong like the following images.
package com.leaderspro.mrlawyer.adapters
import android.graphics.Paint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.leaderspro.mrlawyer.R
import com.leaderspro.mrlawyer.models.TODOModel
import kotlinx.android.synthetic.main.todo_list.view.*
class TODOAdapter(private val mArray: ArrayList<TODOModel>) :
RecyclerView.Adapter<TODOAdapter.ViewHolder>() {
var mView: View? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
mView = LayoutInflater.from(parent.context).inflate(R.layout.todo_list, parent, false)
return ViewHolder(mView!!)
}
override fun getItemCount(): Int {
return mArray.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val mTODO = mArray[position]
if (mTODO.isDone == 0) {//not complete
holder.ivIsDone.setImageResource(R.drawable.ic_checkbox_unchecked)
} else if (mTODO.isDone == 1) {
holder.ivIsDone.setImageResource(R.drawable.ic_checkbox_checked)
holder.tvTodoTask.paintFlags =
holder.tvTodoTask.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG //put line on done Tasks
}
holder.tvTodoTask.text = mTODO.task
holder.tvTODODate.text = mTODO.date
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val tvTodoTask = itemView.tvTodoTask!!
val tvTODODate = itemView.tvTODODate!!
val ivIsDone = itemView.ivIsDone!!
val todoListMainLinear = itemView.todoListMainLinear!!
}
}
works fine
https://i.stack.imgur.com/6mBUJ.png
works fine
https://i.stack.imgur.com/qcpLK.png
Wrongly called onBindView when Scroll Back
https://i.stack.imgur.com/2sRsu.png

use holder.adapterposition instead of position
val mTODO = mArray[holder.adapterposition]
for more info check: https://developer.android.com/reference/androidx/recyclerview/widget/RecyclerView.Adapter.html?hl=en#onBindViewHolder(VH,%20int)
edit:
as #Pawel has pointed out, the flags should be cleared when mTodo.isDone == 0.
that should get the job done

Related

Firebase remove child recyclerview Kotlin

I need to remove child from Firebase after onClick from RecyclerView Adapter.
I have something like this:
Firebase database is
recyclerview is
My biggest problem is not sure how to get the "key" of the child node from the recyclerview.
I have been stuck on this supposedly simple thing for about 3 days so hopefully any help is appreciated.
package com.cpg12.findingfresh.adapters
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.cpg12.findingfresh.R
import com.cpg12.findingfresh.database.ShoppingList
import com.google.firebase.database.FirebaseDatabase
class ShoppingListAdapter : RecyclerView.Adapter<ShoppingListAdapter.ShoppingListViewHolder>() {
private val shoppingList = ArrayList<ShoppingList>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ShoppingListViewHolder {
val itemView = LayoutInflater.from(parent.context)
.inflate(R.layout.shopping_list_item, parent, false)
/** References the node to which market data is stored**/
val databaseReference = FirebaseDatabase.getInstance().getReference("Users")
return ShoppingListViewHolder(itemView)
}
override fun onBindViewHolder(holder: ShoppingListAdapter.ShoppingListViewHolder, position: Int) {
val currentItem = shoppingList[position]
holder.sListItem.text = currentItem.shoppingItem
}
override fun getItemCount(): Int {
return shoppingList.size
}
fun updateShoppinglist(shoppingList: List<ShoppingList>){
this.shoppingList.clear()
this.shoppingList.addAll(shoppingList)
notifyDataSetChanged()
}
class ShoppingListViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
val sListItem : TextView = itemView.findViewById(R.id.ShoppingItemTV)
override fun onClick(v: View?) {
databaseReference.child(marketName).setValue(markets).child(key).setValue("")
}
}
}

How can I use setImageResource (or setImageDrawable) in onBindViewHolder?

I can't manage to uset setImageResource on my holder (which is a part of a CardView).
I've already tried to add a image asset but it didn't seem to work.
I would like to know how can I change an image properly in this case.
This is the code of the entire page:
package com.example.revenuer.adapter
import android.R
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.revenuer.entity.Operation
import com.example.revenuer.listener.OperationListener
class HistoryAdapter(val list: List<Operation>): RecyclerView.Adapter<HistoryAdapter.OperationViewHolder>() {
private var listener: OperationListener? = null
fun setOnOperationListener(listener: OperationListener){
this.listener = listener;
}
class OperationViewHolder(view: View, private val listener: OperationListener?): RecyclerView.ViewHolder(view){
val nameView: TextView
val valueView: TextView
val dateView: TextView
val imageView: ImageView
init {
view.setOnClickListener{
listener?.onListItemClick(view, adapterPosition)
}
nameView = view.findViewById(com.example.revenuer.R.id.item_cardview_name)
valueView = view.findViewById(com.example.revenuer.R.id.item_cardview_value)
dateView = view.findViewById(com.example.revenuer.R.id.item_cardview_date)
imageView = view.findViewById(com.example.revenuer.R.id.operation_image)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OperationViewHolder{
val view = LayoutInflater.from(parent.context).inflate(com.example.revenuer.R.layout.operation_item, parent,false)
return OperationViewHolder(view, listener)
}
override fun onBindViewHolder(holder: OperationViewHolder, position: Int) {
val operation = list[position]
holder.nameView.text = operation.name
holder.valueView.text = operation.value
holder.dateView.text = operation.date
if (operation.type) {
holder.imageView.setImageResource(R.drawable.custom_arrow_up)
}
}
override fun getItemCount(): Int {
return list.size
}
}
You have import android.R, so in the rest of your code you need to write com.example.revenuer.R to refer to your own package's R, just like you did elsewhere.
Solution:
Replace import android.R with import com.example.revenuer.R and you can replace all com.example.revenuer.R with R. Explicitly write android.R when you need to.

How to change the value of Alpha when item is clicked inside RecyclerView?

I am not able to figure out how to change the value of alpha when clicked on the item of the RecyclerView . I want to change the value of alpha from 1 to 0.5 .
Below is the Adapter Class for the same .
package GiftClass
import LeaderboardClass.LeaderboardAdapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.gearsrun.www.R
import kotlinx.android.synthetic.main.item_gift.view.*
class GiftAdapter(private val giftList: List<Gift>) : RecyclerView.Adapter<GiftAdapter.GiftViewHolder>() {
private lateinit var mlistener : onItemClickListener
interface onItemClickListener{
fun onItemClick(position: Int)
}
fun setOnItemClickListener(listener: onItemClickListener){
mlistener = listener
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GiftViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.item_gift,parent,false)
return GiftViewHolder(itemView,mlistener)
}
override fun onBindViewHolder(holder: GiftViewHolder, position: Int) {
val currentItem = giftList[position]
holder.item_img.setImageResource(currentItem.imageResource)
holder.item_price.text = currentItem.price
holder.item_soldNum.text = currentItem.sold_num
holder.item_medal.text = currentItem.medal_num
}
override fun getItemCount() = giftList.size
class GiftViewHolder(itemView: View,listener:onItemClickListener) : RecyclerView.ViewHolder(itemView){
val item_img:ImageView = itemView.item_img
val item_price : TextView = itemView.price
val item_soldNum : TextView = itemView.sold_num
val item_medal : TextView = itemView.medal_num
init {
itemView.setOnClickListener {
listener.onItemClick(absoluteAdapterPosition)
itemView.alpha = 0.5f
}
}
}
}
Added References / Suggestion are appreciated
In the onClickListener , you can get the property itemView.alpha and adjust the alpha values as per your needs

Unresolved reference for applicationContext recycleview element (kotlin app for android)

I'm developing an android app in kotlin, and I want to have a button in every recyclerView element, which will launch an intent - the same in whole recycle view, but with different parameters(for now it's just position for testing, in final form that will be some value from database).
I write the following code for that(inside my adapter class):
override fun onBindViewHolder(holder: ProjectViewHolder, position: Int) {
val Edit: Button = holder.view.EditButton
Edit.setOnClickListener()
{
var projekt: Intent = Intent(applicationContext, Project::class.java)
projekt.putExtra("id", position)
startActivity(projekt)
}
But I get "unresolved refference" error for applicationContext. I used buttons with intent like that before and that worked perfectly fine, though this is the first time I'm trying to do it inside recyclerView element.
How to make it work? Maybe I just take the wrong approach and it should be done in different way?
Edit: Complete adapter class file:
package com.example.legoapp127260
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.project_item_layout.view.*
class ProjectAdapter : RecyclerView.Adapter<ProjectViewHolder>()
{
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ProjectViewHolder {
val layoutInflater = LayoutInflater.from(viewGroup.context)
val projectRow = layoutInflater.inflate(R.layout.project_item_layout, viewGroup, false)
return ProjectViewHolder(projectRow)
}
override fun getItemCount(): Int {
return 2;
}
override fun onBindViewHolder(holder: ProjectViewHolder, position: Int) {
val projectName: TextView = holder.view.projectName
val projectNames: Array<String> = arrayOf("Set 1", "Set 2")
val Edit: Button = holder.view.EditButton
projectName.setText(projectNames[position])
Edit.setOnClickListener()
{
var projekt: Intent = Intent(Edit.context, Project::class.java)
projekt.putExtra("id", position)
Edit.context.startActivity(projekt)
}
}
}
class ProjectViewHolder(val view: View) : RecyclerView.ViewHolder(view)
{
}
You can get context from your button:
var projekt: Intent = Intent(Edit.context, Project::class.java)
projekt.putExtra("id", position)
Edit.context.startActivity(projekt)

How to use androidx.recyclerview.selection in androidx.recyclerview.widget. Or how to select an item in recyclerview using kotlin in android?

I have created a horizontal recycler view with items loaded. After that, I need to select that item and perform the click event. Up to this Archived(code is available in the following ), Now I want to change the color of the clicked item and remaining item should be unselected. Please apologize If I didn't query properly.
This all thing built using Kotlin's Androidx Recyclerview. Here is sample code! I'm finding a solution to the extension of this for selecting the item and changing its color.
Android Activity Coded in kotlin
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.view.WindowManager
import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.android.synthetic.main.activity_sample.*
import androidx.recyclerview.widget.RecyclerView
class SampleActivity : AppCompatActivity() {
val bottle_name: ArrayList<String> = ArrayList()
val bottle_img: ArrayList<Int> = ArrayList()
val bottle_type: ArrayList<String> = ArrayList()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_sample)
addBottles()
val adptr = BottlesAdaptor(bottle_name, bottle_img, bottle_type);
bottles_list.adapter = adptr
val layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
val recyclerView = bottles_list
recyclerView.setLayoutManager(layoutManager)
}
override fun onWindowFocusChanged(hasFocus: Boolean) {
super.onWindowFocusChanged(hasFocus)
if (hasFocus) {
hideSystemUI()
}
}
private fun hideSystemUI() {
val decorView = window.decorView
decorView.systemUiVisibility = (
View.SYSTEM_UI_FLAG_IMMERSIVE
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_FULLSCREEN
)
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
fun addBottles(){
bottle_name.add("Coca1");
bottle_name.add("Coca2");
bottle_name.add("Coca3");
bottle_name.add("Coca4");
bottle_name.add("Coca5");
bottle_name.add("Coca6");
bottle_name.add("Coca7");
bottle_name.add("Coca8");
bottle_type.add("cooldrink");
bottle_type.add("cooldrink");
bottle_type.add("cooldrink");
bottle_type.add("cooldrink");
bottle_type.add("cooldrink");
bottle_type.add("wine");
bottle_type.add("wine");
bottle_type.add("wine");
bottle_img.add(R.drawable.coca1);
bottle_img.add(R.drawable.coca2);
bottle_img.add(R.drawable.coca3);
bottle_img.add(R.drawable.coca4);
bottle_img.add(R.drawable.coca5);
bottle_img.add(R.drawable.coca6);
bottle_img.add(R.drawable.coca7);
bottle_img.add(R.drawable.coca8);
}
Bottles Adaptor coded using Kotlin
import android.content.Context
import android.util.Log
import android.view.LayoutInflater
import android.view.ViewGroup
import android.view.View
import android.widget.ArrayAdapter
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.android.synthetic.main.bottle_list_item.view.*
import androidx.recyclerview.widget.RecyclerView
class BottlesAdaptor(private val dataSet: ArrayList<String>, private val dataSet2: ArrayList<Int>, private val dataSet3: ArrayList<String>) :
RecyclerView.Adapter<BottlesAdaptor.ViewHolder>() {
/**
* Provide a reference to the type of views that you are using (custom ViewHolder)
*/
class ViewHolder(v: View) : RecyclerView.ViewHolder(v) {
val textView: TextView
val imageView: ImageView
val textView2:TextView
init {
// Define click listener for the ViewHolder's View.
v.setOnClickListener {
Log.d(TAG, "Element $adapterPosition clicked.")
// I have tried this but it is not giving me the opportunity to select a color for the selected item
if (v.id==adapterPosition){
v.setBackgroundResource(R.drawable.bottle_card_selected);
}
else{
v.setBackgroundResource(R.drawable.bottle_card);
}
}
textView = v.findViewById(R.id.bottle_list_text)
imageView = v.findViewById(R.id.bottle_list_img)
textView2 = v.findViewById(R.id.bottle_list_subtext)
}
}
// Create new views (invoked by the layout manager)
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
// Create a new view.
val v = LayoutInflater.from(viewGroup.context)
.inflate(R.layout.bottle_list_item, viewGroup, false)
return ViewHolder(v)
}
// Replace the contents of a view (invoked by the layout manager)
override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
Log.d(TAG, "Element $position set.")
// Get element from your dataset at this position and replace the contents of the view
// with that element
viewHolder.textView.text = dataSet[position]
viewHolder.textView2.text = dataSet3[position]
viewHolder.imageView.setImageResource(dataSet2[position])
}
// Return the size of your dataset (invoked by the layout manager)
override fun getItemCount() = dataSet.size
companion object {
private val TAG = "CustomAdapter"
}
}
I am expecting a better way of solving solution. also expecting to disable the particular button if possible. It should give the option to the selectable item of recyclerview
Firstly, add the following to your build.gradle (app-level):
implementation "androidx.recyclerview:recyclerview-selection:1.0.0
Set the selection tracker in your RecyclerView Adapter BottlesAdaptor:
private var tracker: SelectionTracker<Long>? = null
fun setTracker(tracker: SelectionTracker<Long>?) {
this.tracker = tracker
}
Use the following method in your Activity SampleActivity to implement the selection tracker:
private fun trackSelectedItems() {
tracker = SelectionTracker.Builder<Long>(
"selection-1",
bottles_list,
ItemIdKeyProvider(bottles_list),
ItemLookup(bottles_list),
StorageStrategy.createLongStorage()
).withSelectionPredicate(SelectionPredicates.createSelectAnything())
.build()
adptr?.setTracker(tracker)
tracker?.addObserver(object: SelectionTracker.SelectionObserver<Long>() {
override fun onSelectionChanged() {
//handle the selected according to your logic
}
})
}
Add ItemIdKeyProvider() like this:
inner class ItemIdKeyProvider(private val recyclerView: RecyclerView)
: ItemKeyProvider<Long>(SCOPE_MAPPED) {
override fun getKey(position: Int): Long? {
return recyclerView.adapter?.getItemId(position)
?: throw IllegalStateException("RecyclerView adapter is not set!")
}
override fun getPosition(key: Long): Int {
val viewHolder = recyclerView.findViewHolderForItemId(key)
return viewHolder?.layoutPosition ?: RecyclerView.NO_POSITION
}
}
Add ItemLookup like the following:
inner class ItemLookup(private val rv: RecyclerView)
: ItemDetailsLookup<Long>() {
override fun getItemDetails(event: MotionEvent)
: ItemDetails<Long>? {
val view = rv.findChildViewUnder(event.x, event.y)
if(view != null) {
return (rv.getChildViewHolder(view) as BottlesAdaptor.ViewHolder)
.getItemDetails()
}
return null
}
}
Since you've also mentioned that Now I want to change the color of the clicked item and remaining item should be unselected, so add the following code in theonBindViewHolder()` of your Adapter:
tracker?.let {
if (it.isSelected(position.toLong()) ) {
it.select(position.toLong())
//changing the color of the clicked/selected item to light gray
//parent.setBackgroundColor( ContextCompat.getColor(context, R.color.extra_light_gray))
} else {
it.deselect(position.toLong())
// set color white
//parent.setBackgroundColor( ContextCompat.getColor(context, R.color.white))
}
}

Categories

Resources