Data Load in Recyclerview after Generated Click Event Item using Interface on
Activity. code is below but Activity onItemCompanyClick is not execute.
How to Generate click event and get Value from the recyclerview using interfce.
MainActivity.kt
class Company : AppCompatActivity(),CompanyAdapter.Listner{
override fun onItemCompanyClick(company: Company) {
Toast.makeText(this, "You clicked: ${company.Cmp_Name}", Toast.LENGTH_LONG).show()
}
}
CompanyAdapter.kt
class CompanyAdapter(private val listner :Listner, internal var companyList: List<Company>)
:RecyclerView.Adapter<CompanyAdapter.CompanyViewHolder>()
{
interface Listner {
fun onItemCompanyClick(company: Company)
}
override fun onCreateViewHolder(p0: ViewGroup, p1: Int): CompanyViewHolder {
val itemView = LayoutInflater.from(p0.context).inflate(R.layout.list_view_item,p0,false)
return CompanyViewHolder(itemView)
}
override fun getItemCount(): Int {
return companyList.size
}
override fun onBindViewHolder(p0: CompanyViewHolder, p1: Int) {
// p0.rbButton.text = this!!.companyList?.get(p1)?.Cmp_Name
p0.bindModel(companyList[p1])
}
inner class CompanyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
val radioButton : RadioButton = itemView.findViewById(R.id.rbCompanyName)
fun bindModel(company: Company){
radioButton.text = company.Cmp_Name
}
}
}
Your interface is never called, you should call if when user click on your button.
Try something like:
MainActivity.kt
class Company : AppCompatActivity(),CompanyAdapter.Listner{
override fun onItemCompanyClick(company: Company){
Toast.makeText(this, "You clicked: ${company.Cmp_Name}", Toast.LENGTH_LONG).show()
}
}
CompanyAdapter.kt
class CompanyAdapter(private val listner :Listner, internal var companyList: List<Company>)
:RecyclerView.Adapter<CompanyAdapter.CompanyViewHolder>()
{
interface Listner{
fun onItemCompanyClick(company: Company)
}
override fun onCreateViewHolder(p0: ViewGroup, p1: Int): CompanyViewHolder {
val itemView = LayoutInflater.from(p0.context).inflate(R.layout.list_view_item,p0,false)
return CompanyViewHolder(itemView)
}
override fun getItemCount(): Int {
return companyList.size
}
override fun onBindViewHolder(p0: CompanyViewHolder, p1: Int) {
// p0.rbButton.text = this!!.companyList?.get(p1)?.Cmp_Name
p0.bindModel(companyList[p1])
}
inner class CompanyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
val radioButton : RadioButton = itemView.findViewById(R.id.rbCompanyName)
fun bindModel(company: Company){
radioButton.text = company.Cmp_Name
radioButton.setOnClickListener(_ -> listner.onItemCompanyClick(company))
}
}
}
Also read this guide about interface, hope it helps.
Related
I implemented a simple RecyclerView example, with multiple items selection possibility, using the selection library.
Here's my code:
class MainActivity : AppCompatActivity() {
private var listOfItems = ArrayList<Item>()
private var selectionTracker: SelectionTracker<Long>? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val recyclerView = findViewById<RecyclerView>(R.id.rvMainRecyclerView)
for (i in 0..32) {
listOfItems.add(Item(i, "Item $i"))
}
val recyclerViewAdapter = RecyclerViewAdapter(listOfItems)
recyclerView.adapter = recyclerViewAdapter
selectionTracker = SelectionTracker.Builder<Long>(
"Itemselection",
recyclerView,
MyItemKeyProvider(recyclerView),
MyItemDetailsLookup(recyclerView),
StorageStrategy.createLongStorage()
).build()
selectionTracker?.addObserver(
object: SelectionTracker.SelectionObserver<Long>() {
override fun onSelectionChanged() {
super.onSelectionChanged()
val itemsSelected = selectionTracker?.selection?.size()
Log.d("MainActivity", "$itemsSelected items selected")
}
}
)
recyclerViewAdapter.tracker = selectionTracker
}
}
class RecyclerViewAdapter(
val dataSet: ArrayList\<Item\>
): RecyclerView.Adapter\<RecyclerViewAdapter.ViewHolder\>() {
var tracker: SelectionTracker<Long>? = null
init {
setHasStableIds(true)
}
inner class ViewHolder(view: View): RecyclerView.ViewHolder(view) {
val textView: TextView
init {
textView = view.findViewById(R.id.tvRecyclerViewItemTitle)
}
fun getItemDetails(): ItemDetails<Long> {
return object : ItemDetails<Long>() {
override fun getPosition(): Int {
return adapterPosition
}
override fun getSelectionKey(): Long? {
return itemId
}
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(LayoutInflater
.from(parent.context).inflate(R.layout.recycler_view_item, parent, false))
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val currentItem = dataSet[position]
holder.textView.text = currentItem.value
holder.itemView.isActivated = tracker!!.isSelected(position.toLong())
}
override fun getItemCount(): Int {
return dataSet.size
}
override fun getItemId(position: Int): Long {
return dataSet[position].id.toLong()
}
}
I'm curious why the onSelectionChanged (in MainActivity selectionTracker?.addObserver...) is triggered several times while I hold an item to start selection mode?
To be more precise, this is the use case:
Nothing is selected,
Long click on any item => selection mode activated; the item is selected
Here, "1 items selected" is being printed out as long as I hold the first item.
I am using kotlin language with android studio. I want to get the properties of the element I clicked in the RecyclerView.
Ben bu kod ile saderc id alabiliyorum
Ex: date
ListAdapter.kt
class ListAdapter(
private val context: Context
) : RecyclerView.Adapter<ListAdapter.ListViewHolder>() {
private var dataList = mutableListOf<Any>()
private lateinit var mListener: onItemClickListener
interface onItemClickListener {
fun onItemClick(position: Int)
}
fun setOnItemClickListener(listener: onItemClickListener) {
mListener = listener
}
fun setListData(data: MutableList<Any>) {
dataList = data
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListViewHolder {
val view = LayoutInflater.from(context).inflate(R.layout.item_row, parent, false)
return ListViewHolder(view)
}
override fun onBindViewHolder(holder: ListViewHolder, position: Int) {
val question: Questionio = dataList[position] as Questionio
holder.bindView(question)
}
override fun getItemCount(): Int {
return if (dataList.size > 0) {
dataList.size
} else {
return 0
}
}
inner class ListViewHolder(itemView: View, listener: onItemClickListener) :
RecyclerView.ViewHolder(itemView) {
fun bindView(questionio: Questionio) {
itemView.findViewById<TextView>(R.id.txt_policlinic).text = questionio.policlinic
itemView.findViewById<TextView>(R.id.txt_title).text = questionio.title
itemView.findViewById<TextView>(R.id.txt_description).text = questionio.description
itemView.findViewById<TextView>(R.id.txt_date).text = questionio.date
itemView.findViewById<TextView>(R.id.txt_time).text = questionio.time
}
init {
itemView.setOnClickListener {
listener.onItemClick(adapterPosition)
}
}
}
}
My code in onCreateView inside list fragment.Edit
ListFragment
recyclerView.layoutManager = LinearLayoutManager(requireContext())
recyclerView.adapter = adapter
observeData()
adapter.setOnItemClickListener(object : ListAdapter.onItemClickListener {
override fun onItemClick(position: Int) {
showShortToast(position.toString())
}
})
this function is also my observationData(),
I made new edits
private fun observeData() {
binding.shimmerViewContainer.startShimmer()
listViewModel.fetchQuestinData("questions",
requireContext())
.observe(viewLifecycleOwner, {
binding.shimmerViewContainer.startShimmer()
binding.shimmerViewContainer.hideShimmer()
binding.shimmerViewContainer.hide()
adapter.setListData(it)
adapter.notifyDataSetChanged()
})
}
You can pass highOrderFuction into the adapter then setonclickListener for any view you want. Like this:
class ListAdapter(
private val context: Context,
private val onItemClick:(questionio: Questionio)->Unit
) : RecyclerView.Adapter<ListAdapter.ListViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListViewHolder {
val view = LayoutInflater.from(context).inflate(R.layout.item_row, parent, false)
return ListViewHolder(view,onItemClick)
}
...
inner class ListViewHolder(itemView: View,private val onItemClick:(questionio: Questionio)->Unit) : RecyclerView.ViewHolder(itemView) {
fun bindView(questionio: Questionio) {
//set on any view you want
itemView.findViewById<TextView>(R.id.root_view_id).
setOnClickListener{onItemClick(questionio)}
itemView.findViewById<TextView>(R.id.txt_policlinic).text =
questionio.policlinic
itemView.findViewById<TextView>(R.id.txt_title).text = questionio.title
itemView.findViewById<TextView>(R.id.txt_description).text =
questionio.description
itemView.findViewById<TextView>(R.id.txt_date).text = questionio.date
itemView.findViewById<TextView>(R.id.txt_time).text = questionio.time
}
}
}
The problem is related to the fact that I don't manage to implement a OnItemClick listener for a RecyclerView that is located in a "mainFragment" by implementing the OnClickListener in the Adapter.
I would like my application (kotlin) to launch another fragment ("deletePage" in the code bellow) everytime an itemView (an ImageView) from the RecyclerView is clicked, this fragment would display the same photo in big.
My Adapter code is the following one:
class MyAdapter : RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
private var photo = emptyList<Photo>()
inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.row_layout, parent, false)
)
}
override fun getItemCount(): Int {
return photo.size
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.itemView.longitude.text = photo[position].latitude
holder.itemView.latitude.text = photo[position].longitude
holder.itemView.imageView.load(photo[position].photo)
}
fun setData(photo: List<Photo>) {
this.photo = photo
notifyDataSetChanged()
}
}
And my mainFragment code is the following one:
class MainFragment : Fragment(){
private lateinit var myView: MyViewModel
private val adapter by lazy { MyAdapter() }
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_main, container, false)
//Recyclerview
val adapter = MyAdapter()
val recyclerView = view.recycler_view
recyclerView.adapter = adapter
recyclerView.layoutManager = LinearLayoutManager(requireContext())
myView = ViewModelProvider(this).get(MyViewModel::class.java)
myView.readPhoto.observe(viewLifecycleOwner, Observer {photo ->
adapter.setData(photo)
})
setHasOptionsMenu(true)
return view
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_database, menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when {
item.itemId == R.id.deleteAll -> findNavController().navigate(R.id.deletePage)
item.itemId == R.id.refresh -> {
Toast.makeText(activity, "yep", Toast.LENGTH_SHORT).show()
instertDataToDatabase()
}
}
if (item.itemId == R.id.deleteAll) {
}
return super.onOptionsItemSelected(item)
}
}
The objective is that when you click on an item of the RecyclerView the "findNavController().navigate(R.id.deletePage)" fragment is displayed but everytime I try to implement a solution the application crashes when clicking at an item of the RecyclerView. Right now the navigation works by the click on a button in the Menu at the toolbar but is not the ideal solution.
Any sort of help or advice would be very much appreciated!
Firstly you need to give click listener of your itemView in onBindViewHolder
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.itemView.longitude.text = photo[position].latitude
holder.itemView.latitude.text = photo[position].longitude
holder.itemView.imageView.load(photo[position].photo)
holder.itemView.setOnClickListener { navigateToFragment() }
}
For the navigation somehow you should have a context instance.
Here is the possible solutions that came up to my mind:
Give navigator instance to adapter
class Navigator(fragment: Fragment) {
private val fragmentRef = WeakReference(fragment)
fun navigate(){
// make your navigations here with using fragmentRef.get()
}
}
In your fragment:
private val navigator = Navigator(this)
...
val adapter = MyAdapter(navigator)
In your adapter:
class MyAdapter(private val navigator: Navigator) : RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
fun navigateToFragment(){
navigator.navigate()
}
Make interface for callback
2.1. Implement that interface in fragment and give adapter the interface instance
interface Navigable{
fun navigate()
}
In your fragment:
class MainFragment : Fragment(), Navigable{
...
override fun navigate(){
// make your navigation
}
val adapter = MyAdapter(navigator)
In your adapter:
class MyAdapter(private val navigable: Navigable) : RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
fun navigateToFragment(){
navigable.navigate()
}
2.2. Make the interface, but do not pass reference, use findFragment in adapter
In your adapter: override onAttachedToRecyclerView to find fragment
private lateinit var navigable: Navigable
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
super.onAttachedToRecyclerView(recyclerView)
navigable = recyclerView.findFragment<Fragment>() as Navigable
}
fun navigateToFragment(){
navigable.navigate()
}
I create a editText filter search. I want the recyclerView will show when user typing. In my apps, when user typing the filter was show, but the list recyclerView show too. maybe this video can explain what i mean filterSearch
Here is my code which works
ADAPTER
class SearchAdapter(val context: Context, val item:List<Item>) : RecyclerView.Adapter<SearchAdapter.ChildHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChildHolder {
val inflator = LayoutInflater.from(context).inflate(R.layout.search_container,parent,false)
return ChildHolder(inflator)
}
override fun getItemCount(): Int {
return item.size
}
override fun onBindViewHolder(holder: ChildHolder, position: Int) {
val current = item[position]
holder.item.name.setText(current.name)
}
class ChildHolder(view: View) : RecyclerView.ViewHolder(view){
val item = view.country_container
}
}
data class Item(val name:String)
MAINACTIVITY
class MainActivity : AppCompatActivity() {
var item:ArrayList<Item> = ArrayList()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
item.add(
Item("russia")
)
item.add(
Item("india")
)
item.add(
Item("usa")
)
item.add(
Item("china")
)
item.add(
Item("uk")
)
item.add(
Item("brazil")
)
item.add(
Item("pakistan")
)
item.add(
Item("sri lanka")
)
search_view.setOnQueryTextListener(object : SearchView.OnQueryTextListener{
override fun onQueryTextSubmit(query: String?): Boolean {
TODO("Not yet implemented")
}
override fun onQueryTextChange(newText: String?): Boolean {
val filtered = item.filter { item ->
item.name.contains(newText.toString())
}
constructRecycleView(filtered)
return true
}
})
}
private fun constructRecycleView(item:List<Item>){
val adapter = SearchAdapter(this,item)
recycle_view.adapter = adapter
recycle_view.layoutManager = LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false)
}
}
constructRecycleView method always create's new adapter, you can also create methods where you can mutate the adapter item and call notifyDatasetChanged Method ,and please implement onQueryTextSubmit
on your own if not your application gives Error
kotlin.NotImplementedError: An operation is not implemented: Not yet implemented
OUTPUT
I'm new android learner, I'm trying to make a RecyclerView contains of List of (Stories Title, and Stories images).
When you click on an item in the RecyclerView it should open a new activity called ChildrenStoriesPreview contains of ScrollView which have ImageView to put the Story Image in it and TextView to put the Text of the Story in it.
the problem is that I don't know how to set ocItemClickListener to know which item is clicked and how the new activity will contain information depending on this item? Could you please help me?
here is my Main.kt
class MainChildrenStories : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main_children_stories)
var childrenStoriesArraylist = ArrayList<ChildrenStoriesRecyclerView>()
childrenStoriesArraylist.add(ChildrenStoriesRecyclerView("Story1", R.drawable.pic1))
childrenStoriesArraylist.add(ChildrenStoriesRecyclerView("Story2", R.drawable.pic2))
childrenStoriesArraylist.add(ChildrenStoriesRecyclerView("Story3", R.drawable.pic3))
children_stories_recyclerview.layoutManager = LinearLayoutManager(this, LinearLayout.VERTICAL, false)
val childrenStoriesAdapter = ChildrenStoriesAdapter(childrenStoriesArraylist)
children_stories_recyclerview.adapter = childrenStoriesAdapter
childrenStoriesAdapter.setOnItemClickListener(object : ChildrenStoriesAdapter.ClickListener {
override fun onClick(pos: Int, aView: View) {
//The App Crash here
if (pos == 0){
my_text_view.text = "Story number 1"
my_imageview.setImageResource(R.drawable.pic1)
}else if (pos == 1){
my_text_view.text = "Story number 2"
my_imageview.setImageResource(R.drawable.pic2)
}
val intent = Intent(this#MainChildrenStories, ChildrenStoryPreview::class.java)
startActivity(intent)
}
})
}
}
MyRecyclerView Class
data class ChildrenStoriesRecyclerView(var mStoryName: String, var mStoryImage: Int)
My RecyclerView Adapter Class
class ChildrenStoriesAdapter(var myArrayList: ArrayList<ChildrenStoriesRecyclerView>) :
RecyclerView.Adapter<ChildrenStoriesAdapter.ViewHolder>() {
lateinit var mClickListener: ClickListener
fun setOnItemClickListener(aClickListener: ClickListener) {
mClickListener = aClickListener
}
override fun onCreateViewHolder(p0: ViewGroup, p1: Int): ViewHolder {
val v = LayoutInflater.from(p0.context).inflate(R.layout.children_stories_list, p0, false)
return ViewHolder(v)
}
override fun getItemCount(): Int {
return myArrayList.size
}
override fun onBindViewHolder(p0: ViewHolder, p1: Int) {
var infList = myArrayList[p1]
p0.storyName.text = infList.mStoryName
p0.storyImage.setImageResource(infList.mStoryImage)
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
override fun onClick(v: View) {
mClickListener.onClick(adapterPosition, v)
}
val storyName = itemView.findViewById(R.id.txtStoryName) as TextView
val storyImage = itemView.findViewById(R.id.imageViewChildrenStories) as ImageView
init {
itemView.setOnClickListener(this)
}
}
interface ClickListener {
fun onClick(pos: Int, aView: View)
}
}
My new Activity To show Details of the Story
class ChildrenStoryPreview : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_children_story_preview)
}
}
Pass the Event Listener to Adapter constructor also to viewholder to catch view holder (items) clicks.
class ChildrenStoriesAdapter(var myArrayList: ArrayList<ChildrenStoriesRecyclerView>
var clickListener:MyClickListener?) :
RecyclerView.Adapter<ChildrenStoriesAdapter.ViewHolder>() {
...
override fun onCreateViewHolder(p0: ViewGroup, p1: Int): ViewHolder {
val v = LayoutInflater.from(p0.context).inflate(R.layout.children_stories_list, p0, false)
return ViewHolder(v, clickListener)
}
...
inner class ViewHolder(itemView: View, clickListener:MyClickListener?) :
RecyclerView.ViewHolder(itemView) {
itemView.setOnClickListener { clickListener?.myClickedFun(...) }
...
class ChildrenStoryPreview : AppCompatActivity(), MyClickListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_children_story_preview)
}
override fun myClickedFun(...) {
...
}
}
Later init adapter like
..
val childrenStoriesAdapter = ChildrenStoriesAdapter(childrenStoriesArraylist, this)