XAML .NET MAUI中的PinchGestureRecognizer不会留在其容器中

b09cbbtk  于 2023-09-28  发布在  .NET
关注(0)|答案(1)|浏览(129)

我有一个PNG图像,我必须放大(放大和缩小)。每次我放大图像时,图像都会根据需要进行预放大,但它所在的帧会扩展到整个应用程序。左侧有一个锁定的壳弹出菜单(稍后将设置为弹出)。当图像被放大时,它当然应该留在它的框架中,这不应该改变。仅应实现放大。
xaml文件:

<?xml version="1.0" encoding="utf-8" ?>
    <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 Shell.BackgroundColor="#696969"
                 xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
                 x:Class="EngineCheck.Views.EngineView"
                 xmlns:vm="clr-namespace:EngineCheck.ViewModels">
        <!--Engine image view-->
        <Frame x:Name="scaledContentContainer" MaximumHeightRequest="1000" 
            MaximumWidthRequest="1000">
            <Image x:Name="image" 
                   Aspect="AspectFit" 
                   Source="korm110dk1_dwt000280_20230626145746_w3b6rm0110_04_01_io.png">
                <Image.GestureRecognizers>
                    <PinchGestureRecognizer PinchUpdated="OnPinchUpdated" />
                    <PanGestureRecognizer PanUpdated="OnPanUpdated"/>
                </Image.GestureRecognizers>
           </Image>
        </Frame>
    </ContentPage>

xaml.cs文件

public partial class EngineView:ContentPage {
    private double _currentScale = 1;
    private double _startScale = 1;
    private double _xOffset = 0;
    private double _yOffset = 0;
    EngineViewModel vm = new();
    readonly Logger logger = LogManager.GetCurrentClassLogger();

    public EngineView() {
        InitializeComponent();
        BindingContext = vm;
    }

    private void OnPinchUpdated(object sender, PinchGestureUpdatedEventArgs e) {
        try {
            switch(e.Status) {
                case GestureStatus.Started:
                    _startScale = Content.Scale;
                    Content.AnchorX = 0;
                    Content.AnchorY = 0;
                    break;
                case GestureStatus.Running: {
                        _currentScale += (e.Scale - 1) * _startScale;
                        _currentScale = Math.Max(1, _currentScale);
                        _currentScale = Math.Min(4, _currentScale);
                        var renderedX = Content.X + _xOffset;
                        var deltaX = renderedX / Width;
                        var deltaWidth = Width / (Content.Width * _startScale);
                        var originX = (e.ScaleOrigin.X - deltaX) * deltaWidth;
                        var renderedY = Content.Y + _yOffset;
                        var deltaY = renderedY / Height;
                        var deltaHeight = Height / (Content.Height * _startScale);
                        var originY = (e.ScaleOrigin.Y - deltaY) * deltaHeight;
                        var targetX = _xOffset - (originX * Content.Width) *                 
                            (_currentScale - _startScale);
                        var targetY = _yOffset - (originY * Content.Height) * 
                            (_currentScale - _startScale);
                        Content.TranslationX = Math.Min(0, Math.Max(targetX, -    
                            Content.Width * (_currentScale - 1)));
                            Content.TranslationY = Math.Min(0, Math.Max(targetY, -     
                            Content.Height * (_currentScale - 1)));
                        Content.Scale = _currentScale;
                        break;
                    }
                case GestureStatus.Completed:
                    _xOffset = Content.TranslationX;
                    _yOffset = Content.TranslationY;
                    break;
            }
        } catch(Exception ex) {
            logger.Error(ex.Message);
        }
    }

    private void OnPanUpdated(object sender, PanUpdatedEventArgs e) {
        try {
            if(Content.Scale == 1) {
                return;
            }
            switch(e.StatusType) {
                case GestureStatus.Running:
                    var newX = (e.TotalX * Scale) + _xOffset;
                    var newY = (e.TotalY * Scale) + _yOffset;
                    var width = (Content.Width * Content.Scale);
                    var height = (Content.Height * Content.Scale);
                    var canMoveX = width > Application.Current.MainPage.Width;
                    var canMoveY = height > Application.Current.MainPage.Height;
                    if(canMoveX) {
                        var minX = (width - (Application.Current.MainPage.Width / 2)) * 
                        -1;
                        var maxX = Math.Min(Application.Current.MainPage.Width / 2, 
                            width / 2);
                        if(newX < minX) {
                            newX = minX;
                        }
                        if(newX > maxX) {
                            newX = maxX;
                        }
                    } else {
                        newX = 0;
                    }
                    if(canMoveY) {
                        var minY = (height - (Application.Current.MainPage.Height / 2)) 
                            * -1;
                        var maxY = Math.Min(Application.Current.MainPage.Width / 2, 
                            height / 2);
                        if(newY < minY) {
                            newY = minY;
                        }
                        if(newY > maxY) {
                            newY = maxY;
                        }
                    } else {
                        newY = 0;
                    }
                    Content.TranslationX = newX;
                    Content.TranslationY = newY;
                    break;
                case GestureStatus.Completed:
                    _xOffset = Content.TranslationX;
                    _yOffset = Content.TranslationY;
                    break;
                case GestureStatus.Started:
                    break;
                case GestureStatus.Canceled:
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        } catch(Exception ex) {
            logger.Error(ex.Message);
        }
    }
}

我试过用不同的容器。Frame、ScrollView、Stacklayout等,但所有地方的结果都是一样的

dsf9zpds

dsf9zpds1#

每次我放大图像时,图像都会根据需要进行预放大,但它所在的帧会扩展到整个应用程序。左侧有一个锁定的壳弹出菜单(稍后将设置为弹出)。
OnPinchUpdatedOnPanUpdated的所有“Content”替换为“image”(Image控件的x:Name的值)可以解决问题。
“Content”是ContentPage的属性,也就是说你放大和缩小的是整个页面而不是图像。

相关问题