How to change recyclerview item and sub items when clicked and also get the data in the position clicked from a fragment? - android-recyclerview

I have 2 Recyclerviews in a fragment. Each item consists of 2 textview. When clicked, i want to change the color of item background and the 2 tvs and get the listofData(position) clicked also then send these s pieces of data to an activity.
The problem is 2 rvs each have its own adapter so i can't call the activity and check if data is selected from both adapters. And when i try it from the fragment i get the adapter position right but the view colors are not being changed correctly.
My RV element
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="2dp"
android:paddingBottom="10dp"
android:paddingStart="20dp"
android:paddingEnd="20dp"
android:background="#drawable/date_time_background"
android:elevation="0dp"
android:gravity="center"
android:layout_marginEnd="5dp"
android:orientation="vertical"
android:id="#+id/item_linear_layout">
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/dateNameTV"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Sat"
android:textColor="#color/black_65"
android:textSize="16sp" />
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/dateNumTV"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="23/5"
android:textColor="#color/black_65"
android:textSize="16sp" />
</LinearLayout>
My RV adapter
class TimesAdapter(private var availableTimes: List<String>?, private val onTimeListener: OnTimeListener) :
RecyclerView.Adapter<TimesAdapter.TimeViewHolder>() {
private var itemIndex = -1
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TimeViewHolder {
val v = LayoutInflater.from(parent.context)
.inflate(R.layout.date_time_element, parent, false)
return TimeViewHolder(v, onTimeListener)
}
override fun getItemCount(): Int = availableTimes?.size!!
#SuppressLint("ClickableViewAccessibility")
override fun onBindViewHolder(holder: TimeViewHolder, position: Int) {
val currentDate: String? = availableTimes?.get(position) // i.e Sun 23/5
val parts = currentDate?.split(" ")
try {
val part1 = parts?.get(0)
holder.dateNameTV.text = part1
val part2 = parts?.get(1)
holder.dateNumTV.text = part2
} catch (e: IndexOutOfBoundsException) {
e.printStackTrace()
}
holder.itemLinearLayout.setOnClickListener {
itemIndex = position
notifyItemChanged(position)
}
val ctx = holder.itemLinearLayout.context
if (itemIndex == position) {
holder.itemLinearLayout.background = (loadDrawable(ctx, R.drawable.date_time_background_selected))
holder.dateNameTV.setTextColor(loadColor(ctx, android.R.color.white))
holder.dateNumTV.setTextColor(loadColor(ctx, android.R.color.white))
} else {
holder.itemLinearLayout.background = (loadDrawable(ctx, R.drawable.date_time_background))
holder.dateNameTV.setTextColor(loadColor(ctx, R.color.black_65))
holder.dateNumTV.setTextColor(loadColor(ctx, R.color.black_65))
}
}
class TimeViewHolder(itemView: View, onTimeListener: OnTimeListener) :
RecyclerView.ViewHolder(itemView), View.OnClickListener{
var dateNameTV: TextView = itemView.findViewById(R.id.dateNameTV)
var dateNumTV: TextView = itemView.findViewById(R.id.dateNumTV)
var itemLinearLayout: LinearLayout = itemView.findViewById(R.id.item_linear_layout)
private var onTimeListener: OnTimeListener? = null
init {
itemView.setOnClickListener(this)
this.onTimeListener = onTimeListener
}
override fun onClick(v: View?) {
onTimeListener?.onTimeClick(adapterPosition, itemView)
}
}
interface OnTimeListener{
fun onTimeClick(position: Int, itemView: View)
}
}
My fragment
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"
/**
* A simple [Fragment] subclass.
* Use the [DoctorAppointmentsFragment.newInstance] factory method to
* create an instance of this fragment.
*/
class DoctorAppointmentsFragment : Fragment(),
DatesAdapter.OnDateListener, TimesAdapter.OnTimeListener {
private lateinit var datesRV: RecyclerView
private lateinit var timesRV: RecyclerView
private lateinit var linearLayoutManager: LinearLayoutManager
private lateinit var datesAdapter: DatesAdapter
private lateinit var timesAdapter: TimesAdapter
private lateinit var dateNameTV: TextView
private lateinit var dateNumTV: TextView
private lateinit var dateLinearLayout: LinearLayout
private var dates: List<String>? = null
private var times: List<String>? = null
private var isDateSelected = false
private var isTimeSelected = false
private var selectedDate: String? = null
private var selectedTime: String? = null
// TODO: Rename and change types of parameters
private var param1: String? = null
private var param2: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_doctor_appointments, container, false)
datesRV = view.findViewById(R.id.datesRV)
datesRV.setHasFixedSize(true)
linearLayoutManager = LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, false)
linearLayoutManager.isAutoMeasureEnabled = false
datesRV.layoutManager = linearLayoutManager
timesRV = view.findViewById(R.id.timesRV)
timesRV.setHasFixedSize(true)
linearLayoutManager = LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, false)
linearLayoutManager.isAutoMeasureEnabled = false
timesRV.layoutManager = linearLayoutManager
val bookNowBT = view.findViewById<Button>(R.id.bookNowBT)
bookNowBT.setOnClickListener {
if (isDateSelected && isTimeSelected) {
val i = Intent(activity, ConfirmPaymentActivity::class.java)
i.putExtra(SELECTED_DATE, selectedDate)
i.putExtra(SELECTED_TIME, selectedTime)
startActivity(i)
}
}
getDoctorAvailableAppointments("7ab63fd2461bfb0008b72f5d8c0033fs", "basic")
return view
}
companion object {
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param param1 Parameter 1.
* #param param2 Parameter 2.
* #return A new instance of fragment DoctorAppointmentsFragment.
*/
// TODO: Rename and change types and number of parameters
#JvmStatic
fun newInstance(param1: String, param2: String) =
DoctorAppointmentsFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
}
private fun getDoctorAvailableAppointments(doctorID: String, type: String) {
setProgressDialog(this.requireActivity())
if (!InternetConnection.isInternetAvailable(this.requireActivity())) {
alertError(this.requireActivity(),
R.string.no_internet_connection,
R.string.check_internet_connection)
} else {
showProgressDialog()
val builder = ServiceBuilder()
val appointments = builder.getDoctorAvailableReservations()
val call = appointments.getDoctorAvailableReservations(
RequestAvailableReservations(doctorID,type))
call?.enqueue(object : Callback<ResponseAvailableReservations?> {
override fun onResponse(call: Call<ResponseAvailableReservations?>, response: Response<ResponseAvailableReservations?>) {
dismissProgressDialog()
if (!response.isSuccessful) {
alertError(requireActivity(),
R.string.code_not_200,
R.string.try_later)
return
}
val body: ResponseAvailableReservations? = response.body()
if (body == null) {
alertError(requireActivity(),
R.string.null_body,
R.string.try_later)
return
}
val status = body.status
val message = body.message
val data = body.data
if (status == null || message == null || data == null) {
alertError(requireActivity(),
R.string.null_body,
R.string.try_later)
return
}
if (status == "error") {
alertError(requireActivity(), R.string.error, message)
} else if (status == "success") {
dates = data.availableDatesList
datesAdapter = DatesAdapter(dates, this#DoctorAppointmentsFragment)
datesRV.adapter = datesAdapter
times = data.availableTimesList
timesAdapter = TimesAdapter(times, this#DoctorAppointmentsFragment)
timesRV.adapter = timesAdapter
}
}
override fun onFailure(call: Call<ResponseAvailableReservations?>, t: Throwable) {
t.printStackTrace()
dismissProgressDialog()
alertError(requireActivity(),
R.string.fail,
R.string.login_fail)
}
})
}
}
private var dateIndex = -1
override fun onDateClick(position: Int) {
selectedDate = dates?.get(position)
isDateSelected = true
Log.e("selectedDate", "selectedDate")
dateIndex = position
datesAdapter.notifyDataSetChanged()
}
private var timeIndex = -1
override fun onTimeClick(position: Int, itemView: View) {
// selectedTime = times?.get(position)
// isTimeSelected = true
// Log.e("isSelectedTime", "true")
// timeIndex = position
// timesAdapter.notifyItemChanged(position)
// Log.e("timeIndex", timeIndex.toString())
//
// val ctx = itemView.context
// if (timeIndex == position) {
// Log.e("timeIndex", "timeIndex == position")
//
// itemView.background = loadDrawable(ctx, R.drawable.date_time_background_selected)
// itemView.dateNameTV?.setTextColor(loadColor(ctx, android.R.color.white))
// itemView.dateNumTV?.setTextColor(loadColor(ctx, android.R.color.white))
// } else {
// itemView.background = (loadDrawable(ctx, R.drawable.date_time_background))
// itemView.dateNameTV.setTextColor(loadColor(ctx, R.color.black_65))
// itemView.dateNumTV.setTextColor(loadColor(ctx, R.color.black_65))
// }
}
}

Solved
For anyone interested i ended up using a very simple idea. Instead of accessing the RecyclerView selected element from outside the adapter, i did all i wanted to do inside the adapter and used 4 static variables in the Fragment. 2 booleans to check
if date and time are selected or not and 2 Strings having the date and time actually selected.
Inside the Fragment:
companion object {
#JvmStatic var isTimeSelected = false
#JvmStatic var selectedTime = ""
#JvmStatic var isDateSelected = false
#JvmStatic var selectedDate = ""
....
}
Inside the Adapter's onBindViewHolder()
holder.itemLinearLayout.setOnClickListener {
selectedDate = dates?.get(position)!!
isDateSelected = true
listener?.onDateClick(position)
selectedIndex = position
notifyDataSetChanged()
}
val ctx = holder.itemLinearLayout.context
if (selectedIndex == position) {
holder.itemLinearLayout.background = (loadDrawable(ctx, R.drawable.date_time_background_selected))
holder.dateNameTV.setTextColor(loadColor(ctx, android.R.color.white))
holder.dateNumTV.setTextColor(loadColor(ctx, android.R.color.white))
} else {
holder.itemLinearLayout.background = (loadDrawable(ctx, R.drawable.date_time_background))
holder.dateNameTV.setTextColor(loadColor(ctx, R.color.black_65))
holder.dateNumTV.setTextColor(loadColor(ctx, R.color.black_65))
}
And i made sure static variables don't have old values using this
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
isTimeSelected = false
selectedTime = ""
isDateSelected = false
selectedDate = ""
}
I know it's bad practice to put onClickListener inside onBindViewHolder but i don't konw if the static variables thing is good or bad practice. Either way it's working fine for now.

There is many ways to do this, And I recommend the first one.
Using shared ViewModels for communication between fragments in the same activity. The idea is that you will tie up the ViewModel with activity and every fragment can access this ViewModel and in this ViewModel you will have a LiveData object that holds the data and observing it from both fragments and every change in the value of LiveData will affect each fragment. Shared ViewModel
Using interfaces for communication between fragments and it's a hard thing to do these days. Basic communication between fragments
Using EventBus it's easy but not recommended while you can use ViewModel at the first solution. EventBus

Try this
TimesAdapter
class TimesAdapter(
availableTimes: List<String>
) : RecyclerView.Adapter<TimesAdapter.TimeViewHolder>() {
var availableTimes:List<String> = availableTimes
set(value) {
field = value
notifyDataSetChanged()
}
var listener:TimeSelectedListener?=null
var selectedIndex:Int = -1
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TimeViewHolder {
return TimeViewHolder(
LayoutInflater.from(parent.context)
.inflate(R.layout.date_time_element, parent, false)
)
}
override fun getItemCount(): Int = availableTimes.count()
override fun onBindViewHolder(holder: TimeViewHolder, position: Int) {
val currentDate: String? = availableTimes[position] // i.e Sun 23/5
val parts = currentDate?.split(" ")
try {
val part1 = parts?.get(0)
val part2 = parts?.get(1)
holder.dateNameTV.text = part2
holder.dateNumTV.text = part1
} catch (e: IndexOutOfBoundsException) {
e.printStackTrace()
}
holder.itemLinearLayout.setOnClickListener {
listener?.onTimeClick(position)
selectedIndex = position
}
if (selectedIndex == position) {
// Selection Code
} else {
// De selection code
}
}
class TimeViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var dateNameTV: TextView = itemView.findViewById(R.id.dateNameTV)
var dateNumTV: TextView = itemView.findViewById(R.id.dateNumTV)
var itemLinearLayout: LinearLayout = itemView.findViewById(R.id.item_linear_layout)
}
interface TimeSelectedListener {
fun onTimeClick(position: Int)
}
}
Usage from fragment
times = data.availableTimesList
timesAdapter = TimesAdapter(times).apply {
listener = object :TimesAdapter.TimeSelectedListener{
override fun onTimeClick(position: Int) {
// TODO here is where you should implement when an item is selected
}
}
}
timesRV.adapter = timesAdapter

Related

I want to navigate other fragment by Left to Right touch in fragment(kotlin)

I want to navigate to another fragment by findNavigator.
But findNavigator was declared in Fragment. So I must detect the Left to Right touch gesture on Fragment view.
How can I use a detector in one fragment to navigate another fragment? Please help me...
Add(0615)
I made my application by viewpager2, but transtion by currentItem is not work. It's code just respond null.
ViewPagerAdapter.kt
class ViewPagerAdapter(
list: ArrayList<Fragment>,
fm: FragmentManager,
lifecycle: Lifecycle
) : FragmentStateAdapter(fm, lifecycle) {
private val fragmentList = list
override fun getItemCount(): Int {
return fragmentList.size
}
override fun createFragment(position: Int): Fragment {
return fragmentList[position]
}
}
dayspager22.kt
class dayspager22 : Fragment() {
// TODO: Rename and change types of parameters
private var param1: String? = null
private var param2: String? = null
private var _binding: FragmentDayspager22Binding? = null
private val binding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentDayspager22Binding.inflate(inflater, container, false)
val fragmentList = arrayListOf<Fragment>(
days_1(),
days_2(),
days_3()
)
val adapter = ViewPagerAdapter(
fragmentList,
requireActivity().supportFragmentManager,
lifecycle
)
binding.views.adapter = adapter
return binding.root
}
companion object {
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param param1 Parameter 1.
* #param param2 Parameter 2.
* #return A new instance of fragment dayspager22.
*/
// TODO: Rename and change types and number of parameters
#JvmStatic
fun newInstance(param1: String, param2: String) =
dayspager22().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
}
}
days_1.kt
class days_1 : Fragment() {
// TODO: Rename and change types of parameters
private var param1: String? = null
private var param2: String? = null
private var _binding: FragmentDays1Binding? = null
private val binding get() = _binding!!
private var mediaPlayer: MediaPlayer? = null
private val textsize_plus: Float = 10.0f
lateinit var rootView: View
lateinit var mContext: Context
private val j: Int = 0
var size: Float = 70.0f
private lateinit var callback: OnBackPressedCallback
override fun onAttach(context: Context) {
super.onAttach(context)
mContext = context
callback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
findNavController().navigate(R.id.action_days_1_to_1to8)
}
}
requireActivity().onBackPressedDispatcher.addCallback(this, callback)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
}
#RequiresApi(Build.VERSION_CODES.M)
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
_binding = FragmentDays1Binding.inflate(inflater, container, false)
binding.textView2.text = ""
binding.textView4.text = ""
mediaPlayer = MediaPlayer.create(activity, R.raw.days_1)
binding.seekBar.max = mediaPlayer!!.duration
binding.button1.setOnClickListener {
size -= textsize_plus
binding.gangu.setTextSize(Dimension.DP, size)
}
binding.buttonplus.setOnClickListener {
size += textsize_plus
binding.gangu.setTextSize(Dimension.DP, size)
}
binding.seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar, i: Int, b: Boolean) {
if (b) {
mediaPlayer?.seekTo(i/* * 1000*/)
if (mediaPlayer?.isPlaying == true) {
binding.seekBar.setProgress(mediaPlayer!!.currentPosition)
}
seekbar()
}
}
override fun onStartTrackingTouch(seekBar: SeekBar) {
}
override fun onStopTrackingTouch(seekBar: SeekBar) {
}
}
)
mediaPlayer?.start()
// if (mediaPlayer?.isPlaying == true) {
timer(period = 1000)
{
(mContext as Activity).runOnUiThread {
binding.seekBar.setProgress(mediaPlayer!!.currentPosition)
seekbar()
}
// }
mediaPlayer?.setOnCompletionListener {
// findNavController().navigate(R.id.action_day_1_to_days_2)
/* val pager = activity?.findViewById<ViewPager2>(R.id.dayspager)
pager?.currentItem = 2*/
}
}
binding.imageView4.setOnClickListener{
findNavController().navigate(R.id.action_1_to_main)
}
binding.startbutton.setOnClickListener{
mediaPlayer?.start()
}
binding.pausebutton.setOnClickListener {
if (mediaPlayer?.isPlaying == true) {
mediaPlayer?.pause()
binding.seekBar.setProgress(mediaPlayer!!.currentPosition)
} else {
mediaPlayer?.start()
}
}
binding.stopbutton.setOnClickListener {
mediaPlayer?.stop()
mediaPlayer = MediaPlayer.create(activity, R.raw.days_1)
val pager = activity?.findViewById<ViewPager2>(R.id.dayspager)
pager?.currentItem = 2
val pager2 = activity?.findViewById<ViewPager2>(R.id.dayspager22)
pager2?.currentItem = 1
if (pager?.currentItem == null) {
Log.e("ViewPagerFragment", "Page")
}
if (pager2?.currentItem == null) {
Log.e("ViewPagerFragment", "Page2")
}
}
fun onStop() {
super.onStop()
mediaPlayer?.release()
}
return binding.root
}
companion object {
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param param1 Parameter 1.
* #param param2 Parameter 2.
* #return A new instance of fragment days_1.
*/
// TODO: Rename and change types and number of parameters
#JvmStatic
fun newInstance(param1: String, param2: String) =
days_1().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
}
override fun onPause() {
super.onPause()
mediaPlayer?.stop()
}
fun seekbar() {
binding.seekBar.setProgress(mediaPlayer!!.currentPosition)
val min2: Int = mediaPlayer!!.duration / 60000
val sec2: Int = (mediaPlayer!!.duration - min2 * 60000) / 1000
val min: Int = mediaPlayer!!.currentPosition / 60000
val sec: Int = (mediaPlayer!!.currentPosition - min * 60000) / 1000
binding.textView2.text = "" + min + " : " + sec + ""
binding.textView4.text = "" + min2 + " : " + sec2 + ""
}
}
days_2 and days_3 are almost same without currentItem
currentItem is worked in dayspagers22, but not it Fragments
Use the viewPager concept in android. It helps you to move from one fragment to another by sliding the fragment.
https://developer.android.com/training/animation/screen-slide

I don't know why currentItem was not worked and findviewbyId is null

I made my application by viewpager2, but transtion by currentItem is not work. It's code just respond null.(findviewbyId)
ViewPagerAdapter.kt
class ViewPagerAdapter(
list: ArrayList<Fragment>,
fm: FragmentManager,
lifecycle: Lifecycle
) : FragmentStateAdapter(fm, lifecycle) {
private val fragmentList = list
override fun getItemCount(): Int {
return fragmentList.size
}
override fun createFragment(position: Int): Fragment {
return fragmentList[position]
}
}
dayspager22.kt
class dayspager22 : Fragment() {
// TODO: Rename and change types of parameters
private var param1: String? = null
private var param2: String? = null
private var _binding: FragmentDayspager22Binding? = null
private val binding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentDayspager22Binding.inflate(inflater, container, false)
val fragmentList = arrayListOf<Fragment>(
days_1(),
days_2(),
days_3()
)
val adapter = ViewPagerAdapter(
fragmentList,
requireActivity().supportFragmentManager,
lifecycle
)
binding.views.adapter = adapter
return binding.root
}
companion object {
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param param1 Parameter 1.
* #param param2 Parameter 2.
* #return A new instance of fragment dayspager22.
*/
// TODO: Rename and change types and number of parameters
#JvmStatic
fun newInstance(param1: String, param2: String) =
dayspager22().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
}
}
days_1.kt
class days_1 : Fragment() {
// TODO: Rename and change types of parameters
private var param1: String? = null
private var param2: String? = null
private var _binding: FragmentDays1Binding? = null
private val binding get() = _binding!!
private var mediaPlayer: MediaPlayer? = null
private val textsize_plus: Float = 10.0f
lateinit var rootView: View
lateinit var mContext: Context
private val j: Int = 0
var size: Float = 70.0f
private lateinit var callback: OnBackPressedCallback
override fun onAttach(context: Context) {
super.onAttach(context)
mContext = context
callback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
findNavController().navigate(R.id.action_days_1_to_1to8)
}
}
requireActivity().onBackPressedDispatcher.addCallback(this, callback)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
}
#RequiresApi(Build.VERSION_CODES.M)
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
_binding = FragmentDays1Binding.inflate(inflater, container, false)
binding.textView2.text = ""
binding.textView4.text = ""
mediaPlayer = MediaPlayer.create(activity, R.raw.days_1)
binding.seekBar.max = mediaPlayer!!.duration
binding.button1.setOnClickListener {
size -= textsize_plus
binding.gangu.setTextSize(Dimension.DP, size)
}
binding.buttonplus.setOnClickListener {
size += textsize_plus
binding.gangu.setTextSize(Dimension.DP, size)
}
binding.seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar, i: Int, b: Boolean) {
if (b) {
mediaPlayer?.seekTo(i/* * 1000*/)
if (mediaPlayer?.isPlaying == true) {
binding.seekBar.setProgress(mediaPlayer!!.currentPosition)
}
seekbar()
}
}
override fun onStartTrackingTouch(seekBar: SeekBar) {
}
override fun onStopTrackingTouch(seekBar: SeekBar) {
}
}
)
mediaPlayer?.start()
// if (mediaPlayer?.isPlaying == true) {
timer(period = 1000)
{
(mContext as Activity).runOnUiThread {
binding.seekBar.setProgress(mediaPlayer!!.currentPosition)
seekbar()
}
// }
mediaPlayer?.setOnCompletionListener {
// findNavController().navigate(R.id.action_day_1_to_days_2)
/* val pager = activity?.findViewById<ViewPager2>(R.id.dayspager)
pager?.currentItem = 2*/
}
}
binding.imageView4.setOnClickListener{
findNavController().navigate(R.id.action_1_to_main)
}
binding.startbutton.setOnClickListener{
mediaPlayer?.start()
}
binding.pausebutton.setOnClickListener {
if (mediaPlayer?.isPlaying == true) {
mediaPlayer?.pause()
binding.seekBar.setProgress(mediaPlayer!!.currentPosition)
} else {
mediaPlayer?.start()
}
}
binding.stopbutton.setOnClickListener {
mediaPlayer?.stop()
mediaPlayer = MediaPlayer.create(activity, R.raw.days_1)
val pager = activity?.findViewById<ViewPager2>(R.id.dayspager)
pager?.currentItem = 2
val pager2 = activity?.findViewById<ViewPager2>(R.id.dayspager22)
pager2?.currentItem = 1
if (pager?.currentItem == null) {
Log.e("ViewPagerFragment", "Page")
}
if (pager2?.currentItem == null) {
Log.e("ViewPagerFragment", "Page2")
}
}
fun onStop() {
super.onStop()
mediaPlayer?.release()
}
return binding.root
}
companion object {
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param param1 Parameter 1.
* #param param2 Parameter 2.
* #return A new instance of fragment days_1.
*/
// TODO: Rename and change types and number of parameters
#JvmStatic
fun newInstance(param1: String, param2: String) =
days_1().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
}
override fun onPause() {
super.onPause()
mediaPlayer?.stop()
}
fun seekbar() {
binding.seekBar.setProgress(mediaPlayer!!.currentPosition)
val min2: Int = mediaPlayer!!.duration / 60000
val sec2: Int = (mediaPlayer!!.duration - min2 * 60000) / 1000
val min: Int = mediaPlayer!!.currentPosition / 60000
val sec: Int = (mediaPlayer!!.currentPosition - min * 60000) / 1000
binding.textView2.text = "" + min + " : " + sec + ""
binding.textView4.text = "" + min2 + " : " + sec2 + ""
}
}
days_2 and days_3 are almost same without currentItem
currentItem is only worked in dayspagers22, but not it Fragments
All of navigation code were not worked. I want to transit other page when mediaplayer completed.

How to show user dialog box after recyclerview item click

I have an image button in my recylerview and when users click it, I want a dialog box to pop up and allow the user to edit the data in the reyclerview and save the changes.
My Adapter code
class Adapter(private var records: ArrayList<AudioRecord>, var listener: OnItemClickListener) : RecyclerView.Adapter<Adapter.ViewHolder>() {
private var editMode = false
fun isEditMode() :Boolean{return editMode}
#SuppressLint("NotifyDataSetChanged")
fun setEditMode(mode: Boolean){
if(editMode != mode){
editMode = mode
notifyDataSetChanged()
}
}
inner class ViewHolder(val binding: ItemviewLayoutBinding): RecyclerView.ViewHolder(binding.root ), View.OnClickListener, View.OnLongClickListener{
private var tvFileName : TextView = itemView.findViewById(R.id.tvFilename)
private var tvMeta : TextView = itemView.findViewById(R.id.tvMeta)
var checkbox : CheckBox = itemView.findViewById(R.id.checkBox)
val editBtn: ImageButton = itemView.findViewById(R.id.btnEdit)
init {
itemView.setOnClickListener(this)
itemView.setOnLongClickListener(this)
}
fun binding (audioRecord: AudioRecord) {
tvFileName.text = audioRecord.filename
tvMeta.text = audioRecord.duration
// checkbox.text = audioRecord.
}
override fun onClick(p0: View?) {
val position = adapterPosition
if(position != RecyclerView.NO_POSITION)
listener.onItemClickListener(position)
}
override fun onLongClick(p0: View?): Boolean {
val position = adapterPosition
if(position != RecyclerView.NO_POSITION)
listener.onItemLongClickListener(position)
return true
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(ItemviewLayoutBinding.inflate(LayoutInflater.from(parent.context), parent, false))
}
#SuppressLint("SetTextI18n", "SimpleDateFormat")
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
if (position != RecyclerView.NO_POSITION){
val record: AudioRecord = records[position]
val sdf = SimpleDateFormat("dd/MM/yyyy")
val date = Date(record.timestamp)
val strDate = sdf.format(date)
holder.binding.tvFilename.text = record.filename
holder.binding.tvMeta.text = "${record.duration} $strDate"
if(editMode){
holder.checkbox.visibility = View.VISIBLE
holder.checkbox.isChecked = record.isChecked
holder.editBtn.visibility = View.GONE
}else{
holder.checkbox.visibility = View.GONE
holder.checkbox.isChecked = false
holder.editBtn.visibility = View.VISIBLE
}
holder.binding.btnEdit.setOnClickListener {
}
}
}
override fun getItemCount(): Int {
return records.size
}
}
Summary
When users click image button. Input dialog pops up
User must be able to edit data in recyclerview and save it.
change class like this inner class ViewHolder(val binding: ItemviewLayoutBinding), var imageListener:(position:Int)->Unit)
where you call adapter , use imageListener function. Whatever you want to do you can do it inside this function. Then call it in your adapter.
in init
editBtn.setOnClickListener {
imageListener(adapterPosition)
}

Obtain a crash message-App keeps stopping

I get the following trace error java.lang.ClassCastException: com.example.myhouse.MainActivity cannot be cast to com.brsthegck.kanbanboard.TasklistFragment$Callbacks at com.brsthegck.kanbanboard.TasklistFragment.onAttach(TasklistFragment.kt:52)at androidx.fragment.app.Fragment.performAttach(Fragment.java:2672) at androidx.fragment.app.FragmentStateManager.attach(FragmentStateManager.java:263) at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1170) at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1356)
enter image description here
Tasklist Fragment
private const val ARG_TASKLIST_TYPE = "tasklist_type"
private const val TASKLIST_TYPE_TODO = 0
private const val TASKLIST_TYPE_DOING = 1
private const val TASKLIST_TYPE_DONE = 2
class TasklistFragment : Fragment(){
private lateinit var visibleColorPaletteViewList : List<View>
lateinit var taskRecyclerView: RecyclerView
private var tasklistType : Int = -1
private var adapter : TaskViewAdapter? = TaskViewAdapter(LinkedList<Task>())
private var colorPaletteIsVisible : Boolean = false
private var callbacks: Callbacks? = null
//Callback interface to delegate access functions in MainActivity
interface Callbacks{
fun addTaskToViewModel(task: Task, destinationTasklistType: Int)
fun deleteTaskFromViewModel(tasklistType: Int, adapterPosition: Int)
fun getTaskListFromViewModel(tasklistType: Int) : LinkedList<Task>
}
//Attach context as a Callbacks reference to the callbacks variable when fragment attaches to container
override fun onAttach(context: Context) {
super.onAttach(context)
callbacks = activity as Callbacks? // error is here
}
//Detach context (assign to null) when fragment detaches from container
override fun onDetach() {
super.onDetach()
callbacks = null
}
//ItemTouchHelper instance with custom callback, to move task card view positions on hold
private val itemTouchHelper by lazy{
val taskItemTouchCallback = object : ItemTouchHelper.SimpleCallback(UP or DOWN, 0){
override fun onMove(recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder): Boolean {
val adapter = recyclerView.adapter as TaskViewAdapter
val from = viewHolder.adapterPosition
val to = target.adapterPosition
adapter.moveTaskView(from, to)
adapter.notifyItemMoved(from, to)
return true
}
//Make taskview transparent while being moved
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
super.onSelectedChanged(viewHolder, actionState)
if(actionState == ACTION_STATE_DRAG)
viewHolder?.itemView?.alpha = 0.7f
}
//Make taskview opaque while being
override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
super.clearView(recyclerView, viewHolder)
viewHolder.itemView.alpha = 1.0f
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { /* Not implemented on purpose. */ }
}
ItemTouchHelper(taskItemTouchCallback)
}
//Get the fragment arguments, tasklist type to be precise, and assign it to the member of this fragment
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
tasklistType = arguments?.getInt(ARG_TASKLIST_TYPE) as Int
}
//Inflate view of fragment, prepare recycler view and it's layout manager, and update the UI
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View?{
//Inflate the layout of this fragment, get recyclerview ref, set layout manager for recycler view
val view = inflater.inflate(R.layout.tasklist_fragment_layout, container,false)
taskRecyclerView = view.findViewById(R.id.task_recycler_view) as RecyclerView
taskRecyclerView.layoutManager = LinearLayoutManager(context)
itemTouchHelper.attachToRecyclerView(taskRecyclerView)
//Fill the recyclerview with data from viewmodel
updateInterface()
//Return the created view
return view
}
//Populate recyclerview and set up its adapter
private fun updateInterface(){
val tasks = callbacks!!.getTaskListFromViewModel(tasklistType)
adapter = TaskViewAdapter(tasks)
taskRecyclerView.adapter = adapter
}
Kanban class
class Kanban : Fragment(), TasklistFragment.Callbacks{
// TODO: Rename and change types of parameters
private var param1: String? = null
private var param2: String? = null
private lateinit var viewPager: ViewPager2
private lateinit var tabLayout: TabLayout
private lateinit var taskViewModel: TaskViewModel
//When add action bar button is pressed
override fun onOptionsItemSelected(item: MenuItem) = when(item.itemId) {
R.id.action_new_task -> {
val currentTasklistType = viewPager.currentItem
val currentTasklist = when (currentTasklistType) {
TASKLIST_TYPE_TODO -> taskViewModel.todoTaskList
TASKLIST_TYPE_DOING -> taskViewModel.doingTaskList
TASKLIST_TYPE_DONE -> taskViewModel.doneTaskList
else -> throw Exception("Unrecognized tasklist type")
}
val currentFragment = (activity?.supportFragmentManager?.fragments?.get(currentTasklistType) as TasklistFragment)
addTaskToViewModel(Task(), currentTasklistType)
currentFragment.taskRecyclerView.scrollToPosition(currentTasklist.size - 1)
true
}
else -> super.onOptionsItemSelected(item)
}
//Inflate the action bar menu resource on options menu creation
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_action_bar, menu)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
//Get viewmodel
val view: View = inflater.inflate(R.layout.fragment_kanban2, container, false)
taskViewModel = ViewModelProvider(this).get(TaskViewModel::class.java)
//Read tasklist data from shared prefs and populate viewmodel lists with it
readSharedPrefsToViewModel()
//Get ref to viewpager and set up its adapter & attributes
viewPager = view.findViewById(R.id.view_pager)
val viewPagerAdapter = TasklistFragmentStateAdapter(this)
viewPager.apply {
adapter = viewPagerAdapter
offscreenPageLimit = 2
//Get ref to tablayout, set up & attach its mediator
tabLayout = view.findViewById(R.id.tab_layout)
TabLayoutMediator(tabLayout, viewPager) { tab, position ->
tab.text = when (position) {
0 -> getString(R.string.tab_label_todo)
1 -> getString(R.string.tab_label_doing)
else -> getString(R.string.tab_label_done)
}
}.attach()
}
return view
}
override fun onStop() {
super.onStop()
writeViewModelToSharedPrefs()
}
//Adapter class for view pager
private inner class TasklistFragmentStateAdapter(fa: Kanban) : FragmentStateAdapter(fa){
override fun createFragment(position: Int): Fragment {
//Create argument bundle with task list type
val tasklistFragmentArguments = Bundle().apply{
putInt(ARG_TASKLIST_TYPE, position)
}
//Attach the argument bundle to new fragment instance and return the fragment
return TasklistFragment().apply{
arguments = tasklistFragmentArguments
}
}
override fun getItemCount(): Int = NUM_TASKLIST_PAGES
}
override fun addTaskToViewModel(task: Task, destinationTasklistType: Int) {
val destinationFragment = (activity?.supportFragmentManager?.fragments?.get(destinationTasklistType) as TasklistFragment)
val taskList = getTaskListFromViewModel(destinationTasklistType)
taskList.add(task)
destinationFragment.taskRecyclerView.adapter?.notifyItemInserted(taskList.size)
}
override fun deleteTaskFromViewModel(tasklistType: Int, adapterPosition: Int) {
val tasklistFragment = (activity?.supportFragmentManager?.fragments?.get(tasklistType) as TasklistFragment)
getTaskListFromViewModel(tasklistType).removeAt(adapterPosition)
tasklistFragment.taskRecyclerView.adapter?.notifyItemRemoved(adapterPosition)
}
override fun getTaskListFromViewModel(tasklistType: Int): LinkedList<Task> =
when(tasklistType){
TASKLIST_TYPE_TODO -> taskViewModel.todoTaskList
TASKLIST_TYPE_DOING -> taskViewModel.doingTaskList
TASKLIST_TYPE_DONE -> taskViewModel.doneTaskList
else -> throw Exception("Unrecognized tasklist type") }
private fun writeViewModelToSharedPrefs(){
val gson = Gson()
//Convert list to json string
val todoJSON = gson.toJson(taskViewModel.todoTaskList)
val doingJSON = gson.toJson(taskViewModel.doingTaskList)
val doneJSON = gson.toJson(taskViewModel.doneTaskList)
var sharedPref : SharedPreferences = requireActivity().getPreferences(Context.MODE_PRIVATE);
//Save json strings into shared preferences
activity?.getPreferences(MODE_PRIVATE)?.edit()?.apply {
putString(KEY_TODO_JSON, todoJSON)
putString(KEY_DOING_JSON, doingJSON)
putString(KEY_DONE_JSON, doneJSON)
}?.apply()
}
private fun readSharedPrefsToViewModel(){
val gson = Gson()
val sharedPrefs = activity?.getPreferences(MODE_PRIVATE)
val todoJSON = sharedPrefs?.getString(KEY_TODO_JSON, "[]")
val doingJSON = sharedPrefs?.getString(KEY_DOING_JSON, "[]")
val doneJSON = sharedPrefs?.getString(KEY_DONE_JSON, "[]")
val type = object: TypeToken<LinkedList<Task>>() {}.type //Gson requires type ref for generic types
taskViewModel.todoTaskList = gson.fromJson(todoJSON, type)
taskViewModel.doingTaskList = gson.fromJson(doingJSON, type)
taskViewModel.doneTaskList = gson.fromJson(doneJSON, type)
}
Main activity
public class MainActivity extends AppCompatActivity {
private TabLayout tabLayout;
private ViewPager2 viewPager2;
private MyFragment adapter;
private TextView register;
GridView contractorsGV;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tabLayout = findViewById(R.id.tabLayout);
viewPager2 = findViewById(R.id.viewPager2);
tabLayout.addTab(tabLayout.newTab().setText("Home"));
tabLayout.addTab(tabLayout.newTab().setText("Idea Book"));
tabLayout.addTab(tabLayout.newTab().setText("My Profile"));
FragmentManager fragmentManager = getSupportFragmentManager();
adapter = new MyFragment(fragmentManager , getLifecycle());
viewPager2.setAdapter(adapter);
4. Fragment manager
public class MyFragment extends FragmentStateAdapter {
public MyFragment(#NonNull FragmentManager fm,Lifecycle lifecycle) {
super(fm,lifecycle);
}
#NonNull
#Override
public Fragment createFragment(int position) {
if(position==1)
{
return new Kanban();
}
if(position==2) {
return new signOut();
}
return new Navigation_Bar();
}

how to put this arraylist in this method?

how to put this ArrayList in this method?
Could someone tell me how to pass this ArrayList in this method?
I added all the fragment code could anyone guide me?
I tried in several ways to pass this ArrayList but without success always remains blank the fragment
thanks
Array List
<string-array name="object_types">
method
private var issues: ArrayList<Issue> = ArrayList()
private fun getIssues() {
val stream = resources.openRawResource(R.raw.markers)
val inputString = stream.bufferedReader().use {
it.readText()
}
val klaxon = Klaxon()
JsonReader(StringReader(inputString)).use { reader -> // requires kotlin > 1.2 !!
reader.beginArray {
while (reader.hasNext()) { // requires "[]" array and not {"something": []}
val issue = klaxon.parse<Issue>(reader)
this.issues!!.add(issue!!)
} }
}
this.issues = Utils.markers
}
GalleryFragment
all fragment code follows below
class GalleryFragment : Fragment(), IssueItemOnClickListener {
private var productsRecyclerView: RecyclerView? = null
private var recyclerAdapter: IssueRecyclerViewAdapter? = null
private var recyclerLayoutManager: RecyclerView.LayoutManager? = null
private var issues: ArrayList<Issue> = ArrayList()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_gallery, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
getIssues()
this.productsRecyclerView = view.findViewById(R.id.issue_list_recycler_view) as RecyclerView
this.productsRecyclerView!!.setHasFixedSize(true)
// use a grid layout manager -> 2 columns
this.recyclerLayoutManager = GridLayoutManager(context, 2) as RecyclerView.LayoutManager?
this.productsRecyclerView!!.layoutManager = this.recyclerLayoutManager
this.recyclerAdapter = IssueRecyclerViewAdapter(this.issues, this)
this.productsRecyclerView!!.adapter = recyclerAdapter
}
override fun onIssueItemClick(pos: Int, issue: Issue) {
val args = Bundle()
val detailsFragment = IssueDetailsFragment()
args.putDouble("lat", issue.lat)
args.putDouble("lng", issue.lng)
args.putString("description", issue.description)
args.putString("name", issue.name)
args.putString("type", issue.type)
args.putString("imgUrl", issue.imgUrl)
detailsFragment.arguments = args
val ft = activity!!.supportFragmentManager.beginTransaction()
ft.replace(R.id.main_fragment_content, detailsFragment)
.setTransition(android.app.FragmentTransaction.TRANSIT_FRAGMENT_FADE)
.addToBackStack(null).commit()
}
private fun getIssues() {
val stream = resources.openRawResource(R.raw.markers)
val inputString = stream.bufferedReader().use {
it.readText()
}
val klaxon = Klaxon()
JsonReader(StringReader(inputString)).use { reader -> // requires kotlin > 1.2 !!
reader.beginArray {
while (reader.hasNext()) { // requires "[]" array and not {"something": []}
val issue = klaxon.parse<Issue>(reader)
this.issues!!.add(issue!!)
}
}
}
this.issues = Utils.markers
}
}
[SOLVED]
CHANGE
private var issues: ArrayList<Issue> = ArrayList()
TO
private var object_values: ArrayList<Issue> = ArrayList()