WPF实现跳动的字符效果

这篇具有很好参考价值的文章主要介绍了WPF实现跳动的字符效果。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文将介绍一个好玩但实际作用可能不太大的动画效果:跳动的字符。为了提高动画效果的可重用性以及调用的灵活性,通过Behavior实现跳动的字符动画。先看下效果:

WPF实现跳动的字符效果

技术要点与实现

通过TextEffectPositionStartPositionCount属性控制应用动画效果的子字符串的起始位置以及长度,同时使用TranslateTransform设置字符纵坐标的移动变换,以实现跳动的效果。主要步骤如下:

  • 在OnAttached方法中,注册Loaded事件,在Load事件中为TextBlock添加TextEffect效果,其中PositionCount设置为1,每次只跳动一个字符。
  • 添加启动动画效果的BeginEffect方法,并创建控制子字符纵向移动变换的线性动画。然后根据字符串(剔除空字符)的长度n,创建n个关键帧,每个关键帧中把PositionStart设置为要跳动的字符在字符串中的索引
  • 在开启动画属性IsEnabled=trueTextBlock内容变化时,启动动画效果

在创建关键帧设置跳动字符位置时剔除了空字符,是为了是动画效果显得连贯

public class DanceCharEffectBehavior : Behavior<TextBlock>
{
    private TextEffect _textEffect;
    private string _textEffectName;
    private TranslateTransform _translateTransform = null;
    private string _translateTransformName;
    private Storyboard _storyboard;

    protected override void OnAttached()
    {
        base.OnAttached();

        this.AssociatedObject.Loaded += AssociatedObject_Loaded;
        this.AssociatedObject.Unloaded += AssociatedObject_Unloaded;
        this.AssociatedObject.IsVisibleChanged += AssociatedObject_IsVisibleChanged;
        BindingOperations.SetBinding(this, DanceCharEffectBehavior.InternalTextProperty, new Binding("Text") { Source = this.AssociatedObject });
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();

        this.AssociatedObject.Loaded -= AssociatedObject_Loaded;
        this.AssociatedObject.Unloaded -= AssociatedObject_Unloaded;
        this.AssociatedObject.IsVisibleChanged -= AssociatedObject_IsVisibleChanged;
        this.ClearValue(DanceCharEffectBehavior.InternalTextProperty);

        if (_storyboard != null)
        {
            _storyboard.Remove(this.AssociatedObject);
            _storyboard.Children.Clear();
        }
        if (_textEffect != null)
            this.AssociatedObject.TextEffects.Remove(_textEffect);
    }

    private void AssociatedObject_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        if ((bool)e.NewValue == false)
        {
            if (_storyboard != null)
                _storyboard.Stop(this.AssociatedObject);
        }
        else
        {
            BeginEffect(this.AssociatedObject.Text);
        }
    }

    private void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
    {
        if (_textEffect == null)
        {
            this.AssociatedObject.TextEffects.Add(_textEffect = new TextEffect()
            {
                PositionCount = 1,
                Transform = _translateTransform = new TranslateTransform(),
            });
            NameScope.SetNameScope(this.AssociatedObject, new NameScope());
            this.AssociatedObject.RegisterName(_textEffectName = "n" + Guid.NewGuid().ToString("N"), _textEffect);
            this.AssociatedObject.RegisterName(_translateTransformName = "n" + Guid.NewGuid().ToString("N"), _translateTransform);
            if (IsEnabled)
                BeginEffect(this.AssociatedObject.Text);
        }
    }

    private void AssociatedObject_Unloaded(object sender, RoutedEventArgs e)
    {
        StopEffect();
    }


    private void SetEffect(string text)
    {
        if (string.IsNullOrEmpty(text) || this.AssociatedObject.IsLoaded == false)
        {
            StopEffect();
            return;
        }

        BeginEffect(text);

    }

    private void StopEffect()
    {
        if (_storyboard != null)
        {
            _storyboard.Stop(this.AssociatedObject);
        }
    }

    private void BeginEffect(string text)
    {
        StopEffect();

        int textLength = text.Length;
        if (textLength < 1 || _translateTransformName == null || IsEnabled == false) return;

        if (_storyboard == null)
            _storyboard = new Storyboard();
        double duration = 0.5d;
        DoubleAnimation da = new DoubleAnimation();

        Storyboard.SetTargetName(da, _translateTransformName);
        Storyboard.SetTargetProperty(da, new PropertyPath(TranslateTransform.YProperty));
        da.From = 0d;
        da.To = 10d;
        da.Duration = TimeSpan.FromSeconds(duration / 2d);
        da.RepeatBehavior = RepeatBehavior.Forever;
        da.AutoReverse = true;

        char emptyChar = ' ';
        List<int> lsb = new List<int>();
        for (int i = 0; i < textLength; ++i)
        {
            if (text[i] != emptyChar)
            {
                lsb.Add(i);
            }
        }

        Int32AnimationUsingKeyFrames frames = new Int32AnimationUsingKeyFrames();
        Storyboard.SetTargetName(frames, _textEffectName);
        Storyboard.SetTargetProperty(frames, new PropertyPath(TextEffect.PositionStartProperty));
        frames.Duration = TimeSpan.FromSeconds((lsb.Count) * duration);
        frames.RepeatBehavior = RepeatBehavior.Forever;
        frames.AutoReverse = true;

        int ii = 0;
        foreach (int index in lsb)
        {
            frames.KeyFrames.Add(new DiscreteInt32KeyFrame()
            {
                Value = index,
                KeyTime = TimeSpan.FromSeconds(ii * duration),
            });
            ++ii;
        }

        _storyboard.Children.Add(da);
        _storyboard.Children.Add(frames);
        _storyboard.Begin(this.AssociatedObject, true);
    }

    private string InternalText
    {
        get { return (string)GetValue(InternalTextProperty); }
        set { SetValue(InternalTextProperty, value); }
    }

    private static readonly DependencyProperty InternalTextProperty =
    DependencyProperty.Register("InternalText", typeof(string), typeof(DanceCharEffectBehavior),
    new PropertyMetadata(OnInternalTextChanged));

    private static void OnInternalTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var source = d as DanceCharEffectBehavior;
        if (source._storyboard != null)
        {
            source._storyboard.Stop(source.AssociatedObject);
            source._storyboard.Children.Clear();
        }
        source.SetEffect(e.NewValue == null ? string.Empty : e.NewValue.ToString());
    }


    public bool IsEnabled
    {
        get { return (bool)GetValue(IsEnabledProperty); }
        set { SetValue(IsEnabledProperty, value); }
    }

    public static readonly DependencyProperty IsEnabledProperty =
        DependencyProperty.Register("IsEnabled", typeof(bool), typeof(DanceCharEffectBehavior), new PropertyMetadata(true, (d, e) =>
        {
            bool b = (bool)e.NewValue;
            var source = d as DanceCharEffectBehavior;
            source.SetEffect(source.InternalText);
        }));

}

调用的时候只需要在TextBlock添加Behavior即可,代码如下

<TextBlock FontSize="20" Text="Hello">
    <i:Interaction.Behaviors>
        <local:DanceCharEffectBehavior x:Name="titleEffect" IsEnabled="True" />
    </i:Interaction.Behaviors>
</TextBlock>

结尾

本例中还有许多可以完善的地方,比如字符跳动的幅度可以根据实际的FontSize来设置,或者增加依赖属性来控制;动画是否倒退播放,是否循环播放,以及动画的速度都可以通过增加依赖属性在调用时灵活设置。文章来源地址https://www.toymoban.com/news/detail-635734.html

到了这里,关于WPF实现跳动的字符效果的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 打造真实感十足的速度表盘:WPF实现动态效果与刻度绘制

      概述: 这个WPF项目通过XAML绘制汽车动态速度表盘,实现了0-300的速度刻度,包括数字、指针,并通过定时器模拟速度变化,展示了动态效果。详细实现包括界面设计、刻度绘制、指针角度计算等,通过C#代码与XAML文件结合完成。 新建 WPF 项目 : 在 Visual Studio 中创建一个新

    2024年03月16日
    浏览(51)
  • Simple WPF:实现一个透明、无边框、鼠标穿透的WPF窗体

    一个自定义WPF窗体的解决方案,借鉴了吕毅老师的WPF制作高性能的透明背景的异形窗口一文,并在此基础上增加了鼠标穿透的功能。可以使得透明窗体的鼠标事件穿透到下层,在下层窗体中响应。这一功能在开发一些截图工具,直播、会议标注工具的时候会有比较多的应用,

    2024年02月09日
    浏览(92)
  • css 图片好玩的一个属性,添加滤镜

    鼠标经过效果对比: 上图是改变了图片的饱和度,代码如下: 其他滤镜说明如下图:

    2024年02月06日
    浏览(35)
  • Pygame —— 一个好玩的游戏 Python 库

    在电子游戏的世界里,每一个精彩跳跃、每一个刺激冲刺、每一次动听的背景音乐,都是通过精心设计的代码和资源组合出来的奇幻体验。 想象一下,如果你能够制作自己的电子游戏,将内心的奇思妙想实现在屏幕上,那会是多么令人兴奋和自豪的事情。这个梦想,并不遥远

    2024年02月20日
    浏览(57)
  • 发现一个好玩的东西:Markdown 使用 Emoji 表情

    有两种方法可以将表情符号添加到Markdown文件中: 将表情符号复制并粘贴到Markdown格式的文本中 或者键入emoji shortcodes。 在大多数情况下,您可以简单地从Emojipedia等来源复制表情符号并将其粘贴到文档中。许多Markdown应用程序会自动以Markdown格式的文本显示表情符号。从Markd

    2024年02月06日
    浏览(37)
  • 记录--如何实现一个雨滴滑落效果

    下雨天坐在车窗前,看着雨滴顺着车窗渐渐落下,这一唯美的场景,忍不住想记录下来。最近在纠结电脑壁纸时,无意间看到有类似的场景,可以将自己喜欢的壁纸加上这种效果。作为多年切图仔,不由地想到了用css动画应该可以实现这一效果,于是,直接开干。先上效果图

    2024年02月19日
    浏览(33)
  • 用HTML5和JavaScript实现黑客帝国风格的字符雨效果

    目录 一、程序代码 二、代码原理 三、运行效果 这段代码实现了一个基于 HTML5 和 JavaScript 的字符雨效果,类似于电影《黑客帝国》中的场景。下面是对代码的解析: 在 HTML 部分: canvas  标签用于绘制字符雨效果。 通过内联样式和 id 属性设置画布的背景色和标识符为 \\\"canv

    2024年02月19日
    浏览(42)
  • 记录--怎么实现一个3d翻书效果

    本篇主要讨论以下两种翻书动画的实现: 第一种是整页翻转的效果: 这种整页翻转的效果主要是做rotateY的动画,并结合一些CSS的3d属性实现。 第二种折线翻转的效果,如下图所示: 主要是通过计算页面翻折过来的位置。 这两种原理上都不是很复杂,需要各个细节配合好,

    2024年02月11日
    浏览(45)
  • 如何使用CSS实现一个平滑过渡效果?

    前端入门之旅:探索Web开发的奇妙世界 欢迎来到前端入门之旅!感兴趣的可以订阅本专栏哦!这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发者,这里都将为你提供一个系统而又亲切的学习平台。在这个

    2024年02月12日
    浏览(43)
  • 小程序实现一个全局的loadding效果

    前言:         小程序中实现一个全局的loadding效果,也可以根据具体的组件大小来调整他的高度。 1、整个页面 2、局部组件大小 1、 app.js中全局定义字段 2、components中建立loadding的文件信息,load为文件夹  load/index.wxml   load/index.wxss  load/index.js  load/index.json 3、页面上具体

    2024年02月10日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包