I implemented both features, but I’m seeing some weird behavior: the panel shakes and jumps when scrolling finishes. This is not the smooth experience I want.
I’ve uploaded a sample app that contains the full source code for the panel.
https://github.com/ghost1372/App10
How can I fix the shaking and jumping behavior while keeping inertia scrolling and snapping to items functional?

Here’s a snippet of what I currently have:
Код: Выделить всё
public class LoopPanel : Panel
{
private const Double DECELERATION = 0.95;
private const Double MIN_INERTIA_THRESHOLD = 0.05;
private Double inertiaVelocity = 0;
private Boolean isInertiaActive = false;
private Double dragVelocity = 0;
private DateTime lastDragTime;
private Boolean isDragging = false;
private Point lastDragPos;
public LoopPanel()
{
this.PointerWheelChanged += this.OnPointerWheelChanged;
this.PointerPressed += this.OnPointerPressed;
this.PointerMoved += this.OnPointerMoved;
this.PointerReleased += this.OnPointerReleased;
this.PointerCanceled += this.OnPointerCanceled;
}
#region Pointer Events
private void OnPointerWheelChanged( Object sender, PointerRoutedEventArgs e )
{
var delta = e.GetCurrentPoint(this).Properties.MouseWheelDelta;
Double scrollAmount = -delta * MouseWheelScrollFactor;
this.Scroll( scrollAmount );
this.InvalidateArrange();
if( IsInertiaEnabled )
{
this.inertiaVelocity = scrollAmount;
this.StartInertia();
}
e.Handled = true;
}
private void OnPointerPressed( Object sender, PointerRoutedEventArgs e )
{
this.isDragging = true;
this.lastDragTime = DateTime.Now;
this.lastDragPos = e.GetCurrentPoint( this ).Position;
this.CapturePointer( e.Pointer );
e.Handled = true;
}
private void OnPointerMoved( Object sender, PointerRoutedEventArgs e )
{
if( !this.isDragging ) return;
Point current = e.GetCurrentPoint( this ).Position;
Double delta = ( this.Orientation == this.Orientation.Horizontal ) ? ( this.lastDragPos.X - current.X ) : ( this.lastDragPos.Y - current.Y );
this.Scroll( delta * this.DragScrollFactor );
this.InvalidateArrange();
DateTime now = DateTime.Now;
Double milliseconds = ( now - this.lastDragTime ).TotalMilliseconds;
if( milliseconds > 0 )
{
Double v = delta / milliseconds * 16.6667;
this.dragVelocity = this.dragVelocity * 0.35 + v * 0.65;
}
this.lastDragPos = current;
this.lastDragTime = now;
e.Handled = true;
}
private void OnPointerReleased( Object sender, PointerRoutedEventArgs e )
{
if( !this.isDragging ) return;
this.isDragging = false;
this.ReleasePointerCapture( e.Pointer );
e.Handled = true;
if( IsInertiaEnabled && Math.Abs( this.dragVelocity ) > MIN_INERTIA_THRESHOLD )
{
this.inertiaVelocity = this.dragVelocity;
this.StartInertia();
}
}
private void OnPointerCanceled( Object sender, PointerRoutedEventArgs e )
{
if( !this.isDragging ) return;
this.isDragging = false;
this.ReleasePointerCapture( e.Pointer );
e.Handled = true;
}
#endregio
private void StartInertia()
{
if( this.isInertiaActive ) return;
this.isInertiaActive = true;
this.CompositionTarget.Rendering += this.OnInertiaRendering;
}
private void StopInertia()
{
if( !this.isInertiaActive ) return;
this.isInertiaActive = false;
this.CompositionTarget.Rendering -= this.OnInertiaRendering;
}
private void OnInertiaRendering( Object sender, Object e )
{
if( Math.Abs( this.inertiaVelocity ) < MIN_INERTIA_THRESHOLD )
{
this.inertiaVelocity = 0;
this.DispatcherQueue.TryEnqueue( () =>
{
this.SnapToNearestChild();
} );
this.StopInertia();
return;
}
this.Scroll( this.inertiaVelocity );
this.InvalidateArrange();
this.inertiaVelocity *= DECELERATION;
}
private void SnapToNearestChild()
{
if( Children.Count == 0 ) return;
Int32 nearest = (Int32)Math.Round(Offset);
this.Offset = nearest;
this.InvalidateArrange();
}
}
Подробнее здесь: https://stackoverflow.com/questions/798 ... olling-and
Мобильная версия