简体   繁体   English

C# WPF/WinUI 从随机字母显示到文字显示效果 XAML TextBlock 控件

[英]C# From random letters displaying to a text reveal effect for WPF/WinUI XAML TextBlock control

I'm trying to create a custom control in WinUI 3 based on a TextBlock control, that has to show the contained text using a random letter rolling effect (letter by letter) till the full text is revealed.我正在尝试基于TextBlock控件在WinUI 3中创建一个自定义控件,该控件必须使用随机字母滚动效果(逐个字母)显示包含的文本,直到显示全文。 Let's say something like the Airport Departures billboard...比如说机场出发广告牌……

To better understand the desired effect, this is a video where the desired result is made using Adobe After Effects.为了更好地理解所需的效果,这是一个使用 Adobe After Effects 制作所需结果的视频

How can I implement the (closest possible) effect in C# code?如何在 C# 代码中实现(最接近的)效果?

In my solution, the animation is triggered by setting the Text DependencyProperty.在我的解决方案中,通过设置 Text DependencyProperty 触发 animation。 That allows to easily restart the effect if the Text property is overridden during the current animation.如果在当前 animation 期间覆盖 Text 属性,则可以轻松重新启动效果。 But you could also trigger it by some public method.但是你也可以通过一些公共方法来触发它。 But keep in mind that the TextBlock control can get slow with high amounts of text and fast text changes.但请记住,TextBlock 控件可能会因大量文本和快速文本更改而变慢。 If you encounter performance issues you should rewrite this for a Win2D CanvasControl.如果您遇到性能问题,您应该为 Win2D CanvasControl 重写它。

LetterRevealTextBlock.xaml: LetterRevealTextBlock.xaml:

<UserControl
    x:Class="Test.WinUI3.LetterRevealTextBlock"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Test.WinUI3"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <TextBlock x:Name="LRTB" FontFamily="Consolas"/>
    
</UserControl>

LetterRevealTextBlock.xaml.cs: LetterRevealTextBlock.xaml.cs:

namespace Test.WinUI3;

public sealed partial class LetterRevealTextBlock : UserControl
{
    private static readonly DependencyProperty TextProperty = DependencyProperty.Register(
    "Text", typeof(string), typeof(LetterRevealTextBlock), new PropertyMetadata("", (d, e) => ((LetterRevealTextBlock)d).TextChanged(d, e)));
    public string Text { get => (string)GetValue(TextProperty); set => SetValue(TextProperty, value); }

    private static readonly DependencyProperty ScrollIntervalProperty = DependencyProperty.Register(
    "ScrollInterval", typeof(int), typeof(LetterRevealTextBlock), new PropertyMetadata(40, (d, e) => ((LetterRevealTextBlock)d).ScrollIntervalChanged(d, e)));
    public int ScrollInterval { get => (int)GetValue(ScrollIntervalProperty); set => SetValue(ScrollIntervalProperty, value); }

    private static readonly DependencyProperty RevealIntervalProperty = DependencyProperty.Register(
    "RevealInterval", typeof(int), typeof(LetterRevealTextBlock), new PropertyMetadata(200, (d, e) => ((LetterRevealTextBlock)d).RevealIntervalChanged(d, e)));
    public int RevealInterval { get => (int)GetValue(RevealIntervalProperty); set => SetValue(RevealIntervalProperty, value); }

    const string Chars = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789";
    private Random Random = new Random();

    private char[] TextArray {get; set; }

    private int CurrentChar = 0;
 
    private DispatcherTimer RevealTimer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(200) };
    private DispatcherTimer ScrollTimer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(40) };

    private void ScrollIntervalChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ScrollTimer.Interval = TimeSpan.FromMilliseconds((int)e.NewValue);
    }
    private void RevealIntervalChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        RevealTimer.Interval = TimeSpan.FromMilliseconds((int)e.NewValue);
    }

    private void TextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        TextArray = (e.NewValue as string).ToCharArray();
        CurrentChar = 0;
        ScrollTimer.Start();
        RevealTimer.Start();
    }

    private void ScrollTimer_Tick(object sender, object e)
    {
        for (int i = 0; i < Text.Length; i++)
        {
            if (i <= CurrentChar)
            {
                TextArray[i] = Text[i];
            }
            else
            {
                TextArray[i] = Text[i] == ' ' ? ' ' : Chars[Random.Next(Chars.Length - 1)];
            }
        }
        LRTB.Text = new string(TextArray);
        if (CurrentChar >= Text.Length - 1)
        {
            CurrentChar = 0;
            ScrollTimer.Stop();
            RevealTimer.Stop();
            return;
        }
    }

    private void RevealTimer_Tick(object sender, object e)
    {
        CurrentChar++;
    }

    public LetterRevealTextBlock()
    {
        this.InitializeComponent();
        ScrollTimer.Tick += ScrollTimer_Tick;
        RevealTimer.Tick += RevealTimer_Tick;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM