How to add multi countdown timer in Recycler view? - android

I'm new to Android development. I'm trying to add a Multi countdown timer in recycler view but it does not work. Editing and deleting items in the list are okay, but I have no idea how to add a countdown timer function.
When I click the play button for starting the countdown, nothing happens. I would really appreciate it if you could tell me with a simple example.
Here is Adapter.kt.
class UserAdapter(val c: Context, val userList:ArrayList<UserData>): RecyclerView.Adapter<UserAdapter.UserViewHolder>() {
inner class UserViewHolder(val v: View) : RecyclerView.ViewHolder(v) {
var name: TextView
var DeleteButton: ImageView
var EditButton: ImageView
var PlayButton: ImageView
val start = 600_000L
var timer = start
lateinit var countDownTimer: CountDownTimer
init {
name = v.findViewById<TextView>(R.id.alarm_name)
DeleteButton = v.findViewById(R.id.alarm_button_delete)
EditButton=v.findViewById(R.id.alarm_button_edit)
PlayButton=v.findViewById(R.id.alarm_button_start)
DeleteButton.setOnClickListener { DeleteItem(it) }
EditButton.setOnClickListener { EditItem(it) }
PlayButton.setOnClickListener { PlayItem(it)}
}
private fun PlayItem(v: View) {
countDownTimer = object : CountDownTimer(timer,1000){
override fun onFinish() {
}
override fun onTick(millisUntilFinished: Long) {
}
}.start()
}
private fun DeleteItem(v: View) {
userList.removeAt(adapterPosition)
notifyDataSetChanged()
Toast.makeText(c, "Deleted this Information", Toast.LENGTH_SHORT).show()
}
private fun EditItem(v: View){
val position = userList[adapterPosition]
val v = LayoutInflater.from(c).inflate(R.layout.add_item,null)
val name = v.findViewById<EditText>(R.id.add_alarm_name)
AlertDialog.Builder(c)
.setView(v)
.setPositiveButton("Ok"){
dialog,_->
position.add_alram_name = name.text.toString()
notifyDataSetChanged()
Toast.makeText(c,"User Information is Edited",Toast.LENGTH_SHORT).show()
dialog.dismiss()
}
.setNegativeButton("Cancel"){
dialog,_->
dialog.dismiss()
}
.create()
.show()
true
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
val inflater = LayoutInflater.from(parent.context)
val v = inflater.inflate(R.layout.list_item, parent, false)
return UserViewHolder(v)
}
override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
val newList = userList[position]
holder.name.text = newList.add_alram_name
}
override fun getItemCount(): Int {
return userList.size
}

Seems like your adapter is not holding instance for each row items, as per recycling behavior the timer unable to hold the view position.
you can refer this

Related

RecyclerView delete the wrong position item

I have a list of item in RecylerView, with have a delete button with delete the item from the list.
When I click the delete button, the item at last got deleted not the item selected to be deleted.
What's more, it creates a new item with old item's data instead of new data.
The following below is the code written in Kotlin:
class MedicineAdapter(private val activity: Activity, private val dataSet: MutableList<MedicineModel>, private val medicineSet: List<MedicineData>): RecyclerView.Adapter<MedicineAdapter.ViewHolder>() {
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val deleteLayout: LinearLayout
val medicineLayout: LinearLayout
val medicineName: TextView
val timeLayout: LinearLayout
val medicineTime: TextView
init {
deleteLayout = view.findViewById(R.id.delete_layout)
medicineLayout = view.findViewById(R.id.medicine_layout)
medicineName = view.findViewById(R.id.medicine_name)
timeLayout = view.findViewById(R.id.time_layout)
medicineTime = view.findViewById(R.id.medicine_time)
}
}
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(viewGroup.context)
.inflate(R.layout.layout_medicine_item, viewGroup, false)
return ViewHolder(view)
}
override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
viewHolder.deleteLayout.setOnClickListener {
deleteRecord(viewHolder.adapterPosition)
}
viewHolder.medicineLayout.setOnClickListener {
val spinnerDialog = SpinnerDialog(activity, medicineSet.map { p -> p.name } as ArrayList<String>, "请选择药品", "关闭")
spinnerDialog.setCancellable(true)
spinnerDialog.setShowKeyboard(false)
spinnerDialog.bindOnSpinerListener { item, position ->
viewHolder.medicineName.text = item
}
spinnerDialog.showSpinerDialog()
}
}
override fun getItemCount(): Int {
return dataSet.count()
}
fun addRecord() {
val position = dataSet.count()
dataSet.add(position, MedicineModel())
notifyItemInserted(position)
}
#SuppressLint("NotifyDataSetChanged")
private fun deleteRecord(position: Int) {
dataSet.removeAt(position)
notifyItemRemoved(position)
notifyDataSetChanged()
}
I have called notifyDataSetChanged however it does not seems to work.

My onClickListener is not working anymore

I tried my best to make something work with my recyclerView and my onClickListener. Two days ago I have no idea how but I made it work.
Today I tried to work on my app again, and well it's not working anymore. I changed nothing in the code, so I don't get it.
My adapter class with my onClickListener code in my onBindViewHolder :
class LvlAdapter( var items: List<Lvl>, private var c:Context) : RecyclerView.Adapter<LvlAdapter.LvlViewHolder>() {
val limit = 10;
inner class LvlViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var titleLvl: TextView
var buttonLvl: ImageView
init {
titleLvl = itemView.findViewById(R.id.titleLvl)
buttonLvl = itemView.findViewById(R.id.buttonLvl)
}
fun bind(lvl: Lvl) {
titleLvl.text = lvl.title
buttonLvl.setImageResource(lvl.button)
}
}
// return the viewHolder with the item view, but inflate from xml to view first
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LvlViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.lvl_card, parent, false)
return LvlViewHolder(itemView)
}
// what we bind in the viewHolder (ce qu'on injecte)
override fun onBindViewHolder(holder: LvlViewHolder, position: Int) {
var lvl = items[position]
holder.bind(lvl)
holder.itemView.setOnClickListener{
var mode1 = items.get(position)
var title1 : String = mode1.title
var intent = Intent(c, GameQuestionsActivity::class.java)
intent.putExtra("title", title1)
c.startActivity(intent)
}
}
// return a size of the items
override fun getItemCount(): Int {
if(items.size > limit){
return limit
} else {
return items.size
}
}
}

How to display item info on selected item in RecyclerView using Kotlin

How to display some information from recyclerview selected item without using onClick method. When the app is started first item is selected and highlighted. I need to eg. use Toast with value of anything that is in data class. I have implemented onClick method but the question is how to do it without using this method.
This is MainActivity:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val exampleList = generateDummyList(20)
val exampleAdapter = ExampleAdapter(getItem, exampleList)
exampleAdapter.onItemClick = { item, position: Int ->
Toast.makeText(this, "Position: $position", Toast.LENGTH_SHORT).show()
val intent = Intent(this, ItemActivity::class.java).apply {
putExtra("itempos", position)
putExtra("maxSize", maxS)
}
startActivity(intent)
}
}
}
This is adapter:
class ExampleAdapter(val chosen_item: Int, private val exampleList: List<ExampleItem>):
RecyclerView.Adapter<ExampleAdapter.ExampleViewHolder>()
{
var onItemClick: ((ExampleItem, Int) -> Unit)? = null
var selected_item: Int = chosen_item
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ExampleViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.item_recy, parent, false)
return ExampleViewHolder(itemView)
}
override fun onBindViewHolder(holder: ExampleViewHolder, position: Int){
val currentItem = exampleList[position]
holder.tv_ID.text = currentItem.id.toString()
holder.tv_NAME.text = currentItem.name
holder.tv_EMAIL.text = currentItem.email
if (position == selected_item){
holder.tv_NAME.setBackgroundColor(Color.GREEN)
} else {
holder.tv_NAME.setBackgroundColor(Color.TRANSPARENT)
}
}
override fun getItemCount(): Int {
return exampleList.size
}
inner class ExampleViewHolder(itemView:View): RecyclerView.ViewHolder(itemView) {
val tv_ID: TextView = itemView.tv_ID
val tv_NAME: TextView = itemView.tv_NAME
val tv_EMAIL: TextView = itemView.tv_EMAIL
init {
itemView.setOnClickListener{
onItemClick?.invoke(exampleList[absoluteAdapterPosition], absoluteAdapterPosition)
notifyItemChanged(selected_item)
selected_item = absoluteAdapterPosition
notifyItemChanged(selected_item)
}
itemView.isSelected
}
}
}
I have second activity - when user click on item in first activity(recyclerview) - this second activity is open - then I raise the id of item by one and open again first activity where another item is highlighted. And I need to display eg. EMAIL from ExampleItem class.
This is second activity:
class ItemActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_item)
var itempos = intent.getIntExtra("itempos",0)
val maxSize = intent.getIntExtra("maxSize",0)
button2.setOnClickListener {
if (itempos == maxSize){
itempos = itempos
} else {
itempos = itempos + 1
}
val intent = Intent(this, MainActivity::class.java).apply {
putExtra("itemposplus", itempos)
}
startActivity(intent)
}
}
}
If I understood correctly, you want to get the selected item at any time (without a click). There are several ways to do this. I recommend to you use getAdapterPosition() method in ViewHolder
First, save your ViewHolder
class ExampleAdapter(val chosen_item: Int, private val exampleList: List<ExampleItem>):
RecyclerView.Adapter<ExampleAdapter.ExampleViewHolder>()
{
var onItemClick: ((ExampleItem, Int) -> Unit)? = null
var selected_item: Int = chosen_item
lateinit var viewHolder: ExampleViewHolder
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ExampleViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.item_recy, parent, false)
viewHolder = ExampleViewHolder(itemView)
return viewHolder
}
And then write a public method into the adapter for get the current item in activity
fun getCurrentItem(): ExampleItem = exampleList.get(viewHolder.getAdapterPosition())
Finally you can get selected item in activity
val selectedItem = exampleAdapter.getCurrentItem()
Also you can check getLayoutManager().findFirstVisibleItemPosition() method in your RecyclerView

Kotlin RecyclerView start new activity

I would like to start a new activity from a RecyclerView with Kotlin.
I am still exploring Kotlin and currently stuck on how to open a new activity from a RecyclerView.
class HomeScreenRecyclerAdapter : RecyclerView.Adapter<HomeScreenRecyclerAdapter.ViewHolder>()
{
private val titles = arrayOf("About Me",
"About Me", "About Me", "About Me"
)
private val details = arrayOf("Item one details", "Item two details",
"Item three details", "Item four details")
private val images = intArrayOf(R.drawable.ic_launcher_background,
R.drawable.ic_launcher_background, R.drawable.ic_launcher_background,
R.drawable.ic_launcher_background)
override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): ViewHolder {
val v = LayoutInflater.from(viewGroup.context)
.inflate(R.layout.main_card_view, viewGroup, false)
return ViewHolder(v)
}
override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
viewHolder.itemTitle.text = titles[position]
viewHolder.itemDetail.text = details[position]
viewHolder.itemImage.setImageResource(images[position])
}
override fun getItemCount(): Int {
return titles.size
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val intent: Intent? = null
var itemImage: ImageView
var itemTitle: TextView
var itemDetail: TextView
init {
itemImage = itemView.findViewById(R.id.main_image_view)
itemTitle = itemView.findViewById(R.id.main_title_view)
itemDetail = itemView.findViewById(R.id.main_description_view)
itemView.setOnClickListener {
}
}
}
}
I just cant figure out how to start a new activity for each item within the RecyclerView. I know I am making it more complicated than it is.
Just use this :
context.startActivity(Intent(context, Activity::class.java))
Just start the activity within the ViewHolder itemOnClick method as like below. And you need to pass the context reference of adapter's activity.
class HomeScreenRecyclerAdapter(var mContext:Context) : RecyclerView.Adapter<HomeScreenRecyclerAdapter.ViewHolder>()
{
private val titles = arrayOf("About Me",
"About Me", "About Me", "About Me")
private val details = arrayOf("Item one details", "Item two details",
"Item three details", "Item four details")
private val images = intArrayOf(R.drawable.ic_launcher_background,
R.drawable.ic_launcher_background, R.drawable.ic_launcher_background,
R.drawable.ic_launcher_background)
override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): ViewHolder {
val v = LayoutInflater.from(viewGroup.context)
.inflate(R.layout.main_card_view, viewGroup, false)
return ViewHolder(v)
}
override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
viewHolder.itemTitle.text = titles[position]
viewHolder.itemDetail.text = details[position]
viewHolder.itemImage.setImageResource(images[position])
}
override fun getItemCount(): Int {
return titles.size
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val intent: Intent? = null
var itemImage: ImageView
var itemTitle: TextView
var itemDetail: TextView
init {
itemImage = itemView.findViewById(R.id.main_image_view)
itemTitle = itemView.findViewById(R.id.main_title_view)
itemDetail = itemView.findViewById(R.id.main_description_view)
itemView.setOnClickListener {
mContext.startActivity(Intent(mContext, ActivityNameWhichYouWantCall::class.java))
}
}
}
}
Just try this solution:
Firstly in your adapter write listener to your recyclerview items:
class HomeScreenRecyclerAdapter(val data: ArrayList<Data>) : RecyclerView.Adapter<ContactAdapter.ViewHolder>() {
private var listener: ((Data) -> Unit)? = null
...
fun setOnItemClickListener(f: (Data) -> Unit) {
listener = f
}
And inside init :
itemView.setOnClickListener {
listener?.invoke(data[adapterPosition])
}
And Finally in your Activity you can take handle item clickListeners:
private val data = ArrayList<Data>()
val adapter = HomeScreenRecyclerAdapter(data)
adapter.setOnItemClickListener {
when(it){
1->{startActivity(Intent(context, YourActivity1::class.java))}
2->{startActivity(Intent(context, YourActivity2::class.java))}
...
else->{}
}
}
There Data is model class of your item.
That's all, I hope this help you!

How to update live data of the viewModel, when click is performed on recyclerview item

I am new to the Kotlin and I am trying to create an application with MVVM.
so what I am trying to do is to make a web call using retrofit in the repository and returning data to the view model and then observing the data from the fragment and as soon as data changes I am notifying it to the recycler view adapter everything is working fine.
Now, the problem is I want to update that live data of ViewHolder from the recyclerview. when I click on the CheckBox in recyclerView the data should be updated. But I don't know what is the actual way of doing this.
Here is my ViewHolder.
class MainActivityViewModel : ViewModel() {
private var mutableLiveGitUsers: MutableLiveData<ArrayList<GitUsers>>? = null
private lateinit var gitUsersRepository: GitUsersRepository
var allUsersListener: AllUsersListener? = null
fun init() {
gitUsersRepository = GitUsersRepository()
allUsersListener?.onStarted()
mutableLiveGitUsers = gitUsersRepository.getGitUsers()
allUsersListener?.onSuccess(mutableLiveGitUsers!!)
}
fun getGitUsersData(): MutableLiveData<ArrayList<GitUsers>>? {
return mutableLiveGitUsers
}
}
here is how I observe changes in fragment
mutableLiveGitUsers.observe(this, Observer {
progressBar.hide()
rvAllUsersAdapter = AllUsersAdapter(mainActivityViewModel.getGitUsersData()?.value!!)
rvAllUsers.adapter = rvAllUsersAdapter
rvAllUsersAdapter.notifyDataSetChanged()
})
RecylerView Adapter
class AllUsersAdapter(private var gitUsersArrayList: ArrayList<GitUsers>) :
RecyclerView.Adapter<AllUsersAdapter.AllUsersViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AllUsersViewHolder {
val inflater: LayoutInflater = LayoutInflater.from(parent.context)
val v: View = inflater.inflate(R.layout.items_all_users, parent, false)
return AllUsersViewHolder(v)
}
override fun getItemCount(): Int {
return gitUsersArrayList.size
}
override fun onBindViewHolder(holder: AllUsersViewHolder, position: Int) {
holder.tvUserName.text = gitUsersArrayList[position].login
Glide.with(holder.itemView.context)
.load(gitUsersArrayList[position].avatarUrl)
.centerCrop()
.into(holder.imageView)
holder.checkBox.isSelected = gitUsersArrayList.get(position).isSelected
holder.checkBox.setOnCheckedChangeListener{compoundButton, isChecked ->
if (isChecked){
/* Here I want to change the live data so I can observe that changes in my
fragment and can have an effect in UI*/
Log.d("TESTC","AllUsersAdapter IsChecked")
}else{
Log.d("TESTC","AllUsersAdapter UnChecked")
}
}
}
class AllUsersViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var tvUserName: TextView = itemView.findViewById(R.id.tvUserName)
var imageView: ImageView = itemView.findViewById(R.id.imageView)
var checkBox: CheckBox = itemView.findViewById(R.id.checkBox)
}
}
Introduce an item click callback to your adapter:
class AllUsersAdapter(private var gitUsersArrayList: ArrayList<GitUsers>,
private val itemClickCallback: ((Boolean) -> Unit)?) :
RecyclerView.Adapter<AllUsersAdapter.AllUsersViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AllUsersViewHolder {
val inflater: LayoutInflater = LayoutInflater.from(parent.context)
val v: View = inflater.inflate(R.layout.items_all_users, parent, false)
return AllUsersViewHolder(v)
}
override fun getItemCount(): Int {
return gitUsersArrayList.size
}
override fun onBindViewHolder(holder: AllUsersViewHolder, position: Int) {
holder.tvUserName.text = gitUsersArrayList[position].login
Glide.with(holder.itemView.context)
.load(gitUsersArrayList[position].avatarUrl)
.centerCrop()
.into(holder.imageView)
holder.checkBox.isSelected = gitUsersArrayList.get(position).isSelected
holder.checkBox.setOnCheckedChangeListener{compoundButton, isChecked ->
if (isChecked){
/* Here I want to change the live data so I can observe that changes in my
fragment and can have an effect in UI*/
Log.d("TESTC","AllUsersAdapter IsChecked")
itemClickCallback?.invoke(true)
}else{
Log.d("TESTC","AllUsersAdapter UnChecked")
itemClickCallback?.invoke(false)
}
}
}
class AllUsersViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var tvUserName: TextView = itemView.findViewById(R.id.tvUserName)
var imageView: ImageView = itemView.findViewById(R.id.imageView)
var checkBox: CheckBox = itemView.findViewById(R.id.checkBox)
}
}
Handle the click event in your fragment onViewCreated() where you initialise the adapter
val rvAdapter = AllUsersAdapter(
gitUsersArrayList = gitUsersArrayList, itemClickCallback = fun(status: Boolean) {
navController().navigate(
viewModel.updateValue(status)
)
}
)
Create the required ViewModel function:
class MainActivityViewModel : ViewModel() {
private var mutableLiveGitUsers: MutableLiveData<ArrayList<GitUsers>>? = null
private lateinit var gitUsersRepository: GitUsersRepository
var allUsersListener: AllUsersListener? = null
fun init() {
gitUsersRepository = GitUsersRepository()
allUsersListener?.onStarted()
mutableLiveGitUsers = gitUsersRepository.getGitUsers()
allUsersListener?.onSuccess(mutableLiveGitUsers!!)
}
fun getGitUsersData(): MutableLiveData<ArrayList<GitUsers>>? {
return mutableLiveGitUsers
}
fun updateValue(status: Boolean) {
//#Todo Set new value based on status received
// mutableLiveGitUsers.value =
}
}

Categories

Resources