Dentro de um ScrollView, alterno dinamicamente entre dois fragmentos com alturas diferentes. Infelizmente isso leva ao salto. Pode-se vê-lo na seguinte animação:
- Estou rolando para baixo até chegar ao botão "mostrar amarelo".
- Pressionar "mostrar amarelo" substitui um enorme fragmento azul por um pequeno fragmento amarelo. Quando isso acontece, os dois botões saltam para o final da tela.
Eu quero que os dois botões fiquem na mesma posição ao mudar para o fragmento amarelo. Como isso pode ser feito?
Código-fonte disponível em https://github.com/wondering639/stack-dynamiccontent, respectivamente https://github.com/wondering639/stack-dynamiccontent.git
Trechos 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" />
DICA
Observe que este é, obviamente, um exemplo de trabalho mínimo para mostrar meu problema. No meu projeto real, também tenho visualizações abaixo do @+id/fragment_container
. Portanto, atribuir um tamanho fixo a @+id/fragment_container
não é uma opção para mim - isso causaria uma grande área em branco ao mudar para o fragmento baixo e amarelo.
ATUALIZAÇÃO: Visão geral das soluções propostas
Implementei as soluções propostas para fins de teste e adicionei minhas experiências pessoais a elas.
resposta por Cheticamp, https://stackoverflow.com/a/60323255
-> disponível em https://github.com/wondering639/stack-dynamiccontent/tree/60323255
-> FrameLayout agrupa conteúdo, código curto
responder por Pavneet_Singh, https://stackoverflow.com/a/60310807
-> disponível em https://github.com/wondering639/stack-dynamiccontent/tree/60310807
-> FrameLayout obtém o tamanho do fragmento azul. Portanto, sem quebra de conteúdo. Ao alternar para o fragmento amarelo, existe um espaço entre ele e o conteúdo a seguir (se houver algum conteúdo). Nenhuma renderização adicional! ** atualização ** Uma segunda versão foi fornecida mostrando como fazê-lo sem falhas. Verifique os comentários para a resposta.
resposta por Ben P., https://stackoverflow.com/a/60251036
-> disponível em https://github.com/wondering639/stack-dynamiccontent/tree/60251036
-> FrameLayout agrupa o conteúdo. Mais código que a solução da Cheticamp. Tocar no botão "mostrar amarelo" duas vezes leva a um "bug" (os botões saltam para baixo, na verdade, é o meu problema original). Alguém poderia argumentar sobre apenas desativar o botão "mostrar amarelo" depois de mudar para ele, para que eu não considerasse isso um problema real.