识别捏合手势

NET Multi-platform App UI (.NET MAUI) 捏合手势识别器用于执行交互式缩放。 捏合手势的一个常见场景是在捏合位置对图像进行交互式缩放。 这是通过缩放视区的内容来实现的。

在 .NET MAUI 中,捏合手势识别由 PinchGestureRecognizer 类提供,该类定义在检测到的捏合手势更改时触发的 PinchUpdated 事件。 PinchUpdated 事件随附的 PinchGestureUpdatedEventArgs 对象定义了以下属性:

  • Scale,类型为 double,指示自上次收到更新后捏合手势的相对大小。
  • ScaleOrigin,类型 Point,指示捏合手势的更新原点。
  • Status,类型为 GestureStatus,指示是否已针对新启动的手势、正在运行的手势、已完成的手势或已取消的手势引发事件。

创建 PinchGestureRecognizer

若要使 View 识别捏合手势,请创建一个 PinchGestureRecognizer 对象,处理 PinchUpdated 事件,并将新的手势识别器添加到视图上的 GestureRecognizers 集合。 下面的代码示例展示了附加到 ImagePinchGestureRecognizer

<Image Source="waterfront.jpg">
    <Image.GestureRecognizers>
        <PinchGestureRecognizer PinchUpdated="OnPinchUpdated" />
    </Image.GestureRecognizers>
</Image>

OnPinchUpdated 事件处理程序的代码应添加到代码隐藏文件中:

void OnPinchUpdated(object sender, PinchGestureUpdatedEventArgs e)
{
    // Handle the pinch
}

等效 C# 代码如下:

PinchGestureRecognizer pinchGesture = new PinchGestureRecognizer();
pinchGesture.PinchUpdated += (s, e) =>
{
    // Handle the pinch
};
image.GestureRecognizers.Add(pinchGesture);

创建捏合容器

以下示例所示的 PinchToZoomContainer 类是一个通用帮助程序类,可用于以交互方式缩放 View

public class PinchToZoomContainer : ContentView
{
    double currentScale = 1;
    double startScale = 1;
    double xOffset = 0;
    double yOffset = 0;

    public PinchToZoomContainer()
    {
        PinchGestureRecognizer pinchGesture = new PinchGestureRecognizer();
        pinchGesture.PinchUpdated += OnPinchUpdated;
        GestureRecognizers.Add(pinchGesture);
    }

    void OnPinchUpdated(object sender, PinchGestureUpdatedEventArgs e)
    {
        if (e.Status == GestureStatus.Started)
        {
            // Store the current scale factor applied to the wrapped user interface element,
            // and zero the components for the center point of the translate transform.
            startScale = Content.Scale;
            Content.AnchorX = 0;
            Content.AnchorY = 0;
        }
        if (e.Status == GestureStatus.Running)
        {
            // Calculate the scale factor to be applied.
            currentScale += (e.Scale - 1) * startScale;
            currentScale = Math.Max(1, currentScale);

            // The ScaleOrigin is in relative coordinates to the wrapped user interface element,
            // so get the X pixel coordinate.
            double renderedX = Content.X + xOffset;
            double deltaX = renderedX / Width;
            double deltaWidth = Width / (Content.Width * startScale);
            double originX = (e.ScaleOrigin.X - deltaX) * deltaWidth;

            // The ScaleOrigin is in relative coordinates to the wrapped user interface element,
            // so get the Y pixel coordinate.
            double renderedY = Content.Y + yOffset;
            double deltaY = renderedY / Height;
            double deltaHeight = Height / (Content.Height * startScale);
            double originY = (e.ScaleOrigin.Y - deltaY) * deltaHeight;

            // Calculate the transformed element pixel coordinates.
            double targetX = xOffset - (originX * Content.Width) * (currentScale - startScale);
            double targetY = yOffset - (originY * Content.Height) * (currentScale - startScale);

            // Apply translation based on the change in origin.
            Content.TranslationX = Math.Clamp(targetX, -Content.Width * (currentScale - 1), 0);
            Content.TranslationY = Math.Clamp(targetY, -Content.Height * (currentScale - 1), 0);

            // Apply scale factor
            Content.Scale = currentScale;
        }
        if (e.Status == GestureStatus.Completed)
        {
            // Store the translation delta's of the wrapped user interface element.
            xOffset = Content.TranslationX;
            yOffset = Content.TranslationY;
        }
    }
}

在本示例中,OnPinchUpdated 方法根据用户的捏合手势更新包装视图的缩放级别。 这是通过使用 PinchGestureUpdatedEventArgs 对象的 ScaleScaleOriginStatus 属性的值计算要应用于捏合手势原点的比例系数来实现的。 然后,通过将包装视图的 TranslationXTranslationYScale 属性设置为计算值,在捏合手势的原点对其进行缩放。

PinchToZoomContainer 类可以围绕 View 进行包装,以便已识别的捏合手势可以缩放包装的视图。 以下 XAML 示例展示了包装 ImagePinchToZoomContainer

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:PinchGesture;assembly=PinchGesture"
             x:Class="PinchGesture.HomePage">
    <Grid>
        <local:PinchToZoomContainer>
            <Image Source="waterfront.jpg" />
        </local:PinchToZoomContainer>
    </Grid>
</ContentPage>

在本示例中,当 Image 接收到捏合手势时,显示的图像将被放大或缩小。