UWP 从头到尾滚动文本
Posted
技术标签:
【中文标题】UWP 从头到尾滚动文本【英文标题】:UWP Scroll Text from end to start 【发布时间】:2020-01-24 09:55:14 【问题描述】:我正在实现一个滚动文本,当指针进入它时,它开始滚动其内容。
我可以使用下面的代码让它滚动:
private DispatcherTimer ScrollingTextTimer = new DispatcherTimer() Interval = TimeSpan.FromMilliseconds(16) ;
ScrollingTextTimer.Tick += (sender, e) =>
MainTitleScrollViewer.ChangeView(MainTitleScrollViewer.HorizontalOffset + 3, null, null);
if (MainTitleScrollViewer.HorizontalOffset == MainTitleScrollViewer.ScrollableWidth)
MainTitleScrollViewer.ChangeView(0, null, null);
ScrollingTextTimer.Stop();
;
XAML:
<ScrollViewer
x:Name="MainTitleScrollViewer"
Grid.Row="0"
Grid.Column="1"
Margin="10,5"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Disabled">
<TextBlock
x:Name="MainTitleTextBlock"
VerticalAlignment="Bottom"
FontSize="24"
Foreground="White" />
</ScrollViewer>
但是,我还想实现一个附加功能。当文本滚动到结尾时,我不希望它滚动回到开头。我希望它继续滚动到开头。您可以从我在下面发布的屏幕截图中了解我的意思。截图来自 Groove Music。如果我没有很好地解释我的问题,您可能需要检查一下。
一个可能的解决方案可能是将文本加倍并在它们之间放置一些空间。但如果是这样,我不知道何时停止滚动。
【问题讨论】:
【参考方案1】:这种跑马灯的效果推荐使用Storyboard
。由于时间间隔,计时器可能会导致缺少。
这是一个完整的演示,希望对你有所帮助。
xaml
<Grid>
<Grid HorizontalAlignment="Center" VerticalAlignment="Center" BorderBrush="Gray" BorderThickness="1" Padding="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Source="ms-appx:///Assets/StoreLogo.png" Width="100" Height="100" VerticalAlignment="Center"/>
<StackPanel Grid.Column="1" Margin="20,0,0,0" VerticalAlignment="Center">
<ScrollViewer Width="200"
PointerEntered="ScrollViewer_PointerEntered"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"
PointerExited="ScrollViewer_PointerExited">
<TextBlock FontSize="25" x:Name="TitleBlock">
<TextBlock.RenderTransform>
<TranslateTransform X="0"/>
</TextBlock.RenderTransform>
</TextBlock>
</ScrollViewer>
<TextBlock FontSize="20" FontWeight="Bold" Text="Gotye" Margin="0,10,0,0"/>
</StackPanel>
</Grid>
</Grid>
xaml.cs
Storyboard _scrollAnimation;
public ScrollTextPage()
this.InitializeComponent();
string text = "How about you?";
TitleBlock.Text = text + " " + text;
private void ScrollViewer_PointerEntered(object sender, PointerRoutedEventArgs e)
AnimationInit();
_scrollAnimation.Begin();
private void ScrollViewer_PointerExited(object sender, PointerRoutedEventArgs e)
_scrollAnimation.Stop();
public void AnimationInit()
_scrollAnimation = new Storyboard();
var animation = new DoubleAnimation();
animation.Duration = TimeSpan.FromSeconds(5);
animation.RepeatBehavior = new RepeatBehavior(1);
animation.From = 0;
// Here you need to calculate based on the number of spaces and the current FontSize
animation.To = -((TitleBlock.ActualWidth/2)+13);
Storyboard.SetTarget(animation, TitleBlock);
Storyboard.SetTargetProperty(animation, "(UIElement.RenderTransform).(TranslateTransform.X)");
_scrollAnimation.Children.Add(animation);
简单地说,水平滚动 TextBlock 比滚动 ScrollViewer 更可控。
思路和你的差不多,使用字符串拼接的方式实现无缝滚动,通过当前字体大小计算空间宽度,从而准确滚动到第二个字符串的开头。
最好的问候。
【讨论】:
如何根据字体大小计算空间宽度? 这取决于字体。如果是等宽字体,则空间为 1/2 字体大小。如果不是,则需要对其进行测试。没有合适的算法来确定它。你需要自己调整。 如何知道动画是否播放完毕?预期的效果是,当指针进入时,动画开始。无论指针退出事件和指针重新输入事件如何,它都会一直播放动画,直到文本完成滚动。 而且我认为不会缺少,因为我的Interval
是 16 毫秒,大约是 60 赫兹。这对人的眼睛有好处。 Animation Duration 对我来说不好,因为如果文本很长,那么滚动会很快。
注意animation
的From
和To
属性,它们标记了起点和终点。同时还可以收听_scrollAnimation.Completed
事件,这也是我使用Storyboard的原因。【参考方案2】:
这是我的做法,源代码是here(xaml)和here(csharp):
我创建了一个名为ScrollingTextBlock
的UserControl
。
这是UserControl
的 XAML 内容。
<Grid>
<ScrollViewer x:Name="TextScrollViewer">
<TextBlock x:Name="NormalTextBlock" />
</ScrollViewer>
<ScrollViewer x:Name="RealScrollViewer">
<TextBlock x:Name="ScrollTextBlock" Visibility="Collapsed" />
</ScrollViewer>
</Grid>
基本上,您需要两个重叠的ScrollViewer
s。
第一个ScrollViewer
用于检测文本是否可滚动。其中的TextBlock
用于放置文本。
第二个ScrollViewer
是真正的ScrollViewer
。您将滚动这个而不是第一个。并且其中的TextBlock
的Text
等于
ScrollTextBlock.Text = NormalTextBlock.Text + new string(' ', 10) + NormalTextBlock.Text
new string(' ', 10)
只是一些空白,使您的文本看起来不紧密连接,您可以从问题中的图像中看到。您可以将其更改为您想要的任何内容。
然后在你需要的 csharp 代码中(解释在 cmets 中):
// Using 16ms because 60Hz is already good for human eyes.
private readonly DispatcherTimer timer = new DispatcherTimer() Interval = TimeSpan.FromMilliseconds(16) ;
public ScrollingTextBlock()
this.InitializeComponent();
timer.Tick += (sender, e) =>
// Calculate the total offset to scroll. It is fixed after your text is set.
// Since we need to scroll to the "start" of the text,
// the offset is equal the length of your text plus the length of the space,
// which is the difference of the ActualWidth of the two TextBlocks.
double offset = ScrollTextBlock.ActualWidth - NormalTextBlock.ActualWidth;
// Scroll it horizontally.
// Notice the Math.Min here. You cannot scroll more than offset.
// " + 2" is just the distance it advances,
// meaning that it also controls the speed of the animation.
RealScrollViewer.ChangeView(Math.Min(RealScrollViewer.HorizontalOffset + 2, offset), null, null);
// If scroll to the offset
if (RealScrollViewer.HorizontalOffset == offset)
// Re-display the NormalTextBlock first so that the text won't blink because they overlap.
NormalTextBlock.Visibility = Visibility.Visible;
// Hide the ScrollTextBlock.
// Hiding it will also set the HorizontalOffset of RealScrollViewer to 0,
// so that RealScrollViewer will be scrolling from the beginning of ScrollTextBlock next time.
ScrollTextBlock.Visibility = Visibility.Collapsed;
// Stop the animation/ticking.
timer.Stop();
;
public void StartScrolling()
// Checking timer.IsEnabled is to avoid restarting the animation when the text is already scrolling.
// IsEnabled is true if timer has started, false if timer is stopped.
// Checking TextScrollViewer.ScrollableWidth is for making sure the text is scrollable.
if (timer.IsEnabled || TextScrollViewer.ScrollableWidth == 0) return;
// Display this first so that user won't feel NormalTextBlock will be hidden.
ScrollTextBlock.Visibility = Visibility.Visible;
// Hide the NormalTextBlock so that it won't overlap with ScrollTextBlock when scrolling.
NormalTextBlock.Visibility = Visibility.Collapsed;
// Start the animation/ticking.
timer.Start();
【讨论】:
以上是关于UWP 从头到尾滚动文本的主要内容,如果未能解决你的问题,请参考以下文章