Home > OS >  Keep an image visible inside a cardView on a recyclerView after rotating device
Keep an image visible inside a cardView on a recyclerView after rotating device

Time:11-05

I'm trying to make a simple Android app in Kotlin to a school project that shows some images from the internet. The images are being showed inside a cardView, on a recyclerView with a grid layout.

In each cardView I'm getting a random image from picsum and I also have a star icon for marking the image as favourite. The purpose of this work is to work with sharedPreferences. So I have to store which image is being set as favourite (there only can be one at time), and store that position that whenever I rotate the device, the icon stays visible.

How should I store this and in which function should I call the sharedPreferences data to display the icon?

Adapter.kt

package com.example.bottomnavigationapp.fragimages.ui

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import androidx.recyclerview.widget.RecyclerView
import com.example.bottomnavigationapp.R
import com.squareup.picasso.Picasso

class GridItemAdapter(
    val cardImages: Array<String>,
    private val listener: OnItemClickListener) :
    RecyclerView.Adapter<GridItemAdapter.ViewHolder>() {

    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView),
    View.OnClickListener{

        val cardImage : ImageView = itemView.findViewById(R.id.cardImage)
        val favImage : ImageView = itemView.findViewById(R.id.favImage)

        init {
            cardImage.setOnClickListener(this)
        }


        override fun onClick(v: View?) {
            var position : Int = adapterPosition
            val address = cardImages[position]
            if (position != RecyclerView.NO_POSITION) {
                listener.onItemClick(position, favImage, address)
            }
        }
    }

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

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        Picasso.get().load(cardImages[position]).into(holder.cardImage)
    }

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

    interface OnItemClickListener {
        fun onItemClick(position: Int, favImage: ImageView, address: String)
    }
}

Fragment.kt

package com.example.bottomnavigationapp.fragimages.ui

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.GridLayoutManager
import com.example.bottomnavigationapp.R
import com.example.bottomnavigationapp.databinding.FragmentImagesBinding

class ImagesFragment : Fragment(), GridItemAdapter.OnItemClickListener {
    private lateinit var binding: FragmentImagesBinding
    var hasFavourite : Int = -1



    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = FragmentImagesBinding.inflate(inflater, container, false)
        val cardImages : Array<String> = resources.getStringArray(R.array.cardImages)
        val adapter = GridItemAdapter(cardImages, this)
        val gridLayout = GridLayoutManager(context, 2)
        binding.gridItems.layoutManager = gridLayout
        binding.gridItems.adapter = adapter

        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        (activity as AppCompatActivity?)!!.supportActionBar!!.title = "Images Fragment"
        super.onViewCreated(view, savedInstanceState)

    }

    override fun onItemClick(position: Int, favImage: ImageView, address: String) {
        if (hasFavourite < 0) {
            Toast.makeText(context, "Address: $address", Toast.LENGTH_SHORT).show()
            val favAddress = address
            val favStatus = true

            val sharedPreferences = requireActivity().applicationContext.getSharedPreferences("myPref", 0)
            val editor = sharedPreferences.edit()

            editor.apply {
                putString("favAddress", address)
                putBoolean("favStatus", favStatus)
            }

            favImage.visibility = View.VISIBLE
            hasFavourite = position
            Toast.makeText(context, "Item $position set to favourite", Toast.LENGTH_SHORT).show()
        }
         else if (hasFavourite == position) {
            favImage.visibility = View.GONE
            hasFavourite = -1
        }
        else {
            Toast.makeText(context, "Favourite already set at position $hasFavourite", Toast.LENGTH_SHORT).show()
        }
    }

}

CodePudding user response:

It's because you are trying to set preferences all the time but not getting them. Create seperate class named "UserPreferences.kt" and paste below code in it:

 class UserPreferences {
    // Store all Sharedpreferences methods in here
    fun getPositionPref(fragment: Fragment): Int {
        return fragment.requireActivity().getSharedPreferences(
            "myPref",
            Context.MODE_PRIVATE
        ).getInt(
            "positionPref",
            -1
        )
    }

    fun setPositionPref(fragment: Fragment, position: Int) {
        val sharedPreferences =
            fragment.requireActivity().getSharedPreferences(
                "myPref",
                Context.MODE_PRIVATE
            )
        val editor: SharedPreferences.Editor = sharedPreferences.edit()
        editor.putInt(
            "positionPref",
            position
        )
        editor.apply()
    }
}

Coming to your code let's make some adjustments:

class ImagesFragment : Fragment(), GridItemAdapter.OnItemClickListener {
    private lateinit var binding: FragmentImagesBinding
    //edited
    private var hasFavourite : Int = -1

   override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = FragmentImagesBinding.inflate(inflater, container, false)
        hasFavourite = UserPreferences().getPositionPref(this)
        // Now you get what's in sharedPreferences.
        // If it's first time it will be -1 for default.
        val cardImages : Array<String> = 
        resources.getStringArray(R.array.cardImages)
        val adapter = GridItemAdapter(cardImages, this, hasFavourite)
        // send hasFavourite to adapter too.
        val gridLayout = GridLayoutManager(context, 2)
        binding.gridItems.layoutManager = gridLayout
        binding.gridItems.adapter = adapter

        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        (activity as AppCompatActivity?)!!.supportActionBar!!.title = "Images Fragment"
        super.onViewCreated(view, savedInstanceState)

    }

    override fun onItemClick(position: Int, favImage: ImageView, address: String) {
        if (hasFavourite == -1) {
            Toast.makeText(context, "Address: $address", Toast.LENGTH_SHORT).show()

            UserPreferences().setPositionPref(this, position)
            // Now we set it to position, for another time you wanna get

            //putString("favAddress", address)
            //putBoolean("favStatus", favStatus)
            //For this two, you need to create it's own functions in 
            // UserPreferences class we created, you got the idea
            
            favImage.visibility = View.VISIBLE
            hasFavourite = UserPreferences().getPositionPref(this)
            // We get the new value of hasFavourite from shared pref again.
            Toast.makeText(context, "Item $position set to favourite", Toast.LENGTH_SHORT).show()
        }
         else if (hasFavourite == position) {
            favImage.visibility = View.GONE
            //edited
            UserPreferences().setPositionPref(this, -1)
            hasFavourite = UserPreferences().getPositionPref(this)
           // We set it to default, there should be no item favorited
        }
        else {
            Toast.makeText(context, "Favourite already set at position $hasFavourite", Toast.LENGTH_SHORT).show()
        }
    }

}

So let's say you chose one favorite and close the app and open again, it won't start with favorite applied to adapter until you click one of the items to solve this in beginning we sent hasFavourite to adapter:

class GridItemAdapter(
    val cardImages: Array<String>,
    private val listener: OnItemClickListener,
    private val hasFavourite: Int) :
    RecyclerView.Adapter<GridItemAdapter.ViewHolder>() {

   // and onBind we check and set:
   override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        Picasso.get().load(cardImages[position]).into(holder.cardImage)
        if (hasFavourite == position) {
          holder.favImage.visibility = View.VISIBLE
        }
   }

I think this should do the trick, haven't tried, if not works let me know.

  • Related