如何让WPF UI幻灯片动画更具体感?

如果我们想要滑动屏幕,我们需要一些事件。

Mouse Move EventMouse Down EventMouse UP event但问题是我们只能在手指触摸屏幕时做一些动画 ,我的意思是:当它触摸屏幕移动时,它会移动,当我们释放它时,它将停止(或给它一个位置让它停在那里)。 但我想要一些像iPhone主屏幕那样的动画。 如果我们的手指滑动得更快,动画更快(或动画滑到更远的地方)。

就像现在我们使用Photoshop一样,当图片缩小到非常大时,当我们更快地移动手时,它会移动到很远的地方。

另一个例子是它会慢慢减速,而不是立即减速。 它也会知道我的手指快速滑动或缓慢……然后它会慢速或快速滑动……

我在我自己的程序中使用了这里的代码的修改版本。 用法很简单,因为它是附加行为,可以应用于样式,以便所有滚动查看器以这种方式自动运行。 它使用您提到的相同(隧道)事件( OnPreviewMouseDownOnPreviewMouseUpOnPreviewMouseMove )。 在处理OnPreviewMouseMove期间,计算惯性并以模拟的物理方式移动滚动条。 还有一个摩擦属性可以设置为改变滚动条“滑动”的时间长度。

这是我使用ScrollViewer进行惯性测试的控件的快速示例。
希望这可以帮助。

 public partial class HomeFeed : BaseControl { public HomeFeed() { InitializeComponent(); } private bool IsDragging { get { return _isDragging; } set { var start = _isDragging && !value; _isDragging = value; if (start) { new Thread(x => { var c = 0; while (ApplyVelocity()) { c++; Thread.Sleep(15); } }).Start(); } } } private Point _mousePosition; private Velocity _velocity = new Velocity(); private bool _isDragging; private void HomeScrollViewer_OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { IsDragging = true; _velocity.Reset(); _mousePosition = e.GetPosition(this); e.Handled = true; } private void HomeScrollViewer_OnPreviewMouseMove(object sender, MouseEventArgs e) { if (!IsDragging) return; var pos = e.GetPosition(this); var y = pos.Y - _mousePosition.Y; if (y == 0) { return; } _velocity.TryUpdate(y); HomeScrollViewer.ScrollToVerticalOffset(HomeScrollViewer.VerticalOffset - y); _mousePosition = pos; } private void HomeScrollViewer_OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e) { if (!IsDragging) return; IsDragging = false; e.Handled = true; } private void HomeScrollViewer_OnMouseLeave(object sender, MouseEventArgs e) { if (!IsDragging) return; IsDragging = false; e.Handled = true; } private bool ApplyVelocity() { if (IsDragging || _velocity.Value == 0) { return false; } Dispatcher.BeginInvoke(new Action(() => HomeScrollViewer.ScrollToVerticalOffset(HomeScrollViewer.VerticalOffset - _velocity.Value))); var size = Math.Abs(_velocity.Value); var sign = size / _velocity.Value; _velocity.Value = sign * Math.Max(0, Math.Min(size*0.95, size - 1)); return true; } } public class Velocity { private readonly int _timespan; public double Value { get; set; } public DateTime SetAt { get; set; } public Velocity(int timespan = 1000) { _timespan = timespan; Value = 0; SetAt = DateTime.Now; } public void TryUpdate(double value) { if (value == 0) { return; } if (SetAt.Add(TimeSpan.FromMilliseconds(_timespan)) > DateTime.Now) { SetAt = DateTime.Now; Value = value; return; } if (value*Value < 0) { SetAt = DateTime.Now; Value = value; return; } if (Math.Abs(value) > Math.Abs(Value)) { SetAt = DateTime.Now; Value = value; return; } } public void Reset() { Value = 0; SetAt = DateTime.Now; } }