I have a RecyclerView and I have to pass data to another activity when u click on an item. When someone clicks on the first item I need to pass the data of that item to an activity.
This is the part of the fragment where the recycler view is located:
class TrafficFragment : Fragment() {
private lateinit var trafficViewModel: TrafficViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
trafficViewModel =
ViewModelProviders.of(this).get(TrafficViewModel::class.java)
val root = inflater.inflate(R.layout.fragment_traffic, container, false)
//...
val recyclerViewTraffic: RecyclerView = root.findViewById(R.id.recyclerViewTraffic)
recyclerViewTraffic.apply {
layoutManager = LinearLayoutManager (this#TrafficFragment.context)
Log.d("DEBUG", MainActivity.clickArray.toString())
adapter = TrafficAdapter(MainActivity.clickArray){
var intent = Intent(activity, ClickDetail::class.java)
startActivity(intent)
}
}
return root
}
}
The adapter:
package com.example.example
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.traffic_recycler_layout.view.*
class TrafficAdapter(private val trafficClick: List<TrafficClick>, val clickDetail: () -> Unit) :
RecyclerView.Adapter<TrafficAdapter.ViewHolder>(){
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val layoutView = LayoutInflater.from(parent.context).inflate(R.layout.traffic_recycler_layout, parent, false)
return ViewHolder(layoutView)
}
override fun getItemCount(): Int = MainActivity.clicksNumber
companion object{
var idClick: String?= String()
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val clicks = trafficClick[position]
holder.view.indirizzoIp.text = "${clicks.ip}"
holder.view.isp.text= "${clicks.organization}"
holder.view.data.text = "${clicks.data_creation}"
holder.view.numberText.text = "${clicks.id_campaign}"
holder.view.setOnClickListener {
clickDetail.invoke()
}
}
class ViewHolder(val view: View) : RecyclerView.ViewHolder(view)
}
and this is the activity that I need to open when I click on the item with the details of that item:
package com.example.example
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.traffic_click_detail.*
class ClickDetail : AppCompatActivity(){
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.traffic_click_detail)
}
}
var intent = Intent(activity, ClickDetail::class.java)
intent.putExtra("your_key",MainActivity.clickArray.toString())
startActivity(intent)
class ClickDetail : AppCompatActivity(){
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.traffic_click_detail)
val YourData = getIntent().getStringExtra("your_key")
}
}
If I suppose you want to pass and id, replace this
holder.view.setOnClickListener {
clickDetail.invoke()
}
by
holder.view.setOnClickListener {
ClickDetail.launch(holder.itemView.context, /*your ID*/)
}
Then to retrieve your data
class ClickDetail : AppCompatActivity(){
companion object {
private const val EXTRA_KEY_ID = "CLICKDETAIL.EXTRA_KEY_ID"
fun launch(launcher: Activity, id: Int) {
val intent = Intent(launcher, ClickDetail::class.java)
.apply {
putExtra(EXTRA_KEY_ID, id)
}
launcher.startActivity(intent)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.traffic_click_detail)
val id = intent.getIntExtra("EXTRA_KEY_ID")
}
}
Related
I am trying to make a game of life grid based game in Android Studio using kotlin. Essentially, every second the grid will update based off a set of rules. However, I can not for the life of me get the grid to update.
For some reason, notifyItemChanged() is not calling onBindViewHolder to properly update the grid visually. I was able to find a work around for some cases, that being calling onBindViewHolder specifically and passing through the current cellViewHolder and it's position, but this won't get me the result I am looking for. Specifically, in the function I declared testUpdate(), I need to be able to change an array of data that the grid is based on, and then from that function notify the grid that changes were made and it should update. However, notifyItemChanged() as well as notifyDatasetChanged() both do not call onBindViewHolder(). I am at a loss, any help would be much appreciated!
I am very new to Kotlin, so I apologize if this code is horrible.
Here is my code:
package com.example.project2
import android.graphics.Color
import android.os.Bundle
import android.text.Layout
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.ImageButton
import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import android.os.Handler;
class BoardFragment : Fragment() {
private lateinit var recyclerView: RecyclerView
var gridArray = IntArray(400)
val handler = Handler()
var isRunning: Boolean = false
val colorRed = Color.RED
val colorBlue = Color.BLUE
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.board_fragment, container, false)
val startButton = view.findViewById(R.id.start_button) as Button
val recyclerView = view.findViewById(R.id.recycler_view) as RecyclerView
recyclerView.layoutManager = GridLayoutManager(activity, 20)
recyclerView.adapter = GridAdapter()
startButton.setOnClickListener {
isRunning = !isRunning
if (isRunning) {
testUpdate()
}
}
return view
}
fun testUpdate() {
handler.postDelayed({
if (gridArray[3] == 0) {
gridArray[3] = 1
} else {
gridArray[3] = 0
}
if (isRunning) {
testUpdate()
}
GridAdapter().notifyItemChanged(3)
}, 1000)
}
override fun onStart() {
super.onStart()
}
private inner class CellViewHolder(cellView: View): RecyclerView.ViewHolder(cellView) {
val button: ImageButton
init {
button = cellView.findViewById(R.id.cell_button)
button.setColorFilter(null)
button.setOnClickListener {
if (gridArray[position] == 0) {
gridArray[position] = 1
} else {
gridArray[position] = 0
}
GridAdapter().notifyItemChanged(position)
GridAdapter().onBindViewHolder(this, position)
}
}
fun display(position: Int) {
}
}
private inner class GridAdapter: RecyclerView.Adapter<CellViewHolder>() {
final val NUM_CELLS: Int = 400
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CellViewHolder {
val inflater: LayoutInflater = LayoutInflater.from(parent.context)
val cellView: View = inflater.inflate(R.layout.board_cell, parent, false)
return CellViewHolder(cellView)
}
override fun onBindViewHolder(holder: CellViewHolder, position: Int) {
holder.display(position)
if (gridArray[position] == 0) {
holder.button.setColorFilter(null)
} else {
holder.button.setColorFilter(Color.RED)
}
}
override fun getItemCount(): Int {
return NUM_CELLS
}
}
}
I don't know what you're trying to achieve but a few tip
notifyItemChange() should be called from the Adapter class.
You're creating a new instances of GridAdapter GridAdapter().notifyItemChanged(position)
change
GridAdapter().notifyItemChanged(position)
to
recyclerView.adapter.notifyItemChanged(position)
modify your class like this
package com.example.project2
import android.graphics.Color
import android.os.Bundle
import android.text.Layout
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.ImageButton
import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import android.os.Handler;
class BoardFragment : Fragment() {
private lateinit var recyclerView: RecyclerView
var gridArray = IntArray(400)
val handler = Handler()
var isRunning: Boolean = false
val colorRed = Color.RED
val colorBlue = Color.BLUE
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.board_fragment, container, false)
val startButton = view.findViewById(R.id.start_button) as Button
val recyclerView = view.findViewById(R.id.recycler_view) as RecyclerView
recyclerView.layoutManager = GridLayoutManager(activity, 20)
recyclerView.adapter = GridAdapter()
startButton.setOnClickListener {
isRunning = !isRunning
if (isRunning) {
testUpdate()
}
}
return view
}
fun testUpdate() {
handler.postDelayed({
if (gridArray[3] == 0) {
gridArray[3] = 1
} else {
gridArray[3] = 0
}
if (isRunning) {
testUpdate()
}
recyclerView.adapter.notifyItemChanged(3)
}, 1000)
}
override fun onStart() {
super.onStart()
}
private inner class CellViewHolder(cellView: View): RecyclerView.ViewHolder(cellView) {
val button: ImageButton
init {
button = cellView.findViewById(R.id.cell_button)
button.setColorFilter(null)
button.setOnClickListener {
if (gridArray[position] == 0) {
gridArray[position] = 1
} else {
gridArray[position] = 0
}
}
}
fun display(position: Int) {
}
}
private inner class GridAdapter: RecyclerView.Adapter<CellViewHolder>() {
final val NUM_CELLS: Int = 400
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CellViewHolder {
val inflater: LayoutInflater = LayoutInflater.from(parent.context)
val cellView: View = inflater.inflate(R.layout.board_cell, parent, false)
return CellViewHolder(cellView)
}
override fun onBindViewHolder(holder: CellViewHolder, position: Int) {
if (gridArray[position] == 0) {
holder.button.setColorFilter(null)
} else {
holder.button.setColorFilter(Color.RED)
}
holder.display(position)
recyclerView.adapter.notifyItemChanged(3)
}
override fun getItemCount(): Int {
return NUM_CELLS
}
}
}
Peace
i have made simple recyclerview, with interface clickListener
consisting of 4 items showing toast on click.
It works fine if i single click per second,
but if i Rapidly click on different items ( 2 or 3 times in 1 seconds )
it still shows the toast each second,
not rapidly changing the toast
data class code:
package com.elsersy.rv5
data class Items (var textt:String) {
}
adapter code
package com.elsersy.rv5
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
class MyAdapter(private var stringList:ArrayList<Items>,private val listener:MyOnClickListener):
RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
inner class MyViewHolder(itemView:View):RecyclerView.ViewHolder(itemView) {
var text:TextView = itemView.findViewById(R.id.textView)
init {
itemView.setOnClickListener {
val position = absoluteAdapterPosition
if (position != RecyclerView.NO_POSITION)
{
listener.onItemClick(position)
}
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.row_item,parent,false)
return MyViewHolder(itemView)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currentItem = stringList[position]
holder.text.text = currentItem.textt
}
override fun getItemCount(): Int {
return stringList.size
}
interface MyOnClickListener{
fun onItemClick(position: Int)
}
fun setData(newItemList:ArrayList<Items>){
val diffUtil = MyDiffUtil(stringList,newItemList)
val diffResults = DiffUtil.calculateDiff(diffUtil)
stringList = newItemList
diffResults.dispatchUpdatesTo(this)
}
}
ActivityMainCode
package com.elsersy.rv5
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import com.elsersy.rv5.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity(),MyAdapter.MyOnClickListener {
private lateinit var binding: ActivityMainBinding
private lateinit var stringList:ArrayList<Items>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
binding.recyclerView.layoutManager = LinearLayoutManager(this)
stringList = arrayListOf<Items>()
getStrings()
binding.recyclerView.adapter=MyAdapter(stringList,this)
}
private fun getStrings() {
for (a in 0..4){
var string_Array = resources.getStringArray(R.array.string_array)
stringList.add(Items(string_Array[a]))
}
}
override fun onItemClick(position: Int) {
Toast.makeText(this,"$position is clicked", Toast.LENGTH_SHORT).show()
}
}
If you want to cancel the previous toast before showing a new one, assign it as a member variable and cancel it before showing the new one:
private var toast : Toast? = null
..
override fun onItemClick(position: Int) {
toast?.cancel()
toast = Toast.makeText(this,"$position is clicked", Toast.LENGTH_SHORT)
toast?.show()
}
Im trying to make a user recyclerview in a fragment, but i can't make it to work.
The idea is to get the users from the database (except for the actual user loged in) and add the user data to the list. The problem is that the list doesn't even apear.
I don't know much about Kotlin, i've recently started and Im struggling with this. Also I don't know where the problem is.
If you need the XML, ask for it
My Fragment:
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.auth.FirebaseUser
import com.google.firebase.database.*
#Suppress("NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS")
class UsersFragment:Fragment(R.layout.fragment_users) {
private lateinit var recyclerView: RecyclerView
private lateinit var adapterUsers: AdapterUsers
private lateinit var userList: MutableList<ModelUsers>
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
super.onCreate(savedInstanceState)
(activity as AppCompatActivity).supportActionBar?.title = "Users"
val view: View = inflater.inflate(R.layout.fragment_users, container, false)
userList = ArrayList()
getAllUsers()
adapterUsers = AdapterUsers(context!!, userList)
recyclerView = view.findViewById(R.id.users_recyclerView)
recyclerView.setHasFixedSize(true)
recyclerView.layoutManager = LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false)
recyclerView.adapter = adapterUsers
return view
}
private fun getAllUsers() {
val fUser: FirebaseUser = FirebaseAuth.getInstance().currentUser
val ref: DatabaseReference = FirebaseDatabase.getInstance().getReference("Users")
ref.addValueEventListener(object: ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
Log.d("FUNCTION", "ENTER")
userList.clear()
for(ds: DataSnapshot in snapshot.children){
val modelUsers: ModelUsers? = ds.getValue(ModelUsers::class.java)
if(!modelUsers?.uid.equals(fUser.uid)){
userList.add(modelUsers!!)
Toast.makeText(activity, "IN", Toast.LENGTH_SHORT).show()
}
}
}
override fun onCancelled(error: DatabaseError) {
TODO("Not yet implemented")
}
})
}
companion object {
fun newInstance(): ProfileFragment {
return ProfileFragment()
}}}
My Custom Adapter:
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.recyclerview.widget.RecyclerView
import com.squareup.picasso.Picasso
import java.lang.Exception
open class AdapterUsers(private var context:Context, private var userList: MutableList<ModelUsers> = mutableListOf<ModelUsers>()): RecyclerView.Adapter<AdapterUsers.UserViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
val view = LayoutInflater.from(context).inflate(R.layout.row_users, parent, false)
return UserViewHolder(view)
}
override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
val userImage = userList[position].image
val userName = userList[position].name
val userEmail = userList[position].email
holder.mNameTv.text = userName
holder.mEmailTv.text = userEmail
try {
Picasso.get().load(userImage).placeholder(R.drawable.ic_default_image_color).into(holder.mAvatarIv)
}
catch (e: Exception){
}
holder.itemView.setOnClickListener{
Toast.makeText(context, userEmail, Toast.LENGTH_SHORT).show()
}
}
override fun getItemCount(): Int {
return userList.size
}
inner class UserViewHolder(itemView: View): RecyclerView.ViewHolder(itemView){
val mAvatarIv: ImageView = itemView.findViewById(R.id.avatarIv)
val mNameTv: TextView = itemView.findViewById(R.id.nameTv)
val mEmailTv: TextView = itemView.findViewById(R.id.emailTv)
}
}
Model for Users:
data class ModelUsers(
var name: String? = null,
var email: String? = null,
var search: String? = null,
var phone: String? = null,
var image: String? = null,
var cover: String? = null,
var uid: String? = null)
You should refresh your recycler view adapter after your data have changed, try to change your code like this:
class UsersFragment:Fragment(R.layout.fragment_users) {
private lateinit var recyclerView: RecyclerView
private var userList = mutableListOf<ModelUsers>()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
super.onCreate(savedInstanceState)
(activity as AppCompatActivity).supportActionBar?.title = "Users"
val view: View = inflater.inflate(R.layout.fragment_users, container, false)
recyclerView = view.findViewById<RecyclerView>(R.id.users_recyclerView).apply {
setHasFixedSize(true)
layoutManager = LinearLayoutManager(requireContext())
adapter = AdapterUsers(requireContext(), mutableListOf())
}
getAllUsers()
return view
}
private fun getAllUsers() {
val fUser: FirebaseUser = FirebaseAuth.getInstance().currentUser
val ref: DatabaseReference = FirebaseDatabase.getInstance().getReference("Users")
ref.addValueEventListener(object: ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
Log.d("FUNCTION", "ENTER")
userList.clear()
for(ds: DataSnapshot in snapshot.children) {
val modelUsers: ModelUsers? = ds.getValue(ModelUsers::class.java)
if(!modelUsers?.uid.equals(fUser.uid)){
userList.add(modelUsers!!)
Toast.makeText(activity, "IN", Toast.LENGTH_SHORT).show()
}
recyclerView.adapter = AdapterUsers(requireContext(), userList)
}
}
override fun onCancelled(error: DatabaseError) {
TODO("Not yet implemented")
}
})
}
companion object {
fun newInstance(): ProfileFragment {
return ProfileFragment()
}
}
}
The problem is that when you use your adapter the list is empty, then maybe 0.2 seconds later, you have fetched the users from the database and populated the list, but the adapter doesn't know the list has changed. After you have populated the list you can call notifyDataSetChanged() on your Adapter to let it know the list has changed.
I am trying to retrieve data from the Firebase Firestore using the MVVM pattern . The build gets successfull everytime but the app fails to open up. I am not able to find faults in the code.The application is able to add data but retrieving data is the issue. Please help.Thank-You
ViewModel
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.google.firebase.firestore.FirebaseFirestore
import com.karuneshpalekar.firestorepagination.models.Note
import java.lang.Exception
class DataViewModel : ViewModel() {
companion object{
private const val TAG =" VIEWMODEL"
}
private val db = FirebaseFirestore.getInstance()
private val noteref = db.collection("record")
private val _results = MutableLiveData<Exception>()
val results: LiveData<Exception>
get() = _results
private val _notes = MutableLiveData<List<Note>>()
val notes: LiveData<List<Note>>
get() = _notes
fun addData(note: Note) {
noteref.add(note).addOnCompleteListener {
if (it.isSuccessful) {
Log.w("TAG", "success")
_results.value = null
} else {
_results.value = it.exception
}
}
}
fun fetchData() {
noteref.addSnapshotListener{ snapshot,e->
if (e!=null){
Log.w(TAG,"Listen failed",e)
return#addSnapshotListener
}
if (snapshot != null) {
val items = mutableListOf<Note>()
for (docs in snapshot){
val notes = docs.toObject(Note::class.java)
notes.let {
items.add(it)
}
_notes.value = items
}
}
}
}
}
Adapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.karuneshpalekar.firestorepagination.R
import com.karuneshpalekar.firestorepagination.models.Note
import kotlinx.android.synthetic.main.list_item.view.*
class DataAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var items= mutableListOf<Note>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return DataViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.list_item, parent, false)
)
}
override fun getItemCount(): Int {
return items.size
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is DataViewHolder -> {
holder.bind(items[position])
}
}
}
fun setNote(items:List<Note>){
this.items = items as MutableList<Note>
notifyDataSetChanged()
}
class DataViewHolder constructor(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val textName = itemView.text_view_name
fun bind(note: Note) {
textName.text = note.name
}
}
}
Fragment
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import com.karuneshpalekar.firestorepagination.R
import kotlinx.android.synthetic.main.fragment_recyclerview.*
class RecyclerView : Fragment() {
private lateinit var viewModel: DataViewModel
private lateinit var dataadapter : DataAdapter
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
viewModel = ViewModelProviders.of(this).get(DataViewModel::class.java)
return inflater.inflate(R.layout.fragment_recyclerview, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
recycler_view.apply {
dataadapter = DataAdapter()
adapter = dataadapter
}
viewModel.fetchData()
viewModel.notes.observe(viewLifecycleOwner, Observer {
dataadapter.setNote(it)
})
floating_btn_add.setOnClickListener {
DialogFragment().show(childFragmentManager, "")
}
}
}
DialogFragment - To add Data
class DialogFragment :DialogFragment(){
private lateinit var viewmodel:DataViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
viewmodel = ViewModelProviders.of(this).get(DataViewModel::class.java)
return inflater.inflate(R.layout.fragment_dialog, container, false)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStyle(STYLE_NO_TITLE, android.R.style.Theme_DeviceDefault_Light_Dialog_MinWidth)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewmodel.results.observe(viewLifecycleOwner, Observer {
val message = if (it == null) {
getString(R.string.name_added)
} else {
getString(R.string.name_error)
}
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
dismiss()
})
button_add.setOnClickListener {
val names = edit_text_name.text.toString().trim()
val note= Note("",names)
viewmodel.addData(note)
}
}
}
RecyclerView XML
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".ui.RecyclerView">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="#dimen/margin"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="#layout/list_item"
/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/floating_btn_add"
app:fabSize="normal"
android:layout_gravity="bottom|end"
android:layout_margin="#dimen/margin"
/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
The above is the code of my Project
The only thing missing in the code that provided errors was not having null-check in the Model class ,i.e., Note Class.
I want to create a new intent/activity when the user clicks on a cardview respectively and i was wondering how does one do it in kotlin. i noticed most tutorials are in java and i'm a student who did not learn java.
package com.example.ttshfypj.adapters
import androidx.fragment.app.Fragment
import android.view.View
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.ttshfypj.data_class.medications
import android.widget.ImageView
import android.widget.TextView
import com.example.ttshfypj.R
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.list_medication.view.*
class medicationAdapter (val medicationlist: ArrayList<medications>) : RecyclerView.Adapter<medicationAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.list_medication, parent, false)
return ViewHolder(v)
}
override fun getItemCount(): Int {
return medicationlist.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val medicationgroup: medications = medicationlist[position]
holder?.medicationnamevar?.text = medicationgroup.medicineN
holder?.medicationschedulevar?.text = medicationgroup.MedicineTime
val imagemedicine = holder?.itemView?.medicationimageview
Picasso.get().load(medicationgroup.MedicineImage).into(imagemedicine)
}
class ViewHolder(itemView: View) :RecyclerView.ViewHolder(itemView) {
val medicationnamevar = itemView.findViewById(R.id.medicationname) as TextView
val medicationschedulevar = itemView.findViewById(R.id.medicationschedule) as TextView
}
}
If you are using kotlin you can also use method reference where you directly pass a method to be called inside the adapter and you can directly invoke it there.
Activity.kt
Adapter(this::itemClickHandler);
private fun itemClickHandler(int position){
// your logic here
}
Adapter.kt
class Adapater(val itemClickHandler:(Int)->Unit):RecyclerView.Adapter(){
override fun onBindViewHolder(){
//you can invoke it here like this
itemClickHandler.invoke(adapterPosition);
}
}
please refer this full code
MainActivity.kt
package com.example.myapplication
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val list = mutableListOf<Items>()
for(i in 1..25){
list.add(Items(CHILD,"Child"))
}
with(rvList) {
layoutManager = LinearLayoutManager(this#MainActivity)
adapter = Adapter(list, this#MainActivity::onItemClickHandler)
}
}
private fun onItemClickHandler(position:Int){
Log.d("***","${position}");
//here you can start a new intent to open a new activity on click of item
}
}
The adapter code is as following
package com.example.myapplication
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.layout_child.view.*
import kotlinx.android.synthetic.main.layout_header.view.*
const val HEADER = 1;
const val CHILD = 2;
data class Items(val type: Int, val text: String)
class Adapter(private val list: List<Items>, val itemClickHandler: (Int) -> Unit) :
RecyclerView.Adapter<Adapter.HeaderViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HeaderViewHolder {
val headerView =
LayoutInflater.from(parent.context).inflate(R.layout.layout_header, parent, false)
val headerViewHolder = HeaderViewHolder(headerView)
headerView.setOnClickListener {
itemClickHandler.invoke(headerViewHolder.adapterPosition)
}
return headerViewHolder
}
override fun getItemCount(): Int = list.size
override fun onBindViewHolder(holder: HeaderViewHolder, position: Int) {
holder.onBind(list[position].text)
}
inner class HeaderViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun onBind(text: String) {
itemView.tvHeader.text = text
}
}
}
Hope this helps and you are able to follow
You can create an interface for Item Click Listener like
interface MyItemClickListener{
fun itemClick(position: Int)
}
Now you should pass context to the constructor of your adapter.
class medicationAdapter (val medicationlist: ArrayList<medications>, var context: Context) : RecyclerView.Adapter<medicationAdapter.ViewHolder>() {...}
and create an instance of MyItemClickListener inside your adapter
// create instance of MyItemClickListener
private val clickListener = context as MyItemClickListener
And setclick listener on your view inside the onCreateViewHolder.
modify your adapter like this
class medicationAdapter (val medicationlist: ArrayList<medications>, var context: Context) : RecyclerView.Adapter<medicationAdapter.ViewHolder>() {
// create instance of MyItemClickListener
private val clickListener = context as MyItemClickListener
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
var inflater = LayoutInflater.from(parent.context)
var v = inflater.inflate(R.layout.list_medication, parent, false)
var viewHolder = ViewHolder(v)
// here you set click listener on your item view.
v.setOnClickListener {
clickListener.itemClick(viewHolder.adapterPosition)
}
return viewHolder
}
override fun getItemCount(): Int {
return medicationlist.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val medicationgroup: medications = medicationlist[position]
holder?.medicationnamevar?.text = medicationgroup.medicineN
holder?.medicationschedulevar?.text = medicationgroup.MedicineTime
val imagemedicine = holder?.itemView?.medicationimageview
Picasso.get().load(medicationgroup.MedicineImage).into(imagemedicine)
}
class ViewHolder(itemView: View) :RecyclerView.ViewHolder(itemView) {
val medicationnamevar = itemView.findViewById(R.id.medicationname) as TextView
val medicationschedulevar = itemView.findViewById(R.id.medicationschedule) as TextView
}
}
And finally, in your activity, you have to implement the MyItemClickListener interface and override the itemClick() like this
class YourActivity: AppCompatActivity(), MyItemClickListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// ....
}
override fun itemClick(position: Int) {
Log.d("TAG","Click Item Position: "+position)
// here you can call your new activity according to your item position.
}
}