[{"data":1,"prerenderedAt":2397},["ShallowReactive",2],{"page-\u002Fcsharp\u002Favalonia\u002Favalonia的动画":3},{"id":4,"title":5,"body":6,"description":12,"extension":2391,"meta":2392,"navigation":1643,"path":2393,"seo":2394,"stem":2395,"__hash__":2396},"content\u002Fcsharp\u002FAvalonia\u002Favalonia的动画：.md","Avalonia的动画：",{"type":7,"value":8,"toc":2360},"minimark",[9,13,16,24,65,71,132,138,153,159,187,193,220,226,240,246,260,266,280,286,300,303,329,332,379,382,839,842,846,866,870,890,894,914,918,938,942,962,966,986,990,1010,1014,1034,1038,1058,1061,1069,1074,1077,1377,1380,1385,1413,1418,1444,1449,1463,1468,1486,1491,1509,1515,1541,1546,1566,1569,1601,1604,1672,1682,1767,1770,1777,1791,1803,1811,1818,2353,2356],[10,11,12],"p",{},"我们最常使用到的是avalonia的属性动画，比如Transitions标签，我们经常在style标签里去定义Property去指定Transitions，然后在Transitions标签中去影响所有的过渡类型。",[10,14,15],{},"根据Avalonia的实现，Transitions集合支持以下的过渡类型：",[17,18,20],"h3",{"id":19},"doubletransition",[21,22,23],"strong",{},"DoubleTransition",[25,26,27,39,59],"ul",{},[28,29,30,33,34,38],"li",{},[21,31,32],{},"Property 支持",": 所有 ",[35,36,37],"code",{},"double"," 类型的属性 XamlIlTests.cs:31-33",[28,40,41,44,45,48,49,48,52,48,55,58],{},[21,42,43],{},"常见属性",": ",[35,46,47],{},"Opacity","、",[35,50,51],{},"Width",[35,53,54],{},"Height",[35,56,57],{},"FontSize"," 等 ScrollBar.xaml:74",[28,60,61,64],{},[21,62,63],{},"影响的变换",": 数值的平滑过渡",[17,66,68],{"id":67},"transformoperationstransition",[21,69,70],{},"TransformOperationsTransition",[25,72,73,81],{},[28,74,75,44,77,80],{},[21,76,32],{},[35,78,79],{},"RenderTransform"," 属性 TransitionsPage.xaml:49",[28,82,83,86,87],{},[21,84,85],{},"支持的变换函数",":\n",[25,88,89,102,114,120],{},[28,90,91,94,95,94,98,101],{},[35,92,93],{},"translateX()"," \u002F ",[35,96,97],{},"translateY()",[35,99,100],{},"translate()"," - 平移",[28,103,104,94,107,94,110,113],{},[35,105,106],{},"scaleX()",[35,108,109],{},"scaleY()",[35,111,112],{},"scale()"," - 缩放",[28,115,116,119],{},[35,117,118],{},"rotate()"," - 旋转",[28,121,122,94,125,94,128,131],{},[35,123,124],{},"skewX()",[35,126,127],{},"skewY()",[35,129,130],{},"skew()"," - 倾斜",[17,133,135],{"id":134},"cornerradiustransition",[21,136,137],{},"CornerRadiusTransition",[25,139,140,148],{},[28,141,142,44,144,147],{},[21,143,32],{},[35,145,146],{},"CornerRadius"," 属性 ScrollBar.xaml:33",[28,149,150,152],{},[21,151,63],{},": 圆角半径的平滑过渡",[17,154,156],{"id":155},"thicknesstransition",[21,157,158],{},"ThicknessTransition",[25,160,161,169,182],{},[28,162,163,44,165,168],{},[21,164,32],{},[35,166,167],{},"Thickness"," 类型的属性",[28,170,171,44,173,48,176,48,179],{},[21,172,43],{},[35,174,175],{},"Margin",[35,177,178],{},"Padding",[35,180,181],{},"BorderThickness",[28,183,184,186],{},[21,185,63],{},": 边距\u002F内边距的平滑过渡",[17,188,190],{"id":189},"brushtransition",[21,191,192],{},"BrushTransition",[25,194,195,202,215],{},[28,196,197,44,199,168],{},[21,198,32],{},[35,200,201],{},"IBrush",[28,203,204,44,206,48,209,48,212],{},[21,205,43],{},[35,207,208],{},"Background",[35,210,211],{},"Foreground",[35,213,214],{},"BorderBrush",[28,216,217,219],{},[21,218,63],{},": 颜色\u002F画刷的平滑过渡",[17,221,223],{"id":222},"floattransition",[21,224,225],{},"FloatTransition",[25,227,228,235],{},[28,229,230,44,232,168],{},[21,231,32],{},[35,233,234],{},"float",[28,236,237,239],{},[21,238,63],{},": 浮点数值的平滑过渡",[17,241,243],{"id":242},"vectortransition",[21,244,245],{},"VectorTransition",[25,247,248,255],{},[28,249,250,44,252,168],{},[21,251,32],{},[35,253,254],{},"Vector",[28,256,257,259],{},[21,258,63],{},": 向量值的平滑过渡",[17,261,263],{"id":262},"pointtransition",[21,264,265],{},"PointTransition",[25,267,268,275],{},[28,269,270,44,272,168],{},[21,271,32],{},[35,273,274],{},"Point",[28,276,277,279],{},[21,278,63],{},": 点坐标的平滑过渡",[17,281,283],{"id":282},"sizetransition",[21,284,285],{},"SizeTransition",[25,287,288,295],{},[28,289,290,44,292,168],{},[21,291,32],{},[35,293,294],{},"Size",[28,296,297,299],{},[21,298,63],{},": 尺寸的平滑过渡",[10,301,302],{},"所有的过渡类型都是继承自TransitionBase，因此都是支持以下的属性的：",[25,304,305,311,317,323],{},[28,306,307,310],{},[21,308,309],{},"Duration",": 过渡持续时间 TransitionBase.cs:57-61",[28,312,313,316],{},[21,314,315],{},"Delay",": 延迟开始时间 TransitionBase.cs:66-70",[28,318,319,322],{},[21,320,321],{},"Easing",": 缓动函数 TransitionBase.cs:75-79",[28,324,325,328],{},[21,326,327],{},"Property",": 要过渡的属性 TransitionBase.cs:83-87",[10,330,331],{},"这些过渡类型都是可以组合使用的，比如说我们常见的SchrollBar组件：",[333,334,339],"pre",{"className":335,"code":336,"language":337,"meta":338,"style":338},"language-XAML shiki shiki-themes github-light github-dark"," \u003CSetter Property=\"Transitions\">\n      \u003CTransitions>\n        \u003CCornerRadiusTransition Property=\"CornerRadius\" Duration=\"0:0:0.1\" \u002F>\n        \u003CTransformOperationsTransition Property=\"RenderTransform\" Duration=\"0:0:0.1\" \u002F>\n      \u003C\u002FTransitions>\n    \u003C\u002FSetter>\n","XAML","",[35,340,341,349,355,361,367,373],{"__ignoreMap":338},[342,343,346],"span",{"class":344,"line":345},"line",1,[342,347,348],{}," \u003CSetter Property=\"Transitions\">\n",[342,350,352],{"class":344,"line":351},2,[342,353,354],{},"      \u003CTransitions>\n",[342,356,358],{"class":344,"line":357},3,[342,359,360],{},"        \u003CCornerRadiusTransition Property=\"CornerRadius\" Duration=\"0:0:0.1\" \u002F>\n",[342,362,364],{"class":344,"line":363},4,[342,365,366],{},"        \u003CTransformOperationsTransition Property=\"RenderTransform\" Duration=\"0:0:0.1\" \u002F>\n",[342,368,370],{"class":344,"line":369},5,[342,371,372],{},"      \u003C\u002FTransitions>\n",[342,374,376],{"class":344,"line":375},6,[342,377,378],{},"    \u003C\u002FSetter>\n",[10,380,381],{},"过渡类型都是实现了ITransition接口的，过渡只有在被附加到了可视树的时候才会生效。其中我们的TransformOperationsTransition是最为灵活的，可以处理所有的2D变换组合。",[333,383,387],{"className":384,"code":385,"language":386,"meta":338,"style":338},"language-c# shiki shiki-themes github-light github-dark","namespace Avalonia.Animation  \n{  \n    \u002F\u002F\u002F \u003Csummary>  \n    \u002F\u002F\u002F Defines how a property should be animated using a transition.    \u002F\u002F\u002F \u003C\u002Fsummary>    public abstract class TransitionBase : AvaloniaObject, ITransition  \n    {  \n        \u002F\u002F\u002F \u003Csummary>  \n        \u002F\u002F\u002F Defines the \u003Csee cref=\"Duration\"\u002F> property.        \u002F\u002F\u002F \u003C\u002Fsummary>        public static readonly DirectProperty\u003CTransitionBase, TimeSpan> DurationProperty =  \n            AvaloniaProperty.RegisterDirect\u003CTransitionBase, TimeSpan>(  \n                nameof(Duration),  \n                o => o._duration,  \n                (o, v) => o._duration = v);  \n        \u002F\u002F\u002F \u003Csummary>  \n        \u002F\u002F\u002F Defines the \u003Csee cref=\"Delay\"\u002F> property.        \u002F\u002F\u002F \u003C\u002Fsummary>        public static readonly DirectProperty\u003CTransitionBase, TimeSpan> DelayProperty =  \n            AvaloniaProperty.RegisterDirect\u003CTransitionBase, TimeSpan>(  \n                nameof(Delay),  \n                o => o._delay,  \n                (o, v) => o._delay = v);  \n        \u002F\u002F\u002F \u003Csummary>  \n        \u002F\u002F\u002F Defines the \u003Csee cref=\"Easing\"\u002F> property.        \u002F\u002F\u002F \u003C\u002Fsummary>        public static readonly DirectProperty\u003CTransitionBase, Easing> EasingProperty =  \n            AvaloniaProperty.RegisterDirect\u003CTransitionBase, Easing>(  \n                nameof(Easing),  \n                o => o._easing,  \n                (o, v) => o._easing = v);  \n        \u002F\u002F\u002F \u003Csummary>  \n        \u002F\u002F\u002F Defines the \u003Csee cref=\"Property\"\u002F> property.        \u002F\u002F\u002F \u003C\u002Fsummary>        public static readonly DirectProperty\u003CTransitionBase, AvaloniaProperty?> PropertyProperty =  \n            AvaloniaProperty.RegisterDirect\u003CTransitionBase, AvaloniaProperty?>(  \n                nameof(Property),  \n                o => o._prop,  \n                (o, v) => o._prop = v);  \n  \n        private TimeSpan _duration;  \n        private TimeSpan _delay = TimeSpan.Zero;  \n        private Easing _easing = new LinearEasing();  \n        private AvaloniaProperty? _prop;  \n  \n        \u002F\u002F\u002F \u003Csummary>  \n        \u002F\u002F\u002F Gets or sets the duration of the transition.        \u002F\u002F\u002F \u003C\u002Fsummary>public TimeSpan Duration  \n        {  \n            get { return _duration; }  \n            set { SetAndRaise(DurationProperty, ref _duration, value); }  \n        }  \n        \u002F\u002F\u002F \u003Csummary>  \n        \u002F\u002F\u002F Gets or sets delay before starting the transition.        \u002F\u002F\u002F \u003C\u002Fsummary>public TimeSpan Delay  \n        {  \n            get { return _delay; }  \n            set { SetAndRaise(DelayProperty, ref _delay, value); }  \n        }  \n        \u002F\u002F\u002F \u003Csummary>  \n        \u002F\u002F\u002F Gets the easing class to be used.        \u002F\u002F\u002F \u003C\u002Fsummary>        public Easing Easing  \n        {  \n            get { return _easing; }  \n            set { SetAndRaise(EasingProperty, ref _easing, value); }  \n        }  \n        \u002F\u002F\u002F \u003Cinheritdoc\u002F>  \n        [DisallowNull]  \n        public AvaloniaProperty? Property  \n        {  \n            get { return _prop; }  \n            set { SetAndRaise(PropertyProperty, ref _prop, value); }  \n        }  \n        AvaloniaProperty ITransition.Property  \n        {  \n            get => Property ?? throw new InvalidOperationException(\"Transition has no property specified.\");  \n            set => Property = value;  \n        }  \n        \u002F\u002F\u002F \u003Cinheritdoc\u002F>  \n        IDisposable ITransition.Apply(Animatable control, IClock clock, object? oldValue, object? newValue)  \n            => Apply(control, clock, oldValue, newValue);  \n        internal abstract IDisposable Apply(Animatable control, IClock clock, object? oldValue, object? newValue);  \n  \n        internal override void BuildDebugDisplay(StringBuilder builder, bool includeContent)  \n        {            base.BuildDebugDisplay(builder, includeContent);  \n            DebugDisplayHelper.AppendOptionalValue(builder, nameof(Property), Property, includeContent);  \n            DebugDisplayHelper.AppendOptionalValue(builder, nameof(Duration), Duration, includeContent);  \n        }    }\n","c#",[35,388,389,394,399,404,412,417,422,431,437,443,449,455,460,469,474,480,486,492,497,506,512,518,524,530,535,544,550,556,562,568,574,580,586,592,598,603,608,617,623,629,635,641,646,655,660,666,672,677,682,691,696,702,708,713,719,725,731,736,742,748,753,759,764,770,776,781,786,792,798,804,809,815,821,827,833],{"__ignoreMap":338},[342,390,391],{"class":344,"line":345},[342,392,393],{},"namespace Avalonia.Animation  \n",[342,395,396],{"class":344,"line":351},[342,397,398],{},"{  \n",[342,400,401],{"class":344,"line":357},[342,402,403],{},"    \u002F\u002F\u002F \u003Csummary>  \n",[342,405,406,409],{"class":344,"line":363},[342,407,408],{},"    \u002F\u002F\u002F Defines how a property should be animated using a transition.",[342,410,411],{},"    \u002F\u002F\u002F \u003C\u002Fsummary>    public abstract class TransitionBase : AvaloniaObject, ITransition  \n",[342,413,414],{"class":344,"line":369},[342,415,416],{},"    {  \n",[342,418,419],{"class":344,"line":375},[342,420,421],{},"        \u002F\u002F\u002F \u003Csummary>  \n",[342,423,425,428],{"class":344,"line":424},7,[342,426,427],{},"        \u002F\u002F\u002F Defines the \u003Csee cref=\"Duration\"\u002F> property.",[342,429,430],{},"        \u002F\u002F\u002F \u003C\u002Fsummary>        public static readonly DirectProperty\u003CTransitionBase, TimeSpan> DurationProperty =  \n",[342,432,434],{"class":344,"line":433},8,[342,435,436],{},"            AvaloniaProperty.RegisterDirect\u003CTransitionBase, TimeSpan>(  \n",[342,438,440],{"class":344,"line":439},9,[342,441,442],{},"                nameof(Duration),  \n",[342,444,446],{"class":344,"line":445},10,[342,447,448],{},"                o => o._duration,  \n",[342,450,452],{"class":344,"line":451},11,[342,453,454],{},"                (o, v) => o._duration = v);  \n",[342,456,458],{"class":344,"line":457},12,[342,459,421],{},[342,461,463,466],{"class":344,"line":462},13,[342,464,465],{},"        \u002F\u002F\u002F Defines the \u003Csee cref=\"Delay\"\u002F> property.",[342,467,468],{},"        \u002F\u002F\u002F \u003C\u002Fsummary>        public static readonly DirectProperty\u003CTransitionBase, TimeSpan> DelayProperty =  \n",[342,470,472],{"class":344,"line":471},14,[342,473,436],{},[342,475,477],{"class":344,"line":476},15,[342,478,479],{},"                nameof(Delay),  \n",[342,481,483],{"class":344,"line":482},16,[342,484,485],{},"                o => o._delay,  \n",[342,487,489],{"class":344,"line":488},17,[342,490,491],{},"                (o, v) => o._delay = v);  \n",[342,493,495],{"class":344,"line":494},18,[342,496,421],{},[342,498,500,503],{"class":344,"line":499},19,[342,501,502],{},"        \u002F\u002F\u002F Defines the \u003Csee cref=\"Easing\"\u002F> property.",[342,504,505],{},"        \u002F\u002F\u002F \u003C\u002Fsummary>        public static readonly DirectProperty\u003CTransitionBase, Easing> EasingProperty =  \n",[342,507,509],{"class":344,"line":508},20,[342,510,511],{},"            AvaloniaProperty.RegisterDirect\u003CTransitionBase, Easing>(  \n",[342,513,515],{"class":344,"line":514},21,[342,516,517],{},"                nameof(Easing),  \n",[342,519,521],{"class":344,"line":520},22,[342,522,523],{},"                o => o._easing,  \n",[342,525,527],{"class":344,"line":526},23,[342,528,529],{},"                (o, v) => o._easing = v);  \n",[342,531,533],{"class":344,"line":532},24,[342,534,421],{},[342,536,538,541],{"class":344,"line":537},25,[342,539,540],{},"        \u002F\u002F\u002F Defines the \u003Csee cref=\"Property\"\u002F> property.",[342,542,543],{},"        \u002F\u002F\u002F \u003C\u002Fsummary>        public static readonly DirectProperty\u003CTransitionBase, AvaloniaProperty?> PropertyProperty =  \n",[342,545,547],{"class":344,"line":546},26,[342,548,549],{},"            AvaloniaProperty.RegisterDirect\u003CTransitionBase, AvaloniaProperty?>(  \n",[342,551,553],{"class":344,"line":552},27,[342,554,555],{},"                nameof(Property),  \n",[342,557,559],{"class":344,"line":558},28,[342,560,561],{},"                o => o._prop,  \n",[342,563,565],{"class":344,"line":564},29,[342,566,567],{},"                (o, v) => o._prop = v);  \n",[342,569,571],{"class":344,"line":570},30,[342,572,573],{},"  \n",[342,575,577],{"class":344,"line":576},31,[342,578,579],{},"        private TimeSpan _duration;  \n",[342,581,583],{"class":344,"line":582},32,[342,584,585],{},"        private TimeSpan _delay = TimeSpan.Zero;  \n",[342,587,589],{"class":344,"line":588},33,[342,590,591],{},"        private Easing _easing = new LinearEasing();  \n",[342,593,595],{"class":344,"line":594},34,[342,596,597],{},"        private AvaloniaProperty? _prop;  \n",[342,599,601],{"class":344,"line":600},35,[342,602,573],{},[342,604,606],{"class":344,"line":605},36,[342,607,421],{},[342,609,611,614],{"class":344,"line":610},37,[342,612,613],{},"        \u002F\u002F\u002F Gets or sets the duration of the transition.",[342,615,616],{},"        \u002F\u002F\u002F \u003C\u002Fsummary>public TimeSpan Duration  \n",[342,618,620],{"class":344,"line":619},38,[342,621,622],{},"        {  \n",[342,624,626],{"class":344,"line":625},39,[342,627,628],{},"            get { return _duration; }  \n",[342,630,632],{"class":344,"line":631},40,[342,633,634],{},"            set { SetAndRaise(DurationProperty, ref _duration, value); }  \n",[342,636,638],{"class":344,"line":637},41,[342,639,640],{},"        }  \n",[342,642,644],{"class":344,"line":643},42,[342,645,421],{},[342,647,649,652],{"class":344,"line":648},43,[342,650,651],{},"        \u002F\u002F\u002F Gets or sets delay before starting the transition.",[342,653,654],{},"        \u002F\u002F\u002F \u003C\u002Fsummary>public TimeSpan Delay  \n",[342,656,658],{"class":344,"line":657},44,[342,659,622],{},[342,661,663],{"class":344,"line":662},45,[342,664,665],{},"            get { return _delay; }  \n",[342,667,669],{"class":344,"line":668},46,[342,670,671],{},"            set { SetAndRaise(DelayProperty, ref _delay, value); }  \n",[342,673,675],{"class":344,"line":674},47,[342,676,640],{},[342,678,680],{"class":344,"line":679},48,[342,681,421],{},[342,683,685,688],{"class":344,"line":684},49,[342,686,687],{},"        \u002F\u002F\u002F Gets the easing class to be used.",[342,689,690],{},"        \u002F\u002F\u002F \u003C\u002Fsummary>        public Easing Easing  \n",[342,692,694],{"class":344,"line":693},50,[342,695,622],{},[342,697,699],{"class":344,"line":698},51,[342,700,701],{},"            get { return _easing; }  \n",[342,703,705],{"class":344,"line":704},52,[342,706,707],{},"            set { SetAndRaise(EasingProperty, ref _easing, value); }  \n",[342,709,711],{"class":344,"line":710},53,[342,712,640],{},[342,714,716],{"class":344,"line":715},54,[342,717,718],{},"        \u002F\u002F\u002F \u003Cinheritdoc\u002F>  \n",[342,720,722],{"class":344,"line":721},55,[342,723,724],{},"        [DisallowNull]  \n",[342,726,728],{"class":344,"line":727},56,[342,729,730],{},"        public AvaloniaProperty? Property  \n",[342,732,734],{"class":344,"line":733},57,[342,735,622],{},[342,737,739],{"class":344,"line":738},58,[342,740,741],{},"            get { return _prop; }  \n",[342,743,745],{"class":344,"line":744},59,[342,746,747],{},"            set { SetAndRaise(PropertyProperty, ref _prop, value); }  \n",[342,749,751],{"class":344,"line":750},60,[342,752,640],{},[342,754,756],{"class":344,"line":755},61,[342,757,758],{},"        AvaloniaProperty ITransition.Property  \n",[342,760,762],{"class":344,"line":761},62,[342,763,622],{},[342,765,767],{"class":344,"line":766},63,[342,768,769],{},"            get => Property ?? throw new InvalidOperationException(\"Transition has no property specified.\");  \n",[342,771,773],{"class":344,"line":772},64,[342,774,775],{},"            set => Property = value;  \n",[342,777,779],{"class":344,"line":778},65,[342,780,640],{},[342,782,784],{"class":344,"line":783},66,[342,785,718],{},[342,787,789],{"class":344,"line":788},67,[342,790,791],{},"        IDisposable ITransition.Apply(Animatable control, IClock clock, object? oldValue, object? newValue)  \n",[342,793,795],{"class":344,"line":794},68,[342,796,797],{},"            => Apply(control, clock, oldValue, newValue);  \n",[342,799,801],{"class":344,"line":800},69,[342,802,803],{},"        internal abstract IDisposable Apply(Animatable control, IClock clock, object? oldValue, object? newValue);  \n",[342,805,807],{"class":344,"line":806},70,[342,808,573],{},[342,810,812],{"class":344,"line":811},71,[342,813,814],{},"        internal override void BuildDebugDisplay(StringBuilder builder, bool includeContent)  \n",[342,816,818],{"class":344,"line":817},72,[342,819,820],{},"        {            base.BuildDebugDisplay(builder, includeContent);  \n",[342,822,824],{"class":344,"line":823},73,[342,825,826],{},"            DebugDisplayHelper.AppendOptionalValue(builder, nameof(Property), Property, includeContent);  \n",[342,828,830],{"class":344,"line":829},74,[342,831,832],{},"            DebugDisplayHelper.AppendOptionalValue(builder, nameof(Duration), Duration, includeContent);  \n",[342,834,836],{"class":344,"line":835},75,[342,837,838],{},"        }    }\n",[10,840,841],{},"现在我们来讲一下常用的Easing效果，比较常用的有平滑过渡，线性的，二阶的、三阶的，还有可以创造出复杂动画效果的弹簧振子。",[17,843,845],{"id":844},"二次方缓动-quadratic","二次方缓动 (Quadratic)",[25,847,848,854,860],{},[28,849,850,853],{},[21,851,852],{},"QuadraticEaseIn"," - 二次方加速",[28,855,856,859],{},[21,857,858],{},"QuadraticEaseOut"," - 二次方减速",[28,861,862,865],{},[21,863,864],{},"QuadraticEaseInOut"," - 二次方先加速后减速",[17,867,869],{"id":868},"三次方缓动-cubic","三次方缓动 (Cubic)",[25,871,872,878,884],{},[28,873,874,877],{},[21,875,876],{},"CubicEaseIn"," - 三次方加速",[28,879,880,883],{},[21,881,882],{},"CubicEaseOut"," - 三次方减速",[28,885,886,889],{},[21,887,888],{},"CubicEaseInOut"," - 三次方先加速后减速",[17,891,893],{"id":892},"四次方缓动-quartic","四次方缓动 (Quartic)",[25,895,896,902,908],{},[28,897,898,901],{},[21,899,900],{},"QuarticEaseIn"," - 四次方加速",[28,903,904,907],{},[21,905,906],{},"QuarticEaseOut"," - 四次方减速",[28,909,910,913],{},[21,911,912],{},"QuarticEaseInOut"," - 四次方先加速后减速",[17,915,917],{"id":916},"五次方缓动-quintic","五次方缓动 (Quintic)",[25,919,920,926,932],{},[28,921,922,925],{},[21,923,924],{},"QuinticEaseIn"," - 五次方加速",[28,927,928,931],{},[21,929,930],{},"QuinticEaseOut"," - 五次方减速",[28,933,934,937],{},[21,935,936],{},"QuinticEaseInOut"," - 五次方先加速后减速",[17,939,941],{"id":940},"指数缓动-exponential","指数缓动 (Exponential)",[25,943,944,950,956],{},[28,945,946,949],{},[21,947,948],{},"ExponentialEaseIn"," - 指数加速",[28,951,952,955],{},[21,953,954],{},"ExponentialEaseOut"," - 指数减速",[28,957,958,961],{},[21,959,960],{},"ExponentialEaseInOut"," - 指数先加速后减速",[17,963,965],{"id":964},"圆形缓动-circular","圆形缓动 (Circular)",[25,967,968,974,980],{},[28,969,970,973],{},[21,971,972],{},"CircularEaseIn"," - 圆形加速",[28,975,976,979],{},[21,977,978],{},"CircularEaseOut"," - 圆形减速",[28,981,982,985],{},[21,983,984],{},"CircularEaseInOut"," - 圆形先加速后减速",[17,987,989],{"id":988},"回弹缓动-back","回弹缓动 (Back)",[25,991,992,998,1004],{},[28,993,994,997],{},[21,995,996],{},"BackEaseIn"," - 回弹加速(先后退再前进)",[28,999,1000,1003],{},[21,1001,1002],{},"BackEaseOut"," - 回弹减速(超过目标后回弹) KeySplineTests.cs:219-220",[28,1005,1006,1009],{},[21,1007,1008],{},"BackEaseInOut"," - 回弹先加速后减速",[17,1011,1013],{"id":1012},"弹性缓动-elastic","弹性缓动 (Elastic)",[25,1015,1016,1022,1028],{},[28,1017,1018,1021],{},[21,1019,1020],{},"ElasticEaseIn"," - 弹性加速(震荡加速)",[28,1023,1024,1027],{},[21,1025,1026],{},"ElasticEaseOut"," - 弹性减速(震荡减速) KeySplineTests.cs:223",[28,1029,1030,1033],{},[21,1031,1032],{},"ElasticEaseInOut"," - 弹性先加速后减速",[17,1035,1037],{"id":1036},"弹跳缓动-bounce","弹跳缓动 (Bounce)",[25,1039,1040,1046,1052],{},[28,1041,1042,1045],{},[21,1043,1044],{},"BounceEaseIn"," - 弹跳加速",[28,1047,1048,1051],{},[21,1049,1050],{},"BounceEaseOut"," - 弹跳减速 BounceEaseUtils.cs:14",[28,1053,1054,1057],{},[21,1055,1056],{},"BounceEaseInOut"," - 弹跳先加速后减速",[17,1059,1060],{"id":1060},"自定义贝塞尔曲线",[25,1062,1063],{},[28,1064,1065,1068],{},[21,1066,1067],{},"SplineEasing"," - 使用自定义三次贝塞尔曲线控制点 (X1, Y1, X2, Y2) SplineEasing.cs:9",[1070,1071,1073],"h2",{"id":1072},"animation支持的数值类型","Animation支持的数值类型",[10,1075,1076],{},"我们在avalonia里经常使用Animations，比如我们常常创建一个延迟透明度和Translate平移的组合动画，通过设定visual对象和自定义动画关键字和延迟的方式创建：",[333,1078,1080],{"className":384,"code":1079,"language":386,"meta":338,"style":338},"private void TranslateAnimation()    {      \nScrollViewer navigationScrollViewer = NaviScrollViewer;      \nif (navigationScrollViewer.Content is StackPanel stackPanel)      \n    {      \nvar children = stackPanel.Children;      \nforeach (var child in children)      \n        {      \nchild.RenderTransform = new TranslateTransform(-50, 0);    \nchild.Opacity = 0;  \n        }for (int i = 0; i \u003C children.Count; i++)      \n        {      \nvar child = children[i];      \nvar delay = TimeSpan.FromMilliseconds(i * 200);      \nvar animation = new Animation      \n{      \nDuration = TimeSpan.FromMilliseconds(500),      \nDelay = delay,      \nFillMode = FillMode.Forward,      \nEasing = new BackEaseOut(),  \n                Children =      \n                {      \nnew KeyFrame      \n{      \nCue = new Cue(0),      \nSetters =      \n                        {      \nnew Setter(TranslateTransform.XProperty, -50.0),  \u002F\u002F 关键:作为附加属性使用    \n}      \n                    },      \nnew KeyFrame      \n{      \nCue = new Cue(1),      \nSetters =      \n                        {      \nnew Setter(TranslateTransform.XProperty, 0.0),    \n}      \n                    }      \n                }      \n            };  \n            var animation_opacity = new Animation  \n            {  \n                Duration = TimeSpan.FromMilliseconds(500),  \n                Delay = delay,  \n                FillMode = FillMode.Forward,  \n                Children =  \n                {                    new KeyFrame  \n                    {  \n                        Cue = new Cue(0),  \n                        Setters =  \n                        {                            new Setter(OpacityProperty, 0.0),  \n                        }  \n                    },                    new KeyFrame  \n                    {  \n                        Cue = new Cue(1),  \n                        Setters =  \n                        {                            new Setter(OpacityProperty, 1.0),  \n                        }  \n                    }                }            };            animation_opacity.RunAsync(child);  \n            animation.RunAsync(child);    \n        }      \n}    }\n",[35,1081,1082,1087,1092,1097,1102,1107,1112,1117,1122,1127,1132,1136,1141,1146,1151,1156,1161,1166,1171,1176,1181,1186,1191,1195,1200,1205,1210,1215,1220,1225,1229,1233,1238,1242,1246,1251,1255,1260,1265,1270,1275,1280,1285,1290,1295,1300,1305,1310,1315,1320,1325,1330,1335,1339,1344,1348,1353,1357,1362,1367,1372],{"__ignoreMap":338},[342,1083,1084],{"class":344,"line":345},[342,1085,1086],{},"private void TranslateAnimation()    {      \n",[342,1088,1089],{"class":344,"line":351},[342,1090,1091],{},"ScrollViewer navigationScrollViewer = NaviScrollViewer;      \n",[342,1093,1094],{"class":344,"line":357},[342,1095,1096],{},"if (navigationScrollViewer.Content is StackPanel stackPanel)      \n",[342,1098,1099],{"class":344,"line":363},[342,1100,1101],{},"    {      \n",[342,1103,1104],{"class":344,"line":369},[342,1105,1106],{},"var children = stackPanel.Children;      \n",[342,1108,1109],{"class":344,"line":375},[342,1110,1111],{},"foreach (var child in children)      \n",[342,1113,1114],{"class":344,"line":424},[342,1115,1116],{},"        {      \n",[342,1118,1119],{"class":344,"line":433},[342,1120,1121],{},"child.RenderTransform = new TranslateTransform(-50, 0);    \n",[342,1123,1124],{"class":344,"line":439},[342,1125,1126],{},"child.Opacity = 0;  \n",[342,1128,1129],{"class":344,"line":445},[342,1130,1131],{},"        }for (int i = 0; i \u003C children.Count; i++)      \n",[342,1133,1134],{"class":344,"line":451},[342,1135,1116],{},[342,1137,1138],{"class":344,"line":457},[342,1139,1140],{},"var child = children[i];      \n",[342,1142,1143],{"class":344,"line":462},[342,1144,1145],{},"var delay = TimeSpan.FromMilliseconds(i * 200);      \n",[342,1147,1148],{"class":344,"line":471},[342,1149,1150],{},"var animation = new Animation      \n",[342,1152,1153],{"class":344,"line":476},[342,1154,1155],{},"{      \n",[342,1157,1158],{"class":344,"line":482},[342,1159,1160],{},"Duration = TimeSpan.FromMilliseconds(500),      \n",[342,1162,1163],{"class":344,"line":488},[342,1164,1165],{},"Delay = delay,      \n",[342,1167,1168],{"class":344,"line":494},[342,1169,1170],{},"FillMode = FillMode.Forward,      \n",[342,1172,1173],{"class":344,"line":499},[342,1174,1175],{},"Easing = new BackEaseOut(),  \n",[342,1177,1178],{"class":344,"line":508},[342,1179,1180],{},"                Children =      \n",[342,1182,1183],{"class":344,"line":514},[342,1184,1185],{},"                {      \n",[342,1187,1188],{"class":344,"line":520},[342,1189,1190],{},"new KeyFrame      \n",[342,1192,1193],{"class":344,"line":526},[342,1194,1155],{},[342,1196,1197],{"class":344,"line":532},[342,1198,1199],{},"Cue = new Cue(0),      \n",[342,1201,1202],{"class":344,"line":537},[342,1203,1204],{},"Setters =      \n",[342,1206,1207],{"class":344,"line":546},[342,1208,1209],{},"                        {      \n",[342,1211,1212],{"class":344,"line":552},[342,1213,1214],{},"new Setter(TranslateTransform.XProperty, -50.0),  \u002F\u002F 关键:作为附加属性使用    \n",[342,1216,1217],{"class":344,"line":558},[342,1218,1219],{},"}      \n",[342,1221,1222],{"class":344,"line":564},[342,1223,1224],{},"                    },      \n",[342,1226,1227],{"class":344,"line":570},[342,1228,1190],{},[342,1230,1231],{"class":344,"line":576},[342,1232,1155],{},[342,1234,1235],{"class":344,"line":582},[342,1236,1237],{},"Cue = new Cue(1),      \n",[342,1239,1240],{"class":344,"line":588},[342,1241,1204],{},[342,1243,1244],{"class":344,"line":594},[342,1245,1209],{},[342,1247,1248],{"class":344,"line":600},[342,1249,1250],{},"new Setter(TranslateTransform.XProperty, 0.0),    \n",[342,1252,1253],{"class":344,"line":605},[342,1254,1219],{},[342,1256,1257],{"class":344,"line":610},[342,1258,1259],{},"                    }      \n",[342,1261,1262],{"class":344,"line":619},[342,1263,1264],{},"                }      \n",[342,1266,1267],{"class":344,"line":625},[342,1268,1269],{},"            };  \n",[342,1271,1272],{"class":344,"line":631},[342,1273,1274],{},"            var animation_opacity = new Animation  \n",[342,1276,1277],{"class":344,"line":637},[342,1278,1279],{},"            {  \n",[342,1281,1282],{"class":344,"line":643},[342,1283,1284],{},"                Duration = TimeSpan.FromMilliseconds(500),  \n",[342,1286,1287],{"class":344,"line":648},[342,1288,1289],{},"                Delay = delay,  \n",[342,1291,1292],{"class":344,"line":657},[342,1293,1294],{},"                FillMode = FillMode.Forward,  \n",[342,1296,1297],{"class":344,"line":662},[342,1298,1299],{},"                Children =  \n",[342,1301,1302],{"class":344,"line":668},[342,1303,1304],{},"                {                    new KeyFrame  \n",[342,1306,1307],{"class":344,"line":674},[342,1308,1309],{},"                    {  \n",[342,1311,1312],{"class":344,"line":679},[342,1313,1314],{},"                        Cue = new Cue(0),  \n",[342,1316,1317],{"class":344,"line":684},[342,1318,1319],{},"                        Setters =  \n",[342,1321,1322],{"class":344,"line":693},[342,1323,1324],{},"                        {                            new Setter(OpacityProperty, 0.0),  \n",[342,1326,1327],{"class":344,"line":698},[342,1328,1329],{},"                        }  \n",[342,1331,1332],{"class":344,"line":704},[342,1333,1334],{},"                    },                    new KeyFrame  \n",[342,1336,1337],{"class":344,"line":710},[342,1338,1309],{},[342,1340,1341],{"class":344,"line":715},[342,1342,1343],{},"                        Cue = new Cue(1),  \n",[342,1345,1346],{"class":344,"line":721},[342,1347,1319],{},[342,1349,1350],{"class":344,"line":727},[342,1351,1352],{},"                        {                            new Setter(OpacityProperty, 1.0),  \n",[342,1354,1355],{"class":344,"line":733},[342,1356,1329],{},[342,1358,1359],{"class":344,"line":738},[342,1360,1361],{},"                    }                }            };            animation_opacity.RunAsync(child);  \n",[342,1363,1364],{"class":344,"line":744},[342,1365,1366],{},"            animation.RunAsync(child);    \n",[342,1368,1369],{"class":344,"line":750},[342,1370,1371],{},"        }      \n",[342,1373,1374],{"class":344,"line":755},[342,1375,1376],{},"}    }\n",[10,1378,1379],{},"除了Opacity，还有很多属性也是可以这样使用的：",[17,1381,1383],{"id":1382},"数值类型",[21,1384,1382],{},[25,1386,1387,1401,1407],{},[28,1388,1389,44,1392,48,1394,48,1396,48,1398,1400],{},[21,1390,1391],{},"Double",[35,1393,47],{},[35,1395,51],{},[35,1397,54],{},[35,1399,57],{}," 等\u003Clink to Repo AvaloniaUI\u002FAvalonia: src\u002FAvalonia.Base\u002FVisual.cs:64-65>\u003Clink to Repo AvaloniaUI\u002FAvalonia: tests\u002FAvalonia.Base.UnitTests\u002FAnimation\u002FAnimatableTests.cs:461-469>",[28,1402,1403,1406],{},[21,1404,1405],{},"Float",": 浮点数属性",[28,1408,1409,1412],{},[21,1410,1411],{},"Integer",": 整数属性",[17,1414,1416],{"id":1415},"变换属性",[21,1417,1415],{},[25,1419,1420,1426,1432,1438],{},[28,1421,1422,1425],{},[21,1423,1424],{},"TranslateTransform.X \u002F Y",": 平移变换\u003Clink to Repo AvaloniaUI\u002FAvalonia: src\u002FAvalonia.Base\u002FMedia\u002FTranslateTransform.cs:15-22>\u003Clink to Repo AvaloniaUI\u002FAvalonia: tests\u002FAvalonia.Base.UnitTests\u002FAnimation\u002FKeySplineTests.cs:236-242>",[28,1427,1428,1431],{},[21,1429,1430],{},"RotateTransform.Angle",": 旋转角度\u003Clink to Repo AvaloniaUI\u002FAvalonia: samples\u002FRenderDemo\u002FPages\u002FAnimationsPage.xaml:54-62>",[28,1433,1434,1437],{},[21,1435,1436],{},"ScaleTransform.ScaleX \u002F ScaleY",": 缩放比例\u003Clink to Repo AvaloniaUI\u002FAvalonia: samples\u002FRenderDemo\u002FPages\u002FAnimationsPage.xaml:58-71>",[28,1439,1440,1443],{},[21,1441,1442],{},"SkewTransform.AngleX \u002F AngleY",": 倾斜角度\u003Clink to Repo AvaloniaUI\u002FAvalonia: samples\u002FRenderDemo\u002FPages\u002FAnimationsPage.xaml:102-107>",[17,1445,1447],{"id":1446},"颜色和画刷",[21,1448,1446],{},[25,1450,1451,1457],{},[28,1452,1453,1456],{},[21,1454,1455],{},"Color",": 颜色值\u003Clink to Repo AvaloniaUI\u002FAvalonia: src\u002FAvalonia.Base\u002Fcomposition-schema.xml:63-63>",[28,1458,1459,1462],{},[21,1460,1461],{},"Background \u002F Foreground",": 背景和前景画刷\u003Clink to Repo AvaloniaUI\u002FAvalonia: samples\u002FRenderDemo\u002FPages\u002FAnimationsPage.xaml:116-137>",[17,1464,1466],{"id":1465},"布局属性",[21,1467,1465],{},[25,1469,1470,1476,1481],{},[28,1471,1472,1475],{},[21,1473,1474],{},"Width \u002F Height",": 宽度和高度\u003Clink to Repo AvaloniaUI\u002FAvalonia: tests\u002FAvalonia.Base.UnitTests\u002FAnimation\u002FAnimatableTests.cs:105-111>",[28,1477,1478,1480],{},[21,1479,175],{},": 外边距",[28,1482,1483,1485],{},[21,1484,178],{},": 内边距",[17,1487,1489],{"id":1488},"视觉效果",[21,1490,1488],{},[25,1492,1493,1499,1504],{},[28,1494,1495,1498],{},[21,1496,1497],{},"BoxShadow",": 阴影效果\u003Clink to Repo AvaloniaUI\u002FAvalonia: samples\u002FRenderDemo\u002FPages\u002FAnimationsPage.xaml:147-149>",[28,1500,1501,1503],{},[21,1502,146],{},": 圆角半径",[28,1505,1506,1508],{},[21,1507,181],{},": 边框粗细",[17,1510,1512],{"id":1511},"composition-api-属性",[21,1513,1514],{},"Composition API 属性",[25,1516,1517,1523,1529,1535],{},[28,1518,1519,1522],{},[21,1520,1521],{},"Offset",": 位置偏移 (Vector3D)\u003Clink to Repo AvaloniaUI\u002FAvalonia: src\u002FAvalonia.Base\u002Fcomposition-schema.xml:24-24>",[28,1524,1525,1528],{},[21,1526,1527],{},"Scale",": 缩放 (Vector3D)\u003Clink to Repo AvaloniaUI\u002FAvalonia: src\u002FAvalonia.Base\u002Fcomposition-schema.xml:30-30>",[28,1530,1531,1534],{},[21,1532,1533],{},"RotationAngle",": 旋转角度\u003Clink to Repo AvaloniaUI\u002FAvalonia: src\u002FAvalonia.Base\u002Fcomposition-schema.xml:28-28>",[28,1536,1537,1540],{},[21,1538,1539],{},"Visible",": 可见性\u003Clink to Repo AvaloniaUI\u002FAvalonia: src\u002FAvalonia.Base\u002Fcomposition-schema.xml:19-19>",[17,1542,1544],{"id":1543},"其他类型",[21,1545,1543],{},[25,1547,1548,1554,1560],{},[28,1549,1550,1553],{},[21,1551,1552],{},"Boolean",": 布尔值属性\u003Clink to Repo AvaloniaUI\u002FAvalonia: src\u002FAvalonia.Base\u002Fcomposition-schema.xml:62-62>",[28,1555,1556,1559],{},[21,1557,1558],{},"Vector \u002F Vector2 \u002F Vector3",": 向量类型\u003Clink to Repo AvaloniaUI\u002FAvalonia: src\u002FAvalonia.Base\u002Fcomposition-schema.xml:64-67>",[28,1561,1562,1565],{},[21,1563,1564],{},"Quaternion",": 四元数(用于 3D 旋转)\u003Clink to Repo AvaloniaUI\u002FAvalonia: src\u002FAvalonia.Base\u002Fcomposition-schema.xml:69-69>",[10,1567,1568],{},"需要题型一点的是，Children属性不是StackPanel的特权，一般来说，只要是Panel类型，那么都是有Children这个属性的，除了垂直、水平堆叠布局StackPanel以外，我们还有其他常用的Panel类型：",[25,1570,1571,1577,1583,1589,1595],{},[28,1572,1573,1576],{},[21,1574,1575],{},"Grid"," - 网格布局",[28,1578,1579,1582],{},[21,1580,1581],{},"Canvas"," - 绝对定位布局",[28,1584,1585,1588],{},[21,1586,1587],{},"DockPanel"," - 停靠布局",[28,1590,1591,1594],{},[21,1592,1593],{},"WrapPanel"," - 自动换行布局",[28,1596,1597,1600],{},[21,1598,1599],{},"VirtualizingStackPanel"," - 虚拟化堆叠布局",[10,1602,1603],{},"对于使用ItemsControl的场景，我们可以通过ItemsPresenter来获取实际的面板和子元素。",[333,1605,1607],{"className":384,"code":1606,"language":386,"meta":338,"style":338},"  internal Control? ContainerFromIndex(int index)\n        {\n            if (Panel is VirtualizingPanel v)\n                return v.ContainerFromIndex(index);\n            return index >= 0 && index \u003C Panel?.Children.Count ? Panel.Children[index] : null;\n        }\n\n        internal IEnumerable\u003CControl>? GetRealizedContainers()\n        {\n            if (Panel is VirtualizingPanel v)\n                return v.GetRealizedContainers();\n            return Panel?.Children;\n        }\n",[35,1608,1609,1614,1619,1624,1629,1634,1639,1645,1650,1654,1658,1663,1668],{"__ignoreMap":338},[342,1610,1611],{"class":344,"line":345},[342,1612,1613],{},"  internal Control? ContainerFromIndex(int index)\n",[342,1615,1616],{"class":344,"line":351},[342,1617,1618],{},"        {\n",[342,1620,1621],{"class":344,"line":357},[342,1622,1623],{},"            if (Panel is VirtualizingPanel v)\n",[342,1625,1626],{"class":344,"line":363},[342,1627,1628],{},"                return v.ContainerFromIndex(index);\n",[342,1630,1631],{"class":344,"line":369},[342,1632,1633],{},"            return index >= 0 && index \u003C Panel?.Children.Count ? Panel.Children[index] : null;\n",[342,1635,1636],{"class":344,"line":375},[342,1637,1638],{},"        }\n",[342,1640,1641],{"class":344,"line":424},[342,1642,1644],{"emptyLinePlaceholder":1643},true,"\n",[342,1646,1647],{"class":344,"line":433},[342,1648,1649],{},"        internal IEnumerable\u003CControl>? GetRealizedContainers()\n",[342,1651,1652],{"class":344,"line":439},[342,1653,1618],{},[342,1655,1656],{"class":344,"line":445},[342,1657,1623],{},[342,1659,1660],{"class":344,"line":451},[342,1661,1662],{},"                return v.GetRealizedContainers();\n",[342,1664,1665],{"class":344,"line":457},[342,1666,1667],{},"            return Panel?.Children;\n",[342,1669,1670],{"class":344,"line":462},[342,1671,1638],{},[10,1673,1674,1675,1678,1679,1681],{},"在 Composition API 的隐式动画示例中,也使用了 ",[35,1676,1677],{},"ItemsControl"," 配合 ",[35,1680,1593],{}," CompositionPage.axaml:9-14",[333,1683,1685],{"className":384,"code":1684,"language":386,"meta":338,"style":338},"\u003CItemsControl x:Name=\"Items\">\n           \u003CItemsControl.ItemsPanel>\n             \u003CItemsPanelTemplate>\n               \u003CWrapPanel\u002F>\n             \u003C\u002FItemsPanelTemplate>\n           \u003C\u002FItemsControl.ItemsPanel>\n           \u003CItemsControl.DataTemplates>\n             \u003CDataTemplate DataType=\"pages:CompositionPageColorItem\">\n               \u003CBorder \n                 pages:CompositionPage.EnableAnimations=\"True\"\n                 Padding=\"10\" BorderBrush=\"Gray\" BorderThickness=\"2\"\n                 Background=\"{Binding ColorBrush}\" Width=\"100\" Height=\"100\" Margin=\"10\">\n                   \u003CTextBlock Text=\"{Binding ColorHexValue}\"\u002F>\n               \u003C\u002FBorder>\n             \u003C\u002FDataTemplate>\n           \u003C\u002FItemsControl.DataTemplates>\n",[35,1686,1687,1692,1697,1702,1707,1712,1717,1722,1727,1732,1737,1742,1747,1752,1757,1762],{"__ignoreMap":338},[342,1688,1689],{"class":344,"line":345},[342,1690,1691],{},"\u003CItemsControl x:Name=\"Items\">\n",[342,1693,1694],{"class":344,"line":351},[342,1695,1696],{},"           \u003CItemsControl.ItemsPanel>\n",[342,1698,1699],{"class":344,"line":357},[342,1700,1701],{},"             \u003CItemsPanelTemplate>\n",[342,1703,1704],{"class":344,"line":363},[342,1705,1706],{},"               \u003CWrapPanel\u002F>\n",[342,1708,1709],{"class":344,"line":369},[342,1710,1711],{},"             \u003C\u002FItemsPanelTemplate>\n",[342,1713,1714],{"class":344,"line":375},[342,1715,1716],{},"           \u003C\u002FItemsControl.ItemsPanel>\n",[342,1718,1719],{"class":344,"line":424},[342,1720,1721],{},"           \u003CItemsControl.DataTemplates>\n",[342,1723,1724],{"class":344,"line":433},[342,1725,1726],{},"             \u003CDataTemplate DataType=\"pages:CompositionPageColorItem\">\n",[342,1728,1729],{"class":344,"line":439},[342,1730,1731],{},"               \u003CBorder \n",[342,1733,1734],{"class":344,"line":445},[342,1735,1736],{},"                 pages:CompositionPage.EnableAnimations=\"True\"\n",[342,1738,1739],{"class":344,"line":451},[342,1740,1741],{},"                 Padding=\"10\" BorderBrush=\"Gray\" BorderThickness=\"2\"\n",[342,1743,1744],{"class":344,"line":457},[342,1745,1746],{},"                 Background=\"{Binding ColorBrush}\" Width=\"100\" Height=\"100\" Margin=\"10\">\n",[342,1748,1749],{"class":344,"line":462},[342,1750,1751],{},"                   \u003CTextBlock Text=\"{Binding ColorHexValue}\"\u002F>\n",[342,1753,1754],{"class":344,"line":471},[342,1755,1756],{},"               \u003C\u002FBorder>\n",[342,1758,1759],{"class":344,"line":476},[342,1760,1761],{},"             \u003C\u002FDataTemplate>\n",[342,1763,1764],{"class":344,"line":482},[342,1765,1766],{},"           \u003C\u002FItemsControl.DataTemplates>\n",[17,1768,1769],{"id":1769},"视口判断",[10,1771,1772,1773,1776],{},"Avalonia可以通过",[35,1774,1775],{},"EffectiveViewportChanged"," 事件来获取组件是否在视口中，利用它我们可以完成一些加载动画。",[10,1778,1779,1780,1783,1784,1787,1788],{},"我们需要将要判断的控件放在scrollViewer中，如果没有在里面的话，那么被判定的组件的",[35,1781,1782],{},"EffectiveViewport"," 通常会覆盖整个控件区域,导致 ",[35,1785,1786],{},"isInViewport"," 始终为 ",[35,1789,1790],{},"true",[10,1792,1793,1795,1796,1799,1800,1802],{},[35,1794,1782],{}," 的计算会递归考虑所有父控件的 ",[35,1797,1798],{},"ClipToBounds"," 和 ",[35,1801,79],{}," 设置\u003Clink to Repo AvaloniaUI\u002FAvalonia: src\u002FAvalonia.Base\u002FLayout\u002FLayoutManager.cs:404-437>",[333,1804,1809],{"className":1805,"code":1807,"language":1808},[1806],"language-text","private void OnAttachedToVisualTree(object sender, VisualTreeAttachmentEventArgs e)\n{\n    MyBorder.EffectiveViewportChanged += OnEffectiveViewportChanged;\n}\n\nprivate void OnEffectiveViewportChanged(object? sender, EffectiveViewportChangedEventArgs e)\n{\n    var viewport = e.EffectiveViewport;\n    var controlBounds = new Rect(MyBorder.Bounds.Size);\n\n    \u002F\u002F 判断是否部分可见  \n    bool isInViewport = viewport.Intersects(controlBounds);\n\n    \u002F\u002F 判断是否完全可见  \n    bool isFullyInViewport = viewport.Contains(controlBounds);\n\n    if (DataContext is MainViewModel vm)\n    {\n        vm.IsViewport = isInViewport.ToString();\n        vm.IsFullyviewport = isFullyInViewport.ToString();\n    }\n}\n","text",[35,1810,1807],{"__ignoreMap":338},[10,1812,1813,1814,1817],{},"于是我们这样设置，就可以在窗口上观察到我们想要的内容了，可以正确判断是否在视口上，并且是否完整显示了，并且，我们即便是将opacity调整为了0，也是只影响控件的视觉渲染，而不会影响布局和视口检测，我们完全可以用它来",[21,1815,1816],{},"创建一些淡入的加载动画","。",[333,1819,1823],{"className":1820,"code":1821,"language":1822,"meta":338,"style":338},"language-cs shiki shiki-themes github-light github-dark","using Avalonia;\nusing Avalonia.Controls;\nusing Avalonia.Interactivity;\nusing Avalonia.Layout;\nusing Avalonia.LogicalTree;\nusing Avalonia.Media;\nusing Avalonia.Rendering.Composition;\nusing Avalonia.VisualTree;\nusing AvaloniaTestDemo.ViewModels;\nusing System;\n\nnamespace AvaloniaTestDemo.Views;\n\npublic partial class MainView : UserControl\n{\n    public MainView()\n    {\n        InitializeComponent();\n        MyBorder.Loaded += MyBorder_Loaded;\n        MyBorder.AttachedToVisualTree += OnAttachedToVisualTree;\n        MyBorder.AttachedToLogicalTree += WrapPanelLoadAnimation;\n    }\n\n    private void OnAttachedToVisualTree(object sender, VisualTreeAttachmentEventArgs e)\n    {\n        MyBorder.EffectiveViewportChanged += OnEffectiveViewportChanged;\n    }\n\n    private void WrapPanelLoadAnimation(object? sender, LogicalTreeAttachmentEventArgs e)\n    {\n        if (ContentContainer is WrapPanel wrapPanel && ContentContainer is not null)\n        {\n            var childrens = wrapPanel.Children;\n            foreach (var child in childrens)\n            {\n                child.Opacity = 0;\n                child.EffectiveViewportChanged += EffectiveViewportChangedAnimation;\n            }\n        }\n    }\n\n    private void EffectiveViewportChangedAnimation(object? sender, EffectiveViewportChangedEventArgs e)\n    {\n        var viewport = e.EffectiveViewport;\n        if (sender is Border border)\n        {\n            var controlBounds = new Rect(border.Bounds.Size); \n            bool isInViewport = viewport.Intersects(controlBounds);\n\n            if (isInViewport)\n            {\n                border.Opacity = 1;\n                border.EffectiveViewportChanged -= EffectiveViewportChangedAnimation;\n            }\n        }\n    }\n\n    private void OnEffectiveViewportChanged(object? sender, EffectiveViewportChangedEventArgs e)\n    {\n        var viewport = e.EffectiveViewport;\n        var controlBounds = new Rect(MyBorder.Bounds.Size);\n\n        \u002F\u002F 判断是否部分可见  \n        bool isInViewport = viewport.Intersects(controlBounds);\n\n        \u002F\u002F 判断是否完全可见  \n        bool isFullyInViewport = viewport.Contains(controlBounds);\n\n        if (DataContext is MainViewModel vm)\n        {\n            vm.IsViewport = isInViewport.ToString();\n            vm.IsFullyviewport = isFullyInViewport.ToString();\n        }\n    }\n\n    private void MyBorder_Loaded(object? sender, RoutedEventArgs e)\n    {\n        var visual = ElementComposition.GetElementVisual(MyBorder);\n        if (visual == null) return;\n        var compositor = visual.Compositor;\n        if (compositor == null) return;\n\n\n        \u002F\u002F 创建 Offset 动画  \n        var offsetAnimation = compositor.CreateVector3KeyFrameAnimation();\n        offsetAnimation.Target = \"Offset\";\n        offsetAnimation.InsertExpressionKeyFrame(1, \"this.FinalValue\");\n        offsetAnimation.Duration = TimeSpan.FromMilliseconds(2000);\n        var implicitAnimations = compositor.CreateImplicitAnimationCollection();\n        implicitAnimations[\"Offset\"] = offsetAnimation;\n\n        \u002F\u002F 为 visual 设置 Offset 动画  \n        visual.ImplicitAnimations = implicitAnimations;\n        MyBorder.Loaded -= MyBorder_Loaded;\n    }\n\n    private void Border_Click(object? sender, Avalonia.Input.PointerPressedEventArgs e)\n    {\n        if (sender is Border border)\n        {\n            var visual = ElementComposition.GetElementVisual(border);\n            if (visual == null) return; \u002F\u002F Check if visual is null before accessing its properties\n            visual.ClipToBounds = true;\n            visual.Offset += new Vector3D(100, 100, 0); \u002F\u002F x=100, y=100\n        }\n    }\n}\n","cs",[35,1824,1825,1830,1835,1840,1845,1850,1855,1860,1865,1870,1875,1879,1884,1888,1893,1898,1903,1908,1913,1918,1923,1928,1933,1937,1942,1946,1951,1955,1959,1964,1968,1973,1977,1982,1987,1992,1997,2002,2007,2011,2015,2019,2024,2028,2033,2038,2042,2047,2052,2056,2061,2065,2070,2075,2079,2083,2087,2091,2096,2100,2104,2109,2113,2118,2123,2127,2132,2137,2141,2146,2150,2155,2160,2164,2168,2172,2178,2183,2189,2195,2201,2207,2212,2217,2223,2229,2235,2241,2247,2253,2259,2264,2270,2276,2282,2287,2292,2298,2303,2308,2313,2319,2325,2331,2337,2342,2347],{"__ignoreMap":338},[342,1826,1827],{"class":344,"line":345},[342,1828,1829],{},"using Avalonia;\n",[342,1831,1832],{"class":344,"line":351},[342,1833,1834],{},"using Avalonia.Controls;\n",[342,1836,1837],{"class":344,"line":357},[342,1838,1839],{},"using Avalonia.Interactivity;\n",[342,1841,1842],{"class":344,"line":363},[342,1843,1844],{},"using Avalonia.Layout;\n",[342,1846,1847],{"class":344,"line":369},[342,1848,1849],{},"using Avalonia.LogicalTree;\n",[342,1851,1852],{"class":344,"line":375},[342,1853,1854],{},"using Avalonia.Media;\n",[342,1856,1857],{"class":344,"line":424},[342,1858,1859],{},"using Avalonia.Rendering.Composition;\n",[342,1861,1862],{"class":344,"line":433},[342,1863,1864],{},"using Avalonia.VisualTree;\n",[342,1866,1867],{"class":344,"line":439},[342,1868,1869],{},"using AvaloniaTestDemo.ViewModels;\n",[342,1871,1872],{"class":344,"line":445},[342,1873,1874],{},"using System;\n",[342,1876,1877],{"class":344,"line":451},[342,1878,1644],{"emptyLinePlaceholder":1643},[342,1880,1881],{"class":344,"line":457},[342,1882,1883],{},"namespace AvaloniaTestDemo.Views;\n",[342,1885,1886],{"class":344,"line":462},[342,1887,1644],{"emptyLinePlaceholder":1643},[342,1889,1890],{"class":344,"line":471},[342,1891,1892],{},"public partial class MainView : UserControl\n",[342,1894,1895],{"class":344,"line":476},[342,1896,1897],{},"{\n",[342,1899,1900],{"class":344,"line":482},[342,1901,1902],{},"    public MainView()\n",[342,1904,1905],{"class":344,"line":488},[342,1906,1907],{},"    {\n",[342,1909,1910],{"class":344,"line":494},[342,1911,1912],{},"        InitializeComponent();\n",[342,1914,1915],{"class":344,"line":499},[342,1916,1917],{},"        MyBorder.Loaded += MyBorder_Loaded;\n",[342,1919,1920],{"class":344,"line":508},[342,1921,1922],{},"        MyBorder.AttachedToVisualTree += OnAttachedToVisualTree;\n",[342,1924,1925],{"class":344,"line":514},[342,1926,1927],{},"        MyBorder.AttachedToLogicalTree += WrapPanelLoadAnimation;\n",[342,1929,1930],{"class":344,"line":520},[342,1931,1932],{},"    }\n",[342,1934,1935],{"class":344,"line":526},[342,1936,1644],{"emptyLinePlaceholder":1643},[342,1938,1939],{"class":344,"line":532},[342,1940,1941],{},"    private void OnAttachedToVisualTree(object sender, VisualTreeAttachmentEventArgs e)\n",[342,1943,1944],{"class":344,"line":537},[342,1945,1907],{},[342,1947,1948],{"class":344,"line":546},[342,1949,1950],{},"        MyBorder.EffectiveViewportChanged += OnEffectiveViewportChanged;\n",[342,1952,1953],{"class":344,"line":552},[342,1954,1932],{},[342,1956,1957],{"class":344,"line":558},[342,1958,1644],{"emptyLinePlaceholder":1643},[342,1960,1961],{"class":344,"line":564},[342,1962,1963],{},"    private void WrapPanelLoadAnimation(object? sender, LogicalTreeAttachmentEventArgs e)\n",[342,1965,1966],{"class":344,"line":570},[342,1967,1907],{},[342,1969,1970],{"class":344,"line":576},[342,1971,1972],{},"        if (ContentContainer is WrapPanel wrapPanel && ContentContainer is not null)\n",[342,1974,1975],{"class":344,"line":582},[342,1976,1618],{},[342,1978,1979],{"class":344,"line":588},[342,1980,1981],{},"            var childrens = wrapPanel.Children;\n",[342,1983,1984],{"class":344,"line":594},[342,1985,1986],{},"            foreach (var child in childrens)\n",[342,1988,1989],{"class":344,"line":600},[342,1990,1991],{},"            {\n",[342,1993,1994],{"class":344,"line":605},[342,1995,1996],{},"                child.Opacity = 0;\n",[342,1998,1999],{"class":344,"line":610},[342,2000,2001],{},"                child.EffectiveViewportChanged += EffectiveViewportChangedAnimation;\n",[342,2003,2004],{"class":344,"line":619},[342,2005,2006],{},"            }\n",[342,2008,2009],{"class":344,"line":625},[342,2010,1638],{},[342,2012,2013],{"class":344,"line":631},[342,2014,1932],{},[342,2016,2017],{"class":344,"line":637},[342,2018,1644],{"emptyLinePlaceholder":1643},[342,2020,2021],{"class":344,"line":643},[342,2022,2023],{},"    private void EffectiveViewportChangedAnimation(object? sender, EffectiveViewportChangedEventArgs e)\n",[342,2025,2026],{"class":344,"line":648},[342,2027,1907],{},[342,2029,2030],{"class":344,"line":657},[342,2031,2032],{},"        var viewport = e.EffectiveViewport;\n",[342,2034,2035],{"class":344,"line":662},[342,2036,2037],{},"        if (sender is Border border)\n",[342,2039,2040],{"class":344,"line":668},[342,2041,1618],{},[342,2043,2044],{"class":344,"line":674},[342,2045,2046],{},"            var controlBounds = new Rect(border.Bounds.Size); \n",[342,2048,2049],{"class":344,"line":679},[342,2050,2051],{},"            bool isInViewport = viewport.Intersects(controlBounds);\n",[342,2053,2054],{"class":344,"line":684},[342,2055,1644],{"emptyLinePlaceholder":1643},[342,2057,2058],{"class":344,"line":693},[342,2059,2060],{},"            if (isInViewport)\n",[342,2062,2063],{"class":344,"line":698},[342,2064,1991],{},[342,2066,2067],{"class":344,"line":704},[342,2068,2069],{},"                border.Opacity = 1;\n",[342,2071,2072],{"class":344,"line":710},[342,2073,2074],{},"                border.EffectiveViewportChanged -= EffectiveViewportChangedAnimation;\n",[342,2076,2077],{"class":344,"line":715},[342,2078,2006],{},[342,2080,2081],{"class":344,"line":721},[342,2082,1638],{},[342,2084,2085],{"class":344,"line":727},[342,2086,1932],{},[342,2088,2089],{"class":344,"line":733},[342,2090,1644],{"emptyLinePlaceholder":1643},[342,2092,2093],{"class":344,"line":738},[342,2094,2095],{},"    private void OnEffectiveViewportChanged(object? sender, EffectiveViewportChangedEventArgs e)\n",[342,2097,2098],{"class":344,"line":744},[342,2099,1907],{},[342,2101,2102],{"class":344,"line":750},[342,2103,2032],{},[342,2105,2106],{"class":344,"line":755},[342,2107,2108],{},"        var controlBounds = new Rect(MyBorder.Bounds.Size);\n",[342,2110,2111],{"class":344,"line":761},[342,2112,1644],{"emptyLinePlaceholder":1643},[342,2114,2115],{"class":344,"line":766},[342,2116,2117],{},"        \u002F\u002F 判断是否部分可见  \n",[342,2119,2120],{"class":344,"line":772},[342,2121,2122],{},"        bool isInViewport = viewport.Intersects(controlBounds);\n",[342,2124,2125],{"class":344,"line":778},[342,2126,1644],{"emptyLinePlaceholder":1643},[342,2128,2129],{"class":344,"line":783},[342,2130,2131],{},"        \u002F\u002F 判断是否完全可见  \n",[342,2133,2134],{"class":344,"line":788},[342,2135,2136],{},"        bool isFullyInViewport = viewport.Contains(controlBounds);\n",[342,2138,2139],{"class":344,"line":794},[342,2140,1644],{"emptyLinePlaceholder":1643},[342,2142,2143],{"class":344,"line":800},[342,2144,2145],{},"        if (DataContext is MainViewModel vm)\n",[342,2147,2148],{"class":344,"line":806},[342,2149,1618],{},[342,2151,2152],{"class":344,"line":811},[342,2153,2154],{},"            vm.IsViewport = isInViewport.ToString();\n",[342,2156,2157],{"class":344,"line":817},[342,2158,2159],{},"            vm.IsFullyviewport = isFullyInViewport.ToString();\n",[342,2161,2162],{"class":344,"line":823},[342,2163,1638],{},[342,2165,2166],{"class":344,"line":829},[342,2167,1932],{},[342,2169,2170],{"class":344,"line":835},[342,2171,1644],{"emptyLinePlaceholder":1643},[342,2173,2175],{"class":344,"line":2174},76,[342,2176,2177],{},"    private void MyBorder_Loaded(object? sender, RoutedEventArgs e)\n",[342,2179,2181],{"class":344,"line":2180},77,[342,2182,1907],{},[342,2184,2186],{"class":344,"line":2185},78,[342,2187,2188],{},"        var visual = ElementComposition.GetElementVisual(MyBorder);\n",[342,2190,2192],{"class":344,"line":2191},79,[342,2193,2194],{},"        if (visual == null) return;\n",[342,2196,2198],{"class":344,"line":2197},80,[342,2199,2200],{},"        var compositor = visual.Compositor;\n",[342,2202,2204],{"class":344,"line":2203},81,[342,2205,2206],{},"        if (compositor == null) return;\n",[342,2208,2210],{"class":344,"line":2209},82,[342,2211,1644],{"emptyLinePlaceholder":1643},[342,2213,2215],{"class":344,"line":2214},83,[342,2216,1644],{"emptyLinePlaceholder":1643},[342,2218,2220],{"class":344,"line":2219},84,[342,2221,2222],{},"        \u002F\u002F 创建 Offset 动画  \n",[342,2224,2226],{"class":344,"line":2225},85,[342,2227,2228],{},"        var offsetAnimation = compositor.CreateVector3KeyFrameAnimation();\n",[342,2230,2232],{"class":344,"line":2231},86,[342,2233,2234],{},"        offsetAnimation.Target = \"Offset\";\n",[342,2236,2238],{"class":344,"line":2237},87,[342,2239,2240],{},"        offsetAnimation.InsertExpressionKeyFrame(1, \"this.FinalValue\");\n",[342,2242,2244],{"class":344,"line":2243},88,[342,2245,2246],{},"        offsetAnimation.Duration = TimeSpan.FromMilliseconds(2000);\n",[342,2248,2250],{"class":344,"line":2249},89,[342,2251,2252],{},"        var implicitAnimations = compositor.CreateImplicitAnimationCollection();\n",[342,2254,2256],{"class":344,"line":2255},90,[342,2257,2258],{},"        implicitAnimations[\"Offset\"] = offsetAnimation;\n",[342,2260,2262],{"class":344,"line":2261},91,[342,2263,1644],{"emptyLinePlaceholder":1643},[342,2265,2267],{"class":344,"line":2266},92,[342,2268,2269],{},"        \u002F\u002F 为 visual 设置 Offset 动画  \n",[342,2271,2273],{"class":344,"line":2272},93,[342,2274,2275],{},"        visual.ImplicitAnimations = implicitAnimations;\n",[342,2277,2279],{"class":344,"line":2278},94,[342,2280,2281],{},"        MyBorder.Loaded -= MyBorder_Loaded;\n",[342,2283,2285],{"class":344,"line":2284},95,[342,2286,1932],{},[342,2288,2290],{"class":344,"line":2289},96,[342,2291,1644],{"emptyLinePlaceholder":1643},[342,2293,2295],{"class":344,"line":2294},97,[342,2296,2297],{},"    private void Border_Click(object? sender, Avalonia.Input.PointerPressedEventArgs e)\n",[342,2299,2301],{"class":344,"line":2300},98,[342,2302,1907],{},[342,2304,2306],{"class":344,"line":2305},99,[342,2307,2037],{},[342,2309,2311],{"class":344,"line":2310},100,[342,2312,1618],{},[342,2314,2316],{"class":344,"line":2315},101,[342,2317,2318],{},"            var visual = ElementComposition.GetElementVisual(border);\n",[342,2320,2322],{"class":344,"line":2321},102,[342,2323,2324],{},"            if (visual == null) return; \u002F\u002F Check if visual is null before accessing its properties\n",[342,2326,2328],{"class":344,"line":2327},103,[342,2329,2330],{},"            visual.ClipToBounds = true;\n",[342,2332,2334],{"class":344,"line":2333},104,[342,2335,2336],{},"            visual.Offset += new Vector3D(100, 100, 0); \u002F\u002F x=100, y=100\n",[342,2338,2340],{"class":344,"line":2339},105,[342,2341,1638],{},[342,2343,2345],{"class":344,"line":2344},106,[342,2346,1932],{},[342,2348,2350],{"class":344,"line":2349},107,[342,2351,2352],{},"}\n",[10,2354,2355],{},"就这样，我们就可以实现当组件出现在视口的时候进行透明度变化加载（前提是要把属性动画设置好）。",[2357,2358,2359],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":338,"searchDepth":351,"depth":351,"links":2361},[2362,2363,2364,2365,2366,2367,2368,2369,2370,2371,2372,2373,2374,2375,2376,2377,2378,2379,2380,2381],{"id":19,"depth":357,"text":23},{"id":67,"depth":357,"text":70},{"id":134,"depth":357,"text":137},{"id":155,"depth":357,"text":158},{"id":189,"depth":357,"text":192},{"id":222,"depth":357,"text":225},{"id":242,"depth":357,"text":245},{"id":262,"depth":357,"text":265},{"id":282,"depth":357,"text":285},{"id":844,"depth":357,"text":845},{"id":868,"depth":357,"text":869},{"id":892,"depth":357,"text":893},{"id":916,"depth":357,"text":917},{"id":940,"depth":357,"text":941},{"id":964,"depth":357,"text":965},{"id":988,"depth":357,"text":989},{"id":1012,"depth":357,"text":1013},{"id":1036,"depth":357,"text":1037},{"id":1060,"depth":357,"text":1060},{"id":1072,"depth":351,"text":1073,"children":2382},[2383,2384,2385,2386,2387,2388,2389,2390],{"id":1382,"depth":357,"text":1382},{"id":1415,"depth":357,"text":1415},{"id":1446,"depth":357,"text":1446},{"id":1465,"depth":357,"text":1465},{"id":1488,"depth":357,"text":1488},{"id":1511,"depth":357,"text":1514},{"id":1543,"depth":357,"text":1543},{"id":1769,"depth":357,"text":1769},"md",{},"\u002Fcsharp\u002Favalonia\u002Favalonia的动画",{"description":12},"csharp\u002FAvalonia\u002Favalonia的动画：","GwWxeZDfUgMZy5piUXfeBLGDsTDtVI0kZShgfNTVDwQ",1791042464682]