动画文本块从一个点到另一个

Animate a textblock from a point to another

我想将一个 TextBlock 元素从屏幕的右侧移动到左侧(如新闻中的文本)。

<Canvas>
    <!-- Offset the text using a TranslateTransform. -->
    <TextBlock Text="{Binding Picker}" VerticalAlignment="Bottom" Margin="0,0,0,0" TextWrapping="Wrap" FontSize="33" >
         <TextBlock.RenderTransform>
              <TranslateTransform X="2" Y="2" />
         </TextBlock.RenderTransform>
    </TextBlock>

    <TextBlock Text="{Binding Picker}" VerticalAlignment="Bottom" Margin="0,0,0,0" TextWrapping="Wrap" FontSize="33" />
</Canvas>

我找不到 Property/Action 来实现这一点,我真的是 UWP 的新手,而且我知道我拥有的 XAML 不会做那样的事情。 只是把另一个TextBlock像阴影效果一样

这是一种可能的解决方案 - 通过使用一些 VisualStates:

<Canvas>
    <Canvas.Resources>
        <local:InvertBooleanConverter x:Key="InvBoolConverter"/>
    </Canvas.Resources>
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="States">
            <VisualState x:Name="Left">
                <Storyboard>
                    <DoubleAnimation Storyboard.TargetName="myTextBlock" Storyboard.TargetProperty="(Canvas.Left)" To="0" Duration="0:0:1"/>
                </Storyboard>
                <VisualState.StateTriggers>
                    <StateTrigger IsActive="{Binding ElementName=myButton, Path=IsOn, Converter={StaticResource InvBoolConverter}}"/>
                </VisualState.StateTriggers>
            </VisualState>
            <VisualState x:Name="Right">
                <Storyboard>
                    <DoubleAnimation Storyboard.TargetName="myTextBlock" Storyboard.TargetProperty="(Canvas.Left)" To="200" Duration="0:0:1"/>
                </Storyboard>
                <VisualState.StateTriggers>
                    <StateTrigger IsActive="{Binding ElementName=myButton, Path=IsOn}"/>
                </VisualState.StateTriggers>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
    <!-- Offset the text using a TranslateTransform. -->
    <TextBlock x:Name="myTextBlock" Text="Test" VerticalAlignment="Bottom" Margin="0,0,0,0" TextWrapping="Wrap" FontSize="33" />
    <ToggleSwitch  x:Name="myButton" Margin="0,50,0,0" OffContent="Left" OnContent="Right"/>
</Canvas>

后面的转换器:

public class InvertBooleanConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language) => !(bool)value;
    public object ConvertBack(object value, Type targetType, object parameter, string language) => throw new NotImplementedException();
}

我在我的一个项目中创建了一个模板化控件,当文本大于矩形本身时文本会自动移动...也许这会对您有所帮助或给您一个想法

public enum MarqueeScrollingDirection
{
    FromLeft,
    FromRight,
    FromTop,
    FromBottom,
    None,
}

public sealed class MarqueeUserControl : Control
{
    public static readonly DependencyProperty MarqueeDirectionProperty = DependencyProperty.Register(nameof(MarqueeDirection), typeof(MarqueeScrollingDirection), typeof(MarqueeUserControl),new PropertyMetadata(MarqueeScrollingDirection.None));
    public MarqueeScrollingDirection MarqueeDirection
    {
        get { return (MarqueeScrollingDirection)GetValue(MarqueeDirectionProperty); }
        set { SetValue(MarqueeDirectionProperty, value); }
    }

    public static readonly DependencyProperty MarqueeTextProperty = DependencyProperty.Register(nameof(MarqueeText), typeof(string), typeof(MarqueeUserControl), new PropertyMetadata(string.Empty));
    public string MarqueeText
    {
        get { return (string)GetValue(MarqueeTextProperty); }
        set { SetValue(MarqueeTextProperty, value); }
    }

    public MarqueeUserControl()
    {
        this.DefaultStyleKey = typeof(MarqueeUserControl);
        this.SizeChanged += MarqueeUserControl_SizeChanged;
    }

    private Canvas ContentCanvas;
    private TextBlock MarqueeTextBlock;
    private Storyboard storyboard;
    private DoubleAnimation doubleAnimation;

    protected override void OnApplyTemplate()
    {
        MarqueeTextBlock = (TextBlock)GetTemplateChild(nameof(MarqueeTextBlock));
        ContentCanvas = (Canvas)GetTemplateChild(nameof(ContentCanvas));

        if (MarqueeDirection != MarqueeScrollingDirection.None)
        {
            MarqueeTextBlock.SizeChanged += MarqueeUserControl_SizeChanged;

            storyboard = new Storyboard();
            doubleAnimation = new DoubleAnimation();

            doubleAnimation.AutoReverse = true;
            doubleAnimation.RepeatBehavior = RepeatBehavior.Forever;

            if (MarqueeDirection == MarqueeScrollingDirection.FromLeft || MarqueeDirection == MarqueeScrollingDirection.FromRight)
            {
                Storyboard.SetTargetProperty(doubleAnimation, "(UIElement.RenderTransform).(TranslateTransform.X)");
            }
            if (MarqueeDirection == MarqueeScrollingDirection.FromTop || MarqueeDirection == MarqueeScrollingDirection.FromBottom)
            {
                Storyboard.SetTargetProperty(doubleAnimation, "(UIElement.RenderTransform).(TranslateTransform.Y)");
            }

            Storyboard.SetTarget(doubleAnimation, MarqueeTextBlock);
        }
        else
        {
            (MarqueeTextBlock.RenderTransform as TranslateTransform).X = (ContentCanvas.ActualWidth - MarqueeTextBlock.ActualWidth) / 2;
        }
    }

    private void MarqueeUserControl_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        if (MarqueeDirection != MarqueeScrollingDirection.None)
        {
            bool play = false;

            RectangleGeometry rectangleGeometry = new RectangleGeometry()
            {
                Rect = new Rect(0, 0, ContentCanvas.ActualWidth, ContentCanvas.ActualHeight)
            };
            ContentCanvas.Clip = rectangleGeometry;

            storyboard.Stop();
            storyboard.Children.Clear();

            switch (MarqueeDirection)
            {
                case MarqueeScrollingDirection.FromLeft:
                    doubleAnimation.From = MarqueeTextBlock.ActualWidth > ContentCanvas.ActualWidth ? ContentCanvas.ActualWidth - MarqueeTextBlock.ActualWidth : 0;
                    doubleAnimation.To = 0;
                    doubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(MarqueeTextBlock.ActualWidth > ContentCanvas.ActualWidth ? ((MarqueeTextBlock.ActualWidth - ContentCanvas.ActualWidth) / 10) +1 : 0));

                    play = MarqueeTextBlock.ActualWidth > ContentCanvas.ActualWidth;
                    break;
                case MarqueeScrollingDirection.FromRight:
                    doubleAnimation.From = 0;
                    doubleAnimation.To = MarqueeTextBlock.ActualWidth > ContentCanvas.ActualWidth ? ContentCanvas.ActualWidth - MarqueeTextBlock.ActualWidth : 0;
                    doubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(MarqueeTextBlock.ActualWidth > ContentCanvas.ActualWidth ? ((MarqueeTextBlock.ActualWidth - ContentCanvas.ActualWidth) / 10) + 1 : 0));

                    play = MarqueeTextBlock.ActualWidth > ContentCanvas.ActualWidth;
                    break;
                case MarqueeScrollingDirection.FromTop:

                    play = MarqueeTextBlock.ActualWidth > ContentCanvas.ActualWidth;
                    break;
                case MarqueeScrollingDirection.FromBottom:

                    play = MarqueeTextBlock.ActualWidth > ContentCanvas.ActualWidth;
                    break;
                case MarqueeScrollingDirection.None:

                    play = false;
                    break;
                default:
                    break;
            }

            if (play)
            {
                storyboard.Children.Add(doubleAnimation);
                storyboard.Begin();
            }
            else
            {
                (MarqueeTextBlock.RenderTransform as TranslateTransform).X = (ContentCanvas.ActualWidth - MarqueeTextBlock.ActualWidth) / 2;
            }
        }
    }
}

还有 Generic.xaml

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:uc="using:roomZone.UserControls">

<Style TargetType="uc:MarqueeUserControl" >
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="uc:MarqueeUserControl">
                <RelativePanel x:Name="RootElement"
                      Background="{TemplateBinding Background}"
                      BorderBrush="{TemplateBinding BorderBrush}"
                      BorderThickness="{TemplateBinding BorderThickness}" >
                    <Canvas x:Name="ContentCanvas" RelativePanel.AlignLeftWithPanel="True" RelativePanel.AlignRightWithPanel="True" RelativePanel.AlignTopWithPanel="True" RelativePanel.AlignBottomWithPanel="True"
                            MinWidth="100" MinHeight="16" >
                        <Border VerticalAlignment="Center" >
                            <TextBlock x:Name="MarqueeTextBlock"
                                       HorizontalAlignment="Left"
                                       VerticalAlignment="Center"
                                       Text="{TemplateBinding MarqueeText}"
                                       Foreground="{TemplateBinding Foreground}"
                                       FontFamily="{TemplateBinding FontFamily}"
                                       FontSize="{TemplateBinding FontSize}"
                                       FontStyle="{TemplateBinding FontStyle}"
                                       FontStretch="{TemplateBinding FontStretch}"
                                       FontWeight="{TemplateBinding FontWeight}" >
                                <TextBlock.RenderTransform>
                                    <TranslateTransform />
                                </TextBlock.RenderTransform>
                            </TextBlock>
                        </Border>
                    </Canvas>
                </RelativePanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

</ResourceDictionary>