You can use Transition or Animator that changes visibility of section to be expanded/collapsed, or ConstraintSet with different layouts.

Easiest one is to use motionLayout with different to layouts and constraintSets to change from one layout to another on button click. You can change between layouts with
val constraintSet = ConstraintSet()
constraintSet.clone(this, R.layout.layout_collapsed)
val transition = ChangeBounds()
transition.interpolator = AccelerateInterpolator(1.0f)
transition.setDuration(300)
TransitionManager.beginDelayedTransition(YOUR_VIEW, transition)
constraintSet.applyTo(YOUR_VIEW)
Expansion/collapse animation in gif with using Transitions that changes direction of button with rotating x, and expand/collapse setting item visibility and starting TransitionManager.beginDelayed transition
RotateX.kt
class RotateX : Transition {
    @Keep
    constructor() : super()
    @Keep
    constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
    override fun getTransitionProperties(): Array<String> {
        return TRANSITION_PROPERTIES
    }
    override fun captureStartValues(transitionValues: TransitionValues) {
        captureValues(transitionValues)
    }
    override fun captureEndValues(transitionValues: TransitionValues) {
        captureValues(transitionValues)
    }
    override fun createAnimator(
        sceneRoot: ViewGroup,
        startValues: TransitionValues?,
        endValues: TransitionValues?
    ): Animator? {
        if (startValues == null || endValues == null) return null
        val startRotation = startValues.values[PROP_ROTATION] as Float
        val endRotation = endValues.values[PROP_ROTATION] as Float
        if (startRotation == endRotation) return null
        val view = endValues.view
        // ensure the pivot is set
        view.pivotX = view.width / 2f
        view.pivotY = view.height / 2f
        return ObjectAnimator.ofFloat(view, View.ROTATION_X, startRotation, endRotation)
    }
    private fun captureValues(transitionValues: TransitionValues) {
        val view = transitionValues.view
        if (view == null || view.width <= 0 || view.height <= 0) return
        transitionValues.values[PROP_ROTATION] = view.rotationX
    }
    companion object {
        private const val PROP_ROTATION = "iosched:rotate:rotation"
        private val TRANSITION_PROPERTIES = arrayOf(PROP_ROTATION)
    }
}
create xml file that targets expand button
    <?xml version="1.0" encoding="utf-8"?>
    <transitionSet
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:interpolator="@android:interpolator/fast_out_slow_in">
    
        <transition class="com.smarttoolfactory.tutorial3_1transitions.transition.RotateX">
            <targets>
                <target android:targetId="@id/ivExpand" />
            </targets>
        </transition>
    
        <autoTransition android:duration="200" />
    
    </transitionSet>
My layout to be expanded or collapsed
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
    <com.google.android.material.card.MaterialCardView
        android:id="@+id/cardView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginHorizontal="4dp"
        android:layout_marginVertical="2dp"
        android:clickable="true"
        android:focusable="true"
        android:transitionName="@string/transition_card_view"
        app:cardCornerRadius="0dp"
        app:cardElevation="0dp"
        app:cardPreventCornerOverlap="false">
        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingTop="16dp"
            android:paddingBottom="16dp">
            <androidx.appcompat.widget.AppCompatImageView
                android:id="@+id/ivAvatar"
                android:layout_width="40dp"
                android:layout_height="40dp"
                android:layout_marginStart="16dp"
                android:layout_marginTop="8dp"
                android:scaleType="centerCrop"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                tools:src="@drawable/avatar_1_raster" />
            <androidx.appcompat.widget.AppCompatImageView
                android:id="@+id/ivExpand"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginEnd="8dp"
                android:padding="8dp"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                app:srcCompat="@drawable/ic_baseline_expand_more_24" />
            <TextView
                android:id="@+id/tvTitle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="12dp"
                android:layout_marginTop="6dp"
                android:text="Some Title"
                android:textSize="20sp"
                android:textStyle="bold"
                app:layout_constraintStart_toEndOf="@+id/ivAvatar"
                app:layout_constraintTop_toTopOf="parent" />
            <TextView
                android:id="@+id/tvDate"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="4dp"
                android:textColor="?android:textColorSecondary"
                android:textSize="12sp"
                app:layout_constraintStart_toStartOf="@+id/tvTitle"
                app:layout_constraintTop_toBottomOf="@id/tvTitle"
                tools:text="Tuesday 7pm" />
            <TextView
                android:id="@+id/tvBody"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginTop="8dp"
                android:layout_marginEnd="16dp"
                android:ellipsize="end"
                android:lines="1"
                android:text="@string/bacon_ipsum_short"
                android:textSize="16sp"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="@+id/ivAvatar"
                app:layout_constraintTop_toBottomOf="@id/tvDate" />
            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/recyclerView"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginStart="16dp"
                android:layout_marginTop="16dp"
                android:layout_marginEnd="16dp"
                android:orientation="horizontal"
                android:overScrollMode="never"
                android:visibility="gone"
                app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@id/tvBody"
                tools:listitem="@layout/item_image_destination" />
        </androidx.constraintlayout.widget.ConstraintLayout>
    </com.google.android.material.card.MaterialCardView>
</layout>
Change visibility of items to collapse or expand with
private fun setUpExpandedStatus() {
    if (isExpanded) {
        binding.recyclerView.visibility = View.VISIBLE
        binding.ivExpand.rotationX = 180f
    } else {
        binding.recyclerView.visibility = View.GONE
        binding.ivExpand.rotationX = 0f
    }
}
Start animation
val parent = (itemView.parent as? ViewGroup)
    
val transition = TransitionInflater.from(itemView.context)
                .inflateTransition(R.transition.icon_expand_toggle)
    
TransitionManager.beginDelayedTransition(parent, transition)
    
isExpanded = !isExpanded
    
setUpExpandedStatus()
I created animation and transitions samples including the one on the gif, you can check them out there.