-
Notifications
You must be signed in to change notification settings - Fork 0
/
HorizontalSmoothScrollViewer.cs
183 lines (159 loc) · 6.21 KB
/
HorizontalSmoothScrollViewer.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Animation;
namespace TNFlipView
{
public class HorizontalSmoothScrollViewer:ScrollViewer
{
private int _currentIndex;
public static readonly DependencyProperty ScrollAnimationTimeProperty = DependencyProperty.Register(
"ScrollAnimationTime", typeof(int), typeof(HorizontalSmoothScrollViewer), new PropertyMetadata(200));
/// <summary>
/// 毫秒
/// </summary>
public int ScrollAnimationTime
{
get { return (int)GetValue(ScrollAnimationTimeProperty); }
set { SetValue(ScrollAnimationTimeProperty, value); }
}
public static readonly DependencyProperty FlipAnimationTimeProperty = DependencyProperty.Register(
"FlipAnimationTime", typeof(int), typeof(HorizontalSmoothScrollViewer), new PropertyMetadata(300));
public int FlipAnimationTime
{
get { return (int)GetValue(FlipAnimationTimeProperty); }
set { SetValue(FlipAnimationTimeProperty, value); }
}
public static readonly DependencyProperty ScrollRatioProperty = DependencyProperty.Register(
"ScrollRatio", typeof(double), typeof(HorizontalSmoothScrollViewer), new PropertyMetadata(1.2));
/// <summary>
/// 滚动比
/// </summary>
public double ScrollRatio
{
get { return (double)GetValue(ScrollRatioProperty); }
set { SetValue(ScrollRatioProperty, value); }
}
public static readonly DependencyProperty ScrollerBarWidthProperty = DependencyProperty.Register(
"ScrollerBarWidth", typeof(double), typeof(HorizontalSmoothScrollViewer), new PropertyMetadata(0.0, (
(o, args) =>
{
if (o is HorizontalSmoothScrollViewer scrollViewer)
{
scrollViewer.Padding = new Thickness(0, 0, 0, (double)args.NewValue );
}
})));
public double ScrollerBarWidth
{
get { return (double)GetValue(ScrollerBarWidthProperty); }
set { SetValue(ScrollerBarWidthProperty, value); }
}
/// <summary>
/// flip滑动时有效,只读
/// </summary>
public int CurrentIndex
{
get { return _currentIndex; }
private set
{
_currentIndex = value;
OnIndexChange?.Invoke(value);
}
}
/// <summary>
/// 按页滑动
/// </summary>
public bool IsFlipScroll { get; set; }
public Action<int> OnIndexChange { get; set; }
//记录上一次的滚动位置
private double LastLocation = 0;
public HorizontalSmoothScrollViewer()
{
//HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden;
// VerticalScrollBarVisibility = ScrollBarVisibility.Hidden;
}
//重写鼠标滚动事件
protected override void OnMouseWheel(MouseWheelEventArgs e)
{
double WheelChange = e.Delta;
double newOffset = 0.0;
if (!IsFlipScroll)
{
newOffset = LastLocation - WheelChange * ScrollRatio;
}
else
{
//一次滚动一个可视范围
if (WheelChange > 0)
{
WheelChange = 1;
}
else
{
WheelChange = -1;
}
newOffset = LastLocation - ViewportWidth * WheelChange;
//确保按页滚动的对齐
newOffset = newOffset - newOffset % ViewportWidth;
}
//Animation并不会改变真正的VerticalOffset(只是它的依赖属性) 所以将VOffset设置到上一次的滚动位置 (相当于衔接上一个动画)
ScrollToHorizontalOffset(LastLocation);
//碰到底部和顶部时的处理
if (newOffset < 0)
newOffset = 0;
if (newOffset > ScrollableWidth)
newOffset = ScrollableWidth;
AnimateScroll(newOffset);
//自己处理
e.Handled = true;
}
protected override void OnScrollChanged(ScrollChangedEventArgs e)
{
//计算当前滚动的index
var index = e.HorizontalOffset / e.ViewportWidth;
int intIndex = (int)index;
if (index - intIndex >= 0.5)
{
CurrentIndex = intIndex + 1;
}
else
{
CurrentIndex = intIndex;
}
base.OnScrollChanged(e);
}
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.Key == Key.Up || e.Key == Key.Down)
{
e.Handled = true;
}
base.OnKeyDown(e);
}
public void AnimateScroll(double ToValue)
{
//为了避免重复,先结束掉上一个动画
BeginAnimation(ScrollViewerBehavior.HorizontalOffsetProperty, null);
DoubleAnimation Animation = new DoubleAnimation();
Animation.EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut };
Animation.From = HorizontalOffset;
Animation.To = ToValue;
//动画速度
if (IsFlipScroll)
{
Animation.Duration = TimeSpan.FromMilliseconds(FlipAnimationTime);
}
else
{
Animation.Duration = TimeSpan.FromMilliseconds(ScrollAnimationTime);
}
//考虑到性能,可以降低动画帧数
//Timeline.SetDesiredFrameRate(Animation, 40);
BeginAnimation(ScrollViewerBehavior.HorizontalOffsetProperty, Animation);
LastLocation = ToValue;
}
}
}