我的目标非常简单。我希望能够使用主要的触摸屏手势在我的UWP应用程序中对图像进行多次转换。更精确我想处理每个操作,如
平移(翻译) - 用于在画布周围平移图像的一个手指手势。
缩放 - 缩放到缩放,使用手势中心作为缩放中心。
旋转 - 标准的两个手指手势,使用手势中心作为旋转中心。
我创建了一个非常简单的POC,可以找到here
POC非常简单,看起来像这样
<Page
x:Class="GesturesManipulations.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:GesturesManipulations"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Canvas x:Name="container" Background="Silver">
<Image
x:Name="image"
Stretch="Uniform"
Canvas.Left="100" Canvas.Top="200"
Source="Assets/windows10-uwp.jpg"
ManipulationMode="TranslateX,TranslateY,Scale,Rotate"
ManipulationDelta="OnManipulationDelta">
<Image.RenderTransform>
<TransformGroup>
<ScaleTransform x:Name="scaleTransform" />
<RotateTransform x:Name="rotateTransform" />
<TranslateTransform x:Name="translateTransform" />
</TransformGroup>
</Image.RenderTransform>
</Image>
</Canvas>
</Page>
[代码隐藏]
private void OnManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
FrameworkElement origin = sender as FrameworkElement;
FrameworkElement parent = origin.Parent as FrameworkElement;
var localCoords = e.Position;
var relativeTransform = origin.TransformToVisual(parent);
Point parentContainerCoords = relativeTransform.TransformPoint(localCoords);
var center = parentContainerCoords;
// translate/panning
translateTransform.X += e.Delta.Translation.X;
translateTransform.Y += e.Delta.Translation.Y;
rotateTransform.CenterX = center.X;
rotateTransform.CenterY = center.Y;
rotateTransform.Angle += e.Delta.Rotation;
scaleTransform.CenterX = center.X;
scaleTransform.CenterY = center.Y;
scaleTransform.ScaleX *= e.Delta.Scale;
scaleTransform.ScaleY *= e.Delta.Scale;
}
整体而言,功能似乎有效。但似乎转型中心也存在一些问题。开始一个新的手势通常是图像跳跃/偏移和操纵有时使用错误的中心。
过去几天我尝试了很多东西,但我似乎无法掌握真正的问题。也许我只是这么简单。我是否必须在其他一些操作事件中执行操作。希望有人可以帮助我。
提前致谢。
答案 0 :(得分:0)
在解决中心旋转问题很多之后,我终于找到了解决方法。
根据Microsoft Blog entry的实现方式,如下:
void ManipulateMe_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
previousTransform.Matrix = transforms.Value;
// Get center point for rotation
Point center = previousTransform.TransformPoint(new Point(e.Position.X, e.Position.Y));
deltaTransform.CenterX = center.X;
deltaTransform.CenterY = center.Y;
// Look at the Delta property of the ManipulationDeltaRoutedEventArgs to retrieve
// the rotation, scale, X, and Y changes
deltaTransform.Rotation = e.Delta.Rotation;
deltaTransform.TranslateX = e.Delta.Translation.X;
deltaTransform.TranslateY = e.Delta.Translation.Y;
}
但是问题是,e.Position值不是相对于调用ManipulationDelta事件的元素,而是相对于被触摸的元素!因此,如果元素内有多个元素(例如网格),则e.Position相对于被触摸的子元素。 因此,我们首先需要将e.Position转换为容器元素,然后将其转换为屏幕位置。
因此正确的代码应为:
void ManipulateMe_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
previousTransform.Matrix = transforms.Value;
// Get center point for rotation
var posX = e.Position.X;
var posY = e.Position.Y;
////// FIRST GET TOUCH POSITION RELATIVE TO THIS ELEMENT ///
if(e.Container != null)
{
var p = e.Container.TransformToVisual(this).TransformPoint(new Point(posX, posY)); //transform touch point position relative to this element
posX = p.X;
posY = p.Y;
}
Point center = previousTransform.TransformPoint(new Point(posX, posY));
deltaTransform.CenterX = center.X;
deltaTransform.CenterY = center.Y;
// Look at the Delta property of the ManipulationDeltaRoutedEventArgs to retrieve
// the rotation, scale, X, and Y changes
deltaTransform.Rotation = e.Delta.Rotation;
deltaTransform.TranslateX = e.Delta.Translation.X;
deltaTransform.TranslateY = e.Delta.Translation.Y;
}