預覽
廢話不多說,先來預覽一下效果(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中的實現是稍微有區別的,不是複製粘貼就行