wpf 高级 XAML 动画效果。脉搏,行进的蚂蚁,旋转。警报

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25877737/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 12:32:37  来源:igfitidea点击:

Advanced XAML Animation effects. Pulse, Marching ants, Rotations. Alerts

wpfxamlanimation

提问by jrandomuser

I have a list of alarms. When alarms are activated it has been requested to make them more noticeable. When an alarms status changes I wanted to create a pulsing Outer Glow around the item for a few seconds and then have it disappear.

我有一个闹钟列表。当警报被激活时,它被要求使它们更引人注目。当警报状态发生变化时,我想在项目周围创建一个脉冲外发光几秒钟,然后让它消失。

The problem I am having is that I can't seem to make the DropShadowEffect appear only when I need it. I tried setting the opacity to 0 and the color to Transparent but then it seems to disable the animation. I considered adding the effect in with a Style Trigger but then I'm not sure how you would remove it when the animation is done?

我遇到的问题是我似乎无法让 DropShadowEffect 只在我需要的时候出现。我尝试将不透明度设置为 0,将颜色设置为透明,但似乎禁用了动画。我考虑过使用样式触发器添加效果,但是我不确定在动画完成后如何将其删除?

Any advice on how to accomplish this?

关于如何实现这一点的任何建议?

<Rectangle Grid.Column="1" Grid.Row="0">    
    <Rectangle.Effect>
        <DropShadowEffect ShadowDepth="0" BlurRadius="0" Opacity="0" Color="White"    /> 
    </Rectangle.Effect>   
<Rectangle.Style>
<Style>
    <Style.Triggers>
        <DataTrigger Binding="{Binding Value, Converter={StaticResource AlarmConverter}, IsAsync=True}" Value="true">
            <DataTrigger.EnterActions>
               <BeginStoryboard>
                   <Storyboard FillBehavior="Stop" >
                       <DoubleAnimation Storyboard.TargetProperty="Effect.Opacity" To="1" FillBehavior="Stop" />
                        <ColorAnimation Storyboard.TargetProperty="Effect.Color" To="White" FillBehavior="Stop" />
                        <DoubleAnimation Storyboard.TargetProperty="Effect.BlurRadius" From="0" To="20" RepeatBehavior="3x" FillBehavior="Stop" />                                                            
                   </Storyboard>
              </BeginStoryboard>
          </DataTrigger.EnterActions>
      </DataTrigger>

UpdateHere's an example of what a section of the screen looks like. I had to remove the text and other aspects from the screenshot due to security concerns, my apologies. I replaced most of them generic text to still provide context. Another thing to note is that in general this isn't ran on normal monitors. It usually displayed along side other screens on a very long, very large video wall.

更新这是屏幕部分外观的示例。出于安全考虑,我不得不从屏幕截图中删除文本和其他方面,我很抱歉。我替换了其中的大部分通用文本以仍然提供上下文。另一件需要注意的事情是,通常这不会在普通显示器上运行。它通常与其他屏幕一起显示在一个非常长、非常大的视频墙上。

screenshot

截屏

The Alarm with the words Binding Limits (the first word was removed, Text doesn't normally sit over like that) has a reasonable animated rolling gradient that replaced a simple flashing. Additionally the alarm status in the case causes the shape spin.

带有 Binding Limits 字样的警报(第一个字已删除,Text 通常不会像那样坐下)具有合理的动画滚动渐变,取代了简单的闪烁。此外,案件中的警报状态会导致形状旋转。

The feedback was that when an alarm status changes for the first time (from green to yellow or orange to red etc) that they would like some additional indication. I had a few different ideas. My first was to try animating the text to cause it to expand a little almost pulsing. When I tried however it expands very obviously to the right and down only and didn't really give that "Swelling" effect I had hoped for.

反馈是当警报状态第一次改变时(从绿色到黄色或橙色到红色等),他们想要一些额外的指示。我有一些不同的想法。我的第一个尝试是尝试对文本进行动画处理,使其扩展到几乎脉动的程度。然而,当我尝试时,它仅向右和向下扩展非常明显,并没有真正产生我所希望的“膨胀”效果。

Another idea for which I asked here was to possibly animate a glowing border around the alarm item. Something that would get Bright and then Dim 3 or 4 times when the status changed. I am open to other ideas however. I really like the animation abilities in WPF but I am finding difficulty in using it to articulate my ideas. (Something I think will come with time)

我在这里问的另一个想法是可能为警报项目周围的发光边框设置动画。当状态改变时,会先变亮然后变暗 3 或 4 次。然而,我对其他想法持开放态度。我真的很喜欢 WPF 中的动画功能,但我发现用它来表达我的想法很困难。(我认为会随着时间而来的东西)

UpdateTried animating the Stroke and StrokeThickness as well as the effect and while it helps the Glow stand out the border is way too hard and noticible, especially when the alarm color is red.

更新尝试为 Stroke 和 StrokeThickness 以及效果设置动画,虽然它有助于 Glow 突出边框,但边框太硬而且太明显,尤其是当警报颜色为红色时。

<BeginStoryboard>
     <Storyboard FillBehavior="Stop">
         <DoubleAnimation Storyboard.TargetProperty="StrokeThickness" To="2"   />
         <ColorAnimation Storyboard.TargetProperty="Stroke.Color" To="White"  />
         <DoubleAnimation Storyboard.TargetProperty="Effect.Opacity" To="30"   />
         <ColorAnimation Storyboard.TargetProperty="Effect.Color" To="White"  />
         <DoubleAnimation Storyboard.TargetProperty="Effect.BlurRadius" From="0" To="100" AutoReverse="True"  Duration="00:00:02" RepeatBehavior="3x" />                                                            
     </Storyboard>
</BeginStoryboard>

UpdateDemo'd an outer glow for the alarm as a whole and it was deemed too subtle. I'm entertaining the idea of a dancing 7up dot at this point... (not really)

更新演示为整个警报提供了一个外部发光,它被认为太微妙了。在这一点上,我正在考虑跳舞 7up 点的想法......(不是真的)

回答by Chris W.

Ok amigo, so I took about 15-20mins this morning to go ahead and throw together a few random examples of styles I've used in the past for notification type stuff. I'm guessing the mock you show is just a real rough example, so without knowing more precisely what it looks like it's difficult to match the style like a designer would want to.

好的,朋友,所以我今天早上花了大约 15-20 分钟继续将我过去用于通知类型内容的一些随机样式示例放在一起。我猜你展示的模拟只是一个真正的粗略例子,所以如果不更准确地了解它的外观,很难像设计师想要的那样匹配风格。

However, I imagine you could use these examples to get the creative juices flowing on how/what route to go, and just a taste of some of the things you can do real quick and easily. If you want a prettier/more precise example you'll have to share the real screens etc. The animations and stuff could apply to other objects like the icon and stuff but for this example I just threw them at some boxes.

但是,我想您可以使用这些示例来让创意源源不断地流向如何/走哪条路,并尝试一下您可以真正快速轻松地做的一些事情。如果你想要一个更漂亮/更精确的例子,你必须分享真实的屏幕等。动画和东西可以应用于其他对象,比如图标和东西,但对于这个例子,我只是把它们扔到一些盒子里。

These are from my own bag of tricks, use them freely, I have tons more different techniques I could show you if ya want also but if we get too involved, well this sort of in depth advice is how I make a living, so may have to at least charge ya a case of beer or something ;)

这些来自我自己的技巧,可以自由使用它们,如果你愿意,我可以向你展示更多不同的技巧,但如果我们参与太多,那么这种深入的建议是我谋生的方式,所以可能必须至少向你收取一箱啤酒或其他东西;)

Anyhow, throw this in a window, I just did it with a fresh quick wpf proj. so you'll just paste them in and run it, they're set to start on load.

无论如何,把它扔到一个窗口里,我只是用一个新的快速 wpf 项目来做的。所以你只需将它们粘贴进去并运行它,它们就会在加载时启动。

Main thing I've found to avoid, is messing heavily with gradients and the various pixel shader stuff like that in mass animations. However stuff like this seems to do fine.

我发现要避免的主要事情是在大量动画中大量使用渐变和各种像素着色器。然而,像这样的东西似乎做得很好。

OUTPUT (In choppy .gif animated style anyway for visual example.):

输出(对于视觉示例,无论如何都是断断续续的 .gif 动画样式。):

enter image description here

在此处输入图片说明

AND THE MAGIC:

和魔法:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" x:Class="MainWindow"
    Title="MainWindow" Height="450" Width="250">
    <Window.Resources>

        <!-- Marching Ants -->
        <Storyboard x:Key="MarchingAnts">
                <DoubleAnimation BeginTime="00:00:00"
                                Storyboard.TargetName="AlertBox"
                                Storyboard.TargetProperty="StrokeThickness"
                                To="4"
                                Duration="0:0:0.25" />
                           <!-- If you want to run counter-clockwise, just swap the 'From' and 'To' values. -->
                <DoubleAnimation BeginTime="00:00:00" RepeatBehavior="Forever" Storyboard.TargetName="AlertBox" Storyboard.TargetProperty="StrokeDashOffset" 
                                Duration="0:3:0" From="1000" To="0"/>
        </Storyboard>

        <!-- Pulse -->
        <Storyboard x:Key="Pulse" RepeatBehavior="Forever">
            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" Storyboard.TargetName="PulseBox">
                <EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="1.15"/>
                <EasingDoubleKeyFrame KeyTime="0:0:1" Value="1"/>
            </DoubleAnimationUsingKeyFrames>
            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" Storyboard.TargetName="PulseBox">
                <EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="1.15"/>
                <EasingDoubleKeyFrame KeyTime="0:0:1" Value="1"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>

        <!-- Flipper -->
        <Storyboard x:Key="Flipper" RepeatBehavior="Forever">
            <PointAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransformOrigin)" Storyboard.TargetName="FlipperBox">
                <EasingPointKeyFrame KeyTime="0:0:1" Value="0.5,0.5"/>
                <EasingPointKeyFrame KeyTime="0:0:2" Value="0.5,0.5"/>
            </PointAnimationUsingKeyFrames>
            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" Storyboard.TargetName="FlipperBox">
                <EasingDoubleKeyFrame KeyTime="0:0:1" Value="-1"/>
                <EasingDoubleKeyFrame KeyTime="0:0:2" Value="1"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>


        <!-- Elasic Lines -->
        <Storyboard x:Key="ElasticLines" RepeatBehavior="Forever" AutoReverse="True">
            <PointAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(LinearGradientBrush.EndPoint)" Storyboard.TargetName="ElasticBox">
                <EasingPointKeyFrame KeyTime="0:0:4" Value="12,8"/>
            </PointAnimationUsingKeyFrames>
        </Storyboard>

        <!-- Knight Rider -->
        <Storyboard x:Key="KnightRider" RepeatBehavior="Forever" AutoReverse="True">
            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)" Storyboard.TargetName="KRBox">
                <EasingDoubleKeyFrame KeyTime="0:0:1" Value="-50"/>
                <EasingDoubleKeyFrame KeyTime="0:0:2" Value="50"/>
                <EasingDoubleKeyFrame KeyTime="0:0:3" Value="0"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>

    </Window.Resources>
    <Window.Triggers>
        <EventTrigger RoutedEvent="FrameworkElement.Loaded">
            <BeginStoryboard Storyboard="{StaticResource Pulse}"/>
            <BeginStoryboard Storyboard="{StaticResource MarchingAnts}"/>
            <BeginStoryboard Storyboard="{StaticResource Flipper}"/>
            <BeginStoryboard Storyboard="{StaticResource ElasticLines}"/>
            <BeginStoryboard Storyboard="{StaticResource KnightRider}"/>
        </EventTrigger>
    </Window.Triggers>

    <Grid HorizontalAlignment="Center" VerticalAlignment="Center">
        <Grid.Resources>
            <Style TargetType="{x:Type TextBlock}">
                <Setter Property="Foreground" Value="White"/>
                <Setter Property="FontWeight" Value="Bold"/>
                <Setter Property="FontSize" Value="35"/>
                <Setter Property="HorizontalAlignment" Value="Center"/>
                <Setter Property="VerticalAlignment" Value="Center"/>
                <Setter Property="Text" Value="ALERT"/>
            </Style>
            <Style TargetType="{x:Type Grid}">
                <Setter Property="Margin" Value="0,10"/>                
            </Style>
            <Style TargetType="{x:Type Rectangle}">
                <Setter Property="Height" Value="50"/>
                <Setter Property="Width" Value="150"/>
            </Style>
        </Grid.Resources>

        <StackPanel>

        <!-- Marching Ants -->
        <Grid>

            <Rectangle x:Name="AlertBox"
                      Stroke="Red" 
                       StrokeDashOffset="2" StrokeDashArray="5" Margin="5">
                <Rectangle.Fill>
                    <LinearGradientBrush StartPoint="0,0" EndPoint="6,4" MappingMode="Absolute" SpreadMethod="Repeat">
                        <GradientStop Color="Red" Offset="0.25"/>
                        <GradientStop Color="#00000000" Offset="0.15"/>
                    </LinearGradientBrush>
                </Rectangle.Fill>
            </Rectangle>

            <TextBlock/>

        </Grid>
        <!-- End Marching Ants -->


        <!-- Pulse : Will not skew other elements location like width/height animations would. -->
        <Grid>
            <Border x:Name="PulseBox"
                        Background="Red" RenderTransformOrigin="0.5,0.5">
                <Border.RenderTransform>
                    <TransformGroup>
                        <ScaleTransform/>
                        <SkewTransform/>
                        <RotateTransform/>
                        <TranslateTransform/>
                    </TransformGroup>
                </Border.RenderTransform>

                <TextBlock/>

            </Border>
        </Grid>
        <!-- End Pulse -->


        <!-- Flipper -->
        <Grid>
            <Border x:Name="FlipperBox"
                        Background="Red">
                <Border.RenderTransform>
                    <TransformGroup>
                        <ScaleTransform/>
                        <SkewTransform/>
                        <RotateTransform/>
                        <TranslateTransform/>
                    </TransformGroup>
                </Border.RenderTransform>

                <TextBlock/>

            </Border>
        </Grid>
        <!-- End Flipper -->


        <!-- Elastic Lines -->
        <Grid>
            <Rectangle x:Name="ElasticBox"
                      Stroke="Red" StrokeThickness="5" Margin="5">
                <Rectangle.Fill>
                    <LinearGradientBrush StartPoint="0,0" EndPoint="6,4" MappingMode="Absolute" SpreadMethod="Repeat">
                        <GradientStop Color="Red" Offset="0.25"/>
                        <GradientStop Color="#00000000" Offset="0.15"/>
                    </LinearGradientBrush>
                </Rectangle.Fill>
            </Rectangle>

            <TextBlock/>

        </Grid>
        <!-- End Elastic Box -->


        <!-- Knight Rider -->
        <Grid>
            <Rectangle Fill="Red"/>
            <Rectangle x:Name="KRBox" Width="50" Fill="White" RenderTransformOrigin="0.5,0.5">
                <Rectangle.RenderTransform>
                    <TransformGroup>
                        <ScaleTransform/>
                        <SkewTransform/>
                        <RotateTransform/>
                        <TranslateTransform/>
                    </TransformGroup>
                </Rectangle.RenderTransform>
            </Rectangle>

            <TextBlock Foreground="Red"/>

        </Grid>
        <!-- End Knight Rider -->

        </StackPanel>

    </Grid>
</Window>

回答by Sandesh

I am adding a test scenario using TextBox

我正在使用 TextBox 添加一个测试场景

<Grid>
    <Grid.Resources>
        <SolidColorBrush x:Key="BlackColor" Color="Black" />
        <SolidColorBrush x:Key="WhiteColor" Color="White" />
    </Grid.Resources>
    <TextBox Text="{Binding Test}" Width="150" Height="25">
        <TextBox.Effect>
            <DropShadowEffect ShadowDepth="0" BlurRadius="0" Opacity="0" Color="White"    />
        </TextBox.Effect>
        <TextBox.Style>
            <Style TargetType="TextBox">
                <Style.Triggers>
                    <EventTrigger RoutedEvent="TextChanged">
                        <EventTrigger.Actions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <ThicknessAnimation Storyboard.TargetProperty="BorderThickness" From="1" To="2" Duration="0:0:2" AutoReverse="True"/>
                                    <DoubleAnimation Storyboard.TargetProperty="Effect.Opacity" To="1" />
                                    <ColorAnimation Storyboard.TargetProperty="Effect.Color" From="Red" To="Purple" Duration="0:0:2" RepeatBehavior="2x" AutoReverse="True" />
                                    <DoubleAnimation Storyboard.TargetProperty="Effect.ShadowDepth" From="0" To="1" Duration="0:0:2" RepeatBehavior="2x" AutoReverse="True"/>
                                    <DoubleAnimation Storyboard.TargetProperty="Effect.BlurRadius" From="0" To="30" Duration="0:0:2" AutoReverse="True" RepeatBehavior="2x" />
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background">
                                        <DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{StaticResource BlackColor}" />
                                        <DiscreteObjectKeyFrame KeyTime="0:0:1" Value="{StaticResource WhiteColor}" />
                                        <DiscreteObjectKeyFrame KeyTime="0:0:2" Value="{StaticResource BlackColor}" />
                                        <DiscreteObjectKeyFrame KeyTime="0:0:3" Value="{StaticResource WhiteColor}" />
                                        <DiscreteObjectKeyFrame KeyTime="0:0:4" Value="{StaticResource BlackColor}" />
                                        <DiscreteObjectKeyFrame KeyTime="0:0:5" Value="{StaticResource WhiteColor}" />
                                        <DiscreteObjectKeyFrame KeyTime="0:0:6" Value="{StaticResource BlackColor}" />
                                        <DiscreteObjectKeyFrame KeyTime="0:0:7" Value="{StaticResource WhiteColor}" />
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground">
                                        <DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{StaticResource WhiteColor}" />
                                        <DiscreteObjectKeyFrame KeyTime="0:0:1" Value="{StaticResource BlackColor}" />
                                        <DiscreteObjectKeyFrame KeyTime="0:0:2" Value="{StaticResource WhiteColor}" />
                                        <DiscreteObjectKeyFrame KeyTime="0:0:3" Value="{StaticResource BlackColor}" />
                                        <DiscreteObjectKeyFrame KeyTime="0:0:4" Value="{StaticResource WhiteColor}" />
                                        <DiscreteObjectKeyFrame KeyTime="0:0:5" Value="{StaticResource BlackColor}" />
                                        <DiscreteObjectKeyFrame KeyTime="0:0:6" Value="{StaticResource WhiteColor}" />
                                        <DiscreteObjectKeyFrame KeyTime="0:0:7" Value="{StaticResource BlackColor}" />
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </BeginStoryboard>
                        </EventTrigger.Actions>
                    </EventTrigger>
                </Style.Triggers>
            </Style>
        </TextBox.Style>
    </TextBox>
</Grid>

Added some more animation for the Backgroundand Foreground

Background和添加了更多动画Foreground