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(); }
其中 textLineBusy 是一个锁,用于记录各行显示内容是否能继续插入新的弹幕。
基础动画过程:
处理“各行显示内容是否能继续插入新的弹幕”:
动画时间:
未处理内容:
不同 size 的文本是否可重叠?
不同 size 的文本应该使用上下挤压的方式进行显示。
文本 FontSize 获取到 实际的高度的像素点数。