UWP Scroll Text от конца до начала - PullRequest
0 голосов
/ 24 сентября 2019

Я использую прокручиваемый текст, который, когда указатель вводит его, начинает прокручивать его содержимое.

Я могу прокрутить его, используя следующий код:

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.Возможно, вам придется это проверить, если я не очень хорошо объяснил свой вопрос.

Normal

Scroll To the End

Возможное решение может заключаться в дублировании текста и размещении некоторого пространства между ними.Но я не знаю, когда прекратить прокрутку, если так.

Ответы [ 2 ]

0 голосов
/ 25 сентября 2019

Это мой способ сделать это, и исходный код здесь (xaml) и здесь (csharp) :

Я создал UserControl с именем ScrollingTextBlock.

Это XAML-содержимое UserControl.

<Grid>
    <ScrollViewer x:Name="TextScrollViewer">
        <TextBlock x:Name="NormalTextBlock" />
    </ScrollViewer>
    <ScrollViewer x:Name="RealScrollViewer">
        <TextBlock x:Name="ScrollTextBlock" Visibility="Collapsed" />
    </ScrollViewer>
</Grid>

Обычно вам нужно два ScrollViewer с перекрытием.

Первый ScrollViewer предназначен для определения возможности прокрутки текста.И TextBlock в нем для размещения текста.

Второй ScrollViewer является действительным ScrollViewer.Вы будете прокручивать этот не первый.И TextBlock в нем будет иметь Text, равный

ScrollTextBlock.Text = NormalTextBlock.Text + new string(' ', 10) + NormalTextBlock.Text

. new string(' ', 10) - это просто некое пустое пространство, чтобы ваш текст не выглядел плотно сцепленным, что вы можете видеть из изображения ввопрос.Вы можете изменить его на что угодно.

Затем в нужном вам коде csharp (пояснения в комментариях):

    // 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();
    }
0 голосов
/ 24 сентября 2019

Эффект этого типа шатер рекомендуется использовать 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.

Идея аналогична вашей: использовать метод сшивания строк для обеспечения плавной прокрутки и вычисления ширины пространства по текущему размеру шрифта, чтобы точно прокрутить до начала второй строки.

С уважением.

...