Kotlin RecyclerView how select first list item after activity load? tried (code below) failed :( - kotlin

I can select 1st item in RecyclerView (working code below, click on "email" FAB button - boom! 1st selected)
However I cannot get 1st RecyclerView click in code when app starts,
I looked for override fun onViewCreated() but nothing like it for activity,
where can I call selectFirstOnList() after activity & recyclerview fully rendered?
what event fires on activity fully rendered/loaded?
or is my noob kotlin way of thinking flawed? its 99.9% working :(
Thanks in advance for any help :)
SOLUTIUON (code edited to bottom of this post will replace code in ItemListActivity.kt)
postdelay select first (you can see from original code I'd already tried something like this!) PHEW! hope this helps someone :)
ItemListActivity.kt
package ie.dpsystems.asm.list
import android.content.Context
import android.content.Intent
import android.content.res.Configuration
import android.graphics.Color
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.snackbar.Snackbar
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import android.widget.Toast
import ie.dpsystems.asm.R
import ie.dpsystems.asm.data.Orientation
import ie.dpsystems.asm.data.State
import ie.dpsystems.asm.data.State.Companion.trackLog
import ie.dpsystems.asm.detail.ItemDetailActivity
import ie.dpsystems.asm.detail.ItemDetailFragment
import kotlinx.android.synthetic.main.activity_item_list.*
import kotlinx.android.synthetic.main.item_list_content.view.*
import kotlinx.android.synthetic.main.item_list.*
import android.os.Handler
class ItemListActivity : AppCompatActivity() {
private var twoPane: Boolean = false
private var showToastEvents: Boolean = true
private fun uiIsTwoPane():Boolean{
try{
if (item_detail_container != null) {
// The detail container view will be present only in the
// large-screen layouts (res/values-w900dp).
// If this view is present, then the
// activity should be in two-pane mode.
return true
}
}catch(e:Exception)
{
Toast.makeText(this,"E: ${e.toString()}",Toast.LENGTH_SHORT).show()
}
return false
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
trackLog(this,"onCreate()")
setContentView(R.layout.activity_item_list)
twoPane = uiIsTwoPane()
setSupportActionBar(toolbar)
toolbar.title = title
fab.setOnClickListener { view -> onListFabClick(view) }
setupRecyclerView(recycleview_list)
refreshUI()
}
private fun setupRecyclerView(recyclerView: RecyclerView) {
trackLog(this,"setupRecyclerView()")
State.dataRows = ListContent.ITEMS
recyclerView.adapter = SimpleItemRecyclerViewAdapter(
this,
twoPane,
this
)
var recycleViewUI = recycleview_list
postAndNotifyAdapter(Handler(), recycleViewUI)
}
override fun onConfigurationChanged(newConfig: Configuration?) {
super.onConfigurationChanged(newConfig)
trackLog(this,"onConfigurationChanged()")
}
override fun onStart() {
super.onStart()
trackLog(this,"onStart()")
}
override fun onResume() {
super.onResume()
trackLog(this,"onResume() A")
checkOrientationChange()
refreshUI()
trackLog(this,"onResume() B")
}
private fun checkOrientationChange() {
trackLog(this,"checkOrientationChange()")
if (State.lastOrientation != null) {
val thisOrientation = if (twoPane) Orientation.landscape else Orientation.portrate
if (thisOrientation != State.lastOrientation) {
putDetailFragmentOnDetailFragmentHolder()
}
}
}
private fun putDetailFragmentOnDetailFragmentHolder() {
trackLog(this,"putDetailFragmentOnDetailFragmentHolder()")
if(item_detail_container!=null){
val fragment = ItemDetailFragment() //val fragment = ItemDetailFragment().apply {arguments = Bundle().apply {putInt("SOME UNIQUE TAG", selectedItemUniqueID)}}
val container = item_detail_container
container.removeAllViewsInLayout()
supportFragmentManager.beginTransaction().replace(R.id.item_detail_container, fragment).commit()
}
}
override fun onPause() {
super.onPause()
trackLog(this,"onPause()")
}
override fun onStop() {
super.onStop()
trackLog(this,"onStop()")
}
class SimpleItemRecyclerViewAdapter( private val parentActivity: ItemListActivity
,private val twoPane: Boolean
,private val context: Context //private val context = parentActivity.applicationContext
) : RecyclerView.Adapter<SimpleItemRecyclerViewAdapter.ViewHolder>() {
override fun getItemCount(): Int {
return State.dataRows.size
}
override fun onBindViewHolder(recyclerViewRow: ViewHolder, position: Int) {
trackLog(context, "onBindViewHolder()")
val dataThisRow = State.dataRows[position]
dataThisRow.listRowIndex = position
setDataToRecyclerRow(recyclerViewRow, dataThisRow)
recyclerViewRow.itemView.setOnClickListener {
onListItemClick(dataThisRow.uniqueID)
}
if (dataThisRow.uniqueID == State.selectedListItemUniqueId) {
recyclerViewRow.idRow.setBackgroundColor(Color.parseColor("#009688"))
} else {
recyclerViewRow.idRow.setBackgroundColor(Color.WHITE)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
trackLog(context, "onCreateViewHolder()")
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_list_content, parent, false)
return ViewHolder(view, 1)
}
override fun onViewAttachedToWindow(holder: ViewHolder) {
super.onViewAttachedToWindow(holder)
trackLog(context, "onViewAttachedToWindow()")
}
inner class ViewHolder(itemView: View, position: Int) : RecyclerView.ViewHolder(itemView) {
val idView: TextView = itemView.id_text
val contentView: TextView = itemView.content
val idRow = itemView.id_row_linear_layout
}
private fun setDataToRecyclerRow(recyclerViewRow: ViewHolder, data: ListContent.ListItem) {
trackLog(context, "setDataToRecyclerRow(id: ${data.id})")
recyclerViewRow.idView.text = data.id
recyclerViewRow.contentView.text = data.itemTitle
recyclerViewRow.itemView.tag = data
}
private fun onListItemClick(selectedItemUniqueID: Int) {
trackLog(context, "onListItemClick($selectedItemUniqueID)")
State.selectedListItemUniqueId = selectedItemUniqueID
if (twoPane) {
State.lastOrientation = Orientation.landscape
putDetailFragmentOnDetailActivity()
} else {
State.lastOrientation = Orientation.portrate
launchDetailActivity()
}
notifyDataSetChanged()
}
private fun launchDetailActivity() {
trackLog(context, "launchDetailActivity()")
val intent = Intent(
context,
ItemDetailActivity::class.java
) //val intent = Intent(context, ItemDetailActivity::class.java).apply {putExtra(ItemDetailFragment.ARG_ITEM_ID, selectedItemUniqueID)}
context.startActivity(intent)
}
private fun putDetailFragmentOnDetailActivity() {
trackLog(context, "putDetailFragmentOnDetailFragmentHolder()")
val fragment =
ItemDetailFragment() //val fragment = ItemDetailFragment().apply {arguments = Bundle().apply {putInt("SOME UNIQUE TAG", selectedItemUniqueID)}}
val container = parentActivity.item_detail_container
container.removeAllViewsInLayout()
parentActivity.supportFragmentManager.beginTransaction()
.replace(R.id.item_detail_container, fragment).commit()
}
}
private fun onListFabClick(view: View) {
trackLog(this, "onListFabClick()")
selectFirstOnList()
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show()
}
private fun refreshUI() {
trackLog(this, "refreshUI()")
var recycleViewUI = recycleview_list
if (State.selectedListItemUniqueId == null) {
selectFirstOnList()
} else {
val selectedListItem: ListContent.ListItem? =
State.findDataRowByUniqueId(State.selectedListItemUniqueId)
if (selectedListItem == null) {
selectFirstOnList()
recycleViewUI.findViewHolderForAdapterPosition(0)?.itemView?.performClick()
} else {
recycleViewUI.getLayoutManager()
?.scrollToPosition(selectedListItem.listRowIndex)
}
}
}
private fun selectFirstOnList() {
trackLog(this, "selectFirstOnList()")
if (twoPane) {
var recycleViewUI = recycleview_list
//recycleViewUI.getLayoutManager()?.scrollToPosition(0)
recycleViewUI.findViewHolderForAdapterPosition(0)?.itemView?.performClick()
}
}
protected fun postAndNotifyAdapter(handler: Handler, recyclerView: RecyclerView) {
trackLog(this, "postAndNotifyAdapter()")
/*
handler.post(Runnable {
if (!recyclerView.isComputingLayout) {
// This will call first item by calling "performClick()" of view.
(recyclerView.findViewHolderForLayoutPosition(0) as RecyclerView.ViewHolder).itemView.performClick()
} else {
postAndNotifyAdapter(handler, recyclerView) //, adapter
}
})
*/
}
}
class State (hold selected on screen rotation/activity changes)
import android.content.Context
import android.util.Log
import android.widget.Toast
import ie.dpsystems.asm.list.ListContent
import java.util.ArrayList
enum class Orientation { portrate, landscape }
class State {
companion object {
public var selectedListItemUniqueId:Int? = null
public var dataRows: MutableList<ListContent.ListItem> = ArrayList()
public var lastOrientation:Orientation? = null
public fun findDataRowByUniqueId(uniqueID:Int?):ListContent.ListItem?{
if(uniqueID==null) return null
return State.dataRows.find { it.uniqueID == uniqueID}
}
public fun trackLog(context: Context, text:String){
//Toast.makeText(context,text, Toast.LENGTH_LONG).show()
Log.d("track",text)
}
}
}
src/main/res/layout-w900dp/item_list.xml (2 pane for tablet)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:baselineAligned="false"
android:divider="?android:attr/dividerHorizontal"
android:orientation="horizontal"
android:showDividers="middle"
tools:context=".list.ItemListActivity">
<!--
This layout is a two-pane layout for list / detail
-->
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/recycleview_list"
android:name="ie.dpsystems.asm.ItemListFragment"
android:layout_width="#dimen/item_width"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
app:layoutManager="LinearLayoutManager"
tools:context="ie.dpsystems.asm.list.ItemListActivity"
tools:listitem="#layout/item_list_content" />
<FrameLayout
android:id="#+id/item_detail_container"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3" />
</LinearLayout>
item_list_content.xml (RecyclerView per row layout)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/id_row_linear_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="#+id/id_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="#dimen/text_margin"
android:textAppearance="?attr/textAppearanceListItem" />
<TextView
android:id="#+id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="#dimen/text_margin"
android:textAppearance="?attr/textAppearanceListItem" />
</LinearLayout>
object ListContent (to put fake data into list during development)
import java.util.ArrayList
import java.util.HashMap
/**
* Helper class for providing sample itemTitle for user interfaces created by
* Android template wizards.
*
* TODO: Replace all uses of this class before publishing your app.
*/
object ListContent {
/**
* An array of sample (dummy) items.
*/
val ITEMS: MutableList<ListItem> = ArrayList()
/**
* A map of sample (dummy) items, by ID.
*/
val ITEM_MAP: MutableMap<String, ListItem> = HashMap()
private val COUNT = 25
init {
// Add some sample items.
for (i in 1..COUNT) {
addItem(fakeGetRecordFromSqlite(i))
}
}
private fun addItem(item: ListItem) {
ITEMS.add(item)
ITEM_MAP.put(item.id, item)
}
private fun fakeGetRecordFromSqlite(position: Int): ListItem {
return ListItem(position, -1, position.toString(), "Item " + position, fakeGetRecordCollectionFromSqlite(position))
}
private fun fakeGetRecordCollectionFromSqlite(position: Int): String {
val builder = StringBuilder()
builder.append("Details about Item: ").append(position)
for (i in 0..position - 1) {
builder.append("\nMore details information here.")
}
return builder.toString()
}
/**
* A dummy item representing a piece of itemTitle.
*/
data class ListItem(val uniqueID:Int, var listRowIndex:Int, val id: String, val itemTitle: String, val details: String) {
override fun toString(): String = itemTitle
}
}
class ItemDetailFragment (display details in detail fragment)
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import ie.dpsystems.asm.R
import ie.dpsystems.asm.data.State
import ie.dpsystems.asm.list.ListContent
import kotlinx.android.synthetic.main.activity_item_detail.*
import kotlinx.android.synthetic.main.item_detail.view.*
/**
* A fragment representing a single Item detail screen.
* This fragment is either contained in a [ItemListActivity]
* in two-pane mode (on tablets) or a [ItemDetailActivity]
* on handsets.
*/
class ItemDetailFragment : Fragment() {
/**
* The dummy itemTitle this fragment is presenting.
*/
private var item: ListContent.ListItem? = null
private var selectedItemUniqueID:Int? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//arguments?.let { if (it.containsKey(ARG_ITEM_ID)) {val uniqueID = it.getInt(ARG_ITEM_ID)}}
item = State.findDataRowByUniqueId(State.selectedListItemUniqueId)
activity?.toolbar_layout?.title = item?.itemTitle
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,savedInstanceState: Bundle?): View? {
val rootView = inflater.inflate(R.layout.item_detail, container, false)
item?.let {rootView.item_detail.text = it.details}
return rootView
}
}
class ItemDetailActivity (for single pane screen size devices)
import android.content.Intent
import android.os.Bundle
import com.google.android.material.snackbar.Snackbar
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.NavUtils
import android.view.MenuItem
import android.view.View
import ie.dpsystems.asm.list.ItemListActivity
import ie.dpsystems.asm.R
import kotlinx.android.synthetic.main.activity_item_detail.*
import kotlinx.android.synthetic.main.activity_item_detail.fab
/**
* An activity representing a single Item detail screen. This
* activity is only used on narrow width devices. On tablet-size devices,
* item details are presented side-by-side with a list of items
* in a [ItemListActivity].
*/
class ItemDetailActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_item_detail)
setSupportActionBar(detail_toolbar)
fab.setOnClickListener { view -> onListFabClick(view) }
supportActionBar?.setDisplayHomeAsUpEnabled(true) // Show the Up button in the action bar.
putDetailFragmentOnDetailActivity(savedInstanceState)
}
private fun putDetailFragmentOnDetailActivity(savedInstanceState: Bundle?){ // Create the detail fragment and add it to the activity using a fragment transaction.
// savedInstanceState is non-null when there is fragment state
// saved from previous configurations of this activity
// (e.g. when rotating the screen from portrait to landscape).
// In this case, the fragment will automatically be re-added
// to its container so we don't need to manually add it.
// For more information, see the Fragments API guide at:
// http://developer.android.com/guide/components/fragments.html
if (savedInstanceState == null) {
val fragment = ItemDetailFragment() //val fragment = ItemDetailFragment().apply {arguments = Bundle().apply {putString("SOME UNIQUE TAG",intent.getStringExtra("SOME UNIQUE TAG"))}}
supportFragmentManager.beginTransaction().add(R.id.item_detail_container, fragment).commit()
}
}
private fun onListFabClick(view: View?) {
if(view!=null) Snackbar.make(view, "Replace with your own detail action", Snackbar.LENGTH_LONG).setAction("Action", null).show()
}
override fun onOptionsItemSelected(item: MenuItem) =
when (item.itemId) {
android.R.id.home -> {
// This ID represents the Home or Up button. In the case of this
// activity, the Up button is shown. Use NavUtils to allow users
// to navigate up one level in the application structure. For
// more details, see the Navigation pattern on Android Design:
//
// http://developer.android.com/design/patterns/navigation.html#up-vs-back
NavUtils.navigateUpTo(this, Intent(this, ItemListActivity::class.java))
true
}
else -> super.onOptionsItemSelected(item)
}
}
SOLUTIUON
postdelay select first (you can see from original code I'd already tried something like this!) PHEW! hope this helps someone :)
protected fun postAndNotifyAdapter(handler: Handler, recyclerView: RecyclerView) {
trackLog(this, "postAndNotifyAdapter() ${State.selectedListItemUniqueId}")
if (twoPane && State.selectedListItemUniqueId==null) {
Handler().postDelayed({
if (!recyclerView.isComputingLayout) {
trackLog(this, "postAndNotifyAdapter() !recyclerView.isComputingLayout ${State.selectedListItemUniqueId}")
selectFirstOnList()
} else {
postAndNotifyAdapter(handler, recyclerView) //, adapter
}
}, 1000)
}
}

I've edited my original post above to be complete with answer!

I recommend you use an interface to notify when recyclerview is done rendering it's items.
How to know when the RecyclerView has finished laying down the items?

Related

UninitializedPropertyAccessException in Android Studio using Kotlin

I am a beginner making use of a Roomdatabase. Mostly using it to load in and pass items between tables using simple relationships.
package com.example.allin
import android.app.AlertDialog
import android.net.Uri
import android.os.Bundle
import android.view.*
import android.widget.CheckBox
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.allin.model.Clothing
import com.example.allin.viewmodel.ClosetViewModel
import kotlinx.android.synthetic.main.fragment_clothing_tops_list.view.*
import kotlinx.android.synthetic.main.grid_clothing_item.view.*
class ClothingTopsList : Fragment() {
val args: ClothingTopsListArgs by navArgs()
/**
* Use this to get the query form Database of Tops
*/
private lateinit var mClosetViewModel: ClosetViewModel
private var adapter = ClothingTopsAdapter()
//This class should only display Clothing Tops in a RecyclerView
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_clothing_tops_list, container, false)
//instantiate the recyclerView
val recyclerView = view.clothing_top_rv
//asssign the adapter
recyclerView.adapter = adapter
recyclerView.layoutManager = GridLayoutManager(requireContext(), 2)
//Assign the correct data of Tops to the adapter of the RecyclerView
mClosetViewModel = ViewModelProvider(this).get(ClosetViewModel::class.java)
mClosetViewModel.selectAllTops().observe(viewLifecycleOwner, Observer { tops ->
adapter.setData(tops)
}
)
//If Item was selected. Call navController
setHasOptionsMenu(true)
return view
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.add_outfits_menu, menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if(item.itemId == R.id.add_clothing_to_outfit_button){
val selectedDialog = AlertDialog.Builder(this.requireContext())
selectedDialog.setPositiveButton("Yes") { _, _ ->
**//Used Here**
val action = ClothingTopsListDirections.actionClothingTopsListToAddClothingToOutfits(args.currentOutfit,adapter.selectedItem,args.currentBottom,args.currentShoes, args.currentOuterWear)
findNavController().navigate(action)
}
selectedDialog.setNegativeButton("No") { _, _ -> }
**//Used Here**
val temp = adapter.selectedItem.type
selectedDialog.setTitle("Add $temp to the outfit?")
Toast.makeText(this.requireContext(), "Added to Outfit", Toast.LENGTH_SHORT).show()
selectedDialog.create().show()
}
return super.onOptionsItemSelected(item)
}
}
/**
* This page consists of all code for the RecyclerView of Clothing Tops for selection only to add to outfits.
*/
class ClothingTopsAdapter() : RecyclerView.Adapter<ClothingTopsAdapter.MyViewHolder>() {
private var clothingTopList = emptyList<Clothing>()
**//Created Here**
lateinit var selectedItem: Clothing
inner class MyViewHolder(item: View): RecyclerView.ViewHolder(item){
var checkBox: CheckBox = item.findViewById(R.id.clothing_cb)
}
//This inflates the EXACT SAME LAYOUT as ClothingList
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.grid_clothing_top_item, parent, false)
)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currentItem = clothingTopList[position]
holder.itemView.gl_clothing_type.text = currentItem.type
holder.itemView.gl_clothing_item_photo.setImageURI( Uri.parse(currentItem.image))
holder.itemView.grid_item.setOnClickListener {
if (!holder.itemView.clothing_cb.isChecked){
**//Used Here**
selectedItem = currentItem
holder.itemView.clothing_cb.isChecked = true
}else {
holder.itemView.clothing_cb.isChecked = false
}
}
}
override fun getItemCount(): Int {
return clothingTopList.size
}
fun setData(clothing: List<Clothing>) {
this.clothingTopList = clothing
notifyDataSetChanged()
}
}
For some reason it isn't properly adding the selected item from the recyclerView adapter to the selectedItem variable.
Would appreciate any insight into why this is happening all of a sudden.
It turned out that the error occurred because I was tapping the checkbox itself and not just the card.

Errors in connection of CameraFragment.kt with xml

I need help please, i'm getting errors in fragment.kt in process of getting a camera set up
**
//fragmentcamera.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.camera.view.PreviewView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/preview"/>
<Button
android:id="#+id/btnTakePhoto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:text="Take photo"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="#id/btnDisplayGallery"
app:layout_constraintBottom_toBottomOf="parent"/>
<Button
android:id="#+id/btnDisplayGallery"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:layout_marginBottom="300dp"
android:text="Display gallery"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#id/btnTakePhoto" />
</androidx.constraintlayout.widget.ConstraintLayout>**
The following are images for camerafragment.kt
s
the errors that i am getting
import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.Toast
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageCapture
import androidx.camera.core.ImageCaptureException
import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.view.PreviewView
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.net.toUri
import androidx.fragment.app.Fragment
import com.google.common.util.concurrent.ListenableFuture
import java.io.File
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
class cameraFragment : Fragment() {
// TODO: Rename and change types of parameters
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
//ListenableFuture interface listens for async operations external to
// main thread
// requires type of activity being observed - ProcessCameraProvider
private lateinit var cameraProviderFuture:
ListenableFuture<ProcessCameraProvider>
//used to decide whether to use front or back camera
private lateinit var cameraSelector: CameraSelector
//use case for capturing images
private var imageCapture: ImageCapture? = null
//interface that extends Executor to provide thread for capturing an image
private lateinit var imgCaptureExecutor: ExecutorService
//static variables
companion object {
//used for messages output in debugger
val TAG = "cameraFragment"
//used to check request code
private var REQUEST_CODE = 101
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
// Inflate the layout for requireActivity() fragment
val view: View = inflater.inflate(
R.layout.xml_camera,
container,
false
)
//get instance of ProcessCameraProvider
cameraProviderFuture = ProcessCameraProvider.getInstance(requireActivity())
//set default to back camera
cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
//instantiate imgCaptureExecutor
imgCaptureExecutor = Executors.newSingleThreadExecutor()
//check for permissions (similar to other sensors)
if (ActivityCompat.checkSelfPermission(
requireActivity(),
Manifest.permission.CAMERA
) != PackageManager.PERMISSION_GRANTED
)
//request permissions
ActivityCompat.requestPermissions(
requireActivity(),
arrayOf(
//array containing required permissions
Manifest.permission.CAMERA
),
REQUEST_CODE
)
else {
//if permission already granted, start camera
startCamera()
}
//set up event listener for btnCapture click
val btnTakePhoto: Button = view.findViewById(R.id.btnTakePhoto)
btnTakePhoto.setOnClickListener {
takePhoto()
} //set up event listener for btnGallery click
val btnDisplayGallery: Button = view.findViewById(R.id.btnDisplayGallery)
btnDisplayGallery.setOnClickListener {
displayGallery()
}
return view
}
//invoked when permissions change
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
//check that request code matches and permission granted
if (requestCode == REQUEST_CODE &&
grantResults.isNotEmpty() &&
grantResults[0] == PackageManager.PERMISSION_GRANTED
) {
//if permission now granted, start camera
startCamera()
}
}
//listen for data from camera
private fun startCamera() {
cameraProviderFuture.addListener(
{
//create ProcessCameraProvider instance
val cameraProvider = cameraProviderFuture.get()
//connect preview use case to the preview in the xml file
val preview: PreviewView = requireView().findViewById(R.id.preview)
val previewCase = Preview.Builder().build().also {
it.setSurfaceProvider(preview.surfaceProvider)
}
//instantiate capture use case
imageCapture = ImageCapture.Builder().build()
try {
//clear all bindings to previous use cases first
cameraProvider.unbindAll()
//bind lifecycle of camera to lifecycle of application
cameraProvider.bindToLifecycle(
requireActivity(),
cameraSelector, previewCase
)
cameraProvider.bindToLifecycle(
requireActivity(), cameraSelector,
imageCapture
)
} catch (e: Exception) {
Log.d(TAG, "Use case binding failed")
}
},
//run asynchronous operation being listened to by cameraProviderFuture
ContextCompat.getMainExecutor(requireActivity())
)
}
//take photo
private fun takePhoto() {
imageCapture?.let {
//create file with fileName using timestamped in milliseconds
val file = File(
requireActivity().externalMediaDirs[0],
"snap_${System.currentTimeMillis()}"
)
//save image in above file
val outputFileOptions =
ImageCapture.OutputFileOptions.Builder(file).build()
//call takePicture method with where to find image
it.takePicture(
outputFileOptions,
imgCaptureExecutor,
//set up callbacks for when picture is taken
object : ImageCapture.OnImageSavedCallback {
override fun onImageSaved(
outputFileResults:
ImageCapture.OutputFileResults
) {
Log.i(TAG, "Image saved in ${file.toUri()}")
}
override fun onError(exception: ImageCaptureException) {
Toast.makeText(
requireActivity(),
"Error taking photo",
Toast.LENGTH_LONG
).show()
Log.i(TAG, "Error taking photo: $exception")
}
}
)
}
animateFlash()
}
//flash to provide feedback that photo taken
private fun animateFlash() {
val preview: PreviewView = requireView().findViewById(R.id.preview)
preview.postDelayed({
preview.foreground = ColorDrawable(Color.argb(125, 255, 255, 255))
preview.postDelayed({
preview.foreground = null
}, 30)
}, 60)
}
//display gallery
private fun displayGallery() {
val intent = Intent(requireActivity(), GalleryActivity::class.java)
startActivity(intent)
}
}
Replace all "this,getApplicationContext" with getActivity(). In Java
Replace all "this,getApplicationContext" with activity. In Kotlin.
Two likely definitions:
getActivity() in a Fragment returns the Activity the Fragment is currently associated with. (see http://developer.android.com/reference/android/app/Fragment.html#getActivity()).
getActivity() is user-defined.

How to send a variable to an Adapter to send it through an Intent to another activity?

I have an adapter for my RecyclerView where I program that when I click on the element (of my RecyclerView) it executes an Intent with a putExtra to take me to another activity, the variable that contains my putExtra comes from the element that I clicked, but now I need to add a More variable that comes from the activity. The issue is that I don't know how to send it from the adapter.
this is my adapter.
package com.example.atipicoapp
import android.app.Activity
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.LinearLayout
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.view.menu.ActionMenuItemView
import androidx.core.content.ContextCompat.startActivity
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.list_item.view.*
class MyAdapter(private val platoList : ArrayList<Plato>
) : RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyAdapter.MyViewHolder {
val itemView =
LayoutInflater.from(parent.context).inflate(R.layout.list_item, parent, false)
itemView.platoTouch.setOnClickListener(View.OnClickListener { v: View ->
})
return MyViewHolder(itemView)
}
override fun onBindViewHolder(holder: MyAdapter.MyViewHolder, position: Int) {
val plato: Plato = platoList[position]
holder.platoName.text = plato.platoName
holder.platoDescription.text = plato.platoDescription
holder.platoPrecio.text = plato.platoPrecio.toString()
holder.platoCantidad.text = plato.platoCantidad.toString()
when(holder){
is MyViewHolder -> {
holder.bind(platoList[position])
}
}
}
override fun getItemCount(): Int {
return platoList.size
}
public class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val platoName: TextView = itemView.findViewById(R.id.platoNombre)
val platoDescription: TextView = itemView.findViewById(R.id.platoDescripcion)
val platoPrecio: TextView = itemView.findViewById(R.id.platoPrecio)
val platoTouch: LinearLayout = itemView.findViewById(R.id.platoTouch)
val platoCantidad: TextView = itemView.findViewById(R.id.platoCant)
private val mActivity = itemView.context as Activity
private val intent = Intent(mActivity,SlotActivity::class.java)
fun bind(plato: Plato){
platoTouch.setOnClickListener{
intent.putExtra("id", platoName.text.toString())
mActivity.startActivity(intent)
}
}
}
}
And this is my Activity which contains my RecyclerView and the variable I want to send.
package com.example.atipicoapp
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.firebase.firestore.*
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.activity_menu_atipico.*
class MenuAtipicoActivity : AppCompatActivity() {
private lateinit var recyclerView: RecyclerView
private lateinit var platoArrayList: ArrayList<Plato>
private lateinit var myAdapter: MyAdapter
private lateinit var db: FirebaseFirestore
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_menu_atipico)
recyclerView = findViewById(R.id.recyclerView)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.setHasFixedSize(true)
platoArrayList = arrayListOf()
myAdapter = MyAdapter(platoArrayList)
recyclerView.adapter = myAdapter
pedidoId = intent.extras?.getString("pedidoId") //This is the variable I need to send
EventChangeListener()
Setup()
}
private fun EventChangeListener() {
db = FirebaseFirestore.getInstance()
db.collection("Platos").addSnapshotListener(object : EventListener<QuerySnapshot> {
override fun onEvent(
value: QuerySnapshot?,
error: FirebaseFirestoreException?
) {
if (error != null) {
Log.e("Firestore Error", error.message.toString())
return
}
for (dc: DocumentChange in value?.documentChanges!!) {
if (dc.type == DocumentChange.Type.ADDED) {
platoArrayList.add(dc.document.toObject(Plato::class.java))
}
}
myAdapter.notifyDataSetChanged()
}
})
}
private fun Setup() {
botonAceptar.setOnClickListener {
val SlotIntent = Intent(this, SlotActivity::class.java).apply {
}
startActivity(SlotIntent)
}
}
}
How can I send the variable if the Intent is executed from the Adapter?
Or... If it is not recommended to send intent from my Adapter, how can I send them from the activity?
Knowing that I have to carry a variable that is in the item of the RecyclerView.
Thanks for your help <3
Firstly, create a MyAdapter constructor where you pass arrayList as well as pedidoId like, your MyAdapter should be something like below:
MyAdapter.class
class MyAdapter(private val platoList : ArrayList<Plato>, val pedidoId:String
) : RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
........
.....
....
//in your bind(..) method
fun bind(plato: Plato){
platoTouch.setOnClickListener{
intent.putExtra("id", platoName.text.toString())
intent.putExtra("pedidoId", pedidoId)
mActivity.startActivity(intent)
}
}
}
And, in your MenuAtipicoActivity you need to do something like:
MenuAtipicoActivity
class MenuAtipicoActivity : AppCompatActivity() {
...............
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_menu_atipico)
recyclerView = findViewById(R.id.recyclerView)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.setHasFixedSize(true)
platoArrayList = arrayListOf()
pedidoId = intent.extras?.getString("pedidoId") //This is the variable I need to send
myAdapter = MyAdapter(platoArrayList,pedidoId)
recyclerView.adapter = myAdapter
EventChangeListener()
Setup()
}
..........
........
}

Kotlin :Can't get the price of the item of RecyclerView on Fragment

I am attempting to make a recyclerView on Fragment ,
The idea is to get the price of the Item ,when the item been selected ,
and multiply by the select amount from the popup menu also.
Like below :
The recyclerView model item : item_layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="120dp"
android:gravity="center"
android:id="#+id/cardView"
android:layout_margin="10dp"
android:background="#40E0D0"
android:layout_height="200dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Price:"
android:textColor="#color/black"
android:textSize="18sp"/>
<TextView
android:id="#+id/price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="100"
android:textColor="#color/black"
android:textSize="18sp"/>
</LinearLayout>
The model of the item : Product.kt :
package com.gearsrun.popmenuapplication
data class Product(var price : String)
private selectFuntion(itemPrice:Int){
}
ProductAdapter.kt
package com.gearsrun.popmenuapplication
import android.graphics.Color
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.item_layout.view.*
class ProductAdapter(private val productList:List<Product>,private val itemClick:(Int) -> Unit):RecyclerView.Adapter<ProductAdapter.ProductViewHolder>() {
private var selectedItemPosition :Int = 0
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.item_layout,parent,false)
return ProductViewHolder(itemView,itemClick)
}
override fun onBindViewHolder(holder: ProductViewHolder, position: Int) {
val currentItem = productList[position]
holder.price.text = currentItem.price.toString()
holder.itemView.setOnClickListener {
selectedItemPosition = position
notifyDataSetChanged()
}
if(selectedItemPosition == position){
holder.itemView.cardView.setBackgroundColor(Color.parseColor("#FAFAD2"))
}else{
holder.itemView.cardView.setBackgroundColor(Color.parseColor("#FFFFFF"))
}
}
override fun getItemCount() = productList.size
class ProductViewHolder(itemView: View, itemClick: (Int) -> Unit) :
RecyclerView.ViewHolder(itemView) {
val price : TextView = itemView.price
init {
itemView.setOnClickListener {
itemClick(price.text.toString().toInt()) //sortOf if you need String, change that on String in every declaration
}
}
}
}
Fragment.kt
package com.gearsrun.popmenuapplication.fragment
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.Menu
import android.view.View
import android.view.ViewGroup
import android.widget.PopupMenu
import androidx.recyclerview.widget.LinearLayoutManager
import com.gearsrun.popmenuapplication.Product
import com.gearsrun.popmenuapplication.ProductAdapter
import com.gearsrun.popmenuapplication.R
import kotlinx.android.synthetic.main.fragment_home.*
class HomeFragment : Fragment(R.layout.fragment_home) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//init popup menu
val popupMenu = PopupMenu(
context,
selectedTv
)
//add menu items to popup menu
popupMenu.menu.add(Menu.NONE,0,0,"1")
popupMenu.menu.add(Menu.NONE,1,1,"2")
popupMenu.menu.add(Menu.NONE,2,2,"3")
popupMenu.menu.add(Menu.NONE,3,3,"4")
popupMenu.menu.add(Menu.NONE,4,4,"5")
//handle menu clicks
popupMenu.setOnMenuItemClickListener {menuItem ->
//get id of the item clicked
val id = menuItem.itemId
if(id==0){
selectedTv.text = "1"
}else if(id==1){
selectedTv.text = "2"
}else if(id==2){
selectedTv.text = "3"
}else if(id==3){
selectedTv.text = "4"
}else if(id==4){
selectedTv.text = "5"
}
true
}
//handle button click,show menu
selectedTv.setOnClickListener {
popupMenu.show()
}
//display recyclerview
val productList = generateProductList()
fun selectFuntion(itemPrice: Int){
Log.e("haha","You have click${itemPrice}")
}
var adapter = ProductAdapter(productList,::selectFuntion)
giftRecycleView.adapter = adapter
giftRecycleView.layoutManager = LinearLayoutManager(context,LinearLayoutManager.HORIZONTAL,false)
}
private fun generateProductList():List<Product> {
val list = ArrayList<Product>()
list.add(Product(1))
list.add(Product(2))
list.add(Product(3))
return list
}
}
Can anyone help me modify my code ?
I will need that the item's value can be catch once click ,and multiply by the select amount ,in order to get the total price .
Thank you so much in advance !!
ProductAdapter.kt
add this:
class ProductAdapter(
private val productList:List<Product>,
private val itemClick: (Int) -> Unit
): RecyclerView.Adapter<ProductAdapter.ProductViewHolder>() {
delete this:
interface onItemClickListener {
fun onItemClick(position: Int)
}
fun setOnItemClickListener(listener: onItemClickListener) {
mlistener = listener
}
replace this:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.item_layout,parent,false)
return ProductViewHolder(itemView,itemClick)
}
replace this:
class ProductViewHolder(itemView: View, itemClick: (Int) -> Unit) :
RecyclerView.ViewHolder(itemView) {
val price : TextView = itemView.price
init {
itemView.setOnClickListener {
itemclick(price.text.toInt()) //sortOf if you need String, change that on String in every declaration
}
}
}
replace in fragment:
var adapter = ProductAdapter(productList, ::yourFunction)
giftRecycleView.adapter = adapter
add in fragment or ViewModel:
private yourFunction(itemPrice: Int) {
// do something with price
}
if you need to edit that price just make return type:
(Int) -> Int sort of :D
and in adapter
price.text = itemclick(price.text.toInt()).toString()

Kotlin Recycleview ,how to make onItemClick for views

I am attempting to make a function :
In recyclerView
when you click the user image ,navigate to the userActivity,
and when you click the "gift" icon ,navigate to otherActivity .
As follow is my Adapter.kt :
package Users.UserReceiveGiftItem
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.gearsrun.www.R
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.user_receive_gift_item.view.*
class UserReceiveGiftAdapter(val userList : List<UserReceiveGiftItem>) : RecyclerView.Adapter<UserReceiveGiftAdapter.UserHolder>(){
private lateinit var mListener :onItemClickListener
interface onItemClickListener{
fun onItemClick(view:View,position: Int)
}
fun setOnItemClickListener(listener: onItemClickListener){
mListener = listener
}
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): UserHolder {
val layoutInflater = LayoutInflater.from(parent.context)
return UserHolder(layoutInflater.inflate(R.layout.user_receive_gift_item,parent,false),mListener)
}
override fun onBindViewHolder(holder: UserReceiveGiftAdapter.UserHolder, position: Int) {
holder.render(userList[position])
}
override fun getItemCount(): Int = userList.size
class UserHolder(val view : View,listener:onItemClickListener) : RecyclerView.ViewHolder(view){
fun render(userList: UserReceiveGiftItem){
Picasso.get().load(userList.user_img).into(view.user_img)
view.user_name.text = userList.user_name
view.time.text = userList.time
view.userId.text = userList.userId
view.giftImg.setImageResource(userList.giftImg)
}
init {
view.setOnClickListener {
listener.onItemClick(it,absoluteAdapterPosition)
}
}
}
}
And I use in the Activity :
package com.gearsrun.www.UI.Receive
import Users.UserReceiveGiftItem.UserReceiveGiftAdapter
import Users.UserReceiveGiftItem.UserReceiveGiftItem
import android.content.Intent
import android.graphics.drawable.ColorDrawable
import android.os.Build
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.ImageView
import android.widget.Toast
import androidx.appcompat.app.ActionBar
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.LinearLayoutManager
import com.gearsrun.www.R
import com.gearsrun.www.UI.Gift.AwaitingToUnwrapActivity
import com.gearsrun.www.UI.Sunflower.SunflowerAvailableActivity
import com.gearsrun.www.UI.User.UserDetailActivity
import kotlinx.android.synthetic.main.activity_who_receive_gift.*
import kotlinx.android.synthetic.main.user_receive_gift_item.view.*
class ReceiveActivity : AppCompatActivity() {
val userList : List<UserReceiveGiftItem> = listOf(
UserReceiveGiftItem(
"https://i.pinimg.com/564x/63/85/68/63856877880614e0dab080071513156f.jpg",
"Sharry",
"10 mins ago",
"517ddY",
R.drawable.donut
),
)
lateinit var gift_unwrap : ImageView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_receive)
changeColor(R.color.font_green)
initRecycler()
gift_unwrap = findViewById(R.id.gift_unwrap)
gift_unwrap.setOnClickListener {
}
}
private fun changeColor(resourseColor: Int) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.statusBarColor = ContextCompat.getColor(applicationContext, resourseColor)
}
val bar: ActionBar? = supportActionBar
if (bar != null) {
bar.setBackgroundDrawable(ColorDrawable(resources.getColor(resourseColor)))
}
}
fun initRecycler(){
rvUser.layoutManager = LinearLayoutManager(this)
val adapter = UserReceiveGiftAdapter(userList)
rvUser.adapter = adapter
adapter.setOnItemClickListener(object:UserReceiveGiftAdapter.onItemClickListener{
override fun onItemClick(view: View, position: Int) {
view.user_img.setOnClickListener {
val intent = Intent(this#ReceiveActivity,UserDetailActivity::class.java)
startActivity(intent)
}
view.giftImg.setOnClickListener {
val intent =Intent(this#ReceiveActivity,SunflowerAvailableActivity::class.java)
startActivity(intent)
}
}
})
}
}
It is a bit rare that it is able to navigate successfully ,however ,it dosen't react for the first click ..Could you please take a look my code ?Thank you guys in advance !!
You are using the click listener of the list item to add more click listeners to its children. So the first time you click it, the children don't have listeners yet and won't do anything. It is also error prone that a parent and its children both have click listeners, because it's undefined what will happen if you change the click listener as you are clicking it.
Instead, you should define your interface in the adapter to handle both types of clicks. In the ViewHolder, set click listeners only on the relevant children to be clicked.
Also, I think you're misusing lateinit. I would make the property nullable. And it is redundant to have a setter function for a property's value.
If you make the ViewHolder class inner, then you don't have to pass instances of the listener to the view holder instances, which will cause problems if you ever change the Adapter's listener.
Finally, personally I think the listener should return the list item, not the specific view and position in the list. Those are implementation details that the outer class doesn't need to know about.
class UserReceiveGiftAdapter(val userList : List<UserReceiveGiftItem>) : RecyclerView.Adapter<UserReceiveGiftAdapter.UserHolder>(){
var onItemClickListener: OnItemClickListener? = null
interface OnItemClickListener{
fun onUserClick(item: UserReceiveGiftItem)
fun onGiftClick(item: UserReceiveGiftItem)
}
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): UserHolder {
val layoutInflater = LayoutInflater.from(parent.context)
return UserHolder(layoutInflater.inflate(R.layout.user_receive_gift_item,parent,false))
}
override fun onBindViewHolder(holder: UserReceiveGiftAdapter.UserHolder, position: Int) {
holder.render(userList[position])
}
override fun getItemCount(): Int = userList.size
inner class UserHolder(val view : View) : RecyclerView.ViewHolder(view){
fun render(userList: UserReceiveGiftItem){
Picasso.get().load(userList.user_img).into(view.user_img)
view.user_name.text = userList.user_name
view.time.text = userList.time
view.userId.text = userList.userId
view.giftImg.setImageResource(userList.giftImg)
}
init {
view.user_img.setOnClickListener {
onItemClickListener?.onUserClick(userList[absoluteAdapterPosition])
}
view.giftImg.setOnClickListener {
onItemClickListener?.onGiftClick(userList[absoluteAdapterPosition])
}
}
}
}
In Activity or Fragment:
adapter.onItemClickListener = object: UserReceiveGiftAdapter.OnItemClickListener {
override fun onUserClick(item: UserReceiveGiftItem) {
val intent = Intent(this#ReceiveActivity, UserDetailActivity::class.java)
startActivity(intent)
}
override fun onGiftClick(item: UserReceiveGiftItem) {
val intent = Intent(this#ReceiveActivity, SunflowerAvailableActivity::class.java)
startActivity(intent)
}
}
What I think after looking your code is, that you are setting adapter to your recyclerview first and then you are injecting a click listener to adapter.
What happens here is that some items from recycler view are loaded and they wouldn't have the click listener at that time,
for example if you scroll down, the newly appeared items on the screen will have proper click listeners, now if you scroll up, the previous one's will also have listener attached.
What to do to get rid of this problem:
Change your initRecycler() method as below:
fun initRecycler(){
rvUser.layoutManager = LinearLayoutManager(this)
val adapter = UserReceiveGiftAdapter(userList)
adapter.setOnItemClickListener(object:UserReceiveGiftAdapter.onItemClickListener{
override fun onItemClick(view: View, position: Int) {
view.user_img.setOnClickListener {
val intent = Intent(this#ReceiveActivity,UserDetailActivity::class.java)
startActivity(intent)
}
view.giftImg.setOnClickListener {
val intent =Intent(this#ReceiveActivity,SunflowerAvailableActivity::class.java)
startActivity(intent)
}
}
})
//set adapter after setting click listener to your adapter.
rvUser.adapter = adapter
}