最近博主需要实现一个画板功能,可以写字并且支持触屏的手势缩放以及拖动。
找资料的时候发现网上相关资料特别少,于是经历了#$#@!##$#¥#$*就完成了。
上教程:
对InkCanvas如还有不会使用的,参考这篇文章(WPF InkCanvas 画图 基础使用教程)
这样我们便有了一个最基本的画板,下面我们先用鼠标滚轮来实现画板放大缩小。
如果对InkCanvas本身控件进行缩放移动,那么将会露出部分父容器Grid的背景色,要解决这个问题,我们只需要对墨迹进行缩放即可,对ink.Strokes进行操作,使用Transform方法对其进行变换,Matrix是一个矩阵变换的类(C# 矩阵变换Matrix),然而我们用自带的方法就OK了,以鼠标为中心点进行缩放:
private void ink_MouseWheel(object sender, MouseWheelEventArgs e)
{
if (e.Delta < 0)
{
foreach (Stroke stroke in ink.Strokes)
{
Matrix matrix = new Matrix();
//缩小 小于1为缩小(最好不要为负数),大于1为放大,此为缩小0.8倍
matrix.ScaleAt(0.8, 0.8, Mouse.GetPosition(ink).X, Mouse.GetPosition(ink).Y);
//X轴移动 正数为右,负数为左,此为右移1.2倍 斜着移动设置两个值
matrix.Translate(1.2, 0);
stroke.Transform(matrix, false);
}
}
else
{
foreach (Stroke stroke in ink.Strokes)
{
Matrix matrix = new Matrix();
//放大 此为放大1.25倍
matrix.ScaleAt(1.25, 1.25, Mouse.GetPosition(ink).X, Mouse.GetPosition(ink).Y);
//Y轴移动 此为左移1.2倍
matrix.Translate(0, 1.2);
stroke.Transform(matrix, false);
}
}
}
我们需要了解几个事件并通过他们完成各种手势操作:ManipulationStarting(开始)、ManipulationStarted(开始以后)、ManipulationDelta(手势)、ManipulationInertiaStarting(惯性)、ManipulationCompleted(完成),并把控件的IsManipulationEnabled设为"True",于是就出现了下面的代码:
经博主实验,我们面临了几个比较坑的问题:
1.WPF识别多个鼠标或者触摸设备是异步的
2.InkCanvas触摸/点击移动就会留下墨迹
3.手势如何实现
为了解决第一个问题,我们使用PreviewTouchDown事件进行设备的捕获并保存,第二个问题我们只需要让画笔的InkCanvasEditingMode属性为None:
定义全局变量
//记录触摸设备ID
private List dec = new List();
//中心点
Point centerPoint;
PreviewTouchDown事件:
private void ink_PreviewTouchDown(object sender, TouchEventArgs e)
{
dec.Add(e.TouchDevice.Id);
//设备1个的时候,记录中心点
if (dec.Count == 1)
{
TouchPoint touchPoint = e.GetTouchPoint(ink);
centerPoint = touchPoint.Position;
}
//设备两个及两个以上,将画笔功能关闭
if (dec.Count > 1)
{
if (ink.EditingMode != InkCanvasEditingMode.None)
{
ink.EditingMode = InkCanvasEditingMode.None;
}
}
}
PreviewTouchUp事件:
private void ink_PreviewTouchUp_PreviewTouchUp(object sender, TouchEventArgs e)
{
//手势完成后切回之前的状态
if (dec.Count > 1)
{
if (ink.EditingMode == InkCanvasEditingMode.None)
{
ink.EditingMode = InkCanvasEditingMode.Ink;
}
}
dec.Remove(e.TouchDevice.Id);
}
接下来我们需要实现手势的操作:
private void touchGrid_ManipulationStarting(object sender, ManipulationStartingEventArgs e)
{
e.ManipulationContainer = ink;
e.Mode = ManipulationModes.All;
}
private void touchGrid_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
{
//小于两指 不触发事件
if (dec.Count < 2) return;
//两指缩放
if (dec.Count == 2)
{
foreach (Stroke stroke in ink.Strokes)
{
Matrix matrix = new Matrix();
matrix.ScaleAt(e.DeltaManipulation.Scale.X, e.DeltaManipulation.Scale.Y, centerPoint.X, centerPoint.Y);
stroke.Transform(matrix, false);
}
}
//三指滑动
if (dec.Count == 3)
{
foreach (Stroke stroke in ink.Strokes)
{
Matrix matrix = new Matrix();
matrix.Translate(e.DeltaManipulation.Translation.X, e.DeltaManipulation.Translation.Y);
stroke.Transform(matrix, false);
}
}
}
private void touchGride_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
{
//TODO 完成之后需要做的事情
}