本文共2,233字。
版权声明:署名-非商业性使用-相同方式共享
|
CC BY-NC-SA 2.5 CN最近计划用AvaloniaUI写某种跨平台的GUI软件,由于这个框架刚刚发布正式版,网络上的相关资源比较少,所以写起来比WPF是困难多了(也可能是我太菜)。
借着这个机会,我想把过程中碰到的一些问题和解决方法记录下来,以备自己后来查询,也为其他人提供可能的答案参考。
控件拖拽窗口
不太会概括这个功能,总之就是让一个控件可以有和标题栏相同的拖拽窗口功能,实际上和WPF的DragMove()
相同。
1 2 3 4
| private void Control_OnPointerPressed(object? sender, PointerPressedEventArgs e) { BeginMoveDrag(e); }
|
可在官方References中找到:Avalonia UI Framework - API - Window.BeginMoveDrag(PointerPressedEventArgs) Method
顺带吐槽一下,虽然AvaloniaUI确实有和WPF非常相似的开发体验,但是有些东西悄悄给你换个名就会让人很难受。本人在找这个非常简单的功能的实现方法时一直把DragMove
作为搜索关键词,但是Avalonia中把这个称为BeginMoveDrag
,导致我半天没搜到。
关于渐变画刷动画
渐变画刷的动画涉及到GradientStop
的Offset
和Color
的补间问题,Avalonia使用了一种虽然不是很智能但是比较可控的实现方式,但是官方文档没有明说,我在这里碰壁之后总结出以下不完整的经验。
补间实现特点
所谓“虽然不是很智能但是比较可控的实现方式”就是把画刷中相同索引处的GradientStop
对应起来,然后进行补间。虽然说GradientStop
本身包含Offset
属性,但是补间时的对象选择只看索引。
所以当你调换渐变节点的顺序时,静态画面不会产生效果的变化,但是一旦加入KeyframeAnimation
,你就会得到一些鬼畜效果。
GradientStop.Offset
移动(跑马灯效果)
注意以下几点:
- 每个
Keyframe
的GradientStop
数量要一样
- 每个
Keyframe
的相同索引的GradientStop
的Color
要一样
- 每个
Keyframe
的相同索引的GradientStop
的Offset
要均匀变化(如果你想让跑马灯匀速移动)
你可能想问为什么不画好到200%的GradientStop
然后修改StartPoint
和EndPoint
实现平移效果,实际上这种是我第一个碰壁的方案,因为我发现这个画刷只会处理0%-100%内的GradientStop
,超过这个范围就会变成纯色了。
如果觉得我上面的描述比较抽象,可以看一下下面的例子,是一个类似于RGB机械键盘跑马灯效果的动画:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
| <Animation Duration="0:0:5" IterationCount="Infinite" PlaybackDirection="Normal"> <KeyFrame Cue="0%"> <Setter Property="Background"> <LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%"> <GradientStop Offset="0.0" Color="#ff0000" /> <GradientStop Offset="0.0" Color="#ffff00" /> <GradientStop Offset="0.0" Color="#00ff00" /> <GradientStop Offset="0.0" Color="#00ffff" /> <GradientStop Offset="0.0" Color="#0000ff" /> <GradientStop Offset="0.0" Color="#ff00ff" /> <GradientStop Offset="0.0" Color="#ff0000" /> <GradientStop Offset="0.16666666666666666" Color="#ffff00" /> <GradientStop Offset="0.3333333333333333" Color="#00ff00" /> <GradientStop Offset="0.5" Color="#00ffff" /> <GradientStop Offset="0.6666666666666666" Color="#0000ff" /> <GradientStop Offset="0.8333333333333334" Color="#ff00ff" /> <GradientStop Offset="1.0" Color="#ff0000" /> </LinearGradientBrush> </Setter> </KeyFrame> <KeyFrame Cue="16.666666666666668%"> <Setter Property="Background"> <LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%"> <GradientStop Offset="0.0" Color="#ff0000" /> <GradientStop Offset="0.0" Color="#ffff00" /> <GradientStop Offset="0.0" Color="#00ff00" /> <GradientStop Offset="0.0" Color="#00ffff" /> <GradientStop Offset="0.0" Color="#0000ff" /> <GradientStop Offset="0.0" Color="#ff00ff" /> <GradientStop Offset="0.16666666666666666" Color="#ff0000" /> <GradientStop Offset="0.3333333333333333" Color="#ffff00" /> <GradientStop Offset="0.5" Color="#00ff00" /> <GradientStop Offset="0.6666666666666666" Color="#00ffff" /> <GradientStop Offset="0.8333333333333334" Color="#0000ff" /> <GradientStop Offset="1.0" Color="#ff00ff" /> <GradientStop Offset="1.16666666666666666" Color="#ff0000" /> </LinearGradientBrush> </Setter> </KeyFrame> <KeyFrame Cue="33.333333333333336%"> <Setter Property="Background"> <LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%"> <GradientStop Offset="0.0" Color="#ff0000" /> <GradientStop Offset="0.0" Color="#ffff00" /> <GradientStop Offset="0.0" Color="#00ff00" /> <GradientStop Offset="0.0" Color="#00ffff" /> <GradientStop Offset="0.0" Color="#0000ff" /> <GradientStop Offset="0.16666666666666666" Color="#ff00ff" /> <GradientStop Offset="0.3333333333333333" Color="#ff0000" /> <GradientStop Offset="0.5" Color="#ffff00" /> <GradientStop Offset="0.6666666666666666" Color="#00ff00" /> <GradientStop Offset="0.8333333333333334" Color="#00ffff" /> <GradientStop Offset="1.0" Color="#0000ff" /> <GradientStop Offset="1.16666666666666666" Color="#ff00ff" /> <GradientStop Offset="1.3333333333333333" Color="#ff0000" /> </LinearGradientBrush> </Setter> </KeyFrame> <KeyFrame Cue="50.0%"> <Setter Property="Background"> <LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%"> <GradientStop Offset="0.0" Color="#ff0000" /> <GradientStop Offset="0.0" Color="#ffff00" /> <GradientStop Offset="0.0" Color="#00ff00" /> <GradientStop Offset="0.0" Color="#00ffff" /> <GradientStop Offset="0.16666666666666666" Color="#0000ff" /> <GradientStop Offset="0.3333333333333333" Color="#ff00ff" /> <GradientStop Offset="0.5" Color="#ff0000" /> <GradientStop Offset="0.6666666666666666" Color="#ffff00" /> <GradientStop Offset="0.8333333333333334" Color="#00ff00" /> <GradientStop Offset="1.0" Color="#00ffff" /> <GradientStop Offset="1.16666666666666666" Color="#0000ff" /> <GradientStop Offset="1.3333333333333333" Color="#ff00ff" /> <GradientStop Offset="1.5" Color="#ff0000" /> </LinearGradientBrush> </Setter> </KeyFrame> <KeyFrame Cue="66.66666666666667%"> <Setter Property="Background"> <LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%"> <GradientStop Offset="0.0" Color="#ff0000" /> <GradientStop Offset="0.0" Color="#ffff00" /> <GradientStop Offset="0.0" Color="#00ff00" /> <GradientStop Offset="0.16666666666666666" Color="#00ffff" /> <GradientStop Offset="0.3333333333333333" Color="#0000ff" /> <GradientStop Offset="0.5" Color="#ff00ff" /> <GradientStop Offset="0.6666666666666666" Color="#ff0000" /> <GradientStop Offset="0.8333333333333334" Color="#ffff00" /> <GradientStop Offset="1.0" Color="#00ff00" /> <GradientStop Offset="1.16666666666666666" Color="#00ffff" /> <GradientStop Offset="1.3333333333333333" Color="#0000ff" /> <GradientStop Offset="1.5" Color="#ff00ff" /> <GradientStop Offset="1.6666666666666666" Color="#ff0000" /> </LinearGradientBrush> </Setter> </KeyFrame> <KeyFrame Cue="83.33333333333333%"> <Setter Property="Background"> <LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%"> <GradientStop Offset="0.0" Color="#ff0000" /> <GradientStop Offset="0.0" Color="#ffff00" /> <GradientStop Offset="0.16666666666666666" Color="#00ff00" /> <GradientStop Offset="0.3333333333333333" Color="#00ffff" /> <GradientStop Offset="0.5" Color="#0000ff" /> <GradientStop Offset="0.6666666666666666" Color="#ff00ff" /> <GradientStop Offset="0.8333333333333334" Color="#ff0000" /> <GradientStop Offset="1.0" Color="#ffff00" /> <GradientStop Offset="1.16666666666666666" Color="#00ff00" /> <GradientStop Offset="1.3333333333333333" Color="#00ffff" /> <GradientStop Offset="1.5" Color="#0000ff" /> <GradientStop Offset="1.6666666666666666" Color="#ff00ff" /> <GradientStop Offset="1.8333333333333334" Color="#ff0000" /> </LinearGradientBrush> </Setter> </KeyFrame> <KeyFrame Cue="100.0%"> <Setter Property="Background"> <LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%"> <GradientStop Offset="0.0" Color="#ff0000" /> <GradientStop Offset="0.16666666666666666" Color="#ffff00" /> <GradientStop Offset="0.3333333333333333" Color="#00ff00" /> <GradientStop Offset="0.5" Color="#00ffff" /> <GradientStop Offset="0.6666666666666666" Color="#0000ff" /> <GradientStop Offset="0.8333333333333334" Color="#ff00ff" /> <GradientStop Offset="1.0" Color="#ff0000" /> <GradientStop Offset="1.16666666666666666" Color="#ffff00" /> <GradientStop Offset="1.3333333333333333" Color="#00ff00" /> <GradientStop Offset="1.5" Color="#00ffff" /> <GradientStop Offset="1.6666666666666666" Color="#0000ff" /> <GradientStop Offset="1.8333333333333334" Color="#ff00ff" /> <GradientStop Offset="2.0" Color="#ff0000" /> </LinearGradientBrush> </Setter> </KeyFrame> </Animation>
|
写的比较丑,用后台代码而不是axaml可能会好点。
GradientStop.Color
渐变
实际上注意事项和前者是几乎一样的,鉴于上面有一堆难看的代码还是不要让读者拖滚动条了:
- 每个
Keyframe
的GradientStop
数量要一样
- 每个
Keyframe
的相同索引的GradientStop
的Offset
要一样
- 每个
Keyframe
的相同索引的GradientStop
的Color
要变化
不过我没想出这样的动画的应用场景,其实这是我本来用于实现跑马灯的第二个失败方案,最后做成了类似于毛毛虫的效果。
GradientStop
增减
没有试验这一部分,如果后续有需求可能会补充。
非主线程操作UI
如果直接操作会InvalidOperationException: “Call from invalid thread”,只需要用下面的方式即可解决。
1
| Dispatcher.UIThread.InvokeAsync(() => { });
|