Why first elements in recycler view displayed incorrectly? - android

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" />

Related

Dynamically add item into recyclerview when button pressed

I am trying to build a layout in which there is a recyclerview where each item has three edittexts horizontally aligned. I want to add the next item when a button is pressed.
This the design I am trying to build
This is the Adapter class for the recycler view
class AddProjectAdapter(private val itemsList : ArrayList<ItemDetails>) : RecyclerView.Adapter<AddProjectAdapter.AddProjectViewHolder>() {
inner class AddProjectViewHolder(private val binding : AddProjectItemViewBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(item : ItemDetails){
binding.item = item
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AddProjectViewHolder{
return AddProjectViewHolder(AddProjectItemViewBinding.inflate(LayoutInflater.from(parent.context), parent, false))
}
override fun onBindViewHolder(holder: AddProjectViewHolder, position: Int) {
holder.bind(itemsList[position])
}
override fun getItemCount(): Int = itemsList.size
}
Layout file for the item add_project_item_view.xml
`
<?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="item"
type="com.example.hero.models.ItemDetails" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.card.MaterialCardView
android:id="#+id/item_name_cardview"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:flow_horizontalBias="3"
app:cardBackgroundColor="#color/light_background"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="#id/g_v_1"
android:layout_marginRight="5dp">
<EditText
android:id="#+id/item_name_edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Item Name"
android:text="#={item.itemName}"
android:textColor="#color/t_dark"
android:fontFamily="#font/metropolislight"
android:textSize="14dp"
android:textColorHint="#color/t_dark"
android:background="#null"
android:padding="10dp" />
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.card.MaterialCardView
android:id="#+id/rate_unit_cardview"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:flow_horizontalBias="2"
android:layout_marginRight="5dp"
app:cardBackgroundColor="#color/light_background"
app:layout_constraintStart_toEndOf="#id/g_v_1"
app:layout_constraintEnd_toEndOf="#id/g_v_2">
<EditText
android:id="#+id/rate_unit_edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Rate/Unit"
android:text="#={item.rate}"
android:textColorHint="#color/t_dark"
android:textColor="#color/t_dark"
android:fontFamily="#font/metropolislight"
android:textSize="14dp"
android:padding="10dp"
android:background="#null" />
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.card.MaterialCardView
android:id="#+id/unit_cardview"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:flow_horizontalBias="2"
app:cardBackgroundColor="#color/light_background"
app:layout_constraintStart_toEndOf="#id/g_v_2"
app:layout_constraintEnd_toEndOf="parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/unit_textview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:background="#null"
android:fontFamily="#font/metropolislight"
android:hint="Unit"
android:padding="10dp"
android:text="#={item.unit}"
android:textColor="#color/t_dark"
android:textColorHint="#color/t_dark"
android:textSize="14dp" />
<ImageView
android:id="#+id/drop_down_imageview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:src="#drawable/dropdown"
android:layout_centerVertical="true" />
</RelativeLayout>
</com.google.android.material.card.MaterialCardView>
<androidx.constraintlayout.widget.Guideline
android:id="#+id/g_v_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.4" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/g_v_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.8" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
`
//code of the activity in which the recycler view is present
private val itemsList : ArrayList<ItemDetails> = ArrayList()
private lateinit var addProjectAdapter: AddProjectAdapter
private lateinit var binding: ActivityAddProjectBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityAddProjectBinding.inflate(layoutInflater)
setContentView(binding.root)
setAdapter()
setListner()
}
private fun setAdapter(){
addProjectAdapter = AddProjectAdapter(itemsList)
binding.itemDetailsRecyclerview.apply {
layoutManager = LinearLayoutManager(this#AddProject)
adapter = addProjectAdapter
}
}
override fun onClick(v : View?) {
when(v?.id){
binding.addItemButton.id -> {
itemsList.add(ItemDetails())
addProjectAdapter.notifyItemInserted(itemsList.size-1)
}
}
}
private fun setListner(){
binding.addItemButton.setOnClickListener(this)
}
data class ItemDetails(
var itemName : String = "",
var rate : String = "",
var unit : String = "")
And my recyclerview id is item_details_recyclerview.
Output for the above code
When I click the add button the item added is not visible but the add button moves down.
Can someone help me out with this issue? And also if you could provide some better approach it would be great.
Thanks in advance.
Change height of ConstraintLayout from add_project_item_view.xml
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
to this
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">

EditText in RecyclerView with Kotlin not working

I'm new in app developpement and I have a problem with an EditText in recyclerview's item.
When user clicks on the editText nothing appens. I tried with an itemClickListener on EditText, click did worked but not edtion of text.
Here is my code :
the Activity :
class MyIngredientListActivity : AppCompatActivity() {
val ingerdientOfListArray = database.getAllIngredientOfList()
val adapter = IngredientOfListAdapter(ingerdientOfListArray)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.ingredient_list_recyclerview)
findViewById<Button>
(R.id.ingredient_list_activity_search_button).setOnClickListener {
val intent = Intent(this, IngredientSearchableActivity::class.java)
startActivity(intent)
}
val recyclerView = findViewById<RecyclerView>
(R.id.ingredientoflist_recyclerview)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter = adapter
}
override fun onResume() {
super.onResume()
adapter.updateIngredientList()
}
The adapter :
class IngredientOfListAdapter(val ingredientOfListDisplay:
ArrayList<IngredientOfList>
): RecyclerView.Adapter<IngredientOfListAdapter.ViewHolder>() {
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val cardView = itemView.findViewById<CardView>
(R.id.ingredientoflist_cardview_name)
val name = itemView.findViewById<TextView>(R.id.ingredientoflist_name)
val checkbox = itemView.findViewById<CheckBox>
(R.id.ingredientoflist_checkbox)
val editText = itemView.findViewById<EditText>
(R.id.ingredientoflist_quantity)
val unitmeasure = itemView.findViewById<TextView>
(R.id.ingredientoflist_unitmeasure)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(parent.context)
val viewItem = inflater.inflate(R.layout.ingredient_list_item, parent, false)
return ViewHolder(viewItem)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val ingredientOfList = ingredientOfListDisplay[position]
val ingredientFromId = database.readIngredientById(ingredientOfList).first()
val unitMeasureId = database.readUnitMeasureById(ingredientFromId).first()
holder.cardView?.tag = position
holder.name.text = ingredientFromId.name
holder.unitmeasure.text = unitMeasureId.symbol
holder.editText?.tag = position
holder.editText.setText(0)
}
override fun getItemCount(): Int {
return ingredientOfListDisplay.size
}
fun updateIngredientList(ingredientOfListArray: ArrayList<IngredientOfList> = database.getAllIngredientOfList()) {
ingredientOfListDisplay.clear()
ingredientOfListDisplay.addAll(ingredientOfListArray)
notifyDataSetChanged()
}
}
RelativeLayout here
cardview here
android:id="#+id/ingredientoflist_cardview_name"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:cardUseCompatPadding="true"
android:focusable="false"
android:clickable="false"
android:foreground="?android:attr/selectableItemBackground">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#C3FFFFFF">
<TextView
android:id="#+id/ingredientoflist_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_gravity="center_vertical"
android:layout_marginStart="20dp"
android:layout_marginLeft="20dp"
android:textColor="#403E3E"
android:textSize="17sp"
android:textStyle="bold"
tools:text="ingredient"/>
<EditText
android:id="#+id/ingredientoflist_quantity"
android:layout_width="50sp"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_gravity="center_vertical"
android:layout_alignParentBottom="true"
android:layout_marginStart="250dp"
android:layout_marginLeft="250dp"
android:layout_marginBottom="8dp"
android:clickable="true"
android:focusable="true"
android:inputType="number"
android:imeOptions="actionDone"
android:saveEnabled="true"
android:hint="00"
android:textColor="#403E3E"
android:textSize="17sp"
android:textStyle="bold"
android:gravity="center_horizontal"
android:background="#drawable/abc_vector_test" />
<TextView
android:id="#+id/ingredientoflist_unitmeasure"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_gravity="center_vertical"
android:gravity="center_vertical"
android:layout_marginStart="305dp"
android:layout_marginLeft="305dp"
android:hint="cl"
android:textColor="#403E3E"
android:textSize="17sp"
android:textStyle="bold"/>
<CheckBox
android:id="#+id/ingredientoflist_checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_gravity="center_vertical"
android:layout_marginStart="350dp"
android:layout_marginLeft="350dp"
android:gravity="center_vertical"/>
</RelativeLayout>
</CardView>
RecyclerView Layout:
<RelativeLayout
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"
style="#style/NoActionBar"
android:background="#000000">
<ImageView
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_below="#+id/ingredient_search_activity_search_button"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:paddingBottom="60dp"
app:srcCompat="#drawable/baseline_no_food_white_48"
app:tint="#40FFFFFF" />
<Button
android:id="#+id/ingredient_search_activity_search_button"
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="#android:color/white"
android:drawableStart="#android:drawable/ic_search_category_default"
android:drawableLeft="#android:drawable/ic_search_category_default"
android:gravity="start|center_vertical"
android:text="#string/my_searchables_ingredients"
android:textAlignment="textStart"
android:focusable="false"
android:clickable="true"/>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/ingredientoflist_recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#C3FFFFFF"
app:queryHint="your ingredients"
android:layout_below="#id/ingredient_search_activity_search_button"
android:clickable="false"
android:focusable="false"/>
</RelativeLayout>
Thanks and have a good day !
I think adding
holder.editText.setOnClickListener(Object : View.OnClickListener {
override fun OnClick(v: View?) {
v.requestFocus()
}
}
Should do the trick. I'm not very good at Kotlin, so there might be a syntax error there.

Recycler view strange behaviour when height is match_parent

I am facing an strange behaviour now days. I am using view binding for refrencing ids. When RecyclerView height is wrap_content the item display perfectly but when I set recyclerview height match_parent the item width is automatically wrapped (wrap_content) in run time but in xml I have set item width is match_parent.
Please help me to solve this problem.
Please look at my xml and kt files -:
<LinearLayou ------
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/idRvTrainerReview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
row_item
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/_1sdp"
android:background="#color/colorWhite"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="#dimen/_10sdp">
<TextView
android:id="#+id/idTvDate"
style="#style/MediumText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="14 feb"
android:includeFontPadding="false"
android:textColor="#color/colorBlack"
android:textStyle="bold" />
<TextView
android:id="#+id/idTvStartTime"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.2"
android:gravity="center"
android:includeFontPadding="false"
android:text="19:30" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_right_arrow" />
</LinearLayout>
adapter file -:
class FeedbackDataAdapter(
private var mcontext: Context,
private var mItemList: MutableList<ResponseTrainerFeedback.Result.Training>,
var mClickListener: OnClickListener?
) : RecyclerView.Adapter<TrainingDataViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TrainingDataViewHolder {
var layoutInflater = mcontext.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as (LayoutInflater)
val rowEventMemberBinding =
RowEventDataBinding.inflate(layoutInflater, parent, false)
return TrainingDataViewHolder(rowEventMemberBinding)
}
override fun getItemCount(): Int = mItemList.size
override fun onBindViewHolder(holder: TrainingDataViewHolder, position: Int) {
holder.mBinding.idTvDate.text = mItemList[holder.adapterPosition].trainingName
holder.mBinding.idTvStartTime.invisible()
holder.itemView.setOnClickListener {
if(mItemList.size > 0){
mClickListener?.onItemClick(holder.adapterPosition)
}
}
}
fun refreshList(mFeedbackList: MutableList<ResponseTrainerFeedback.Result.Training>) {
this.mItemList = mFeedbackList
notifyDataSetChanged()
}
}
class TrainingDataViewHolder(var mBinding: RowEventDataBinding) :
RecyclerView.ViewHolder(mBinding.root) {
}
I've tried your code and It's working.
I've only refactored your adapter according to Android training and if you want to do the codelab: https://codelabs.developers.google.com/codelabs/kotlin-android-training-diffutil-databinding
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TrainingDataViewHolder {
return TrainingDataViewHolder.from(parent)
}
override fun getItemCount(): Int = mItemList.size
override fun onBindViewHolder(holder: TrainingDataViewHolder, position: Int) {
holder.bind(mItemList[position])
holder.itemView.setOnClickListener {
if(mItemList.size > 0){
mClickListener?.onItemClick(holder.adapterPosition)
}
}
}
fun refreshList(mFeedbackList: MutableList<ResponseTrainerFeedback.Result.Training>) {
this.mItemList = mFeedbackList
notifyDataSetChanged()
}
}
class TrainingDataViewHolder(var mBinding: RowEventDataBinding) :
RecyclerView.ViewHolder(mBinding.root) {
fun bind(data: YOURDATA) {
mBinding.idTv = data // it'll map automatically all the property, replace idTv by the name of your variable in your layout
mBinding.idTvStartTime.invisible()
}
companion object {
fun from(parent: ViewGroup): TrainingDataViewHolder {
return TrainingDataViewHolder(RowEventDataBinding.inflate(LayoutInflater.from(parent.context), parent, false))
}
}
}
row_item
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="idTv"
type="package.name.to.data" />
</data>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="1dp"
android:background="#android:color/white"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="10dp">
<TextView
android:id="#+id/idTvDate"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.8"
android:text="#{idTv.idTvDate}"
android:includeFontPadding="false"
android:textColor="#android:color/black"
android:textStyle="bold"
tools:text="14 feb"/>
<TextView
android:id="#+id/idTvStartTime"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.2"
android:gravity="center"
android:includeFontPadding="false"
android:text="19:30" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#android:drawable/arrow_up_float" />
</LinearLayout>
</layout>
PS: I don't see <layout> in your row_item, are you sure you're doing binding correctly ?

Adding multiple OnClickListeners to a RecyclerView using Kotlin

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")
}
})

Nested RecyclerView Adding Space Between Items After First Scroll

I am trying to implement a simple nested recyclerview with a vertical parent and horizontal children.
The layout for the parent is:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/parentLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp">
<include layout="#layout/loading_indicator" />
<include layout="#layout/error_layout" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/podcasts"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/podcastsTitle"
android:layout_marginTop="5dp" />
</RelativeLayout>
The layout for the child recyclerview is:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="10dp"
android:orientation="vertical">
<TextView
android:id="#+id/title"
style="#style/TitleTextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="3dp"
android:textAppearance="#style/TextAppearance.AppCompat.Large" />
<TextView
android:id="#+id/description"
style="#style/AuxTextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:maxLines="2"
android:textAppearance="#style/TextAppearance.AppCompat.Medium" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/podcastsItems"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
The adapter for the parent is as follows:
class CuratedPodcastsAdapter(val context: Context, private val podcastLists: ArrayList<PodcastList>) : RecyclerView.Adapter<CuratedPodcastsAdapter.ViewHolder>() {
private val viewPool = RecyclerView.RecycledViewPool()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder = ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.podcast_section_layout, parent, false))
override fun getItemCount(): Int = podcastLists.size
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bindItems(podcastLists[holder.adapterPosition])
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
#BindView(R.id.title)
lateinit var title: TextView
#BindView(R.id.description)
lateinit var description: TextView
#BindView(R.id.podcastsItems)
lateinit var podcastItems: RecyclerView
init {
ButterKnife.bind(this, itemView)
}
fun bindItems(curatedPodcastList: PodcastList) {
title.text = curatedPodcastList.title
description.text = curatedPodcastList.description
title.typeface = FontUtils.boldTypeface
description.typeface = FontUtils.mediumTypeface
val childLayoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
childLayoutManager.initialPrefetchItemCount = 4
podcastItems.apply {
layoutManager = childLayoutManager
adapter = PodcastAdapter(this#CuratedPodcastsAdapter.context, curatedPodcastList.podcasts!!)
setItemViewCacheSize(20)
setRecycledViewPool(viewPool)
}
}
}
}
while the children's adapter is:
class PodcastAdapter(val context: Context, private val episodes: ArrayList<Podcast>): RecyclerView.Adapter<PodcastAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder = ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.podcast_item_layout, parent, false))
override fun getItemCount(): Int = episodes.size
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bindItems(episodes[holder.adapterPosition])
}
inner class ViewHolder(view: View): RecyclerView.ViewHolder(view) {
#BindView(R.id.art)
lateinit var art: ImageView
#BindView(R.id.title)
lateinit var title: TextView
#BindView(R.id.publisher)
lateinit var publisher: TextView
#BindView(R.id.card)
lateinit var card: CardView
init {
ButterKnife.bind(this, view)
}
fun bindItems(podcast: Podcast){
title.text = podcast.title
publisher.text = podcast.publisher
GlideApp.with(context).load(podcast.image).error(R.drawable.no_cover).into(art)
card.setOnClickListener {
context.startActivity(context.intentFor<PodcastActivity>(PodcastActivity.PODCAST_ID to podcast.id, PodcastActivity.PODCAST_TITLE to podcast.title))
}
}
}
}
When content is loaded for the first time, everything appears correctly like below:
After scrolling downwards then back up again, spaces begin to appear between the content like so:
None of the recyclerviews have any item decoration added to them. My perception was that using a common viewpool would at least improve performance and help with such layout inconsistencies but it hasn't helped.
What is the cause of this problem and how can it be fixed?
You need to change the height of your child layout of recyclerview
to android:layout_height="wrap_content"
Sample code
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:orientation="vertical">
<TextView
android:id="#+id/title"
style="#style/TitleTextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="3dp"
android:textAppearance="#style/TextAppearance.AppCompat.Large" />
<TextView
android:id="#+id/description"
style="#style/AuxTextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:maxLines="2"
android:textAppearance="#style/TextAppearance.AppCompat.Medium" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/podcastsItems"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>

Categories

Resources