@@ -34,6 +34,7 @@ struct CompositionTypeTraits<WindowsTypeTag> {
3434 using AnimationDelayBehavior = winrt::Windows::UI::Composition::AnimationDelayBehavior;
3535 using AnimationDirection = winrt::Windows::UI::Composition::AnimationDirection;
3636 using AnimationIterationBehavior = winrt::Windows::UI::Composition::AnimationIterationBehavior;
37+ using CompositionAnimation = winrt::Windows::UI::Composition::CompositionAnimation;
3738 using CompositionBackfaceVisibility = winrt::Windows::UI::Composition::CompositionBackfaceVisibility;
3839 using CompositionBrush = winrt::Windows::UI::Composition::CompositionBrush;
3940 using CompositionDrawingSurface = winrt::Windows::UI::Composition::CompositionDrawingSurface;
@@ -89,6 +90,7 @@ struct CompositionTypeTraits<MicrosoftTypeTag> {
8990 using AnimationDelayBehavior = winrt::Microsoft::UI::Composition::AnimationDelayBehavior;
9091 using AnimationDirection = winrt::Microsoft::UI::Composition::AnimationDirection;
9192 using AnimationIterationBehavior = winrt::Microsoft::UI::Composition::AnimationIterationBehavior;
93+ using CompositionAnimation = winrt::Microsoft::UI::Composition::CompositionAnimation;
9294 using CompositionBackfaceVisibility = winrt::Microsoft::UI::Composition::CompositionBackfaceVisibility;
9395 using CompositionBrush = winrt::Microsoft::UI::Composition::CompositionBrush;
9496 using CompositionDrawingSurface = winrt::Microsoft::UI::Composition::CompositionDrawingSurface;
@@ -536,13 +538,22 @@ struct CompScrollerVisual : winrt::implements<
536538
537539 void CustomAnimationStateEntered (
538540 typename TTypeRedirects::InteractionTracker sender,
539- typename TTypeRedirects::InteractionTrackerCustomAnimationStateEnteredArgs args) noexcept {}
541+ typename TTypeRedirects::InteractionTrackerCustomAnimationStateEnteredArgs args) noexcept {
542+ m_outer->m_custom = true ;
543+ m_outer->m_inertia = false ;
544+ }
540545 void IdleStateEntered (
541546 typename TTypeRedirects::InteractionTracker sender,
542- typename TTypeRedirects::InteractionTrackerIdleStateEnteredArgs args) noexcept {}
547+ typename TTypeRedirects::InteractionTrackerIdleStateEnteredArgs args) noexcept {
548+ m_outer->m_custom = false ;
549+ m_outer->m_inertia = false ;
550+ }
543551 void InertiaStateEntered (
544552 typename TTypeRedirects::InteractionTracker sender,
545- typename TTypeRedirects::InteractionTrackerInertiaStateEnteredArgs args) noexcept {}
553+ typename TTypeRedirects::InteractionTrackerInertiaStateEnteredArgs args) noexcept {
554+ m_outer->m_custom = false ;
555+ m_outer->m_inertia = true ;
556+ }
546557 void InteractingStateEntered (
547558 typename TTypeRedirects::InteractionTracker sender,
548559 typename TTypeRedirects::InteractionTrackerInteractingStateEnteredArgs args) noexcept {}
@@ -552,6 +563,7 @@ struct CompScrollerVisual : winrt::implements<
552563 void ValuesChanged (
553564 typename TTypeRedirects::InteractionTracker sender,
554565 typename TTypeRedirects::InteractionTrackerValuesChangedArgs args) noexcept {
566+ m_outer->m_currentPosition = args.Position ();
555567 m_outer->FireScrollPositionChanged ({args.Position ().x , args.Position ().y });
556568 }
557569
@@ -715,20 +727,54 @@ struct CompScrollerVisual : winrt::implements<
715727 return m_interactionTracker.Position ();
716728 }
717729
718- void ScrollBy (winrt::Windows::Foundation::Numerics::float3 const &offset) noexcept {
719- m_interactionTracker.TryUpdatePositionBy (offset);
730+ // ChangeOffsets scrolling constants
731+ static constexpr int64_t s_offsetsChangeMsPerUnit{5 };
732+ static constexpr int64_t s_offsetsChangeMinMs{50 };
733+ static constexpr int64_t s_offsetsChangeMaxMs{1000 };
734+
735+ typename TTypeRedirects::CompositionAnimation GetPositionAnimation (float x, float y) {
736+ const int64_t distance =
737+ static_cast <int64_t >(std::sqrt (std::pow (x - m_currentPosition.x , 2 .0f ) + pow (y - m_currentPosition.y , 2 .0f )));
738+ auto compositor = m_visual.Compositor ();
739+ auto positionAnimation = compositor.CreateVector3KeyFrameAnimation ();
740+
741+ positionAnimation.InsertKeyFrame (1 .0f , {x, y, 0 .0f });
742+ positionAnimation.Duration (std::chrono::milliseconds (
743+ std::clamp (distance * s_offsetsChangeMsPerUnit, s_offsetsChangeMinMs, s_offsetsChangeMaxMs)));
744+
745+ return positionAnimation;
746+ }
747+
748+ void ScrollBy (winrt::Windows::Foundation::Numerics::float3 const &offset, bool animate) noexcept {
749+ auto restingPosition = m_inertia ? m_interactionTracker.NaturalRestingPosition () : m_interactionTracker.Position ();
750+ if (m_custom) {
751+ restingPosition = m_targetPosition;
752+ }
753+ if (animate) {
754+ auto maxPosition = m_interactionTracker.MaxPosition ();
755+ m_custom = true ;
756+ m_targetPosition = {
757+ std::clamp (restingPosition.x + offset.x , 0 .0f , maxPosition.x ),
758+ std::clamp (restingPosition.y + offset.y , 0 .0f , maxPosition.y ),
759+ std::clamp (restingPosition.z + offset.z , 0 .0f , maxPosition.z )};
760+
761+ auto kfa = GetPositionAnimation (m_targetPosition.x , m_targetPosition.y );
762+ m_interactionTracker.TryUpdatePositionWithAnimation (kfa);
763+ } else {
764+ m_interactionTracker.TryUpdatePositionBy (offset);
765+ }
720766 };
721767
722768 void TryUpdatePosition (winrt::Windows::Foundation::Numerics::float3 const &position, bool animate) noexcept {
769+ auto maxPosition = m_interactionTracker.MaxPosition ();
723770 if (animate) {
724- auto compositor = m_visual.Compositor ();
725- auto cubicBezier = compositor.CreateCubicBezierEasingFunction ({0 .17f , 0 .67f }, {1 .0f , 1 .0f });
726- auto kfa = compositor.CreateVector3KeyFrameAnimation ();
727- kfa.Duration (std::chrono::seconds{1 });
728- kfa.InsertKeyFrame (1 .0f , position, cubicBezier);
771+ auto kfa = GetPositionAnimation (std::min (maxPosition.x , position.x ), std::min (maxPosition.y , position.y ));
729772 m_interactionTracker.TryUpdatePositionWithAnimation (kfa);
730773 } else {
731- m_interactionTracker.TryUpdatePosition (position);
774+ m_interactionTracker.TryUpdatePosition (
775+ {std::min (maxPosition.x , position.x ),
776+ std::min (maxPosition.y , position.y ),
777+ std::min (maxPosition.z , position.z )});
732778 }
733779 }
734780
@@ -744,6 +790,10 @@ struct CompScrollerVisual : winrt::implements<
744790 0 });
745791 }
746792
793+ bool m_inertia{false };
794+ bool m_custom{false };
795+ winrt::Windows::Foundation::Numerics::float3 m_targetPosition;
796+ winrt::Windows::Foundation::Numerics::float3 m_currentPosition;
747797 winrt::Windows::Foundation::Numerics::float2 m_contentSize{0 };
748798 winrt::Windows::Foundation::Numerics::float2 m_visualSize{0 };
749799 winrt::event<
0 commit comments