Heyy, it's the first time i use android studio and i want to display the content of a class in a card view dynamically on my page. For exemple I have a class Book that contains the Book title and a little description and i initialise 3 instances of books.. I want 3 cards in my page containing the books titles and description. How can this be done ? Thankz
You should create a recycleview.
They are the steps }
First. Import the dependecy
dependencies {
implementation 'androidx.recyclerview:recyclerview:1.0.0'
}
Second. Add RecyclerView in xml
<androidx.recyclerview.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
Third. Create the adapter view
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="4dp">
<ImageView android:id="#+id/foto"
android:layout_width="?android:attr/listPreferredItemHeight"
android:layout_height="?android:attr/listPreferredItemHeight"
android:contentDescription="fotografía"
android:src="#drawable/bar"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"/>
<TextView android:id="#+id/nombre"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Nombres del lugar"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textStyle="bold"
android:maxLines="1"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="#+id/foto"
app:layout_constraintEnd_toEndOf="parent"/>
<TextView android:id="#+id/direccion"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center"
android:maxLines="1"
android:text="dirección del lugar"
app:layout_constraintTop_toBottomOf="#id/nombre"
app:layout_constraintStart_toEndOf="#+id/foto"
app:layout_constraintEnd_toEndOf="parent"/>
<RatingBar android:id="#+id/valoracion"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="?android:attr/ratingBarStyleSmall"
android:isIndicator="true"
android:rating="3"
app:layout_constraintTop_toBottomOf="#id/direccion"
app:layout_constraintLeft_toRightOf="#+id/foto"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
Fourth. Create the adpater's class
class AdaptadorLugares(private val lugares: RepositorioLugares) :
RecyclerView.Adapter<AdaptadorLugares.ViewHolder>() {
class ViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
fun personaliza(lugar: Lugar) = with(itemView){
nombre.text = lugar.nombre
direccion.text = lugar.direccion
foto.setImageResource(when (lugar.tipoLugar) {
TipoLugar.RESTAURANTE -> R.drawable.restaurante
TipoLugar.BAR -> R.drawable.bar
TipoLugar.COPAS -> R.drawable.copas
TipoLugar.ESPECTACULO -> R.drawable.espectaculos
TipoLugar.HOTEL -> R.drawable.hotel
TipoLugar.COMPRAS -> R.drawable.compras
TipoLugar.EDUCACION -> R.drawable.educacion
TipoLugar.DEPORTE -> R.drawable.deporte
TipoLugar.NATURALEZA -> R.drawable.naturaleza
TipoLugar.GASOLINERA -> R.drawable.gasolinera
TipoLugar.OTROS -> R.drawable.otros
})
foto.setScaleType(ImageView.ScaleType.FIT_END)
valoracion.rating = lugar.valoracion
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int):
ViewHolder {
val v = LayoutInflater.from(parent.context)
.inflate(R.layout.elemento_lista, parent, false)
return ViewHolder(v)
}
override fun onBindViewHolder(holder: ViewHolder, posicion: Int) {
val lugar = lugares.elemento(posicion)
holder.personaliza(lugar)
}
override fun getItemCount() = lugares.tamanyo()
}
Finally call the adapter in activity's main
You can check the oficial documentation in google
https://developer.android.com/guide/topics/ui/layout/recyclerview
Example code
http://www.androidcurso.com/index.php/691
Related
So I am trying to create a simple Note App, where the user gives data, gets stored in a database, and is displayed using a recycler view. Up until now, I can confirm that data is being stored in my database, and that data is also being retrieved from it and being initialized to a variable in the adapter class, but for some reason, the Adapter's OnCreateViewHolder(), OnBindViewHolder() and getItemCount() functions are not being called even after notifying the adapter of the change in data. This is my MainActivity and Adapter class.
class MainActivity : AppCompatActivity() {
private lateinit var viewModel: NoteViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val noteAdapter = NotesRVAdapter(this)
notesRV.adapter = noteAdapter
notesRV.layoutManager = LinearLayoutManager(this)
viewModel = ViewModelProvider(this,ViewModelProvider.AndroidViewModelFactory.getInstance(application)).get(NoteViewModel::class.java)
//access getAllNotes from NoteViewModel class from created instance
viewModel.getAllNotes.observe(
this,
Observer { list ->
list?.let {
Log.d("TAG","Observing")
NotesRVAdapter(this).updateList(it as ArrayList<NoteEntity>)
// Toast.makeText(this,"$it",Toast.LENGTH_LONG).show()
}
},
)
}
fun createNote(view: View) {
val intent = Intent(this,SecondActivity::class.java) // for creating a note
startActivity(intent)
}
}
Adapter Class
class NotesRVAdapter(private val context: Context) : RecyclerView.Adapter<NotesRVAdapter.NotesVH>() {
private var noteItem = ArrayList<NoteEntity>()
inner class NotesVH(noteView: View): RecyclerView.ViewHolder(noteView)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NotesVH {
val view = LayoutInflater.from(parent.context).inflate(R.layout.note_item,parent,false)
return NotesVH(view)
}
override fun onBindViewHolder(holder: NotesVH, position: Int) {
holder.itemView.Heading.text = noteItem[position].heading
holder.itemView.Description.text = noteItem[position].text
holder.itemView.Priority.text = noteItem[position].priority.toString()
}
override fun getItemCount(): Int {
return noteItem.size
}
fun updateList(list: ArrayList<NoteEntity>){
noteItem.clear()
noteItem.addAll(list)
// Toast.makeText(context,"${noteItem[0].text}",Toast.LENGTH_LONG).show()
notifyDataSetChanged()
}
}
The updateList function is getting called in mainactivity and the list is being passed in the noteitem and the toast also works, but that's it. All the override functions seem to be not working as I tried running a Log statement in them, but there was no entry for any Log in the Logcat.
I don't think there's a problem in the XML file as I could see the preview using the tools statement, but if someone needs to check it, here it is:
note_item.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:tools="http://schemas.android.com/tools"
android:paddingHorizontal="30dp"
android:paddingVertical="30dp"
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView
android:id="#+id/Heading"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintRight_toLeftOf="#id/Priority"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text = "Note Heading"
android:textSize="35sp"
android:textStyle="bold"
android:textColor="#color/black"
/>
<TextView
android:id="#+id/Description"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="#id/Heading"
app:layout_constraintRight_toLeftOf="#id/Priority"
tools:text="Description"
android:textSize="25sp"
android:textColor="#color/black"
/>
<TextView
android:id="#+id/Priority"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="1"
android:textSize="60sp"
android:textColor="#color/black"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/notesRV"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:layout_width="0dp"
android:layout_height="0dp"
tools:listitem="#layout/note_item"
/>
<ImageView
android:id="#+id/createNote"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginBottom="80dp"
android:layout_marginRight="40dp"
android:layout_width="80dp"
android:layout_height="80dp"
android:src="#drawable/ic_baseline_add_24"
android:onClick="createNote"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
I would appreciate it if someone could help me with this issue. Thanks!
you are creating a new adapter instance here which is not attached to your recyclerview
NotesRVAdapter(this).updateList(it as ArrayList<NoteEntity>)
change it to the one attached to your recyclerview and that will be
noteAdapter.updateList(it as ArrayList<NoteEntity>)
As the official material.io documentation says:
Chips are compact elements that represent an input, attribute, or action.
I want to add chips as attributes (tags) for any blog post, a recyclerview is used to show the list of blog posts:
item_post.xml
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/mcv_container_item_blog"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="true"
android:clickable="true"
android:background="?selectableItemBackground"
app:cardUseCompatPadding="true">
<androidx.appcompat.widget.LinearLayoutCompat
android:id="#+id/llc_container_item_project"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="#dimen/item_margin"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatImageView
android:id="#+id/aciv_item_post_image"
android:layout_width="match_parent"
android:layout_height="#dimen/item_project_Image_size"
android:scaleType="centerCrop"
android:adjustViewBounds="true"
app:srcCompat="#drawable/drawer_bg"/>
<com.google.android.material.textview.MaterialTextView
android:id="#+id/mtv_item_post_title"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="#dimen/item_margin"
android:textAppearance="#style/TextAppearance.AppCompat.Large"
android:textColorHighlight="#color/design_default_color_background"
android:text="Chameleon UI Kit" />
<com.google.android.material.textview.MaterialTextView
android:id="#+id/mtv_item_post_date"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textColor="#color/red_lighten"
android:layout_marginTop="#dimen/user_name_margin_start"
android:layout_marginEnd="#dimen/user_name_margin_start"
android:layout_marginBottom="#dimen/user_name_margin_start"
android:text="10 Sept"/>
<com.google.android.material.textview.MaterialTextView
android:id="#+id/mtv_item_post_short_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="#style/TextAppearance.AppCompat.Small"
android:text="#string/about_me" />
<include layout="#layout/item_divider"/>
<HorizontalScrollView
android:id="#+id/hsv_item_post_tags"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none">
<com.google.android.material.chip.ChipGroup
android:id="#+id/cg_item_post_tags"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:singleLine="true"/>
</HorizontalScrollView>
</androidx.appcompat.widget.LinearLayoutCompat>
</com.google.android.material.card.MaterialCardView>
then the PostAdapter class:
class PostAdapter(
private val postList: List<Post>
): RecyclerView.Adapter<PostAdapter.PostViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PostViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_post, parent, false)
return PostViewHolder(view)
}
override fun onBindViewHolder(holder: PostViewHolder, position: Int) {
val post = postList[position]
holder.postTitle.text = post.postTitle
holder.postDescription.text = post.postDescription
holder.postDate.text = post.postDate
val tagChip = Chip(holder.itemView.context).apply {
id = View.generateViewId()
text = "label"
}
holder.postTagsChipGroup.addView(tagChip)
}
override fun getItemCount(): Int {
return postList.size
}
inner class PostViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val postTitle: MaterialTextView = itemView.findViewById(R.id.mtv_item_post_title)
val postDescription: MaterialTextView = itemView.findViewById(R.id.mtv_item_post_short_description)
val postTagsChipGroup: ChipGroup = itemView.findViewById(R.id.cg_item_post_tags)
val postDate: MaterialTextView = itemView.findViewById(R.id.mtv_item_post_date)
}
}
at this stage a weird thing happens, when I 'scroll recyclerview' other Chips are added from nowhere as you can see this behavior in gif below:
how to avoid such behavior, what changes should I make in adapters onBindViewHolder method?
I have created the adapter below which shows two different data models in the recycler view.
However, I am not sure how to do the bindings in the bind functions written in the ViewHolders. I have two seperate xml files which I would like to bind when this "bind" function is called but how do I set the data?
My code is as follows:
class HomeAdapter(
private val context: Context
) :
RecyclerView.Adapter<HomeAdapter.BaseViewHolder<*>>() {
private var homeList: List<Any> = emptyList()
companion object {
private const val TYPE_VISIT = 0
private const val TYPE_WASH = 1
}
abstract class BaseViewHolder<T>(itemView: View) : RecyclerView.ViewHolder(itemView) {
abstract fun bind(item: T)
}
inner class VisitViewHolder(itemView: View) : BaseViewHolder<HomeVisitLabel>(itemView) {
override fun bind(item: HomeVisitLabel) {
//Do your view assignment here from the data model
}
}
inner class WashViewHolder(itemView: View) : BaseViewHolder<HomeWashLabel>(itemView) {
override fun bind(item: HomeWashLabel) {
//Do your view assignment here from the data model
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<*> {
return when (viewType) {
TYPE_VISIT -> {
val view = LayoutInflater.from(context)
.inflate(R.layout.reward_label_visit_card, parent, false)
VisitViewHolder(view)
}
TYPE_WASH -> {
val view = LayoutInflater.from(context)
.inflate(R.layout.reward_label_wash_card, parent, false)
WashViewHolder(view)
}
else -> throw IllegalArgumentException("Invalid view type")
}
}
override fun onBindViewHolder(holder: BaseViewHolder<*>, position: Int) {
val element = homeList[position]
when (holder) {
is VisitViewHolder -> holder.bind(element as HomeVisitLabel)
is WashViewHolder -> holder.bind(element as HomeWashLabel)
else -> throw IllegalArgumentException()
}
}
override fun getItemViewType(position: Int): Int {
val comparable = homeList[position]
return when (comparable) {
is HomeVisitLabel -> TYPE_VISIT
is HomeWashLabel -> TYPE_WASH
else -> throw IllegalArgumentException("Invalid type of data " + position)
}
}
override fun getItemCount(): Int {
return homeList.size
}
}
One of the two XML files
<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="VisitLabel"
type="com.modelz.HomeVisitLabel" />
</data>
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="5dp"
android:layout_margin="5dp"
app:cardBackgroundColor="#color/colorPrimary">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginLeft="10dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18sp"
android:text="Visit:"
android:gravity="left"
android:layout_weight="1"
android:layout_marginTop="5dp"
android:textStyle="bold"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18sp"
android:text="#{VisitLabel.Name}"
android:gravity="left"
android:layout_weight="1"
android:layout_marginTop="5dp"
android:textStyle="bold"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Redeem"
android:visibility="invisible"/>
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_weight="0.5"
android:gravity="left"
android:text="#{VisitLabel.descript}"
android:textSize="16dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_weight="0.5"
android:gravity="left"
android:text="Progress:"
android:textSize="16dp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_weight="0.9"
android:text="#{VisitLabel.countUser}"
android:gravity="right"
android:textSize="16sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_weight="0.5"
android:text="#{VisitLabel.countSet}"
android:gravity="left"
android:textSize="16sp" />
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
</layout>
if you want to use data binding, you need to inflate your layouts from Binding class as follow:
val binding = RewardLabelVisitCardBinding.inflate(layoutInflater, parent, false)
and same for the other layout.
You can get layoutInflator using:
val layoutInflater = LayoutInflater.from(parent.context)
And then in the bind function you need to use that binding variable to assign attributes. like,
binding.textView.text = item.name
The overall code for better understanding is given below:
class VisitViewHolder(private val binding: RewardLabelVisitCardBinding) : BaseViewHolder<HomeVisitLabel>(binding.root) {
override fun bind(item: HomeVisitLabel) {
binding.VisitLabel = item
binding.executePendingBindings()
}
}
Just pass binding variable to ViewHolder after inflating the layout in onCreateViewHolder
return VisitViewHolder(binding)
Hope, that answers your question!
You will need to complete the bind functions for both the viewholders:
override fun bind(item: HomeVisitLabel) {
// textView.text = item.name // example
}
You should be able to assign the values in the function above as demonstrated by the example, this should work as in onBindViewHolder, the bind function is called depending on the type of data at the position in the array, allowing the data to be bound to different xml layout files.
You will have to complete the bind functions for both viewholders, setting text views to item data strings for example or setting images resources for image views, corresponding to the correct xml layout file for the data type.
I'm in the process of fiddling my way to a working app using Kotlin and I have hit a roadblock when trying to implement OnClickListeners for my three buttons. I have my RecyclerView populate properly, but despite following the recommendations on this SO post (except in Kotlin) and following the documentation, though I am still having trouble getting the implementation to work.
The code below is my adapter class for the implementation.
class BrowseHabitsAdapter(private val habits: ArrayList<Habit>) :
RecyclerView.Adapter<BrowseHabitsAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.habit_card, parent, false)
return ViewHolder(itemView, object: HabitClickListener {
override fun onDecrease(position: Int) {
val streak = itemView.dayCounter.text.toString().toInt()
itemView.dayCounter.text = streak.dec().toString()
}
override fun onIncrease(position: Int) {
val streak = itemView.dayCounter.text.toString().toInt()
itemView.dayCounter.text = streak.inc().toString()
}
override fun onEdit(position: Int) {
TODO("Change Activity to Edit")
}
})
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val currentItem = habits[position]
holder.habitTitle.text = currentItem.title
holder.streak.text = currentItem.streak.toString()
}
override fun getItemCount() = habits.size
class ViewHolder(itemView : View, listener : HabitClickListener) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
val habitTitle: TextView = itemView.habitTitle
val streak: TextView = itemView.dayCounter
val decreaseCounterButton : Button = itemView.decreaseCounterButton
val increaseCounterButton : Button = itemView.increaseCounterButton
val listener = listener
init {
decreaseCounterButton.setOnClickListener(this)
increaseCounterButton.setOnClickListener(this)
}
override fun onClick(v: View?) {
when (itemView.id) {
itemView.decreaseCounterButton.id -> listener.onDecrease(this.layoutPosition)
itemView.increaseCounterButton.id -> listener.onIncrease(this.layoutPosition)
}
}
}
interface HabitClickListener {
fun onDecrease(position : Int)
fun onIncrease(position : Int)
fun onEdit(position : Int)
}
}
and the following is my XML code defining one of my cards:
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/cardView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="10dp"
app:cardBackgroundColor="#eeeeee"
app:cardCornerRadius="10dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:id="#+id/cardHeader"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
android:id="#+id/habitTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_marginRight="10dp"
android:text="#string/default_card_title"
android:textSize="18sp" />
<Space
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1" />
<ImageView
android:id="#+id/settingsIcon"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_gravity="bottom"
android:layout_marginRight="10dp"
app:srcCompat="#android:drawable/ic_menu_manage" />
</LinearLayout>
<LinearLayout
android:id="#+id/cardControls"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="horizontal">
<Button
android:id="#+id/decreaseCounterButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="-"
android:textAllCaps="false"
android:textSize="30sp" />
<Space
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" />
<TextView
android:id="#+id/dayCounter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:fontFamily="sans-serif-medium"
android:text="0"
android:textAlignment="center"
android:textSize="30sp"
android:textStyle="bold" />
<Space
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" />
<Button
android:id="#+id/increaseCounterButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="+"
android:textSize="30sp" />
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
Any additional explanation that can be provided as to what I did wrong and what is going on in detail would be really appreciated!
You are in kotlin so need to implement View.OnClickListener you can directly use setOnClickListener on any view.
Inside your ViewHolder Class:
itemView.increaseCounterButton.setOnClickListener{
listener.onIncrease(this.layoutPosition)
}
itemView.decreaseCounterButton.setOnClickListener{
listener.onDecrease(this.layoutPosition)
}
It should be view?.id instead of itemView.id
override fun onClick(v: View?) {
when (v?.id) {
itemView.decreaseCounterButton.id -> listener.onDecrease(this.layoutPosition)
itemView.increaseCounterButton.id -> listener.onIncrease(this.layoutPosition)
}
}
Additionally, your code with bugs. You handle HabitClickListener only update UI, when you scroll your data will be update base on habits. It means it will be revert when you scroll. Make sure streak of model Habit is var
return ViewHolder(itemView, object: HabitClickListener {
override fun onDecrease(position: Int) {
habits[position].streak = habits[position].streak.dec()
itemView.dayCounter.text = shabits[position].streak.toString()
}
override fun onIncrease(position: Int) {
habits[position].streak = habits[position].streak.inc()
itemView.dayCounter.text = shabits[position].streak.toString()
}
override fun onEdit(position: Int) {
TODO("Change Activity to Edit")
}
})
Now I writing my small game "Bulls and Cows". I added to the bottom of my layout recycler view and write sample code to test it:
val adapter = MyAdapter(this, null)
turnStory.adapter = adapter
repeat(100) {
adapter.updateData(Triple("test$it", "test$it", "test$it")
}
I started my activity on the phone and saw that
But when I scrolled down and scrolled back everything became normal
MyAdapter.kt
class MyAdapter(private val ctx: Context, private val data: Triple<String, String, String>?) :
RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
private val dataset = mutableListOf<Triple<String, String, String>>()
init {
if (data != null) dataset.add(data)
}
class MyViewHolder(val frameLayout: FrameLayout) : RecyclerView.ViewHolder(frameLayout)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val frameLayout = LayoutInflater.from(parent.context)
.inflate(R.layout.frame_layout, parent, false) as FrameLayout
return MyViewHolder(frameLayout)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.frameLayout.numberView.text = dataset[position].first
holder.frameLayout.bullsView.text =
ctx.resources.getString(R.string.bulls_counter, dataset[position].second)
holder.frameLayout.cowsView.text =
ctx.resources.getString(R.string.cows_counter, dataset[position].third)
}
override fun getItemCount(): Int = dataset.size
fun updateData(data: Triple<String, String, String>) {
dataset.add(data)
notifyDataSetChanged()
}
}
frame_layout.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="100dp">
<TextView
android:id="#+id/numberView"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:gravity="center"
android:maxLines="1"
android:singleLine="false"
android:textColor="#000000"
android:textSize="36sp"
android:textStyle="bold"
app:autoSizeTextType="none" />
<TextView
android:id="#+id/bullsView"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_gravity="end"
android:gravity="center"
android:maxLines="1"
android:singleLine="false"
android:textColor="#000000"
android:textSize="24sp" />
<TextView
android:id="#+id/cowsView"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_gravity="bottom|end"
android:gravity="center"
android:maxLines="1"
android:singleLine="false"
android:textColor="#000000"
android:textSize="24sp" />
Why first elements in recycler view displayed incorrectly before I scroll down?
computer_game_activity.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".GameComputerActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/turnStory"
android:layout_width="0dp"
android:layout_height="500dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />