c# - 连续背景画笔动画
问题描述
每当鼠标悬停在我的用户控件上时,我都想制作一个连续的画笔动画。
我已经有了这个:
private void MainControl_MouseEnter(object sender, MouseEventArgs e)
{
BeginColorAnimation(Background, BackgroundHover);
}
private void BeginColorAnimation(Brush from, Brush to)
{
BrushAnimation anim = new BrushAnimation()
{
From = from,
To = to,
Duration = AnimationDuration
};
BackgroundBorder.BeginAnimation(Border.BackgroundProperty, anim);
}
private void MainControl_MouseLeave(object sender, MouseEventArgs e)
{
BeginColorAnimation(BackgroundHover, Background);
}
BrushAnimation 类可以在这里找到
我现在遇到的问题是,如果我将鼠标快速移到控件上,我的控件的背景会立即从背景画笔转移到 BackgroundHover 画笔(反之亦然),我不希望这样。
我怎样才能使它看起来像画笔之间的连续变化?
编辑 1
在这里你可以看到我遇到的问题的视频。
让我解释一下自己:
想象一下,我们有两把刷子,一把黑色,一把蓝色(或任何其他颜色)。当鼠标悬停在控件上时,我想将颜色的背景从黑色更改为蓝色,当鼠标退出控件时,我想将背景更改回黑色。那么如果鼠标悬停在控件上并在动画中途退出会发生什么?看起来好像是从一个画笔弹跳到另一个画笔。我想避免这种情况。
我尝试使用:
private void MainControl_MouseEnter(object sender, MouseEventArgs e)
{
BeginColorAnimation(BackgroundBorder.Background, BackgroundHover);
}
private void MainControl_MouseLeave(object sender, MouseEventArgs e)
{
BeginColorAnimation(BackgroundBorder.Background, Background);
}
但后来我收到:'System.InvalidOperationException' 这个freezable 不能被冻结。
编辑 2
最终使用 SolidColorBrush 而不是 Brush,并使用 ColorAnimation 类。
public bool BackgroundFrozen = true;
private void MainControl_MouseEnter(object sender, MouseEventArgs e)
{
BeginColorAnimation((SolidColorBrush)BackgroundBorder.Background, BackgroundHover);
}
private void BeginColorAnimation(SolidColorBrush from, SolidColorBrush to)
{
if(BackgroundFrozen)
{
BackgroundBorder.Background = BackgroundBorder.Background.CloneCurrentValue();
BackgroundFrozen = false;
}
ColorAnimation anim = new ColorAnimation()
{
From = from.Color,
To = to.Color,
Duration = AnimationDuration
};
BackgroundBorder.Background.BeginAnimation(SolidColorBrush.ColorProperty, anim);
}
private void MainControl_MouseLeave(object sender, MouseEventArgs e)
{
BeginColorAnimation((SolidColorBrush)BackgroundBorder.Background, Background);
}
由于某种原因,Border Background 属性最初被冻结,所以我使用 BackgroundFrozen 布尔值在动画第一次运行时使用 CloneCurrentValue()“解冻”它。
结果在这里
解决方案
阅读“编辑 2”,因为它是解决方案的一部分
正如某人所建议的那样,我删除From = from,
并为动画制作了一个“动态”持续时间,同时考虑了from
和end
值。
结果:
start
是原始值
end
是目标值
actual
是介于start
和之间的东西end
(可能相同)
private ColorAnimation GetColorAnimation(SolidColorBrush start, SolidColorBrush end, SolidColorBrush actual)
{
ColorAnimation anim = new ColorAnimation()
{
To = end.Color,
Duration = new Duration(TimeSpan.FromMilliseconds(GetAnimationDuration(start, end, actual)))
};
return anim;
}
GetAnimationDuration
返回一个double
包含持续时间(以毫秒为单位)的
private double GetAnimationDuration(SolidColorBrush start, SolidColorBrush end, SolidColorBrush actual)
{
Color s = start.Color;
Color e = end.Color;
Color a = actual.Color;
double Rdif = Math.Abs(s.R - e.R);
double Gdif = Math.Abs(s.G - e.G);
double Bdif = Math.Abs(s.B - e.B);
//Console.WriteLine("Rdif: {0}, Gdif: {1}, Bdif: {2}", Rdif, Gdif, Bdif);
double Rp = Math.Abs(a.R - e.R) / Rdif;
double Gp = Math.Abs(a.G - e.G) / Gdif;
double Bp = Math.Abs(a.B - e.B) / Bdif;
double p = 0;
int c = 0;
if(!double.IsNaN(Rp))
{
p += Rp;
c += 1;
}
if (!double.IsNaN(Gp))
{
p += Gp;
c += 1;
}
if (!double.IsNaN(Bp))
{
p += Bp;
c += 1;
}
p /= c;
//Console.WriteLine("Rp: {0}, Gp: {1}, Bp: {2}", Rp, Gp, Bp);
double r = p * AnimationDuration;
//Console.WriteLine("Result: {0}", r);
return r;
}
它是这样称呼的:
BackgroundBorder.Background.BeginAnimation(SolidColorBrush.ColorProperty, GetColorAnimation(startColor, endColor, (SolidColorBrush)BackgroundBorder.Background));
GetAnimationDuration()
持续时间为 500 毫秒的测试结果
---------------------------
Mouse enter
---------------------------
R: 0, G: 0, B: 255
Rdif: 255, Gdif: 0, Bdif: 255
Rp: 1, Gp: NaN, Bp: 1
Result: 500
---------------------------
Mouse leave (after having passed half of the animation (approximately))
---------------------------
R: 193, G: 0, B: 182
Rdif: 255, Gdif: 0, Bdif: 255
Rp: 0,756862745098039, Gp: NaN, Bp: 0,286274509803922
Result: 260,78431372549
推荐阅读
- python - How to find index before the max-value index, idxmax()?
- amazon-web-services - Cloudwatch 警报违反和警报状态更改之间的显着延迟
- javascript - bootstrap 4 导航栏按钮
- scala - SBT confused about Scala types
- python - 如何使用 scikit-learn 对 python 中的数据集执行多元线性回归?
- c++ - Casting int16_t to uint_8t*
- azure-iot-edge - Azure IoT Edge 模块日志位置
- c# - 每个人都可以访问的命名管道
- splunk - Splunk:找出 2 个事件之间的差异
- java - Spring Boot 中所有 @RabbitListener-s 使用 RabbitMQ 消息