Alright, after combining multiple answers, I have the solution that I needed.
First
I needed to use a NestedScrollView
instead of a regular ScrollView
.
It solves the conflict between the two scroll containers (ScrollView
and ListView
).
Reference: Android: ScrollView vs NestedScrollView
NOTE: My list content is dynamic, so it can be too short to fill the remaining space. I had to set android:fillViewport="true"
on the NestedScrollView
. If the list is longer than the remaining space, it will not cause any trouble.
layout.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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.cardview.widget.CardView
android:id="@+id/card1"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- NOTE: constraints properties are missing from here for easier reading -->
<!-- card content here -->
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:id="@+id/card2"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- NOTE: constraints properties are missing from here for easier reading -->
<ListView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<!-- NOTE: this will change in step 3 -->
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
Second
Following the steps above will make the ListView
collapse to the height of its first item. To solve this, I needed to create a subclass from ListView
and override its onMeasure()
method, so it can calculate the proper height at runtime.
Reference: Android - NestedScrollView which contains ExpandableListView doesn't scroll when expanded
NonScrollListView.java
package my.package.name
import ...
public class NonScrollListView extends ListView {
// NOTE: right click -> create constructors matching super
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int heightMeasureSpec_custom = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightMeasureSpec_custom);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
}
}
Third
I needed to use my custom View instead of the regular ListView
in my layout XML.
layout.xml excerpt
<my.package.name.NonScrollListView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
This way I managed to make it work. Both cards move together on scroll, even if I tap the ListView
area.
I don't know whether it causes performance issues with really long lists, because mine contains a few dozen items at most, but I have no problem on a low end Galaxy A20e.