Finished overscroll indiciator.

This commit is contained in:
Samuel Guerra 2023-09-08 14:41:29 -03:00
parent 7c6cf7ec36
commit cf71cf0279
4 changed files with 81 additions and 16 deletions

View File

@ -28,8 +28,6 @@
# Scroll
* Implement over-scroll indicator.
- Animation release.
* Implement touch scroll inertia.
* Implement `ScrollMode::ZOOM`.
- Touch gesture.
@ -43,17 +41,6 @@
- We want the same gesture in combo box of clicking and dragging to the option.
- Maybe use the swipe/fling gesture?
* Gesture propagation:
- Create property helper, only subscribes to touch move when gesture pending?
- OR, a `GESTURES.register_gesture` or with a boxed trait.
- OR, events that check `has_hooks` and `is_subscriber`.
- Setting a `on_touch_gesture` only in `when` still subscribes to the event always.
- Because we move the when resolver inside an event handler.
- Refactor `WidgetHandler` to signal when it is nil?
- CLICK_EVENT is just an aggregator that includes TOUCH_TAP_EVENT, but the gestures manager
must subscribe to it globally to work.
- Ideally we only include the subscribers of CLICK_EVENT in TOUCH_TAP_EVENT.
* Implement gestures:
- Context tap.
- Long press?

View File

@ -97,6 +97,12 @@ impl Drop for AnimationHandleData {
#[repr(transparent)]
#[must_use = "the animation stops if the handle is dropped"]
pub struct AnimationHandle(crate_util::Handle<AnimationHandleData>);
impl Default for AnimationHandle {
/// `dummy`.
fn default() -> Self {
Self::dummy()
}
}
impl AnimationHandle {
pub(super) fn new() -> (crate_util::HandleOwner<AnimationHandleData>, Self) {
let (owner, handle) = crate_util::Handle::new(AnimationHandleData::default());

View File

@ -666,9 +666,15 @@ pub fn scroll_touch_node(child: impl UiNode) -> impl UiNode {
TouchPhase::End => {
// TODO inertia
applied_offset = PxVector::zero();
SCROLL.clear_overscroll_vertical();
SCROLL.clear_overscroll_horizontal();
}
TouchPhase::Cancel => {
applied_offset = PxVector::zero();
SCROLL.clear_overscroll_vertical();
SCROLL.clear_overscroll_horizontal();
}
}
}

View File

@ -1,4 +1,4 @@
use std::{fmt, sync::Arc, time::Duration};
use std::{fmt, mem, sync::Arc, time::Duration};
use crate::core::{
context::{context_local, with_context_local_init, StaticStateId, WIDGET},
@ -114,6 +114,9 @@ struct ScrollConfig {
// last rendered horizontal, vertical offsets.
rendered: Atomic<RenderedOffsets>,
overscroll_horizontal: Mutex<AnimationHandle>,
overscroll_vertical: Mutex<AnimationHandle>,
}
impl Default for ScrollConfig {
fn default() -> Self {
@ -122,6 +125,8 @@ impl Default for ScrollConfig {
horizontal: Default::default(),
vertical: Default::default(),
rendered: Atomic::new(RenderedOffsets { h: 0.fct(), v: 0.fct() }),
overscroll_horizontal: Default::default(),
overscroll_vertical: Default::default(),
}
}
}
@ -287,7 +292,13 @@ impl SCROLL {
let _ = SCROLL_VERTICAL_OFFSET_VAR.set(next);
if overscroll != 0.fct() {
let _ = OVERSCROLL_VERTICAL_OFFSET_VAR.modify(move |o| *o.to_mut() += overscroll);
let new_handle = Self::increment_overscroll(OVERSCROLL_VERTICAL_OFFSET_VAR, overscroll);
let config = SCROLL_CONFIG.get();
let mut handle = config.overscroll_vertical.lock();
mem::replace(&mut *handle, new_handle).stop();
} else {
self.clear_overscroll_vertical();
}
}
@ -317,7 +328,62 @@ impl SCROLL {
let _ = SCROLL_HORIZONTAL_OFFSET_VAR.set(next);
if overscroll != 0.fct() {
let _ = OVERSCROLL_HORIZONTAL_OFFSET_VAR.modify(move |o| *o.to_mut() += overscroll);
let new_handle = Self::increment_overscroll(OVERSCROLL_HORIZONTAL_OFFSET_VAR, overscroll);
let config = SCROLL_CONFIG.get();
let mut handle = config.overscroll_horizontal.lock();
mem::replace(&mut *handle, new_handle).stop();
} else {
self.clear_overscroll_horizontal();
}
}
fn increment_overscroll(overscroll: ContextVar<Factor>, delta: Factor) -> AnimationHandle {
enum State {
Increment,
ClearDelay,
Clear(Transition<Factor>),
}
let mut state = State::Increment;
overscroll.animate(move |a, o| match &mut state {
State::Increment => {
// set the increment and start delay to animation.
*o.to_mut() += delta;
a.sleep(300.ms());
state = State::ClearDelay;
}
State::ClearDelay => {
a.restart();
let t = Transition::new(**o, 0.fct());
state = State::Clear(t);
}
State::Clear(t) => {
let step = easing::linear(a.elapsed_stop(300.ms()));
o.set(t.sample(step));
}
})
}
/// Quick ease [`OVERSCROLL_VERTICAL_OFFSET_VAR`] to zero.
pub fn clear_overscroll_vertical(&self) {
if OVERSCROLL_VERTICAL_OFFSET_VAR.get() != 0.fct() {
let new_handle = OVERSCROLL_VERTICAL_OFFSET_VAR.ease(0.fct(), 100.ms(), easing::linear);
let config = SCROLL_CONFIG.get();
let mut handle = config.overscroll_vertical.lock();
mem::replace(&mut *handle, new_handle).stop();
}
}
/// Quick ease [`OVERSCROLL_HORIZONTAL_OFFSET_VAR`] to zero.
pub fn clear_overscroll_horizontal(&self) {
if OVERSCROLL_HORIZONTAL_OFFSET_VAR.get() != 0.fct() {
let new_handle = OVERSCROLL_HORIZONTAL_OFFSET_VAR.ease(0.fct(), 100.ms(), easing::linear);
let config = SCROLL_CONFIG.get();
let mut handle = config.overscroll_horizontal.lock();
mem::replace(&mut *handle, new_handle).stop();
}
}