In einer ScrollView wechsle ich dynamisch zwischen zwei Fragmenten mit unterschiedlichen Höhen. Das führt leider zum Springen. Man kann es in der folgenden Animation sehen:
- Ich scrolle nach unten, bis ich die Schaltfläche "gelb anzeigen" erreiche.
- Durch Drücken von "gelb anzeigen" wird ein riesiges blaues Fragment durch ein winziges gelbes Fragment ersetzt. In diesem Fall springen beide Tasten zum Ende des Bildschirms.
Ich möchte, dass beide Tasten an derselben Position bleiben, wenn Sie zum gelben Fragment wechseln. Wie kann das gemacht werden?
Quellcode verfügbar unter https://github.com/wondering639/stack-dynamiccontent bzw. https://github.com/wondering639/stack-dynamiccontent.git
Relevante Codefragmente:
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" />
HINWEIS
Bitte beachten Sie, dass dies natürlich ein Mindestarbeitsbeispiel ist, um mein Problem aufzuzeigen. In meinem realen Projekt habe ich auch Ansichten unter dem @+id/fragment_container
. Daher @+id/fragment_container
ist es für mich keine Option , eine feste Größe anzugeben - dies würde beim Umschalten auf das niedrige gelbe Fragment einen großen leeren Bereich verursachen.
UPDATE: Überblick über die vorgeschlagenen Lösungen
Ich habe die vorgeschlagenen Lösungen zu Testzwecken implementiert und meine persönlichen Erfahrungen mit ihnen hinzugefügt.
Antwort von Cheticamp, https://stackoverflow.com/a/60323255
-> verfügbar unter https://github.com/wondering639/stack-dynamiccontent/tree/60323255
-> FrameLayout umschließt Inhalt und Funktionscode
Antwort von Pavneet_Singh, https://stackoverflow.com/a/60310807
-> verfügbar unter https://github.com/wondering639/stack-dynamiccontent/tree/60310807
-> FrameLayout erhält die Größe des blauen Fragments. Also kein Content Wrapping. Wenn Sie zum gelben Fragment wechseln, besteht eine Lücke zwischen diesem und dem darauf folgenden Inhalt (falls ein Inhalt darauf folgt). Kein zusätzliches Rendering! ** Update ** Es wurde eine zweite Version bereitgestellt, die zeigt, wie es ohne Lücken geht. Überprüfen Sie die Kommentare zur Antwort.
Antwort von Ben P., https://stackoverflow.com/a/60251036
-> verfügbar unter https://github.com/wondering639/stack-dynamiccontent/tree/60251036
-> FrameLayout umschließt den Inhalt. Mehr Code als die Lösung von Cheticamp. Das zweimalige Berühren der Schaltfläche "Gelb anzeigen" führt zu einem "Fehler" (Schaltflächen springen nach unten, eigentlich meine ursprüngliche Ausgabe). Man könnte darüber streiten, nur die Schaltfläche "Gelb anzeigen" nach dem Wechsel zu deaktivieren, daher würde ich dies nicht als echtes Problem betrachten.