SkiaSharp 自绘弹幕效果

控件名:SkiaSharpBarrage

作者: 驚鏵

原文链接:    https://github.com/yanjinhuagood/SkiaSharpBarrage

  • 框架使用.NET60

  • Visual Studio 2022;

  • 项目使用 MIT 开源许可协议;

  • 接着上一篇 WPF 弹幕

  • 上期有网友建议使用Skia实现弹幕。

    • 弹幕消息使用SKElement做弹幕展现,然后在SKCanvas进行绘制弹幕。

    • 由于需要绘制矩形与文本所以需要使用到SKBitmap进行绘制弹幕类。

    • 创建SKBitmap设置宽(根据文本的长度定义宽度)与高度40

    • 创建对象SKCanvas并实例化的时候将SKBitmap传入,然后对SKCanvas进行绘制背景DrawRoundRect 与文本DrawText ,使用属性记录XY的值方便在动画的时候让弹幕动起来。

    • BarrageRender的时候进行绘制弹幕图片DrawImage(SKBitmap,x,y)

    • 弹幕每次移动多少值 等于SKCanvas的宽除以弹幕的

    • 当弹幕移动Move()时如超过-Width则通过out返回GUID 就移除弹幕对象。

1) 准备 MsgInfo 弹幕消息类如下:

using System;
using SkiaSharp;namespace SkiaSharpBarrage
{/// <summary>///     msg info/// </summary>public class MsgInfo{private string _msg;public string GUID;public MsgInfo(string msg, SKTypeface _font, float windowsWidth){_msg = msg;var _random = new Random();var skColor = new SKColor((byte) _random.Next(1, 255),(byte) _random.Next(1, 255), (byte) _random.Next(1, 233));using var paint = new SKPaint{Color = skColor,Style = SKPaintStyle.Fill,IsAntialias = true,StrokeWidth = 2};paint.Shader = SKShader.CreateLinearGradient(new SKPoint(0, 0),new SKPoint(1, 1),new[] {SKColors.Transparent, skColor},new float[] {0, 1},SKShaderTileMode.Repeat);using var paintText = new SKPaint{Color = SKColors.White,IsAntialias = true,Typeface = _font,TextSize = 24};var textBounds = new SKRect();paintText.MeasureText(msg, ref textBounds);var width = textBounds.Width + 100;SKImage skImage;using (var bitmap = new SKBitmap((int) width, 40, true))using (var canvas = new SKCanvas(bitmap)){canvas.DrawRoundRect(0, 0, width, 40, 20, 20, paint);canvas.DrawText(msg, width / 2 - textBounds.Width / 2, bitmap.Height / 2 + textBounds.Height / 2,paintText);var image = SKImage.FromBitmap(bitmap);skImage = image;}SKImage = skImage;Width = width;X = windowsWidth + Width;CanvasWidth = windowsWidth;CostTime = TimeSpan.FromMilliseconds(Width);GUID = Guid.NewGuid().ToString("N");}public float X { get; set; }public float Y { get; set; }public float Width { get; set; }public float CanvasWidth { get; set; }public SKImage SKImage { get; set; }public float MoveNum => CanvasWidth / (float) CostTime.TotalMilliseconds;public TimeSpan CostTime { get; set; }/// <summary>///     定时调用,移动指定距离/// </summary>public void Move(out string guid){guid = string.Empty;X = X - MoveNum;if (X <= -Width)guid = GUID;}}
}

2) 新建 Barrage.cs 类如下:

using System.Collections.Generic;
using System.Linq;
using SkiaSharp;namespace SkiaSharpBarrage
{public class Barrage{private readonly SKTypeface _font;private readonly List<MsgInfo> _MsgInfo;private int _num, _index;private double _right, _top;private float _width;private readonly float _height;public Barrage(SKTypeface font, float width, float height, List<string> strList){_width = width;_height = height;_font = font;_num = (int) height / 40;_MsgInfo = new List<MsgInfo>();foreach (var item in strList) BuildMsgInfo(item);}private void BuildMsgInfo(string text){_index++;if (_right != 0)_width = (float) _right;var model = new MsgInfo(text, _font, _width);_right = _right == 0 ? _height + model.Width : _right;var y = _height - 40;_top = _top + 40 >= y ? 40 : _top;model.Y = (float) _top;_MsgInfo.Add(model);_top += 60;}public void AddBarrage(string text){BuildMsgInfo(text);}public void Render(SKCanvas canvas, SKTypeface font, int width, int height, List<string> strList){for (var i = 0; i < _MsgInfo.Count; i++){var info = _MsgInfo[i];var guid = string.Empty;info.Move(out guid);if (!string.IsNullOrEmpty(guid)){var model = _MsgInfo.FirstOrDefault(x => x.GUID == guid);_MsgInfo.Remove(model);}canvas.DrawImage(info.SKImage, info.X, info.Y);}}}
}

3) MainWindow.xaml.cs 如下:

<wpfdev:Window x:Class="SkiaSharpBarrage.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:wpfdev="https://github.com/WPFDevelopersOrg/WPFDevelopers"xmlns:skia="clr-namespace:SkiaSharp.Views.WPF;assembly=SkiaSharp.Views.WPF"mc:Ignorable="d" WindowStartupLocation="CenterScreen"ResizeMode="CanMinimize"Title="SkiaSharpBarrage - 弹幕篇" Height="450" Width="800"><Grid Margin="4"><Grid.RowDefinitions><RowDefinition /><RowDefinition Height="Auto" /></Grid.RowDefinitions><MediaElement Stretch="Uniform" Grid.RowSpan="2"Name="myMediaElement" /><skia:SKElement x:Name="skElement" /><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>
</wpfdev:Window>

3) 逻辑 MainWindow.xaml.cs 如下:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using SkiaSharp;
using SkiaSharp.Views.Desktop;namespace SkiaSharpBarrage
{/// <summary>///     Interaction logic for MainWindow.xaml/// </summary>public partial class MainWindow{private readonly Barrage _barrage;private readonly SKTypeface _font;private readonly List<string> list = new List<string>();public MainWindow(){list.Add("2333");list.Add("测试弹幕公众号:WPF开发者");list.Add("很难开心");list.Add("LOL~");list.Add("青春记忆");list.Add("bing");list.Add("Microsoft");InitializeComponent();var index = SKFontManager.Default.FontFamilies.ToList().IndexOf("微软雅黑");_font = SKFontManager.Default.GetFontStyles(index).CreateTypeface(0);_barrage = new Barrage(_font, (float) Width, (float) Height - (float) MyGrid.ActualHeight, list);skElement.PaintSurface += SkElement_PaintSurface;Loaded += delegate{myMediaElement.Source =new Uri(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Leagueoflegends.mp4"));};_ = Task.Run(() =>{try{while (true){Dispatcher.Invoke(() => { skElement.InvalidateVisual(); });_ = SpinWait.SpinUntil(() => false, 1000 / 60); //每秒60帧}}catch (Exception e){}});}private void SkElement_PaintSurface(object? sender, SKPaintSurfaceEventArgs e){var canvas = e.Surface.Canvas;canvas.Clear();_barrage.Render(canvas, _font, e.Info.Width, e.Info.Height, list);}private void ButtonBase_OnClick(object sender, RoutedEventArgs e){_barrage.AddBarrage(tbBarrage.Text);}}
}

Github|SkiaSharpBarrage[1]
Gitee|SkiaSharpBarrage[2]

参考资料

[1]

Github|SkiaSharpBarrage: https://github.com/yanjinhuagood/SkiaSharpBarrage

[2]

Gitee|SkiaSharpBarrage: https://gitee.com/yanjinhua/SkiaSharpBarrage

SkiaSharp 自绘弹幕效果相关推荐

  1. android 循环弹幕,Android自定义View实现弹幕效果

    原标题:Android自定义View实现弹幕效果 在很多视频直播中都有弹幕功能,而安卓上没有简单好用的弹幕控件,本文介绍一个自定义弹幕view的demo. 效果图: 思路: 自定义Textitem类表 ...

  2. 使用css绘制弹幕,实现弹幕效果的方法总结(css和canvas)

    这篇文章主要介绍了关于实现弹幕效果的方法总结(css和canvas) ,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下 之前在一个移动端的抽奖页面中,在抽奖结果的展示窗口需要弹幕轮播显示 ...

  3. 【Android效果集】弹幕效果

    之前在网上有看到过iOS的弹幕效果实现,搜了一下发现Android实现弹幕效果的帖子比较少,而且写得都不是很好理解,于是尝试自己做了一下,写成这篇博客,分享出来. 最终效果展示: 实现思路: 1.自定 ...

  4. 前端将数据转化为弹幕效果的实现方式

    前言 这个需求如题,大体上是将文章的评论数据,在文章的首图上面以弹幕的形式出现.当时在做这个需求的时候,花了挺多精力的,踩了很多坑,现将弹幕的实现思路写出来,如果喜欢的话可以点波赞/关注,支持一下,希 ...

  5. flutter 弹幕插件_Flutter 实现虎牙/斗鱼 弹幕效果 | 秒速技术

    老孟导读:用Flutter实现弹幕功能,轻松实现虎牙.斗鱼的弹幕效果. 先来一张效果图: 实现原理 弹幕的实现原理非常简单,即将一条弹幕从左侧平移到右侧,当然我们要计算弹幕垂直方向上的偏移,不然所有的 ...

  6. Android:简单的弹幕效果达到

    首先,效果图.分类似至360检测到的骚扰电话页面: 布局非常easy,上面是一个RelativeLayout,以下一个Button. 功能: (1)弹幕生成后自己主动从右側往左側滚动(Translat ...

  7. c#控件弹幕效果_C# Form 实现桌面弹幕

    使用C# Form 简单的实现了弹幕效果 1.创建一个Form 设置 2.添加一个计时器 3. 代码 using System; using System.Collections.Generic; u ...

  8. 微信小程序视频弹幕效果

    这次,和大家一起探讨下小程序视频弹幕 一.按照老规矩,先附上gif效果图:   二.接下来看下官方文档API对vide说明   PS:相关属性解析: danmu-list:弹幕列表 enable-da ...

  9. 【jQuery学习】—实现弹幕效果

    [jQuery学习]-实现弹幕效果

最新文章

  1. RandomUnderSampler 中的fit_resample 是 imblearn.base.py中调用output = self._fit_resample(X, y)
  2. 实例1 -- 判断输入年份是否为闰年
  3. AI真的会杀人?DeepMind开发了二维网格游戏来做测试
  4. 【转】tcp链接的状态
  5. ASP.NET Redis 开发
  6. 软件工程师生存指南:面试准备、工作经验和实用工具
  7. 转载:Linux kernel SPI驱动解释
  8. 双指针法(leetcode分类解题,C++代码详细注释)
  9. DPDK 绑定网卡之后的解绑
  10. 【报告分享】2022十大科技趋势-达摩院.pdf(附下载链接)
  11. 解决html5中video标签无法播放mp4问题的办法
  12. java gridlayout 设置列宽_在Kivy的GridLayout中设置网格列宽?
  13. 实现MySQL的Replication
  14. java输入输出流实例代码
  15. Radasm 配置goasm
  16. 常用公差配合表图_机械密封零件的公差配合与技术要求
  17. Mybatis插件动态数据库链接
  18. 如何搭建清晰易懂的数据看板?
  19. 拆t460拆机图解_雷神st pro怎么拆机?雷神st pro拆解详细评测图解
  20. IDEA在Mac下格式化代码快捷键

热门文章

  1. fget函数读取一行数据,非二进制文件 -- linux
  2. 衡阳计算机网络学校,2020衡阳市信息网络工程学校简章
  3. Ntp-server
  4. html css 横杠样式设置
  5. java的特点是什么?
  6. mybatis转义符
  7. java emd,MATLAB实现EMD分解及希尔伯特谱分析
  8. 对象序列化成JSON格式
  9. 取消文件夹git同步
  10. 【Android】自定义View、画家(画布)Canvas与画笔Paint的应用——画图、涂鸦板app的实现