Я реализовал обе функции, но наблюдаю странное поведение: панель трясется и подпрыгивает при завершении прокрутки. Это не тот плавный процесс, который мне нужен.
Я загрузил образец приложения, содержащий полный исходный код панели.
https://github.com/ghost1372/App10
Как исправить тряску и прыжки, сохраняя при этом функциональность инерционной прокрутки и привязки к элементам?

Вот фрагмент того, что у меня есть на данный момент:
Код: Выделить всё
public class LoopPanel : Panel
{
private double _inertiaVelocity = 0;
private const double Deceleration = 0.95;
private bool _isInertiaActive = false;
private double _dragVelocity = 0;
private DateTime _lastDragTime;
private const double MinInertiaThreshold = 0.05;
private bool _isDragging = false;
private Point _lastDragPos;
public LoopPanel()
{
this.PointerWheelChanged += OnPointerWheelChanged;
this.PointerPressed += OnPointerPressed;
this.PointerMoved += OnPointerMoved;
this.PointerReleased += OnPointerReleased;
this.PointerCanceled += OnPointerCanceled;
}
private void OnPointerPressed(object sender, PointerRoutedEventArgs e)
{
_isDragging = true;
_lastDragTime = DateTime.Now;
_lastDragPos = e.GetCurrentPoint(this).Position;
CapturePointer(e.Pointer);
e.Handled = true;
}
private void OnPointerMoved(object sender, PointerRoutedEventArgs e)
{
if (!_isDragging) return;
Point current = e.GetCurrentPoint(this).Position;
double delta = Orientation == Orientation.Horizontal
? _lastDragPos.X - current.X
: _lastDragPos.Y - current.Y;
Scroll(delta * DragScrollFactor);
InvalidateArrange();
DateTime now = DateTime.Now;
double milliseconds = (now - _lastDragTime).TotalMilliseconds;
if (milliseconds > 0)
{
double v = delta / milliseconds * 16.6667;
_dragVelocity = _dragVelocity * 0.35 + v * 0.65;
}
_lastDragPos = current;
_lastDragTime = now;
e.Handled = true;
}
private void OnPointerReleased(object sender, PointerRoutedEventArgs e)
{
if (!_isDragging) return;
_isDragging = false;
ReleasePointerCapture(e.Pointer);
e.Handled = true;
if (IsInertiaEnabled && Math.Abs(_dragVelocity) > MinInertiaThreshold)
{
_inertiaVelocity = _dragVelocity;
StartInertia();
}
}
private void OnInertiaRendering(object sender, object e)
{
if (Math.Abs(_inertiaVelocity) < MinInertiaThreshold)
{
_inertiaVelocity = 0;
DispatcherQueue.TryEnqueue(() =>
{
SnapToNearestChild();
});
StopInertia();
return;
}
Scroll(_inertiaVelocity);
InvalidateArrange();
_inertiaVelocity *= Deceleration;
}
private void SnapToNearestChild()
{
if (Children.Count == 0) return;
int nearest = (int)Math.Round(Offset);
Offset = nearest;
InvalidateArrange();
}
private void StartInertia()
{
if (_isInertiaActive) return;
_isInertiaActive = true;
CompositionTarget.Rendering += OnInertiaRendering;
}
private void StopInertia()
{
if (!_isInertiaActive) return;
_isInertiaActive = false;
CompositionTarget.Rendering -= OnInertiaRendering;
}
private void OnPointerCanceled(object sender, PointerRoutedEventArgs e)
{
if (!_isDragging) return;
_isDragging = false;
ReleasePointerCapture(e.Pointer);
e.Handled = true;
}
private void OnPointerWheelChanged(object sender, PointerRoutedEventArgs e)
{
var delta = e.GetCurrentPoint(this).Properties.MouseWheelDelta;
double scrollAmount = -delta * MouseWheelScrollFactor;
Scroll(scrollAmount);
InvalidateArrange();
if (IsInertiaEnabled)
{
_inertiaVelocity = scrollAmount;
StartInertia();
}
e.Handled = true;
}
}
Подробнее здесь: https://stackoverflow.com/questions/798 ... olling-and
Мобильная версия