WPF滚动字幕文本动画(WPF Marquee Text Animation)

2019-07-21 06:42发布

我可以滚动文本,与TranslateTransform但是当动画接近完成,我想它重新开始。 像蛇:)

这是我得到了什么:

<StackPanel Orientation="Horizontal" Margin="0,0,0,0">
    <StackPanel.RenderTransform>
        <TranslateTransform x:Name="transferCurreny" X="-40"/>
    </StackPanel.RenderTransform>
    <StackPanel.Triggers>
        <EventTrigger RoutedEvent="StackPanel.Loaded">
            <BeginStoryboard>
                <Storyboard>
                    <DoubleAnimation From="0" To="-900" Duration="00:00:10"
                      Storyboard.TargetProperty="X"
                      Storyboard.TargetName="transferCurreny"
                      RepeatBehavior="Forever"/>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </StackPanel.Triggers>
    <TextBlock FontSize="25"  x:Name="txtKron" Margin="10,0,7,0"/>
</StackPanel>

这是想什么我:

Answer 1:

这样的事情应该做的伎俩。

您可以添加一个CanvasStackPanel 2周TextBlocks一组到位置0和一组到ActualWidth的的StackPanel ,然后在文本的首块进入屏幕外的其他块将映入眼帘。

我使用的原因Canvas是因为Canvas是实际支持的唯一元素ClipToBounds="false" ,这允许第二个TextBlock是可见的,即使其放置在边界之外Canvas本身

我们还需要一个IValueConverter如果你想从右向左滚动,以获得正确的负值。

我还增加了事件触发SizeChanged因此如果调整窗口的大小动画值将正确更新。

码:

namespace WpfApplication9
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

        public MainWindow()
        {
            InitializeComponent();
        }
    }

    public class NegatingConverter : IValueConverter
    {

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value is double)
            {
                return -((double)value);
            }
            return value;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value is double)
            {
                return +(double)value;
            }
            return value;
        }
    }
}

XAML:

<Window x:Class="WpfApplication9.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication9"
        Title="MainWindow" Height="83" Width="222" Name="UI" Tag="Tol Level">
    <StackPanel Orientation="Horizontal" x:Name="stack">
        <StackPanel.Resources>
            <local:NegatingConverter x:Key="NegatingConverter" />
            <Storyboard x:Key="slide">
                <DoubleAnimation From="0" To="{Binding Width, ElementName=canvas, Converter={StaticResource NegatingConverter}}" Duration="00:00:10"
                      Storyboard.TargetProperty="X"
                      Storyboard.TargetName="transferCurreny"
                      RepeatBehavior="Forever"/>
            </Storyboard>
        </StackPanel.Resources>
        <StackPanel.RenderTransform>
            <TranslateTransform x:Name="transferCurreny" X="0"/>
        </StackPanel.RenderTransform>
        <StackPanel.Triggers>
            <EventTrigger RoutedEvent="StackPanel.Loaded">
                <BeginStoryboard Storyboard="{StaticResource slide}" />
            </EventTrigger>
            <EventTrigger RoutedEvent="StackPanel.SizeChanged">
                <BeginStoryboard Storyboard="{StaticResource slide}" />
            </EventTrigger>
        </StackPanel.Triggers>
        <Canvas x:Name="canvas" Width="{Binding ActualWidth, ElementName=stack}">
            <TextBlock Text="StackOverflow" FontSize="25"  x:Name="txtKron" Canvas.Left="0"/>
            <TextBlock Text="{Binding Text, ElementName=txtKron}" FontSize="25" Canvas.Left="{Binding Width, ElementName=canvas}"/>
        </Canvas>
    </StackPanel>
</Window>

结果:

编辑:左到右

 <StackPanel Orientation="Horizontal" x:Name="stack">
        <StackPanel.Resources>
            <local:NegatingConverter x:Key="NegatingConverter" />
            <Storyboard x:Key="slide">
                <DoubleAnimation From="0" To="{Binding Width, ElementName=canvas}" Duration="00:00:10"
                      Storyboard.TargetProperty="X"
                      Storyboard.TargetName="transferCurreny"
                      RepeatBehavior="Forever"/>
            </Storyboard>
        </StackPanel.Resources>
        <StackPanel.RenderTransform>
            <TranslateTransform x:Name="transferCurreny" X="0"/>
        </StackPanel.RenderTransform>
        <StackPanel.Triggers>
            <EventTrigger RoutedEvent="StackPanel.Loaded">
                <BeginStoryboard Storyboard="{StaticResource slide}" />
            </EventTrigger>
            <EventTrigger RoutedEvent="StackPanel.SizeChanged">
                <BeginStoryboard Storyboard="{StaticResource slide}" />
            </EventTrigger>
        </StackPanel.Triggers>
        <Canvas x:Name="canvas" Width="{Binding ActualWidth, ElementName=stack}">
            <TextBlock Text="StackOverflow" FontSize="25"  x:Name="txtKron" Canvas.Left="0"/>
            <TextBlock Text="{Binding Text, ElementName=txtKron}" FontSize="25" Canvas.Left="{Binding Width, ElementName=canvas, Converter={StaticResource NegatingConverter}}"/>
        </Canvas>
    </StackPanel>


Answer 2:

在上面的回答的代码不会产生连续滚动。 下面是连续的平滑滚动的代码。

XAML:

<Window x:Class="Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Grid>
        <Canvas Margin="6,83,9,0" Name="ViewingBox" Background="YellowGreen" Height="35" VerticalAlignment="Top">
            <Label Canvas.Left="263" Canvas.Top="-2" Height="49" Name="BoxOne" FontSize="20">I need breakfast.</Label>
            <Label Canvas.Left="263" Canvas.Top="-2" Height="49" HorizontalAlignment="Stretch" Name="BoxTwo" VerticalAlignment="Top" FontSize="20">You can have oranges and egg.</Label>
        </Canvas>   
    </Grid>
</Window>

VB代码背后:

Imports System.Windows.Media.Animation

Public Enum Texts
    BoxOne
    BoxTwo
End Enum

Class Window1
    Private dubAnim As New DoubleAnimation()
    Private dubAnim2 As New DoubleAnimation()
    Private NewsTimer As New Windows.Threading.DispatcherTimer()
    Dim leadText As Texts = Texts.BoxOne

    Private Sub Window1_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
        dubAnim.From = ViewingBox.ActualWidth
        dubAnim.To = -BoxOne.ActualWidth
        dubAnim.SpeedRatio = 0.05
        AddHandler dubAnim.Completed, AddressOf dubAnim_Completed
        Timeline.SetDesiredFrameRate(dubAnim, 320)
        BoxOne.BeginAnimation(Canvas.LeftProperty, dubAnim)

        dubAnim2.From = ViewingBox.ActualWidth
        dubAnim2.To = -BoxTwo.ActualWidth
        dubAnim2.SpeedRatio = 0.05
        Timeline.SetDesiredFrameRate(dubAnim2, 320)
        AddHandler dubAnim2.Completed, AddressOf dubAnim2_Completed

        AddHandler NewsTimer.Tick, AddressOf NewsTimer_Tick
        NewsTimer.Interval = New TimeSpan(0, 0, 0.9)
        NewsTimer.Start()
    End Sub

    Private Sub NewsTimer_Tick(ByVal sender As Object, ByVal e As EventArgs)
        Dim BoxOneLocation As Point = BoxOne.TranslatePoint(New Point(0, 0), ViewingBox)
        Dim BoxTwoLocation As Point = BoxTwo.TranslatePoint(New Point(0, 0), ViewingBox)

        If leadText = Texts.BoxOne Then
            Dim loc As Double = BoxOneLocation.X + BoxOne.ActualWidth
            If loc < ViewingBox.ActualWidth / 1.5 Then
                BoxTwo.BeginAnimation(Canvas.LeftProperty, dubAnim2)
                NewsTimer.Stop()
            End If
        Else
            Dim loc As Double = BoxTwoLocation.X + BoxTwo.ActualWidth
            If loc < ViewingBox.ActualWidth / 1.5 Then
                BoxOne.BeginAnimation(Canvas.LeftProperty, dubAnim)
                NewsTimer.Stop()
            End If
        End If
    End Sub

    Private Sub dubAnim_Completed(ByVal sender As Object, ByVal e As EventArgs)
        leadText = Texts.BoxTwo
        NewsTimer.Start()
    End Sub

    Private Sub dubAnim2_Completed(ByVal sender As Object, ByVal e As EventArgs)
        leadText = Texts.BoxOne
        NewsTimer.Start()
    End Sub
End Class


Answer 3:

Exteding的sa_ddam213的答案 ,这是第一个动画(从右到左)的修改。 这会为长串的工作。 :)

<StackPanel Orientation="Horizontal"
                    x:Name="stack" 
                    Grid.Column="0"
                    Margin="0"                        >

            <StackPanel.Resources>
                <local1:NegatingConverter x:Key="NegatingConverter" />
                <Storyboard x:Key="slide">
                    <DoubleAnimation From="{Binding ActualWidth, ElementName=stack}" 
                                     To="{Binding ActualWidth, ElementName=txtKron, Converter={StaticResource NegatingConverter}}" 
                                     Duration="00:00:30"
                                     Storyboard.TargetProperty="X"
                                     Storyboard.TargetName="transferCurreny2"
                                     RepeatBehavior="Forever"/>
                </Storyboard>
            </StackPanel.Resources>

            <Label Content="{Binding Path=RSSFeed}" 
                       x:Name="txtKron" 
                       Canvas.Left="0"
                       Foreground="#E9D460"
                       Padding="0"
                       Margin="0"
                       VerticalAlignment="Center">

                <Label.Triggers>
                    <EventTrigger RoutedEvent="Label.Loaded">
                        <BeginStoryboard Storyboard="{StaticResource slide}"/>
                    </EventTrigger>
                    <EventTrigger RoutedEvent="Label.SizeChanged">
                        <BeginStoryboard Storyboard="{StaticResource slide}"/>
                    </EventTrigger>
                </Label.Triggers>

                <Label.RenderTransform>
                    <TranslateTransform x:Name="transferCurreny2" X="0"/>
                </Label.RenderTransform>
            </Label>

        </StackPanel>


文章来源: WPF Marquee Text Animation