本文來告訴大家如何通過 Win2d 完全控制筆跡繪制邏輯,本文適合用來實作復雜的自定義邏輯,可以完全控制筆跡的行為,包括在書寫程序中切換模式,如進行手勢擦除切換為橡皮擦模式
本文提供的方法適合用來做復雜的自定義,本文的方法的優點也是缺點,優點是啥都可以自己控制,缺點是啥都需要自己控制,需要自己處理筆跡的多筆同步問題,處理筆跡的長筆跡分段問題,處理筆跡的繪制問題,處理動態筆跡切換
本文提供的方法依然可以實作非常高性能的筆跡,比 WPF 最快的筆跡實作還要快,但需要自己處理好各個部分的邏輯,如動態筆跡和靜態筆跡,筆跡分段等邏輯,本文提供的方法的性能依然不如只使用默認的 InkCanvas 快
界面
在開始之前,請先安裝 Win2d 庫,可參閱 win10 uwp win2d 入門 看這一篇就夠了 博客了解如何安裝
在 XAML 界面上加上 xmlns:canvas="using:Microsoft.Graphics.Canvas.UI.Xaml" 命名空間,用來匯入 Win2d 控制元件,界面如下
<Grid Background="#565656">
<canvas:CanvasControl x:Name="Canvas" Draw="Canvas_OnDraw"/>
<InkCanvas x:Name="InkCanvas" />
</Grid>
本文將使用一個 InkCanvas 放在 Win2d 的 CanvasControl 上層,讓 InkCanvas 作為快速的事件接收層,讓 Win2d 的 CanvasControl 作為實際的繪制層,其實,更好的界面框架是存放兩個 Win2d 的 CanvasControl 分別用來存放動態筆跡和靜態筆跡,如果自己實作的筆跡沒有分動態筆跡和靜態筆跡,那么可以忽略,本文為了簡潔將不演示動態筆跡和靜態筆跡的處理
此時的界面邏輯如下
<Page
x:
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:KeanearkallhawDaherenenallyi"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:canvas="using:Microsoft.Graphics.Canvas.UI.Xaml"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid Background="#565656">
<canvas:CanvasControl x:Name="Canvas" Draw="Canvas_OnDraw"/>
<InkCanvas x:Name="InkCanvas" />
</Grid>
</Page>
初始化筆跡接收
在建構式初始化筆跡的接收邏輯,通過 InkCanvas 進行快速的事件接收
private readonly InkSynchronizer _inkSynchronizer;
public MainPage()
{
this.InitializeComponent();
_inkSynchronizer = InkCanvas.InkPresenter.ActivateCustomDrying();
InkCanvas.InkPresenter.SetPredefinedConfiguration(InkPresenterPredefinedConfiguration
.SimpleMultiplePointer);
InkCanvas.InkPresenter.InputDeviceTypes =
CoreInputDeviceTypes.Touch | CoreInputDeviceTypes.Pen | CoreInputDeviceTypes.Mouse;
InkCanvas.InkPresenter.UnprocessedInput.PointerMoved += UnprocessedInput_PointerMoved;
InkCanvas.InkPresenter.InputProcessingConfiguration.Mode = InkInputProcessingMode.None;
InkCanvas.InkPresenter.InputProcessingConfiguration.RightDragAction =
InkInputRightDragAction.LeaveUnprocessed;
}
以上的代碼里面,只是監聽了 UnprocessedInput 的 PointerMoved 事件,事實上需要監聽更多的事件用來了解筆跡的繪制開始和完成邏輯,本文為了方便演示,就不詳細寫所有邏輯
以上各個部分邏輯的含義,請參閱 win10 uwp 通過 win2d 畫出筆跡
收集筆跡
在 UnprocessedInput_PointerMoved 將是本文的核心邏輯,在這里通過事件引數了解到當前是哪個手指或筆觸摸,以及通過 InkStrokeBuilder 將輸入的點構造筆跡
private void UnprocessedInput_PointerMoved(InkUnprocessedInput sender, Windows.UI.Core.PointerEventArgs args)
{
var id = args.CurrentPoint.PointerId;
// 需要根據 id 分開多個手指
InkStrokeBuilder.SetDefaultDrawingAttributes(new InkDrawingAttributes()
{
Color = Colors.Blue,
Size = new Size(5, 5)
});
_currentPointerList.AddRange(args.GetIntermediatePoints());
_inkStroke = InkStrokeBuilder.CreateStrokeFromInkPoints(
_currentPointerList.Select(t => new InkPoint(t.Position, t.Properties.Pressure)), Matrix3x2.Identity);
Canvas.Invalidate();
}
private readonly List<PointerPoint> _currentPointerList = new List<PointerPoint>();
private InkStroke _inkStroke;
private InkStrokeBuilder InkStrokeBuilder { get; } = new InkStrokeBuilder();
以上代碼沒有撰寫的部分是了解當前是由哪個 id 的設備觸發的事件,如有多個手指在觸摸,那么不同的手指的 id 是不相同的,需要自己創建串列陣列進行處理
另外,通過 InkStrokeBuilder 的 CreateStrokeFromInkPoints 創建的 InkStroke 是需要預先在 SetDefaultDrawingAttributes 設定繪制屬性的,而不是在創建之后依然可以設定,另外上面代碼只使用了一個 InkStroke 欄位,實際上需要根據當前是否有多指觸摸的需求,使用串列存放多個筆跡
本文以上代碼通過 CreateStrokeFromInkPoints 創建是不包含筆跡分段的,也就是說在用戶繪制一段長線,將會需要使用較多的計算資源創建筆跡,請在自己的產品邏輯里面,手動分開為多個不同的筆跡段,用來提升性能
上面代碼通過呼叫 CanvasControl 的 Invalidate 讓 Win2d 的畫布重新繪制,重新繪制會進入 Canvas_OnDraw 方法,將在此方法繪制出筆跡
繪制筆跡
繪制筆跡的方法十分簡單,呼叫 Win2d 的 DrawInk 方法傳入筆跡即可
private void Canvas_OnDraw(CanvasControl sender, CanvasDrawEventArgs args)
{
if (_inkStroke != null)
{
args.DrawingSession.DrawInk(new []{_inkStroke});
}
}
為什么在 Win2d 的設計里面,是傳入陣列?原因是筆跡是需要分段的,多段筆跡可以一起繪制,另外,如果有筆跡分段,那么邏輯上就需要額外的轉換為靜態筆跡的功能,大概就是將一段連續的多段筆跡合成一段筆跡的程序,建議繪制動態筆跡和靜態筆跡放在兩個 Win2d 的 CanvasControl 里,這樣也能提升筆跡的動態繪制性能,因為筆跡在繪制的時候需要不斷呼叫 Win2d 的重繪,如果此時重繪的是一個只包含很少筆跡的動態筆跡層的畫布,那每次重繪的性能就比較好
無限漫游
如果需要做無限漫游,可以使用 CanvasVirtualControl 做一個超級大的畫布,同時只畫出可見的范圍
使用時需要自己轉換坐標,可以在 InkStrokeBuilder 的 CreateStrokeFromInkPoints 方法傳入縮放和平移的矩陣,此時創建出來的筆跡是包含了變換的
代碼
本文所有代碼放在github 和 gitee 歡迎訪問
可以通過如下方式獲取本文的源代碼,先創建一個空檔案夾,接著使用命令列 cd 命令進入此空檔案夾,在命令列里面輸入以下代碼,即可獲取到本文的代碼
git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin d33e26640f0108ae6bb29b90e7b189a14a92d624
以上使用的是 gitee 的源,如果 gitee 不能訪問,請替換為 github 的源
git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
獲取代碼之后,進入 KeanearkallhawDaherenenallyi 檔案夾
參考
更多筆跡和觸摸,請參閱 觸摸相關
博客園博客只做備份,博客發布就不再更新,如果想看最新博客,請到 https://blog.lindexi.com/

本作品采用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可,歡迎轉載、使用、重新發布,但務必保留文章署名[林德熙](http://blog.csdn.net/lindexi_gd)(包含鏈接:http://blog.csdn.net/lindexi_gd ),不得用于商業目的,基于本文修改后的作品務必以相同的許可發布,如有任何疑問,請與我[聯系](mailto:[email protected]),
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/308048.html
標籤:UWP
下一篇:Cannot find setup engine instance. Visual Studio 2017 安裝拓展失敗解決方案
