65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIconstarIcon

5.00/5 (12投票s)

2023 年 11 月 8 日

CPOL

4分钟阅读

viewsIcon

19831

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

引言

切换开关按钮

ThemeSwitch 控件是一个基于 WPF ToggleButton 构建的 CustomControl。该控件可作为 NuGet 包下载,您也可以从 GitHub 仓库运行演示项目,其中包含原始源代码和说明。

ThemeSwitch 通过 NuGet 包作为多目标框架免费库分发,确保与所有 WPF 版本兼容。

它具有三种动画类型

  1. ValueItem (DoubleAnimation)
  2. ThickItem (ThicknessAnimation)
  3. 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 日:初始版本
© . All rights reserved.