I have a ViewPager2 which have a reusable Fragment with a LinearLayout inside, that LinearLayout is populated dynamically via clickListener on a bottom toolbar with 3 buttons, one for add an EditText, second for take a picture and add the image to an ImageView, and last one opens the gallery to pick a picture and add it to an ImageView.
This way, pages on ViewPager are independently populated dynamically.
The problem is, when I swipe to latest pages and return to firsts, new Views are added to the last page and not in the page (or fragment) where the user is positioned.
I think a gif can explain all this in a better way:
I use FragmentStateAdapter for ViewPager Adapter:
class NoteAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) {
override fun getItemCount(): Int = 3
override fun createFragment(position: Int): Fragment {
return if (position == itemCount - 1){
LastPageFragment().apply { arguments = Bundle().apply { putInt(ARG_KEY, position) } }
}else {
NoteFragment().apply { arguments = Bundle().apply { putInt(ARG_KEY, position) } }
}
}
companion object {
private const val ARG_KEY = "key"
}
}
NoteFragment is holding the button onClick toolbar logic:
class NoteFragment : Fragment() {
private var layout: LinearLayout? = null
private lateinit var currentPhotoPath: String
private lateinit var uri: Uri
private val viewModel by activityViewModels<ViewModel>()
private var pageNumber: Int? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
pageNumber = arguments?.getInt(ARG_KEY)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_note, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
layout = view.findViewById(R.id.note_layout)
val navHost = parentFragment?.parentFragment as NavHostFragment
view.findViewById<TextView>(R.id.page_date_tv).apply { text = SimpleDateFormat("E, dd MMM yyyy HH:mm", Locale.getDefault()).format(Date()) }
addTextFieldOnTextButtonClick()
openGalleryOnImageButtonClickIfPermissionGranted()
openCameraOnCameraButtonClickIfPermissionGranted()
parentFragment?.view?.findViewById<ImageView>(R.id.back_cross)?.setOnClickListener { navHost.findNavController().popBackStack() }
parentFragment?.view?.findViewById<TextView>(R.id.appbar_done)?.setOnClickListener {
viewModel.isInEditMode.value = !viewModel.isInEditMode.value!!
}
}
private fun addTextFieldOnTextButtonClick() {
parentFragment?.view?.findViewById<TextView>(R.id.toolbar_add_text)?.setOnClickListener {
layout?.addView(EditText(context).apply {
hint = getString(R.string.add_a_text_hint)
background = null
updatePadding(bottom = 16F.toDP(context))
})
}
}
private fun openGalleryOnImageButtonClickIfPermissionGranted() {
val getImageFromGallery = registerForActivityResult(ActivityResultContracts.GetContent()) {
if (it == null) Toast.makeText(context, getString(R.string.not_image_selected), Toast.LENGTH_SHORT).show()
else loadImageFromUri(it)
}
val requestPermission = registerForActivityResult(ActivityResultContracts.RequestPermission()) { success ->
if (success) getImageFromGallery.launch("image/*")
else Toast.makeText(context, getString(R.string.permission_denied_message), Toast.LENGTH_SHORT).show()
}
parentFragment?.view?.findViewById<TextView>(R.id.toolbar_add_image)?.setOnClickListener {
requestPermission.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
}
}
private fun openCameraOnCameraButtonClickIfPermissionGranted() {
val getCameraImage = registerForActivityResult(ActivityResultContracts.TakePicture()) { success ->
if (success) loadImageFromUri(uri)
}
val requestMultiplePermission = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { resultsMap ->
resultsMap.forEach {
Toast.makeText(context, "Permission ${it.key} was granted ${it.value}", Toast.LENGTH_SHORT).show()
}
if (resultsMap.values.contains(false)) Toast.makeText(context, "One or more permission was denied", Toast.LENGTH_SHORT).show()
else {
uri = FileProvider.getUriForFile(requireContext(), "com.example.app.fileprovider", createImageFile())
getCameraImage.launch(uri)
}
}
parentFragment?.view?.findViewById<TextView>(R.id.toolbar_add_image_from_camera)?.setOnClickListener {
requestMultiplePermission.launch(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA))
}
}
private fun loadImageFromUri(data : Uri?){
layout?.addView(ImageView(context).apply {
Glide.with(requireContext()).load(data).apply(RequestOptions.centerInsideTransform()).into(this)
})
}
companion object {
private const val ARG_KEY = "key"
}
}
Hope you can help me!
question from:
https://stackoverflow.com/questions/65873847/why-linearlayout-addviewview-is-adding-views-on-last-page-inside-viewpager2 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…