Aiman_Irfan
Aiman_Irfan

Reputation: 375

How to add RecyclerView in a Fragment?

Currently, I am trying to implement RecyclerView inside of Fragment but I cannot find a way to display it.

Here is my MainActivity:

package com.example

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import androidx.fragment.app.Fragment
import com.example.projectdrivemark.R
import com.example.projectdrivemark.databinding.ActivityMainBinding
import com.example.recyclerView.MockDatabase.Companion.createMockData
import com.example.recyclerView.PostAdapter
import com.example.recyclerView.RecyclerViewFragment
import com.example.tempConverter.TempConverterFragment
import com.example.uploaderView.UploaderFragment

class MainActivity : AppCompatActivity(), PostAdapter.OnPostClickListener {
    private lateinit var binding: ActivityMainBinding
    val dummyList = createMockData()
    val adapter = PostAdapter(dummyList, this)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        title = "First Kotlin App"
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        val recyclerView = RecyclerViewFragment()
        val tempConverterView = TempConverterFragment()
//        recyclerView.layoutManager = LinearLayoutManager(this)
        val uploaderView = UploaderFragment(this)
        setFragmentView(recyclerView)

        binding.bottomNavBar.setOnNavigationItemSelectedListener {
            when(it.itemId){
                R.id.listView ->  setFragmentView(recyclerView)
                R.id.tempConverterView -> setFragmentView(tempConverterView)
                R.id.videoUploaderView -> setFragmentView(uploaderView)
            }
            true
        }
    }

    private fun setFragmentView(fragment: Fragment){
        supportFragmentManager.beginTransaction().apply {
            replace(R.id.main_fragment_view, fragment)
            //Will return to previous page when tap "Back Button" on the phone
            addToBackStack(null)
            commit()
        }
    }

    override fun onEditPost(position: Int){
        val clickedPost = dummyList[position]
        clickedPost.title = "Updated title"
        clickedPost.body = "Updated body"
        adapter.notifyItemChanged(position)
    }

    override fun onDeletePost(position: Int) {
        dummyList.removeAt(position)
        adapter.notifyItemRemoved(position)
    }

    fun celsiusFunction(view: View) {
        val tempConverter = TempConverterFragment()
        tempConverter.celsiusFunction(view)
    }

    fun farenheitFunction(view: View){
       val fahrenheitConverter = TempConverterFragment()
        fahrenheitConverter.farenheitFunction(view)
    }
}

Here is my RecyclerFragment:

package com.example.recyclerView

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.MainActivity
import com.example.projectdrivemark.R

class RecyclerViewFragment: Fragment() {
    var adapter: RecyclerView.Adapter<PostAdapter.PostViewHolder>? = null
    var layoutManager: RecyclerView.LayoutManager? = null

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        super.onCreate(savedInstanceState)
        val binding = inflater.inflate(R.layout.fragment_list, container, false)
        return binding
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        view.apply{
            layoutManager = LinearLayoutManager(activity)
            adapter = PostAdapter(dummyData = ArrayList<Post>(), MainActivity())
        }
    }
}

Here is my PostAdapter code:

package com.example.recyclerView

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.MainActivity
import com.example.projectdrivemark.R

class PostAdapter(val dummyData: ArrayList<Post>, val myListener: MainActivity) : RecyclerView.Adapter<PostAdapter.PostViewHolder>() {

    inner class PostViewHolder(postView: View) : RecyclerView.ViewHolder(postView), View.OnClickListener{
        val iconImage: ImageView = postView.findViewById(R.id.icon_image_view)
        val title: TextView = postView.findViewById(R.id.title)
        val body: TextView = postView.findViewById(R.id.body)
        val deleteIcon: ImageView = postView.findViewById(R.id.delete_post_image)
        val editIcon: ImageView = postView.findViewById(R.id.edit_post_image)

        init {
            deleteIcon.setOnClickListener(this)
            editIcon.setOnClickListener(this)
        }

        override fun onClick(v: View?){
            val position = adapterPosition
            if(v?.id == editIcon.id){
                myListener.onEditPost(position)
            }else{
                myListener.onDeletePost(position)
            }
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PostViewHolder {
        val postView = LayoutInflater.from(parent.context).inflate(R.layout.post, parent, false)
        return PostViewHolder(postView)
    }

    override fun onBindViewHolder(holder: PostViewHolder, position: Int) {
        val currentPost = dummyData[position]
        holder.iconImage.setImageResource(currentPost.image)
        holder.title.text = currentPost.title
        holder.body.text = currentPost.body
    }

    override fun getItemCount(): Int {
        return dummyData.size
    }

    interface OnPostClickListener{

        fun onEditPost(position: Int)
        fun onDeletePost(position: Int)
    }
}

If anyone saw something I miss, please do tell me because I am stuck at how to display the RecyclerView. Any help would be appreciate.

Edit:

Here is my MockDatabase:

package com.example.recyclerView

import com.example.projectdrivemark.R

class MockDatabase {
    companion object{
        fun createMockData(): ArrayList<Post>{
            val list = ArrayList<Post>()
            for(i in 0 until 20){
                val imageToSelect = when (i % 3){
                    0 -> R.drawable.ic_baseline_account_balance
                    1 -> R.drawable.ic_baseline_account_circle
                    2 ->R.drawable.ic_baseline_ac_unit
                    else -> R.drawable.ic_baseline_access_alarms
                }
                list.add(
                        Post(
                            imageToSelect,
                            title = "Title post of $i",
                            body = "Title post of $i"
                        )
                )
            }
            return list
        }
    }
}

Here is my Layout_list xml file:

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

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycleViewMain"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="10dp"
        tools:listitem="@layout/recycler_view_item" />
</androidx.constraintlayout.widget.ConstraintLayout>

Upvotes: 0

Views: 441

Answers (2)

Rajan Kali
Rajan Kali

Reputation: 12953

You need to cast view to RecyclerView to access RecyclerView properties inside apply, also you cannot create instances of Activity by yourself, MainActivity() is wrong and won't work, instead use requireActivity() which will provide context of Activity to which Fragment is attached to

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    view.findViewbyId<RecyclerView>(R.id.recycleViewMain).apply{
        layoutManager = LinearLayoutManager(requireActivity())
        adapter = PostAdapter(dummyData = ArrayList<Post>(), requireActivity() as OnPostClickListener)
    }
}

Also, as @Necronet mentioned, add some mock data to see if it is actually rendering.

UPDATE

Instead of passing MainActivity to Adapter, pass OnPostClickListener

adapter = PostAdapter(dummyData = ArrayList<Post>(), requireActivity() as OnPostClickListener)

Adapter

class PostAdapter(val dummyData: ArrayList<Post>, val myListener: OnPostClickListener) : RecyclerView.Adapter<PostAdapter.PostViewHolder>(){
   // you can use myListener to call methods
}

Upvotes: 1

Necronet
Necronet

Reputation: 6813

It's simple you are passing empty dummyData try using createMockData() instead. Also as a rule of thumb in Android, never ever instatiate an Activity yourself, if you need the reference from within a fragment you can use getActivity() method. So this:

adapter = PostAdapter(dummyData = ArrayList<Post>(), MainActivity())

Should be:

adapter = PostAdapter(dummyData = createMockData(), getActivity() as MainActivity)

Upvotes: 1

Related Questions