预览
废话不多说,先来预览一下效果(windows 原生的 lodingring 在uwp应用中的样式可以在windows sdk中找到,我将其移植到了WPF中*)
- WPF中样式
- JS样式
当然了,JS中动画的参数也是我根据UWP移植过来的(无情的搬运工)
可以看到,动画基本如出一辙
实现
作为一名c#开发者,现在还做WPF桌面应用的应该已经绝无仅有了,但是我最初学这个框架也是被Windows和VisualStudio的扁平UI吸引的。在WPF中可以相对容易的同步应用与Windows的风格,包括一些系统UI的样式。
好了,废话不多说,来看今天的主角 —— Win10加载圆环
我给你们看看WPF动画的源码吧
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="E1"
Storyboard.TargetProperty="Opacity"
BeginTime="0">
<DiscreteDoubleKeyFrame KeyTime="0"
Value="1" />
<DiscreteDoubleKeyFrame KeyTime="0:0:3.21"
Value="1" />
<DiscreteDoubleKeyFrame KeyTime="0:0:3.22"
Value="0" />
<DiscreteDoubleKeyFrame KeyTime="0:0:3.47"
Value="0" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="E2"
Storyboard.TargetProperty="Opacity"
BeginTime="00:00:00.167">
<DiscreteDoubleKeyFrame KeyTime="0"
Value="1" />
<DiscreteDoubleKeyFrame KeyTime="0:0:3.21"
Value="1" />
<DiscreteDoubleKeyFrame KeyTime="0:0:3.22"
Value="0" />
<DiscreteDoubleKeyFrame KeyTime="0:0:3.47"
Value="0" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="E3"
Storyboard.TargetProperty="Opacity"
BeginTime="00:00:00.334">
<DiscreteDoubleKeyFrame KeyTime="0"
Value="1" />
<DiscreteDoubleKeyFrame KeyTime="0:0:3.21"
Value="1" />
<DiscreteDoubleKeyFrame KeyTime="0:0:3.22"
Value="0" />
<DiscreteDoubleKeyFrame KeyTime="0:0:3.47"
Value="0" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="E4"
Storyboard.TargetProperty="Opacity"
BeginTime="00:00:00.501">
<DiscreteDoubleKeyFrame KeyTime="0"
Value="1" />
<DiscreteDoubleKeyFrame KeyTime="0:0:3.21"
Value="1" />
<DiscreteDoubleKeyFrame KeyTime="0:0:3.22"
Value="0" />
<DiscreteDoubleKeyFrame KeyTime="0:0:3.47"
Value="0" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="E5"
Storyboard.TargetProperty="Opacity"
BeginTime="00:00:00.668">
<DiscreteDoubleKeyFrame KeyTime="0"
Value="1" />
<DiscreteDoubleKeyFrame KeyTime="0:0:3.21"
Value="1" />
<DiscreteDoubleKeyFrame KeyTime="0:0:3.22"
Value="0" />
<DiscreteDoubleKeyFrame KeyTime="0:0:3.47"
Value="0" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="E6"
Storyboard.TargetProperty="Opacity"
BeginTime="00:00:00.835">
<DiscreteDoubleKeyFrame KeyTime="0"
Value="1" />
<DiscreteDoubleKeyFrame KeyTime="0:0:3.21"
Value="1" />
<DiscreteDoubleKeyFrame KeyTime="0:0:3.22"
Value="0" />
<DiscreteDoubleKeyFrame KeyTime="0:0:3.47"
Value="0" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="E1R"
BeginTime="0"
Storyboard.TargetProperty="Angle">
<SplineDoubleKeyFrame KeyTime="0"
Value="-110"
KeySpline="0.13,0.21,0.1,0.7" />
<SplineDoubleKeyFrame KeyTime="0:0:0.433"
Value="10"
KeySpline="0.02,0.33,0.38,0.77" />
<SplineDoubleKeyFrame KeyTime="0:0:1.2"
Value="93" />
<SplineDoubleKeyFrame KeyTime="0:0:1.617"
Value="205"
KeySpline="0.57,0.17,0.95,0.75" />
<SplineDoubleKeyFrame KeyTime="0:0:2.017"
Value="357"
KeySpline="0,0.19,0.07,0.72" />
<SplineDoubleKeyFrame KeyTime="0:0:2.783"
Value="439" />
<SplineDoubleKeyFrame KeyTime="0:0:3.217"
Value="585"
KeySpline="0,0,0.95,0.37" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="E2R"
BeginTime="00:00:00.167"
Storyboard.TargetProperty="Angle">
<SplineDoubleKeyFrame KeyTime="0"
Value="-116"
KeySpline="0.13,0.21,0.1,0.7" />
<SplineDoubleKeyFrame KeyTime="0:0:0.433"
Value="4"
KeySpline="0.02,0.33,0.38,0.77" />
<SplineDoubleKeyFrame KeyTime="0:0:1.2"
Value="87" />
<SplineDoubleKeyFrame KeyTime="0:0:1.617"
Value="199"
KeySpline="0.57,0.17,0.95,0.75" />
<SplineDoubleKeyFrame KeyTime="0:0:2.017"
Value="351"
KeySpline="0,0.19,0.07,0.72" />
<SplineDoubleKeyFrame KeyTime="0:0:2.783"
Value="433" />
<SplineDoubleKeyFrame KeyTime="0:0:3.217"
Value="579"
KeySpline="0,0,0.95,0.37" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="E3R"
BeginTime="00:00:00.334"
Storyboard.TargetProperty="Angle">
<SplineDoubleKeyFrame KeyTime="0"
Value="-122"
KeySpline="0.13,0.21,0.1,0.7" />
<SplineDoubleKeyFrame KeyTime="0:0:0.433"
Value="-2"
KeySpline="0.02,0.33,0.38,0.77" />
<SplineDoubleKeyFrame KeyTime="0:0:1.2"
Value="81" />
<SplineDoubleKeyFrame KeyTime="0:0:1.617"
Value="193"
KeySpline="0.57,0.17,0.95,0.75" />
<SplineDoubleKeyFrame KeyTime="0:0:2.017"
Value="345"
KeySpline="0,0.19,0.07,0.72" />
<SplineDoubleKeyFrame KeyTime="0:0:2.783"
Value="427" />
<SplineDoubleKeyFrame KeyTime="0:0:3.217"
Value="573"
KeySpline="0,0,0.95,0.37" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="E4R"
BeginTime="00:00:00.501"
Storyboard.TargetProperty="Angle">
<SplineDoubleKeyFrame KeyTime="0"
Value="-128"
KeySpline="0.13,0.21,0.1,0.7" />
<SplineDoubleKeyFrame KeyTime="0:0:0.433"
Value="-8"
KeySpline="0.02,0.33,0.38,0.77" />
<SplineDoubleKeyFrame KeyTime="0:0:1.2"
Value="75" />
<SplineDoubleKeyFrame KeyTime="0:0:1.617"
Value="187"
KeySpline="0.57,0.17,0.95,0.75" />
<SplineDoubleKeyFrame KeyTime="0:0:2.017"
Value="339"
KeySpline="0,0.19,0.07,0.72" />
<SplineDoubleKeyFrame KeyTime="0:0:2.783"
Value="421" />
<SplineDoubleKeyFrame KeyTime="0:0:3.217"
Value="567"
KeySpline="0,0,0.95,0.37" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="E5R"
BeginTime="00:00:00.668"
Storyboard.TargetProperty="Angle">
<SplineDoubleKeyFrame KeyTime="0"
Value="-134"
KeySpline="0.13,0.21,0.1,0.7" />
<SplineDoubleKeyFrame KeyTime="0:0:0.433"
Value="-14"
KeySpline="0.02,0.33,0.38,0.77" />
<SplineDoubleKeyFrame KeyTime="0:0:1.2"
Value="69" />
<SplineDoubleKeyFrame KeyTime="0:0:1.617"
Value="181"
KeySpline="0.57,0.17,0.95,0.75" />
<SplineDoubleKeyFrame KeyTime="0:0:2.017"
Value="331"
KeySpline="0,0.19,0.07,0.72" />
<SplineDoubleKeyFrame KeyTime="0:0:2.783"
Value="415" />
<SplineDoubleKeyFrame KeyTime="0:0:3.217"
Value="561"
KeySpline="0,0,0.95,0.37" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="E6R"
BeginTime="00:00:00.835"
Storyboard.TargetProperty="Angle">
<SplineDoubleKeyFrame KeyTime="0"
Value="-140"
KeySpline="0.13,0.21,0.1,0.7" />
<SplineDoubleKeyFrame KeyTime="0:0:0.433"
Value="-20"
KeySpline="0.02,0.33,0.38,0.77" />
<SplineDoubleKeyFrame KeyTime="0:0:1.2"
Value="63" />
<SplineDoubleKeyFrame KeyTime="0:0:1.617"
Value="175"
KeySpline="0.57,0.17,0.95,0.75" />
<SplineDoubleKeyFrame KeyTime="0:0:2.017"
Value="325"
KeySpline="0,0.19,0.07,0.72" />
<SplineDoubleKeyFrame KeyTime="0:0:2.783"
Value="409" />
<SplineDoubleKeyFrame KeyTime="0:0:3.217"
Value="555"
KeySpline="0,0,0.95,0.37" />
</DoubleAnimationUsingKeyFrames>
由于是 xaml 生成的动画,没办法循环设置参数(UWP源码中也是如此),当时看到的时候就在想,调这个参数的美工真TM是个天才…
可以看到,其中有许多的贝塞尔缓动关键帧,要是用原生CSS3实现的话似乎有些麻烦,而且也不知道切换缓动函数的时候润不润,不润的话就很难受了,于是我就找到了anime.js这个动画库,刚好发现了其可以实现这个级别的动画。
/**
* @param {} size : int the rect clip width of the loding svg
* @param {} dotsize : int the r of a loading dot
* @param {} dotcolor : "#xxxxxx" the color of the dot
*/
function CreateLodingRing(size, dotsize, dotcolor) {
//#region Create Element
var ring = Object();
let loadingring = document.createElementNS("http://www.w3.org/2000/svg", "svg");
loadingring.id = "winloding";
loadingring.setAttribute("viewBox", "0 0" + " " + size + " " + size);
for (let i = 0; i < 6; i++) {
let dot = document.createElementNS("http://www.w3.org/2000/svg", "circle");
dot.style.transformOrigin = "center center";
dot.style.opacity = 0;
dot.setAttribute("class", "d" + (i + 1));
dot.setAttribute("fill", dotcolor);
dot.setAttribute("cx", size / 2);
dot.setAttribute("cy", dotsize + 2);
dot.setAttribute("r", dotsize);
loadingring.appendChild(dot);
}
document.body.appendChild(loadingring);
console.log(loadingring);
//#endregion
var tl = anime.timeline({
loop: true
});
// #region add animation
// tl.add({
// targets: "#winloding d1",
// rotate: [
// { value: -110, duration: 0, easing: "cubicBezier(0.13,0.21,0.1,0.7)" },
// { value: 10, duration: 433, easing: "cubicBezier(0.02,0.33,0.38,0.77)" },
// { value: 93, duration: 767, easing: "cubicBezier(0, 0, 1, 1)" },
// { value: 205, duration: 417, easing: "cubicBezier(0.57,0.17,0.95,0.75)" },
// { value: 357, duration: 400, easing: "cubicBezier(0,0.19,0.07,0.72)" },
// { value: 439, duration: 766, easing: "cubicBezier(0, 0, 1, 1)" },
// { value: 585, duration: 434, easing: "cubicBezier(0,0,0.95,0.37)" }
// ]
// })
// .add(
// {
// targets: "#winloding d2",
// rotate: [
// { value: -116, duration: 0, easing: "cubicBezier(0.13,0.21,0.1,0.7)" },
// { value: 4, duration: 433, easing: "cubicBezier(0.02,0.33,0.38,0.77)" },
// { value: 87, duration: 767, easing: "cubicBezier(0, 0, 1, 1)" },
// { value: 199, duration: 417, easing: "cubicBezier(0.57,0.17,0.95,0.75)" },
// { value: 351, duration: 400, easing: "cubicBezier(0,0.19,0.07,0.72)" },
// { value: 433, duration: 766, easing: "cubicBezier(0, 0, 1, 1)" },
// { value: 579, duration: 434, easing: "cubicBezier(0,0,0.95,0.37)" }
// ]
// },
// 167
// )
// .add(
// {
// targets: "#winloding d3",
// rotate: [
// { value: -122, duration: 0, easing: "cubicBezier(0.13,0.21,0.1,0.7)" },
// { value: -2, duration: 433, easing: "cubicBezier(0.02,0.33,0.38,0.77)" },
// { value: 81, duration: 767, easing: "cubicBezier(0, 0, 1, 1)" },
// { value: 193, duration: 417, easing: "cubicBezier(0.57,0.17,0.95,0.75)" },
// { value: 345, duration: 400, easing: "cubicBezier(0,0.19,0.07,0.72)" },
// { value: 427, duration: 766, easing: "cubicBezier(0, 0, 1, 1)" },
// { value: 573, duration: 434, easing: "cubicBezier(0,0,0.95,0.37)" }
// ]
// },
// 334
// )
// .add(
// {
// targets: "#winloding d4",
// rotate: [
// { value: -128, duration: 0, easing: "cubicBezier(0.13,0.21,0.1,0.7)" },
// { value: -8, duration: 433, easing: "cubicBezier(0.02,0.33,0.38,0.77)" },
// { value: 75, duration: 767, easing: "cubicBezier(0, 0, 1, 1)" },
// { value: 187, duration: 417, easing: "cubicBezier(0.57,0.17,0.95,0.75)" },
// { value: 339, duration: 400, easing: "cubicBezier(0,0.19,0.07,0.72)" },
// { value: 421, duration: 766, easing: "cubicBezier(0, 0, 1, 1)" },
// { value: 567, duration: 434, easing: "cubicBezier(0,0,0.95,0.37)" }
// ]
// },
// 501
// )
// .add(
// {
// targets: "#winloding d5",
// rotate: [
// { value: -134, duration: 0, easing: "cubicBezier(0.13,0.21,0.1,0.7)" },
// { value: -14, duration: 433, easing: "cubicBezier(0.02,0.33,0.38,0.77)" },
// { value: 69, duration: 767, easing: "cubicBezier(0, 0, 1, 1)" },
// { value: 181, duration: 417, easing: "cubicBezier(0.57,0.17,0.95,0.75)" },
// { value: 331, duration: 400, easing: "cubicBezier(0,0.19,0.07,0.72)" },
// { value: 415, duration: 766, easing: "cubicBezier(0, 0, 1, 1)" },
// { value: 561, duration: 434, easing: "cubicBezier(0,0,0.95,0.37)" }
// ]
// },
// 668
// )
// .add(
// {
// targets: "#winloding d6",
// rotate: [
// { value: -140, duration: 0, easing: "cubicBezier(0.13,0.21,0.1,0.7)" },
// { value: -20, duration: 433, easing: "cubicBezier(0.02,0.33,0.38,0.77)" },
// { value: 63, duration: 767, easing: "cubicBezier(0, 0, 1, 1)" },
// { value: 175, duration: 417, easing: "cubicBezier(0.57,0.17,0.95,0.75)" },
// { value: 325, duration: 400, easing: "cubicBezier(0,0.19,0.07,0.72)" },
// { value: 409, duration: 766, easing: "cubicBezier(0, 0, 1, 1)" },
// { value: 555, duration: 434, easing: "cubicBezier(0,0,0.95,0.37)" }
// ]
// },
// 835
// );
// #endregion
for (let i = 0; i < 6; i++) {
let basevalue = -110 - 6 * i;
tl.add(
{
targets: "#winloding .d" + (i + 1),
rotate: [
{
value: basevalue, duration: 0, easing: "cubicBezier(0.13,0.21,0.1,0.7)" },
{
value: basevalue + 120, duration: 433, easing: "cubicBezier(0.02,0.33,0.38,0.77)" },
{
value: basevalue + 203, duration: 767, easing: "linear" },
{
value: basevalue + 315, duration: 417, easing: "cubicBezier(0.57,0.17,0.95,0.75)" },
{
value: basevalue + 467, duration: 400, easing: "cubicBezier(0,0.19,0.07,0.72)" },
{
value: basevalue + 549, duration: 766, easing: "linear" },
{
value: basevalue + 695, duration: 434, easing: "cubicBezier(0,0,0.95,0.37)" }
],
opacity: [
{
value: 1, duration: 1, easing: "linear" },
{
value: 1, duration: 3210, easing: "linear" },
{
value: 0, duration: 10, easing: "linear" },
{
value: 0, duration: 260, easing: "linear" }
]
},
167 * i
);
}
ring.timeline = tl;
ring.svgitem = loadingring;
return ring;
}
JS中的参数与WPF一模一样,这应该是最贴近Win10原版的动画样式了[狗头](不常用JS,写的不好请见谅)。
解释一下 (*)标注的问题,由于WPF动画不能将动画参数作为动态绑定源,因此和UWP中的实现是稍微有区别的,不是复制粘贴就行