本质上大家只要接管ScrollViewer的轮转逻辑

一、先看看效果

图片 1

 

 

二、原理

  纵然效果很轻易,不过互连网的一对材质涉及的代码量极度惊人,何况意义亦不是很理想,滚动的时候未有一个顺滑感。笔者这里提供的源码一共120多行,就会兑现上海体育地方的效果。

  本质上我们即便接管ScrollViewer的轮转逻辑,况且把这么些逻辑替换到带有惯性的就可以,那么怎么样去接管呢?这里的根本是先屏蔽ScrollViewer的鼠标滚轮事件:

1 protected override void OnMouseWheel(MouseWheelEventArgs e)
2 {
3      e.Handled = true;
4 }

  那样一来,ScrollViewer就不会响应滚轮事件了,大家就在那做小说。首先大家给那么些ScrollViewer增多五天性质 IsEnableInertia ,用来决定是或不是利用惯性,因为萝卜油麻菜籽各有所爱,不要想着强制全部人使用惯性,所以滚轮响应措施成为:

1 protected override void OnMouseWheel(MouseWheelEventArgs e)
2 {
3     if (!IsEnableInertia)
4     {
5         base.OnMouseWheel(e);
6         return;
7     }
8     e.Handled = true;
9 }    

  调控ScrollViewer的垂直滚动能够选取 ScrollViewer.ScrollToVerticalOffset ,横向也千篇一律。为啥不能够用 VerticalOffset ?因为 VerticalOffset 在登记的时候就注脚了是只读的:

1 private static readonly DependencyPropertyKey VerticalOffsetPropertyKey = DependencyProperty.RegisterReadOnly(nameof (VerticalOffset), typeof (double), typeof (ScrollViewer), (PropertyMetadata) new FrameworkPropertyMetadata((object) 0.0));
2 
3 public static readonly DependencyProperty VerticalOffsetProperty = ScrollViewer.VerticalOffsetPropertyKey.DependencyProperty;

  好了,接下去正是怎么在滚轮响应措施中落到实处惯性运动了,也正是一种减速运动。想到那儿,熟谙动画的博友非常快就精通要用WPF的动画来实现了,私下认可的卡通片都以三遍线性的,要有惯性成效就得用缓动函数,WPF的缓动函数有不菲,而 CubicEase 特别符合用来做惯性,它的叙说图如下:

图片 2

  图中,横轴表示时间,纵轴代表运动间距。很明白,中间的 EaseOut 情势就是大家想要的。到了那边思路就清楚了,我们得以定义叁性格能 CurrentVerticalOffset ,我们会在它上边达成动画,在它的值回调函数中调用 ScrollViewer.ScrollToVerticalOffset 来更新ScrollViewer的轮转地方。当然大家还亟需二个私人商品房字段 _totalVerticalOffset ,那么些是用来存放ScrollViewer滚动目的地方的,滚轮向下滚动三个单位大家就给它减去一次 e.Delta ,这里的e是滚轮响应措施传进来的参数,每趟给它赋值之后,就足以在 CurrentVerticalOffset 上实行动画了: BeginAnimation(CurrentVerticalOffsetProperty,
animation) ,需求非常注意的是,当四个凭仗属性用了动画退换后,再对其赋值则不会卓有效用,原因是在贰个动画片达到活动期的终点后,时间线暗中同意会保持其速度,直到其父级的活动期和保持期停止甘休。假诺想在动画甘休后还足以手动更换信赖属性的值,则要求把 FillBehavior 设置为Stop。也才那样又会油可是生二个标题,一旦动画结束,这一个依附属性又会回复最早值,所以还要给那个动画订阅一个 Completed 事件,在事件响应措施中为 CurrentVerticalOffset 给定指标值,相当于 _totalVerticalOffset 。

  最终还会有二个冲突难题,当手动拖动滑块只怕当用上下文菜单改动滚动条地方时是不能够用动画的,因为那时候未有触发 OnMouseWheel ,没涉及,那多亏大家想要的,不过只要重复触发 OnMouseWheel 就有标题了,因为手动触发滚动的时候大家从未给 CurrentVerticalOffset 和 _totalVerticalOffset 赋值( CurrentVerticalOffset 和 _totalVerticalOffset 只在 OnMouseWheel 中赋值),所以在用动画执行滚动操作前要先判别一下是或不是供给先更新一下它们俩,怎样剖断?我们能够用八个私家字段 _isRunning 来保证状态,每当动画早先就给它赋值true,甘休则赋值false。那样一来,当 _isRunning = false 时,表达在调用 OnMouseWheel 前,动画已经截至,顾客大概曾经手动改动了滚动条地方(也或者未有,但那并不影响),所以将在给前边俩汉子更新一下值了。

  因为相近的惯性滚动以垂直方向居多,所以本人尚未写水平方向的逻辑,但也很轻便扩充,有意思味的博友能够下载源代码本人探讨。

 

三、源码

  本文所议论的控件源码已经在github开源:

 

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*
*
Website