Ask for the scroll in the gesture, not from the layout
A correction made from the layout is a frame late whatever phase it is made in: from placement it is never picked up by another measure and does nothing at all, and from measure it lands on the next frame with the uncorrected one drawn first. That is the flick when a card is opened, and it is why a close could finish somewhere other than where it was aimed -- the two are the same fault. Asked for at the tap instead, the request is consumed by the same measure pass that first lays the row out at its new size, so the resize is drawn once, in its right place. What makes that possible is that none of the three positions needs to know the new height. A top edge holds by placing the item *above* the row where it already is -- that item's bottom edge is the row's top edge whatever becomes of the row, and it does not have to be composed for the list to place it. A close places the row itself against the height it had at the moment it was opened, which is the height it is going back to. So the measure-phase hold, its modifier and the list's `afterMeasure` hook are all gone, and this is 75 lines shorter than the version that could not do it. Checked with ktfmtFormat, compileDebugKotlin, lintDebug and testDebugUnitTest, and on the emulator against a real imported conversation as well as the sandbox: a group closed by its heading lands centred on the tap (1467..1593 for a tap at 1530), a card closed at 1500 and at 1800 lands centred on each, opening by a heading holds the heading to the pixel, and opening or closing a real call inside a group of two leaves that group's heading exactly where it was.
This commit is contained in:
1 parent
581e07624f
commit
914985b8b2
3 files changed
+58
-133
No files matched your search
@@ -1208,22 +1208,22 @@ dev-updater (Kotlin 2.4.x, CMP 1.11.x, JDK 21).
|
||||
included — exactly where it is. Centring the group instead threw a group
|
||||
of six the length of the screen. Where there is not enough conversation
|
||||
on the far side to scroll, the row lands as close as the list can put it.
|
||||
**The position is stated, not converged on, and it is asked for from
|
||||
inside the list's own measure** (`settleHold`, called from
|
||||
`TranscriptList`'s `afterMeasure`). Three things were paid for to get
|
||||
there. A scroll asked for during the *placement* phase is never picked up
|
||||
by another measure, so it does nothing whatever; from a coroutine it
|
||||
arrives a frame late, which is the flick this mechanism exists to avoid.
|
||||
Working the scroll out from the change in height needs the list to behave
|
||||
the way the arithmetic assumed, and it does not — which item it holds
|
||||
still across a resize depends on what it has composed, and a row taller
|
||||
than the screen is anchored on *itself*. And correcting by the error a
|
||||
pass can see, then asking again, is a *frame* per pass with the ones in
|
||||
between drawn: opening a card visibly stepped. What is exact and takes
|
||||
one pass is `requestScrollToItem` against the row itself, which places it
|
||||
wherever it has ended up and whether or not it is still on screen — a
|
||||
negative offset included, which is the list being asked for the rows
|
||||
below a card that has just given the screen its whole height back.
|
||||
**The scroll is asked for in the gesture, not from the layout that
|
||||
discovers the new height**, and that is what makes it invisible: a
|
||||
request made at the tap is consumed by the same measure pass that first
|
||||
lays the row out at its new size, so the resize is drawn once, in its
|
||||
right place. Everything else was tried and is a frame late — a request
|
||||
from the placement phase is never picked up by another measure and does
|
||||
nothing at all; one from the measure phase lands on the *next* frame,
|
||||
with the uncorrected one drawn first; and correcting by the error each
|
||||
pass can see is that again, once per pass. None of the three positions
|
||||
needs the new height, which is what lets them be asked for before it
|
||||
exists: a top edge holds by placing the item *above* the row where it
|
||||
already is, since that item's bottom edge is the row's top edge whatever
|
||||
becomes of the row, and it does not have to be composed for the list to
|
||||
place it. A close places the row itself, against the height it had at the
|
||||
moment it was opened — what the reader is shutting is the card they
|
||||
opened, so that is the height it is going back to (`closedHeights`).
|
||||
- **The full-screen image lives on the screen, not in the row that drew
|
||||
the thumbnail** (`SessionImageViewer`). A `Read` whose result is an image
|
||||
is a row of one call until the next call arrives and makes it a group — a
|
||||
|
||||
Reference in new issue
Block a user