在UWP中旋转,缩放和平移元素

时间:2017-12-14 21:47:56

标签: uwp gestures

我的目标非常简单。我希望能够使用主要的触摸屏手势在我的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;
}

整体而言,功能似乎有效。但似乎转型中心也存在一些问题。开始一个新的手势通常是图像跳跃/偏移和操纵有时使用错误的中心。

过去几天我尝试了很多东西,但我似乎无法掌握真正的问题。也许我只是这么简单。我是否必须在其他一些操作事件中执行操作。希望有人可以帮助我。

提前致谢。

1 个答案:

答案 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;
}