Dentro de un ScrollView, estoy cambiando dinámicamente entre dos fragmentos con diferentes alturas. Lamentablemente eso lleva a saltar. Se puede ver en la siguiente animación:
- Me desplazo hacia abajo hasta llegar al botón "mostrar amarillo".
- Al presionar "mostrar amarillo" se reemplaza un enorme fragmento azul con un pequeño fragmento amarillo. Cuando esto sucede, ambos botones saltan al final de la pantalla.
Quiero que ambos botones permanezcan en la misma posición al cambiar al fragmento amarillo. ¿Cómo se puede hacer eso?
Código fuente disponible en https://github.com/wondering639/stack-dynamiccontent respectivamente https://github.com/wondering639/stack-dynamiccontent.git
Fragmentos de código relevantes:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/myScrollView"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="0dp"
android:layout_height="800dp"
android:background="@color/colorAccent"
android:text="@string/long_text"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button_fragment1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:text="show blue"
app:layout_constraintEnd_toStartOf="@+id/button_fragment2"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView" />
<Button
android:id="@+id/button_fragment2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:text="show yellow"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/button_fragment1"
app:layout_constraintTop_toBottomOf="@+id/textView" />
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/button_fragment2">
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.kt
package com.example.dynamiccontent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// onClick handlers
findViewById<Button>(R.id.button_fragment1).setOnClickListener {
insertBlueFragment()
}
findViewById<Button>(R.id.button_fragment2).setOnClickListener {
insertYellowFragment()
}
// by default show the blue fragment
insertBlueFragment()
}
private fun insertYellowFragment() {
val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.fragment_container, YellowFragment())
transaction.commit()
}
private fun insertBlueFragment() {
val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.fragment_container, BlueFragment())
transaction.commit()
}
}
fragment_blue.xml:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="400dp"
android:background="#0000ff"
tools:context=".BlueFragment" />
fragment_yellow.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="20dp"
android:background="#ffff00"
tools:context=".YellowFragment" />
INSINUACIÓN
Tenga en cuenta que este es, por supuesto, un ejemplo mínimo de trabajo para mostrar mi problema. En mi proyecto real, también tengo vistas debajo de @+id/fragment_container
. Entonces dando un tamaño fijo a@+id/fragment_container
no es una opción para mí: causaría un área en blanco grande al cambiar al fragmento amarillo bajo.
ACTUALIZACIÓN: Descripción general de las soluciones propuestas
Implementé las soluciones propuestas para propósitos de prueba y agregué mis experiencias personales con ellas.
respuesta por Cheticamp, https://stackoverflow.com/a/60323255
-> disponible en https://github.com/wondering639/stack-dynamiccontent/tree/60323255
-> FrameLayout envuelve contenido, código corto
respuesta por Pavneet_Singh, https://stackoverflow.com/a/60310807
-> disponible en https://github.com/wondering639/stack-dynamiccontent/tree/60310807
-> FrameLayout obtiene el tamaño del fragmento azul. Así que no hay envoltura de contenido. Al cambiar al fragmento amarillo, hay una brecha entre este y el contenido que lo sigue (si algún contenido lo sigue). Sin embargo, no hay renderizado adicional. ** actualización ** se proporcionó una segunda versión que muestra cómo hacerlo sin vacíos. Revisa los comentarios a la respuesta.
respuesta por Ben P., https://stackoverflow.com/a/60251036
-> disponible en https://github.com/wondering639/stack-dynamiccontent/tree/60251036
-> FrameLayout ajusta el contenido. Más código que la solución de Cheticamp. Tocar el botón "mostrar amarillo" dos veces conduce a un "error" (los botones saltan hacia abajo, en realidad mi problema original). Uno podría discutir sobre simplemente deshabilitar el botón "mostrar amarillo" después de cambiar a él, por lo que no consideraría esto como un problema real.