My app is a single activity with multiple parent and nested fragments. In one of the child fragments I use viewpager2 component to show different fragments depending on the tab selected.
For the sake of simplicity, let's say I have a TextInputLayout + AutoCompleteTextView control on tab1. There are a total of 8 tabs and other tabs have a combination of other controls - TextViews, EditTexts, etc.
Steps on how to reproduce:
On first creation of tab1, I can see all the drop down items on the AutoCompleteTextView control.
I navigate to tab2, tab3, tab4... so on... until at some point fragment manager decides to destroy tab1 and onDestroyView is called on tab1 Fragment
Now, if I navigate back to tab1, onCreateView is called and I cannot see all the items in AutoCompleteTextView control anymore, except the previously selected one.
Sample code:
To make my layouts more clear and consistent, I use compound views to encapsulate the TextInputLayout and the child AutoCompleteTextView or TextInputEditText
For the sake of keeping the explanation short, I have omited code for my viewModel class and the parent fragment that hosts the viewpager2
class SpinnerSharedView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyle: Int = 0
) : LinearLayout(context, attrs, defStyle) {
private var binding: ViewSharedSpinnerBinding
private var currentSelectedItemPosition: Int = -1
init {
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
binding = ViewSharedSpinnerBinding.inflate(inflater, this)
binding.spName.hint = "my spinner"
}
fun getSelectedItemPosition(): Int {
return currentSelectedItemPosition
}
// This method is used to attach a view to the 'Register' data model object. It is called in onViewCreated method of the fragment. This is how user updates the data object
fun attach(
reg: Register?, items: Array<String>, callback: (Register) -> Unit
) {
reg?.let { // Register is just a data model class
val adapter: ArrayAdapter<String> = ArrayAdapter<String>(context, R.layout.list_item_spinner, items)
binding.spValue.setAdapter(adapter)
// setOnItemSelectedListener doesn't work on AutoCompleteTextView, instead we should use
// setOnItemClickListener
binding.spValue.setOnItemClickListener { _, _, position, _ ->
if (currentSelectedItemPosition != position) {
currentSelectedItemPosition = position
it.value = position.toDouble()
callback.invoke(reg)
}
clearFocus()
}
}
}
// This method is called when ViewModel observer sees changes to the 'Register' data model object. This is how updates to the data object are passed to the view
fun update(reg: RegisterDec?, map: Map<Int, Int>? = null) {
reg?.let {
val tmp = reg.value.toInt()
val mappedValue = if (map == null) tmp
else map[tmp] ?: 0
currentSelectedItemPosition = mappedValue
binding.spValue.setText(binding.spValue.adapter.getItem(mappedValue).toString(), false)
}
}
Description:
My app is a single activity with multiple parent and nested fragments. In one of the child fragments I use viewpager2 component to show different fragments depending on the tab selected.
For the sake of simplicity, let's say I have a TextInputLayout + AutoCompleteTextView control on tab1. There are a total of 8 tabs and other tabs have a combination of other controls - TextViews, EditTexts, etc.
Steps on how to reproduce:
Sample code:
view_shared_spinner.xml:
SpinnerSharedView.kt:
Tab1 layout:
Version Info: Andnrod API 11 Navigation version: 2.3.5 Fragment version: 1.3.2 Material design version: 1.2.1 also tried with 1.3.0