From 799ee3374d9fd38b113a6d45d7c66f18e667f8ac Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Thu, 16 Sep 2021 12:29:09 -0400 Subject: [PATCH] widget,widget/material: scroll using only drag position delta This commit is based on a patch by Elias that improved drag scrolling on the scrollbar by locking some parameters of the math at the start of the scroll event. I discovered while playing with that implementation that there was an even simpler approach within his changeset. You can actually use no information other than the delta between the current and previous frame's scroll position to compute the scroll distance. By simplifying the math to rely on no other inputs, the jitter that we've been fighting simply disappears (it came from other inputs). Turns out my attempts to make the logic smart were the problem. Signed-off-by: Chris Waldon --- widget/list.go | 20 ++++++++++++++++++-- widget/material/list.go | 3 +-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/widget/list.go b/widget/list.go index 1d0c2a66..42d01d09 100644 --- a/widget/list.go +++ b/widget/list.go @@ -24,6 +24,9 @@ type Scrollbar struct { track, indicator gesture.Click drag gesture.Drag delta float32 + + dragging bool + oldDragPos float32 } // Layout updates the internal state of the scrollbar based on events @@ -60,12 +63,25 @@ func (s *Scrollbar) Layout(gtx layout.Context, axis layout.Axis, viewportStart, // Offset to account for any drags. for _, event := range s.drag.Events(gtx.Metric, gtx, gesture.Axis(axis)) { - if event.Type != pointer.Drag { + switch event.Type { + case pointer.Drag: + case pointer.Release: + s.dragging = false + case pointer.Cancel: + s.dragging = false + continue + default: continue } dragOffset := axis.FConvert(event.Position).X normalizedDragOffset := dragOffset / trackHeight - s.delta += normalizedDragOffset - viewportStart + + if !s.dragging { + s.dragging = true + s.oldDragPos = normalizedDragOffset + } + s.delta += normalizedDragOffset - s.oldDragPos + s.oldDragPos = normalizedDragOffset } // Process events from the indicator so that hover is diff --git a/widget/material/list.go b/widget/material/list.go index 49d7ddcb..281c77b9 100644 --- a/widget/material/list.go +++ b/widget/material/list.go @@ -285,8 +285,7 @@ func (l ListStyle) Layout(gtx layout.Context, length int, w layout.ListElement) if delta := l.state.ScrollDistance(); delta != 0 { // Handle any changes to the list position as a result of user interaction // with the scrollbar. - deltaPx := int(math.Round(float64(float32(l.state.Position.Length) * delta))) - l.state.List.Position.Offset += deltaPx + l.state.List.Position.Offset += int(math.Round(float64(float32(l.state.Position.Length) * delta))) // Ensure that the list pays attention to the Offset field when the scrollbar drag // is started while the bar is at the end of the list. Without this, the scrollbar