I am developing an application with a viewpager2, when the element selected in the viewpager is changed the visibility of some views is changed. The problem is that when the adapter is assigned to the viewpager it is called onPageSelected with index 0 but the visibility of the view does not change, if I scroll then they change correctly.
fragment_layout
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btn1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:text="btn1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="@+id/btn2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:text="btn2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
BaseFragment code
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.viewpager2.widget.ViewPager2
import kotlinx.android.synthetic.main.fragment_layout.*
class BaseFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_layout,container,false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewpager.adapter = MyAdapter(arrayOf("Page1","Page2"))
viewpager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback(){
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
if (position == 0){
btn1.visibility = View.VISIBLE
btn2.visibility = View.GONE
}else {
btn1.visibility = View.GONE
btn2.visibility = View.VISIBLE
}
}
})
}
}
MyAdapter code
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
class MyAdapter(private val myDataset: Array<String>) :
RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder.
// Each data item is just a string in this case that is shown in a TextView.
class MyViewHolder(val textView: TextView) : RecyclerView.ViewHolder(textView)
// Create new views (invoked by the layout manager)
override fun onCreateViewHolder(parent: ViewGroup,
viewType: Int): MyAdapter.MyViewHolder {
// create a new view
val textView = LayoutInflater.from(parent.context)
.inflate(R.layout.my_text_view, parent, false) as TextView
// set the view's size, margins, paddings and layout parameters
return MyViewHolder(textView)
}
// Replace the contents of a view (invoked by the layout manager)
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
// - get element from your dataset at this position
// - replace the contents of the view with that element
holder.textView.text = myDataset[position]
}
// Return the size of your dataset (invoked by the layout manager)
override fun getItemCount() = myDataset.size
}
my_text_view
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:background="@color/colorPrimary"
android:textColor="@android:color/white"
android:textSize="32sp"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
obviously if I change the visibility in the post of the view or the viewpager it works normally.
like
viewpager.post {
if (position == 0){
btn1.visibility = View.VISIBLE
btn2.visibility = View.GONE
}else {
btn1.visibility = View.GONE
btn2.visibility = View.VISIBLE
}
}
or
if (position == 0){
btn1.post {
btn1.visibility = View.VISIBLE
}
btn2.post {
btn2.visibility = View.GONE
}
}else {
btn1.visibility = View.GONE
btn2.visibility = View.VISIBLE
}
but I don't want to use this method, i also tried to call the change of visibility on the main thread but it doesn't seem to solve the problem.
I solved the problem with livedata.
I have declared a mutableLiveData and post the index change, than i register an observer with fragment lifecycle.
val liveData:MutableLiveData<Int> = MutableLiveData()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
liveData.observe(this, Observer {
if (position == 0){
btn1.visibility = View.VISIBLE
btn2.visibility = View.GONE
}else {
btn1.visibility = View.GONE
btn2.visibility = View.VISIBLE
}
})
}
then in viewpager onPageSelected
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewpager.adapter = MyAdapter(arrayOf("Page1","Page2"))
viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
liveData.postValue(position)
}
})
}
I did not understand the reason of the problem but it is clear that it is connected to the lifecycle of the fragment, but I do not understand why the change of visibility did not work if called in the viewpager's callback even recording it in the onResume or onStart method.