[WPF] 玩玩彩虹文字及动画
1. 前言
兴致来了玩玩 WPF 的彩虹文字。不是用 LinearGradientBrush 制作渐变色那种,是指每个文字独立颜色那种彩虹文字。虽然没什么实用价值,但希望这篇文章里用 ItemsControl 拆分文字,以及用工具类提供递增和随机变量的做法可以给读者一些启发,就好了。
2. 用 TextBlock 的 Run
<TextBlock><Run Foreground="#4a0e68">b</Run><Run Foreground="#b62223">l</Run><Run Foreground="#fdd70c">o</Run><Run Foreground="#f16704">c</Run><Run Foreground="#69982d">k</Run><Run Foreground="#0075a5">.</Run><Run Foreground="#0b0045">R</Run><Run Foreground="#4a0e68">u</Run><Run Foreground="#b62223">n</Run>
</TextBlock>

用 TextBlock 的 Run 是做基本的做法,还有其它各种给 TextBlock 设置格式的方法,具体可以参考 text-block#formatting-text这篇文档。
3. 写代码
这种方案就是用代码将字符串拆分,然后逐个字符塞进 TextBlock 然后放进 StackPanel,实现方式很无趣,我就不写了。
4. 用 ItemsControl
第三种方案是用 ItemsControl 实现,这个方案虽然会绕些弯路,但胜在够有趣,而且能扩展其它玩法。
首先,因为 string 是个集合,其实它可以用作 ItemsControl 的 ItemsSource。但在 Xaml 上直接写 `ItemsSource=“somestring”``会报错,可以用 ContentControl 包装一下,写成这样:
<ContentControl Content="ItemsControl" ><ContentControl.Template><ControlTemplate TargetType="ContentControl"><ItemsControl ItemsSource="{TemplateBinding Content}" ></ItemsControl></ControlTemplate></ContentControl.Template>
</ContentControl>
然后设置 ItemsControl 的 ItemsPanel,让内容横向排列;设置 DataTemplate,让拆分后的字符显示在 TextBlock 上:
<ItemsControl ItemsSource="{TemplateBinding Content}" ><ItemsControl.ItemsPanel><ItemsPanelTemplate><StackPanel Orientation="Horizontal" /></ItemsPanelTemplate></ItemsControl.ItemsPanel><ItemsControl.ItemTemplate><DataTemplate><TextBlock Text="{Binding}" /></DataTemplate></ItemsControl.ItemTemplate>
</ItemsControl>
接下来,为了让每个字符显示不同的颜色,需要实现一个 Collection 类并在 Xaml 上实例化它,将用到的颜色放进去:
<common:RepeatCollection x:Key="RepeatCollection"><SolidColorBrush>#4a0e68<SolidColorBrush>#b62223<SolidColorBrush>#fdd70c<SolidColorBrush>#f16704<SolidColorBrush>#69982d<SolidColorBrush>#0075a5<SolidColorBrush>#0b0045
</common:RepeatCollection>
这个 RepeatCollection 的代码如下,它其实是个循环队列,每次调用 Next 的 getter 方法就拿下一个元素(叫 CircleCollection 会不会好些?):
public class RepeatCollection : Collection<object>
{private int _offset;public object Next{get{if (this.Count == 0)return null;var result = this[_offset];_offset++;if (_offset > this.Count - 1)_offset = 0;return result;}}
}
最后,TextBlock 的 Foreground 绑定到集合的 Next 属性,实现每一个 TextBlock 都使用不同的颜色:
[
]
5. 动画
从第三种方案延申,我试玩了几种动画。
首先我写了个 TimeSpanIncreaser 类,它包含 Start、Setp、Next 三个属性,其中 Next 的代码如下:
public override TimeSpan Next => Start + (_current += Step);
它的作用就是每次调用 Next 属性,这个属性返回的值都递增。
回到 Xaml,首先在 Resources 中定义一个实例:
<common:TimeSpanIncreaser x:Key="TimeSpanIncreaser" Step="0:0:0.2" />
然后在 TextBlock 里加上这段:
<TextBlock.RenderTransform><TranslateTransform Y="-90" />
</TextBlock.RenderTransform>
<FrameworkElement.Triggers><EventTrigger RoutedEvent="FrameworkElement.Loaded"><BeginStoryboard><Storyboard><DoubleAnimation BeginTime="{Binding Next, Source={StaticResource TimeSpanIncreaser}}"Storyboard.TargetName="TextElement"Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.Y)"To="0"Duration="0:0:0.7"><DoubleAnimation.EasingFunction><BounceEase EasingMode="EaseOut" /></DoubleAnimation.EasingFunction></DoubleAnimation></Storyboard></BeginStoryboard></EventTrigger>
</FrameworkElement.Triggers>
每个 TextBlock 使用相同的动画,但动画的开始时间是逐个递增的,运行起来效果如下:

再大胆些,ItemsControl 嵌套 ItemsControl,就可以做出下面这种效果:

又或者,这次不玩递增,玩随机。首先实现这两个类然后实例化,代码我就不贴出来了,看名字就能懂它们实现了什么功能:
<common:RandomColorCreator x:Key="RandomColorCreator" />
<common:RandomDoubleCreator x:Key="RandomDoubleCreator" Max="20" />
然后让 TextBlock 的 Foreground 和 TranslateTransform 动画的 X、Y 绑定到这两个实例的 Next 属性:
<TextBlock.Foreground><SolidColorBrush Color="{Binding Next, Source={StaticResource RandomColorCreator}}" />
</TextBlock.Foreground>
<TextBlock.RenderTransform><TranslateTransform />
</TextBlock.RenderTransform>
<FrameworkElement.Triggers><EventTrigger RoutedEvent="FrameworkElement.Loaded"><BeginStoryboard><Storyboard><DoubleAnimation AutoReverse="True"RepeatBehavior="Forever"Storyboard.TargetName="TextElement"Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"To="{Binding Next, Source={StaticResource RandomDoubleCreator}}"Duration="0:0:.08" /><DoubleAnimation AutoReverse="True"RepeatBehavior="Forever"Storyboard.TargetName="TextElement"Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.Y)"To="{Binding Next, Source={StaticResource RandomDoubleCreator}}"Duration="0:0:.1" /></Storyboard></BeginStoryboard></EventTrigger>
</FrameworkElement.Triggers>
又一个毫无实用价值的动画诞生了:

6. 最后
虽然很遗憾没什么用,我只能安慰自己“结果不重要,最重要是享受过程”。
https://github.com/DinoChan/wpf_design_and_animation_lab
作者:Dino.C出处:https://www.cnblogs.com/dino623/p/wpf_rainbow_text.html
版权:本文采用「CC BY 4.0」知识共享许可协议进行许可。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
