使用 WPF 创建白天和黑夜主题切换按钮





5.00/5 (12投票s)
如何使用 WPF 创建白天和黑夜主题切换按钮
引言
切换开关按钮
ThemeSwitch
控件是一个基于 WPF ToggleButton
构建的 CustomControl
。该控件可作为 NuGet 包下载,您也可以从 GitHub 仓库运行演示项目,其中包含原始源代码和说明。
ThemeSwitch
通过 NuGet 包作为多目标框架免费库分发,确保与所有 WPF 版本兼容。
它具有三种动画类型
ValueItem
(DoubleAnimation
)ThickItem
(ThicknessAnimation
)ColorItem
(ColorAnimation
)
YouTube:使用 WPF 创建日夜切换开关按钮 | GitHub 源代码 | NuGet - YouTube
背景
最初的灵感来自一个 YouTube 视频,该视频展示了一个在 Figma 中设计的日夜切换按钮,我便着手在我的专业领域 WPF 中复现这一概念。最终效果令人瞩目,我很高兴能与大家分享。这次经历也让我有机会将我的编码技巧和技巧传授给那些喜爱或正在学习 WPF 开发的人。
1. 项目构成分析
我们通过软件工具分析发现,这个按钮是 WPF ToggleButton
的一个自定义变体。它包含了代表白天(太阳/云彩)和夜晚(月亮/星空)的元素。此外,我们还加入了自定义动画来增强日夜过渡效果。
2. 在 WPF 中绘制特殊形状
绘制特殊形状的方法有很多,例如使用预编辑的 SVG 图像或使用 Blend 中的 Path 工具进行绘制。然而,在这个项目中,我们展示了如何在 WPF 项目中直接绘制所需的形状,而无需任何外部设计软件。
- 白天(太阳/云彩)和夜晚(月亮/星空)
- 对于白天模式,太阳可以用简单的椭圆表示。云彩看似复杂,但实际上相当容易创建。为了实时查看绘制效果,我们在
MainWindow
中进行操作。我们绘制一个大小合适的圆,并复制大约八次。这些圆可以通过鼠标或箭头键定位,以达到类似云朵的外观。Visual Studio 会根据这些形状的位置生成相应的边距值,然后我们将其合并到 App.xaml 中。我们通过添加不同程度的透明度来创建云彩效果。
<Grid Width="60" Height="30"> <Ellipse Width="17" Height="17" Fill="#FFFFFF" Margin="26,1,16,12"/> <Ellipse Width="17" Height="17" Fill="#FFFFFF" Margin="38,1,5,12"/> <Ellipse Width="17" Height="17" Fill="#FFFFFF" Margin="10,12,33,1"/> <Ellipse Width="17" Height="17" Fill="#FFFFFF" Margin="23,12,20,1"/> <Ellipse Width="17" Height="17" Fill="#FFFFFF" Margin="32,13,11,0"/> <Ellipse Width="17" Height="17" Fill="#FFFFFF" Margin="43,8,0,5"/> <Ellipse Width="17" Height="17" Fill="#FFFFFF" Margin="16,3,27,10"/> <Ellipse Width="17" Height="17" Fill="#FFFFFF" Margin="5,2,38,11"/> <Ellipse Width="17" Height="17" Fill="#FFFFFF" Margin="0,8,43,5"/> </Grid>
- 对于白天模式,太阳可以用简单的椭圆表示。云彩看似复杂,但实际上相当容易创建。为了实时查看绘制效果,我们在
- 夜间主题
- 夜间主题中的星空也是用同样的方法创建的。我们将星空的基本元素定义为矩形,通过调整不透明度来实现亮度效果。我们将基本不透明度设置为
55
,对于更亮的星星,我们只需移除不透明度。
<Rectangle Width="1" Height="1" Fill="#55FFFFFF" Margin="60,35,19,14"/> <Rectangle Width="1" Height="1" Fill="#FFFFFF" Margin="36,6,43,43"/>
- 夜间主题中的星空也是用同样的方法创建的。我们将星空的基本元素定义为矩形,通过调整不透明度来实现亮度效果。我们将基本不透明度设置为
3. 为项目添加动画
为了生动地展示按钮的切换效果,我们为每个元素添加了动画。这些动画由 jamesnet.WPF Nuget 包提供支持,该包简化了 WPF 中动画的集成。
-
元素移动动画 - ThickItem
元素移动是通过 jamesnet.WPF 的
ThickItem
动画(类似于 WPF 中的ThicknessAnimation
)实现的。我们选择“Margin
”作为“Property
”,使用Cubieaseinout
添加更自然的动画效果,将持续时间设置为 0.5 秒,并使用边距值来确定移动的终点。<james:ThickItem TargetName="cloud1" Property="Margin" Mode="CubicEaseInOut" Duration="0:0:0.5" To="-70 20 0 0"/>
-
颜色过渡动画 - ColorItem
从太阳到月亮或从白天到夜晚元素的颜色过渡是通过 jamesnet.WPF 的
ColorItem
动画(类似于 WPF 中的ColorAnimation
)实现的。一般的属性设置与ThickItem
类似,但Property
语法略有不同Ellipse
-(Fill).Color;
Border
-(Background).Color
“
To
”部分更改为所需的颜色。<james:ColorItem TargetName="ellipse" Property="(Fill).Color" Mode="CubicEaseInOut" Duration="0:0:0.5" To="#E5B91A"/> <james:ColorItem TargetName="border" Property="(Background).Color" Mode="CubicEaseInOut" Duration="0:0:0.5" To="#191C25"/>
-
显示/隐藏动画 - ValueItem
对于夜间模式中不需要初始显示的
galaxy
元素,我们使用了 jamesnet.WPF 的ValueItem
动画(相当于 WPF 中的DoubleAnimation
)。我们将Property
设置为Opacity
,将To
设置为0
,表示初始不可见状态。 -
<james:ValueItem TargetName="galaxy" Property="Opacity" Mode="CubicEaseInOut" Duration="0:0:0.5" To="0"/>
4. Clip 属性
遵循上述代码,我们实现了元素交替移动的效果。然而,我们注意到云彩超出了切换按钮的范围并保持可见。为了解决这个问题,我们为项目设置了一个限制区域,将所有元素仅限于显示在我们定义的区域内。
这是通过 Clip
属性实现的。
我们使用 Geometry
,特别是 RectangleGeometry
,定义了一个剪裁形状,将项目的尺寸设置为 120x50
。我们还添加了 25
的圆角半径值,确保所有元素都只显示在指定的 Clip
区域内。
<Setter Property="Clip">
<Setter.Value>
<RectangleGeometry Rect="0,0,120,50">
<RectangleGeometry.RadiusX>25</RectangleGeometry.RadiusX>
<RectangleGeometry.RadiusY>25</RectangleGeometry.RadiusY>
</RectangleGeometry>
</Setter.Value>
</Setter>
关注点
开发过程中带来了一些独特的挑战,例如仅使用 Visual Studio 和简单的操作,在 WPF 编程中实现 UI 设计要求的可行性。此外,我还探索了通过实现更自然流畅的动画来增强视觉体验。
历史
- 2023 年 11 月 8 日:初始版本