WPF实现聚光灯效果

WPF开发者QQ群: 340500857  | 微信群 -> 进入公众号主页 加入组织

前言

        效果仿照 CSS聚光灯效果  

实现思路:

 

1. 设置底部Canvas背景色 #222222 。

2. 准备两个 TextBlock 控件在同一位置。

3. 设置底部 TextBlock 字体颜色Foreground="#323232"。

4. 设置上层 TextBlock  字体颜色为渐变色。

5. 设置上层 TextBlock.Clip 针对 EllipseGeometry 做 TranslateTransform 的X轴移动动画。

6. DoubleAnimation的To值为上层或者下层控件的ActualWidth获取此元素的呈现宽度。

7. 故事板初始化 Storyboard RepeatBehavior =RepeatBehavior.Forever,AutoReverse = true。

 

效果预览(更多效果请下载源码体验)

 一、SpotLight.cs 代码如下

复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;

namespace WPFDevelopers.Controls
{
    [TemplatePart(Name = TextBlockBottomTemplateName, Type = typeof(TextBlock))]
    [TemplatePart(Name = TextBlockTopTemplateName, Type = typeof(TextBlock))]
    [TemplatePart(Name = EllipseGeometryTemplateName, Type = typeof(EllipseGeometry))]
    public class SpotLight : Control
    {
        private const string TextBlockBottomTemplateName = "PART_TextBlockBottom";
        private const string TextBlockTopTemplateName = "PART_TextBlockTop";
        private const string EllipseGeometryTemplateName = "PART_EllipseGeometry";
        private TextBlock _textBlockBottom, _textBlockTop;
        private EllipseGeometry _ellipseGeometry;
        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }

        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register("Text", typeof(string), typeof(SpotLight), new PropertyMetadata("WPFDevelopers"));
        static SpotLight()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(SpotLight), new FrameworkPropertyMetadata(typeof(SpotLight)));
        }
        public SpotLight()
        {
            this.Loaded += SpotLight_Loaded;
        }

        private void SpotLight_Loaded(object sender, RoutedEventArgs e)
        {
            Canvas.SetLeft(_textBlockBottom, ActualWidth / 3);
            Canvas.SetTop(_textBlockBottom, ActualHeight / 3);
            Canvas.SetLeft(_textBlockTop, ActualWidth / 3);
            Canvas.SetTop(_textBlockTop, ActualHeight / 3);
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            _textBlockBottom = GetTemplateChild(TextBlockBottomTemplateName) as TextBlock;
            _textBlockTop = GetTemplateChild(TextBlockTopTemplateName) as TextBlock;
           
            _ellipseGeometry = GetTemplateChild(EllipseGeometryTemplateName) as EllipseGeometry;
            var center = new Point(FontSize/2, FontSize/2); 
            _ellipseGeometry.RadiusX = FontSize;
            _ellipseGeometry.RadiusY = FontSize;
            _ellipseGeometry.Center = center;
            if (_textBlockBottom != null && _textBlockTop != null && _ellipseGeometry != null)
                _textBlockTop.Loaded += _textBlockTop_Loaded;
        }


        private void _textBlockTop_Loaded(object sender, RoutedEventArgs e)
        {
            var doubleAnimation = new DoubleAnimation
            {
                To = _textBlockTop.ActualWidth,
                Duration = TimeSpan.FromSeconds(3)
            };
           
            Storyboard.SetTarget(doubleAnimation, _textBlockTop);
            Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("(UIElement.Clip).(EllipseGeometry.Transform).(TranslateTransform.X)"));
            var storyboard = new Storyboard
            {
                RepeatBehavior = RepeatBehavior.Forever,
                AutoReverse = true
            };
            storyboard.Children.Add(doubleAnimation);
            storyboard.Completed += (s, q) => 
            {

            };
            storyboard.Begin();
        }
    }
}
复制代码

二、SpotLight.xaml 代码如下

复制代码
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:controls="clr-namespace:WPFDevelopers.Controls">
    
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="Basic/ControlBasic.xaml"/>
    </ResourceDictionary.MergedDictionaries>

    <Style TargetType="{x:Type controls:SpotLight}" BasedOn="{StaticResource ControlBasicStyle}">
        <Setter Property="Background" Value="#222222"/>
        <Setter Property="FontSize" Value="60"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type controls:SpotLight}">
                    <Canvas x:Name="PART_Canvas" Background="{TemplateBinding Background}">
                        <TextBlock x:Name="PART_TextBlockBottom" Text="{TemplateBinding Text}"
                                   FontSize="{TemplateBinding FontSize}" FontFamily="Arial Black"
                                   FontWeight="Bold" Foreground="#323232"/>
                        <TextBlock x:Name="PART_TextBlockTop" Text="{TemplateBinding Text}"
                                   FontSize="{TemplateBinding FontSize}" FontFamily="Arial Black"
                                   FontWeight="Bold">
                            <TextBlock.Foreground>
                                <LinearGradientBrush EndPoint="1,1" MappingMode="RelativeToBoundingBox" StartPoint="0,0">
                                    <GradientStop Color="#FF9C1031" Offset="0.1"/>
                                    <GradientStop Color="#FFBE0E20" Offset="0.2"/>
                                    <GradientStop Color="#FF9C12AC" Offset="0.7"/>
                                    <GradientStop Color="#FF0A8DC3" Offset="0.8"/>
                                    <GradientStop Color="#FF1AEBCC" Offset="1"/>
                                </LinearGradientBrush>
                            </TextBlock.Foreground>
                            <TextBlock.Clip>
                                <EllipseGeometry x:Name="PART_EllipseGeometry">
                                    <EllipseGeometry.Transform>
                                        <TranslateTransform/>
                                    </EllipseGeometry.Transform>
                                </EllipseGeometry>
                            </TextBlock.Clip>
                        </TextBlock>
                    </Canvas>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
</Style>

</ResourceDictionary>
复制代码

三、SpotLightExample.Xaml 代码如下

复制代码
<UserControl x:Class="WPFDevelopers.Samples.ExampleViews.SpotLightExample"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WPFDevelopers.Samples.ExampleViews"
             xmlns:wpfdev="https://github.com/yanjinhuagood/WPFDevelopers"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <UniformGrid Rows="2">
        <wpfdev:SpotLight FontSize="50" Text="YanJinHua"/>
        <wpfdev:SpotLight/>
    </UniformGrid>
</UserControl>
复制代码

更多教程欢迎关注微信公众号:

WPF开发者QQ群: 340500857 

blogs: https://www.cnblogs.com/yanjinhua/p/14345136.html

源码Github:https://github.com/yanjinhuagood/WPFDevelopers.git

gitee:https://gitee.com/yanjinhua/WPFDevelopers.git

Github https://github.com/WPFDevelopersOrg

码云 https://gitee.com/WPFDevelopersOrg

posted @   驚鏵  阅读(1238)  评论(9编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端
点击右上角即可分享
微信分享提示
主题色彩