I am trying to add a RecyclerView to a fragment, but without success. I have followed this guide, but in there the RecyclerView is added to MainActivity, so I tried to adapt it. However, I cannot get the RecyclerView to show up.
I have already looked at similar questions, for example this one.
Here is the fragment_add_recipe.xml
where the RecyclerView should appear:
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView 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=".AddRecipeFragment">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/recipe_name_text_input_layout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/recipe_name_text_input"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:inputType="text"
android:hint="@string/recipe_name_hint"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</com.google.android.material.textfield.TextInputLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/ingredient_row_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:itemCount="5"
tools:listitem="@layout/ingredient_row_view"
app:layout_constraintTop_toBottomOf="@id/recipe_name_text_input_layout"/>
<Button
android:id="@+id/save_recipe_button"
android:layout_width="150sp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="20sp"
android:text="Save"
android:textColor="#ffffff"
android:textSize="20sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/ingredient_row_recycler_view"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
AddRecipeFragment.kt
:
package com.example.recipy
import CustomAdapter
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.recipy.databinding.FragmentAddRecipeBinding
class AddRecipeFragment : Fragment() {
private var _binding: FragmentAddRecipeBinding? = null
// For the ingredient row
private val ingredientList : ArrayList<IngredientRowViewModel> = ArrayList()
private lateinit var customAdapter : CustomAdapter
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the Fragment layout
_binding = FragmentAddRecipeBinding.inflate(inflater, container, false)
setAdapter()
return binding.root
}
private fun setAdapter(){
customAdapter = CustomAdapter(ingredientList)
binding.ingredientRowRecyclerView.apply {
layoutManager = LinearLayoutManager(requireContext())
adapter = customAdapter
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Make button save the recipe in the SQL db
binding.saveRecipeButton.setOnClickListener{
// Some code for SQL connection here
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
The IngredientRowViewModel.kt
:
package com.example.recipy
data class IngredientRowViewModel(var ingredient: String) {
}
The CustomAdapter.kt
:
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.recipy.IngredientRowViewModel
import com.example.recipy.R
import com.example.recipy.databinding.IngredientRowViewBinding
class CustomAdapter(private val ingredientList: ArrayList<IngredientRowViewModel>) : RecyclerView.Adapter<CustomAdapter.IngredientRowViewHolder>() {
inner class IngredientRowViewHolder(private val binding : IngredientRowViewBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(ingredient : IngredientRowViewModel){
binding.ingredient = ingredient
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): IngredientRowViewHolder =
IngredientRowViewHolder(IngredientRowViewBinding.inflate(LayoutInflater.from(parent.context), parent, false))
override fun onBindViewHolder(holder: IngredientRowViewHolder, position: Int) {
holder.bind(ingredientList[position])
}
override fun getItemCount(): Int {
return ingredientList.size
}
}
and finally ingredient_row_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="ingredient"
type="com.example.recipy.IngredientRowViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:padding="5dp">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/ingredient_name_text_input_layout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/ingredient_name_text_input"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:inputType="text"
android:hint="@string/ingredient_name_hint"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
</layout>
I updated your code a little, As i mentioned earlier in the comments, you have to add some items to the list if you want to see it. You can add button for adding items or you can go with fixed size list.
fragment_add_receipe.xml
Add new button for adding ingredients into your list. If you don't need this and want fixed count list, just create the list with empty items, for instance like this:
//This will show 5 empty text inputs in the recyclerView
private val ingredientList: ArrayList<IngredientRowViewModel> = arrayListOf(
IngredientRowViewModel(""),
IngredientRowViewModel(""),
IngredientRowViewModel(""),
IngredientRowViewModel(""),
IngredientRowViewModel(""),
)
fragment_add_receipe.xml with new button:
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView
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=".AddRecipeFragment">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/recipe_name_text_input_layout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/recipe_name_text_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Receipe name"
android:inputType="text"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</com.google.android.material.textfield.TextInputLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/ingredient_row_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_constraintTop_toBottomOf="@id/recipe_name_text_input_layout"
tools:itemCount="5"
tools:listitem="@layout/ingredient_row_view" />
<!-- Add new button so you can add ingredients into your list -->
<Button
android:id="@+id/addIngredient"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="20sp"
android:text="Add Ingredient"
android:textColor="#ffffff"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/ingredient_row_recycler_view" />
<Button
android:id="@+id/save_recipe_button"
android:layout_width="150sp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="20sp"
android:text="Save"
android:textColor="#ffffff"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/addIngredient" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
AddRecipeFragment.kt
set onClickListener
to the addIngredient Button
and notify your adapter when adding new ingredients. After you add it, RecyclerView
will show one item (or more) with empty TextField
.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.addIngredient.setOnClickListener {
//add new ingredient with empty name into your list so your item will be shown
ingredientList.add(IngredientRowViewModel(ingredient = ""))
//Use notifyItemInserted instead of notifyDataSetChanged for better performance
if (ingredientList.size == 0)
customAdapter.notifyItemInserted(0)
else
customAdapter.notifyItemInserted(ingredientList.size - 1)
}
...
}
ingredient_row_view.xml
This is just optional, you have android:layout_height="match_parent"
which means single item would use to much space and you have to scroll in order to see second item, you should change it to wrap_content
.
Suggestions