WPF模拟直播弹幕

xaml代码:

<Window ...
    Topmost="True"
    Background="Transparent"
    AllowsTransparency="True" WindowStyle="None">
<Grid>
    <Canvas x:Name="MainCanvas" Background="Transparent" />
    <Button Content="发送弹幕" BorderThickness="0" FontSize="24" Click="Button_Click" Margin="0,0,20,160" Height="40" Width="160"  HorizontalAlignment="Right" VerticalAlignment="Bottom"/>
    <Button Content="退出" BorderThickness="0" FontSize="24" Click="Button_Click_1" Margin="0,0,20,100" Height="40" Width="160" HorizontalAlignment="Right" VerticalAlignment="Bottom"/>
</Grid>
</Window>

xaml.cs代码:

Random rd = new Random();
bool[] textLineBusy;
List<string> texts = new List<string>();
double screenWidth = 0;
double animaTime = 8;

public MainWindow()
{
    WindowState = WindowState.Maximized;
    InitializeComponent();
    textLineBusy = new bool[] { false, false, false, false, false, false };
    texts.Add("(๑°⌓°๑)");
    texts.Add("二次元の美好");
    texts.Add("三次元最恶心了啊魂淡!");
    texts.Add("滋嘛叠磨瓦撕裂嘛赛!!!");
    texts.Add("大人什么的、最·讨·厌·了★♪");
    texts.Add("阁下已经「二·次·元·失·格」了吧?");
    texts.Add("嘛……说到底,你们都只是污秽の「来自三次元的大人」吧?");

    // 添加引用 System.Windows.Forms.dll
    //screenWidth = System.Windows.Forms.Screen.AllScreens[0].Bounds.Width; // 根据需求是否处理多屏幕场景
    screenWidth = SystemParameters.PrimaryScreenWidth;
}

[Obsolete]
private void Button_Click(object sender, RoutedEventArgs e)
{
    Thread animationThread = new Thread(TextInfoAnimation);
    animationThread.IsBackground = true;
    animationThread.Start();
}

[Obsolete]
private void TextInfoAnimation()
{
    for (int lineIndex = 0; lineIndex < textLineBusy.Length; lineIndex++)
    {
        if (textLineBusy[lineIndex] == false)
        {
            textLineBusy[lineIndex] = true;
            Dispatcher.Invoke(new Action(() => {
                var TextInfo = new Label() { };
                TextInfo.Foreground = new SolidColorBrush(Colors.Pink);
                TextInfo.HorizontalAlignment = HorizontalAlignment.Left;
                TextInfo.VerticalAlignment = VerticalAlignment.Bottom;

                TextInfo.Content = texts[rd.Next(texts.Count)];
                TextInfo.FontSize = 28; // 字体固定

                Canvas.SetLeft(TextInfo, screenWidth);
                Canvas.SetTop(TextInfo, 12 + lineIndex * 42); // 42 是 28 号字体的高度 + 两行文本间隔

                var formattedText = new FormattedText(
                    TextInfo.Content.ToString(),
                    System.Globalization.CultureInfo.CurrentUICulture,
                    FlowDirection.LeftToRight,
                    new Typeface(TextInfo.FontFamily, TextInfo.FontStyle, TextInfo.FontWeight, TextInfo.FontStretch),
                    TextInfo.FontSize,
                    System.Windows.Media.Brushes.Black);
                //MessageBox.Show(formattedText.Width);

                MainCanvas.Children.Add(TextInfo);
                //分为两个阶段
                //1.screenWidth 到 screenWidth-formattedText.Width
                //归零
                //2.screenWidth-formattedText.Width 到 -formattedText.Width
                var TextMove = new DoubleAnimation()
                {
                    To = screenWidth - formattedText.Width,
                    Duration = TimeSpan.FromSeconds(animaTime * formattedText.Width / screenWidth),
                };
                var TextMove2 = new DoubleAnimation()
                {
                    From = screenWidth - formattedText.Width,
                    To = -formattedText.Width,
                    Duration = TimeSpan.FromSeconds(animaTime),
                };
                TextMove.Completed += (a, b) =>
                {
                    TextInfo.BeginAnimation(Canvas.LeftProperty, TextMove2);
                    // 释放
                    textLineBusy[lineIndex] = false;
                };
                TextMove2.Completed += (a, b) =>
                {
                    MainCanvas.Children.Remove(TextInfo);
                };
                TextInfo.BeginAnimation(Canvas.LeftProperty, TextMove);
            }));
            break;
        }
    }
}

private void Button_Click_1(object sender, RoutedEventArgs e)
{
    System.Windows.Application.Current.Shutdown();
}
View Code

其中 textLineBusy 是一个锁,用于记录各行显示内容是否能继续插入新的弹幕。
基础动画过程:

 

处理“各行显示内容是否能继续插入新的弹幕”:

 

动画时间:

未处理内容:
不同 size 的文本是否可重叠?
不同 size 的文本应该使用上下挤压的方式进行显示。
文本 FontSize 获取到 实际的高度的像素点数。

posted @ 2022-05-17 11:11  Drake19  阅读(118)  评论(0编辑  收藏  举报