动画ScrollViewer
中的滚动似乎是一项常见任务。我使用计时器实现它,类似于here找到的方法。这种方法效果很好,非常流畅,看起来很完美。
但是,现在我的ScrollViewer
中包含的对象的复杂性和数量增加了,动画看起来非常不稳定。我发现这很奇怪,因为如果我手动滚动它会正常工作。
public void ShiftLeft(int speed = 11)
{
CustomTimer timer = new CustomTimer(); //DispatchTimer with "life"
timer.Interval = new TimeSpan(0, 0, 0, 0, 5);
timer.Tick += ((sender, e) =>
{
scrollViewer1.ScrollToHorizontalOffset(
scrollViewer1.HorizontalOffset - (scrollViewer1.ScrollableWidth / (gridColumnCount - 3) / speed));
if (scrollViewer1.HorizontalOffset == 0) //cant scroll any more
((CustomTimer)sender).Stop();
((CustomTimer)sender).life++;
if (((CustomTimer)sender).life >= speed) //reached destination
((CustomTimer)sender).Stop();
});
timer.Start();
}
我的方法有问题导致这种奇怪的抽搐吗?知道怎么解决吗?
答案 0 :(得分:4)
CompositionTarget.Rendering
将更适合动画制作,因为每次渲染帧时都会触发。尝试这样的事情:
public void Shift(ScrollViewer target, double speed = 11, double distance = 20)
{
double startOffset = target.HorizontalOffset;
double destinationOffset = target.HorizontalOffset + distance;
if (destinationOffset < 0)
{
destinationOffset = 0;
distance = target.HorizontalOffset;
}
if (destinationOffset > target.ScrollableWidth)
{
destinationOffset = target.ScrollableWidth;
distance = target.ScrollableWidth - target.HorizontalOffset;
}
double animationTime = distance / speed;
DateTime startTime = DateTime.Now;
EventHandler renderHandler = null;
renderHandler = (sender, args) =>
{
double elapsed = (DateTime.Now - startTime).TotalSeconds;
if (elapsed >= animationTime)
{
target.ScrollToHorizontalOffset(destinationOffset);
CompositionTarget.Rendering -= renderHandler;
}
target.ScrollToHorizontalOffset(startOffset + (elapsed * speed));
};
CompositionTarget.Rendering += renderHandler;
}
编辑:添加范围检查
使用负距离值向左滚动。
编辑2:
您可能希望使用此CompositionTargetEx
实现而不是CompositionTarget
,因为它只会在渲染线程实际绘制新帧时触发:
https://stackoverflow.com/a/16334423/612510
编辑3:
由于您使用的是WPF(而不是像我更习惯的Silverlight),您可以使用Stopwatch
类来测量经过的秒数而不是我的DateTime.Now
方法。