Skip to content
This repository was archived by the owner on Dec 27, 2024. It is now read-only.
This repository was archived by the owner on Dec 27, 2024. It is now read-only.

MotionLayout in RecyclerView appears to not properly size cell when ViewHolder is bound for a recycled, animated cell #448

@sschendel

Description

@sschendel

Trying to use a MotionLayout to expand/collapse a particular view (change size and rearrange slightly) in a row in a RecyclerView list and seeing an issue with the cell height not properly being restored when I try to reset the MotionLayout transition when binding a new ViewHolder.

When a ViewHolder that was expanded is recycled the views that are part of the ViewHolder look like they've been correctly transitioned to the collapsed state, but the entire cell seems to stay the full expanded size.

Is there something obvious I'm missing? Using version: 2.1.2

A screen capture and minimal code sample follows...

Screen capture...
demo_small

Activity...

class MotionLayoutPlayground : AppCompatActivity() {
  private lateinit var binding: ActivityMotionLayoutPlaygroundBinding
  private val things = IntRange(0, 40).toList().map {
    Thing(
      name = "Thing $it",
      description = "This is the description for thing $it"
    )
  }
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivityMotionLayoutPlaygroundBinding.inflate(layoutInflater)
    setContentView(binding.root)
    binding.recyclerView.layoutManager = LinearLayoutManager(this)
    binding.recyclerView.adapter = ThingAdapter(things)
  }
}

Activity layout (activity_motion_layout_playground.xml) ...

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:context=".motionplay.MotionLayoutPlayground">
  <androidx.recyclerview.widget.RecyclerView
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    />
</androidx.constraintlayout.widget.ConstraintLayout>

Model...

data class Thing(
  val name: String,
  val description: String
)

Adapter...

class ThingAdapter(private val things: List<Thing>) : RecyclerView.Adapter<ThingAdapter.ViewHolder>() {
  override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
    val binding = RowThingBinding.inflate(LayoutInflater.from(parent.context), parent, false)
    return ViewHolder(binding = binding)
  }
  override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    holder.bind(things.get(position))
  }
  override fun getItemCount() = things.size
  class ViewHolder(val binding: RowThingBinding) : RecyclerView.ViewHolder(binding.root) {
    fun bind(thing: Thing) {
      // reset the MotionLayout to collapsed state
      binding.rootMotionLayout.setTransition(R.id.start, R.id.end)
      binding.rootMotionLayout.transitionToStart()

      binding.nameTextView.text = thing.name
      binding.descriptionTextView.text = thing.description
    }
  }
}

Row layout (row_thing.xml) ...

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.motion.widget.MotionLayout
  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/rootMotionLayout"
  android:minHeight="168dp"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:background="@color/light_blue"
  app:layoutDescription="@xml/thing_cell_scene"
  app:currentState="@id/start"
  >
  <TextView
    android:id="@+id/nameTextView"
    android:layout_width="150dp"
    android:layout_height="150dp"
    android:gravity="center"
    android:padding="16dp"
    android:background="@color/light_green"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    tools:text="This is a name"
    />
  <TextView
    android:id="@+id/descriptionTextView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="16dp"
    android:background="@color/light_red"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintStart_toEndOf="@id/nameTextView"
    tools:text="This is the description"
    />
</androidx.constraintlayout.motion.widget.MotionLayout>

Motion scene (thing_cell_scene.xml) ...

<?xml version="1.0" encoding="utf-8"?>
<MotionScene
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  >
  <Transition
    app:constraintSetStart="@id/start"
    app:constraintSetEnd="@id/end"
    app:duration="250"
    >
    <OnClick
      app:clickAction="toggle"
      app:targetId="@+id/nameTextView"
      />
  </Transition>
  <!-- Collapsed constraints -->
  <ConstraintSet android:id="@+id/start">
    <Constraint
      android:id="@+id/nameTextView"
      android:layout_width="150dp"
      android:layout_height="150dp"
      app:layout_constraintTop_toTopOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintBottom_toBottomOf="parent"
      />
    <Constraint
      android:id="@+id/descriptionTextView"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:padding="16dp"
      android:background="@color/light_red"
      app:layout_constraintTop_toTopOf="parent"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintStart_toEndOf="@id/nameTextView"
      />
  </ConstraintSet>
  <!-- Expanded constraints -->
  <ConstraintSet android:id="@+id/end">
    <Constraint
      android:id="@+id/nameTextView"
      android:layout_width="300dp"
      android:layout_height="300dp"
      app:layout_constraintTop_toTopOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      />
    <Constraint
      android:id="@+id/descriptionTextView"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:padding="16dp"
      android:background="@color/light_red"
      app:layout_constraintTop_toBottomOf="@id/nameTextView"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      />
  </ConstraintSet>
</MotionScene>

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions