square / Listable

Declarative list views for iOS apps.
Apache License 2.0
204 stars 28 forks source link

Fix supplementary view + contained first responder reuse issue #507

Closed kyleve closed 1 year ago

kyleve commented 1 year ago

The below works around a (seeming?) bug or odd behavior in UICollectionView, where it tries to be smart about recycling supplementary views that contain a first responder such as a text field. Specifically, it holds onto a supplementary view that contains a first responder, not immediately recycling it when it is scrolled out of view. That ensures that the keyboard isn't immediately dismissed, which would be jarring.

...Unfortunately, this doesn't seem to actually work in practice very well. When the supplementary view is scrolled back into view, and we're asked to dequeue a view, the collection view hands us back a different view, leading to double views that get stacked on top of each other in the layout, leading to a bunch of weirdness.

So, to work around this, we do a few things:

1) We begin tracking which supplementary views currently contain a first responder. For practicality of implementation, we only track text fields right now. This could change, but is harder, given there's no generic "first responder changed" notification. This code lives in ListView.

2) We update ListLayoutContent.content(in: ...) to always return supplementary info when a supplementary view contains a first responder, even when out of frame. This ensures the supplementary view instance is kept alive by the collection view. You can see that happening here:

image

3) Within collectionView(_:viewForSupplementaryElementOfKind:at:), we check to see if there's a live, existing visibleContainer (aka the supplementary view) view, and if there is, we return that, instead of just dequeuing a new, wrong view.

After all that, the correct thing happens.

Checklist

Please do the following before merging:

kyleve commented 1 year ago

Do you happen to have a vanilla UICollectionView repro of this problem? I can file a feedback with Apple if you haven't already.

I haven't, I couldn't repro in Flow layout which makes me think its either doing something similarly special, or I didn't quite poke things right.