WPF 实现弹幕效果
控件名:BarrageExample
作者:WPFDevelopersOrg
原文链接: https://github.com/WPFDevelopersOrg/WPFDevelopers
-
框架使用大于等于
.NET40
; -
Visual Studio 2022
; -
项目使用 MIT 开源许可协议;
-
此篇代码目的只是为了分享思路
-
实现基础弹幕一定是要使用
Canvas
比较简单,只需实现Left
动画从右到左。 -
弹幕消息使用 Border
做弹幕背景。 -
内容使用 TextBlock
做消息文本展示。 -
当动画执行完成默认移除 Canvas
中的弹幕控件。 -
使用这种方式去加载弹幕 GPU
会占较高。
1) 准备BarrageExample.xaml如下:
<UserControl x:Class="WPFDevelopers.Samples.ExampleViews.BarrageExample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:wpfdev="https://github.com/WPFDevelopersOrg/WPFDevelopers"
xmlns:local="clr-namespace:WPFDevelopers.Samples.ExampleViews"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Canvas Name="MyCanvas" Background="Transparent">
</Canvas>
<Grid Grid.Row="1" Name="MyGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBox wpfdev:ElementHelper.IsWatermark="True"
x:Name="tbBarrage"
wpfdev:ElementHelper.Watermark="请弹幕内容"/>
<Button Grid.Column="1" Style="{StaticResource PrimaryButton}"
Content="发射弹幕" Margin="4,0,0,0"
Click="ButtonBase_OnClick"/>
</Grid>
</Grid>
</UserControl>
2) 逻辑BarrageExample.xaml.cs如下:
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
namespace WPFDevelopers.Samples.ExampleViews
{
/// <summary>
/// BarrageExample.xaml 的交互逻辑
/// </summary>
public partial class BarrageExample : UserControl
{
private Dictionary<TimeSpan, List<Border>> _dicBorder;
private long _num, _index;
private double _right, _top;
private Random _random = new Random();
public BarrageExample()
{
InitializeComponent();
_dicBorder = new Dictionary<TimeSpan, List<Border>>();
Loaded += delegate
{
_num = (int)(ActualHeight - MyGrid.ActualHeight) / 40;
var list = new List<string>();
list.Add("2333");
list.Add("测试弹幕");
list.Add("很难开心");
list.Add("map");
list.Add("map加载");
list.Add("bing");
list.Add("地图");
foreach (var item in list)
{
SolidColorBrush brush = new SolidColorBrush(Color.FromRgb((byte)_random.Next(1, 255),
(byte)_random.Next(1, 255), (byte)_random.Next(1, 233)));
AddBarrage(brush.Color, item);
}
};
}
void AddBarrage(Color color, string text)
{
_index++;
TimeSpan time = default;
var linearGradientBrush = new LinearGradientBrush()
{
StartPoint = new Point(0, 0),
EndPoint = new Point(1, 1),
MappingMode = BrushMappingMode.RelativeToBoundingBox,
GradientStops = new GradientStopCollection
{
new GradientStop { Color = Colors.Transparent, Offset = 2},
new GradientStop { Color = color },
},
};
var border = new Border()
{
Background = linearGradientBrush,
Height = 40,
CornerRadius = new CornerRadius(20),
Padding = new Thickness(40, 0, 40, 0)
};
var textBlock = new TextBlock()
{
Text = text,
Foreground = Brushes.White,
VerticalAlignment = VerticalAlignment.Center,
};
border.Child = textBlock;
MyCanvas.Children.Add(border);
border.Loaded += delegate
{
time = TimeSpan.FromMilliseconds(border.ActualWidth * 60);
_right = _right == 0 ? ActualWidth + border.ActualWidth : _right;
var y = ActualHeight - MyGrid.ActualHeight - border.ActualHeight;
_top = _top + 40 >= y ? border.ActualHeight : _top;
Canvas.SetLeft(border, _right);
Canvas.SetTop(border, _top);
var doubleAnimation = new DoubleAnimation
{
From = _right,
To = -(ActualWidth + border.ActualWidth),
Duration = time
};
doubleAnimation.Completed += (s, e) =>
{
var animationClock = s as AnimationClock;
if (animationClock == null) return;
var duration = animationClock.Timeline.Duration;
var bordersList = new List<Border>();
_dicBorder.TryGetValue(duration.TimeSpan, out bordersList);
if (bordersList != null && bordersList.Count > 0)
{
foreach (var item in bordersList)
{
MyCanvas.Children.Remove(item);
}
_dicBorder.Remove(duration.TimeSpan);
}
};
border.BeginAnimation(Canvas.LeftProperty, doubleAnimation);
_top += border.ActualHeight + 20;
if (!_dicBorder.ContainsKey(time))
_dicBorder.Add(time, new List<Border> { border });
else
{
var bordersList = new List<Border>();
_dicBorder.TryGetValue(time, out bordersList);
bordersList.Add(border);
}
};
if (_index > _num)
{
_index = 0;
}
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
SolidColorBrush brush = new SolidColorBrush(Color.FromRgb((byte)_random.Next(1, 255),
(byte)_random.Next(1, 255), (byte)_random.Next(1, 233)));
AddBarrage(brush.Color, tbBarrage.Text);
}
}
}
Github|BarrageExample.xaml.cs[1]
Gitee|BarrageExample.xaml.cs[2]
参考资料
Github|BarrageExample.xaml.cs: https://github.com/WPFDevelopersOrg/WPFDevelopers/blob/master/src/WPFDevelopers.Samples/ExampleViews/BarrageExample.xaml.cs
[2]Gitee|BarrageExample.xaml.cs: https://gitee.com/WPFDevelopersOrg/WPFDevelopers/blob/master/src/WPFDevelopers.Samples/ExampleViews/BarrageExample.xaml.cs
原文始发于微信公众号(WPF开发者):WPF 实现弹幕效果
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/55027.html