forked from joejulian/gio
widget/material: use offsetlast in scroll position calculations
This commit updates the logic that computes scroll viewport coordinates to correctly consume layout.Position.OffsetLast, which was previously ignored. The impact of ignoring that field was that dragging on a scroll indicator could sometimes fail to reach the end of the list. I've updated the logic to consume that field, which increased the amount of visual jitter in the position of the scrollbar. I then also added a mechanism for smoothing the jitter by using both methods of deriving the viewport and synthesizing a viewport from both. This new strategy exhibits a lower standard deviation than the other options on each of: - the length of the scroll indicator - the change in the start coordinate of the viewport when scrolling smoothly - the change in the end coordinate of the viewport when scrolling smoothly Fixes: https://todo.sr.ht/~eliasnaur/gio/504 Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
This commit is contained in:
+27
-6
@@ -23,18 +23,39 @@ import (
|
||||
// start will be less than or equal to end.
|
||||
func fromListPosition(lp layout.Position, elements int, majorAxisSize int) (start, end float32) {
|
||||
// Approximate the size of the scrollable content.
|
||||
lengthPx := float32(lp.Length)
|
||||
meanElementHeight := lengthPx / float32(elements)
|
||||
lengthEstPx := float32(lp.Length)
|
||||
elementLenEstPx := lengthEstPx / float32(elements)
|
||||
|
||||
// Determine how much of the content is visible.
|
||||
listOffsetF := float32(lp.Offset)
|
||||
listOffsetL := float32(lp.OffsetLast)
|
||||
|
||||
// Compute the location of the beginning of the viewport using estimated element size and known
|
||||
// pixel offsets.
|
||||
viewportStart := clamp1((float32(lp.First)*elementLenEstPx + listOffsetF) / lengthEstPx)
|
||||
viewportEnd := clamp1((float32(lp.First+lp.Count)*elementLenEstPx + listOffsetL) / lengthEstPx)
|
||||
viewportFraction := viewportEnd - viewportStart
|
||||
|
||||
// Compute the expected visible proportion of the list content based solely on the ratio
|
||||
// of the visible size and the estimated total size.
|
||||
visiblePx := float32(majorAxisSize)
|
||||
visibleFraction := visiblePx / lengthPx
|
||||
visibleFraction := visiblePx / lengthEstPx
|
||||
|
||||
// Compute the location of the beginning of the viewport.
|
||||
viewportStart := (float32(lp.First)*meanElementHeight + listOffsetF) / lengthPx
|
||||
// Compute the error between the two methods of determining the viewport and diffuse the
|
||||
// error on either end of the viewport based on how close we are to each end.
|
||||
err := visibleFraction - viewportFraction
|
||||
adjStart := viewportStart
|
||||
adjEnd := viewportEnd
|
||||
if viewportFraction < 1 {
|
||||
startShare := viewportStart / (1 - viewportFraction)
|
||||
endShare := (1 - viewportEnd) / (1 - viewportFraction)
|
||||
startErr := startShare * err
|
||||
endErr := endShare * err
|
||||
|
||||
return viewportStart, clamp1(viewportStart + visibleFraction)
|
||||
adjStart -= startErr
|
||||
adjEnd += endErr
|
||||
}
|
||||
return adjStart, adjEnd
|
||||
}
|
||||
|
||||
// rangeIsScrollable returns whether the viewport described by start and end
|
||||
|
||||
Reference in New Issue
Block a user