xamarin / Xamarin.Forms

Xamarin.Forms is no longer supported. Migrate your apps to .NET MAUI.
https://aka.ms/xamarin-upgrade
Other
5.63k stars 1.87k forks source link

Xamarin 3.5 - pinch gesture is choking #5381

Open hyurii opened 5 years ago

hyurii commented 5 years ago

Description

Try to use PinchGestureRecognizer Tested on Android API 28

Steps to Reproduce

Install Xamarin Forms 3.5.0.169047 or 3.5.0.129452 Try zoom in/out image with pinch

Expected Behavior

Works fluent like in Xamarin Forms 3.4.0.1029999

Actual Behavior

zooming jumps and stops

samhouts commented 5 years ago

@hyurii Can you attach a sample project that shows the issue, please? Thank you!

hyurii commented 5 years ago

http://chettrigroup.xyz/2018/09/26/xamarin-forms-image-zoomtutorial-37/

rizamarhaban commented 5 years ago

Shell Issue

Looks like this is also a Shell issue. Just tested inside an AppShell item content page using Xamarin.Forms with preview version 4.0.0.394984-pre10 and the chocking still there. Cannot pinch or pan properly and sometimes the gestures not working.

However, if the Xamarin.Forms app not using Shell at all, and I just add one content page, then the gesture works normally.

jsuarezruiz commented 4 years ago

The link to the repro sample is no longer available :pensive:. Could you upload it again or add another repro sample? I have done some tests (using Shell and PinchGestureRecognizer) and need more details to reproduce the problem.

ezgif-2-084fe9f4886b

hyurii commented 4 years ago

Try this code: `public class PinchZoom : ContentView { private double currentScale = 1; private double startScale = 1; private double xOffset = 0; private double yOffset = 0;

    public PinchZoom()
    {
        PinchGestureRecognizer pinchGesture = new PinchGestureRecognizer();
        pinchGesture.PinchUpdated += PinchUpdated;
        GestureRecognizers.Add(pinchGesture);

        var panGesture = new PanGestureRecognizer();
        panGesture.PanUpdated += OnPanUpdated;
        GestureRecognizers.Add(panGesture);
    }

    private void PinchUpdated(object sender, PinchGestureUpdatedEventArgs e)
    {
        if (e.Status == GestureStatus.Started)
        {
            startScale = Content.Scale;
            Content.AnchorX = 0;
            Content.AnchorY = 0;
        }

        if (e.Status == GestureStatus.Running)
        {
            currentScale += (e.Scale - 1) * startScale;
            currentScale = Math.Max(1, currentScale);

            double renderedX = Content.X + xOffset;
            double deltaX = renderedX / Width;
            double deltaWidth = Width / (Content.Width * startScale);
            double originX = (e.ScaleOrigin.X - deltaX) * deltaWidth;

            double renderedY = Content.Y + yOffset;
            double deltaY = renderedY / Height;
            double deltaHeight = Height / (Content.Height * startScale);
            double originY = (e.ScaleOrigin.Y - deltaY) * deltaHeight;

            double targetX = xOffset - (originX * Content.Width) * (currentScale - startScale);
            double 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;
        }

        if (e.Status == GestureStatus.Completed)
        {
            xOffset = Content.TranslationX;
            yOffset = Content.TranslationY;
        }
    }

    public void OnPanUpdated(object sender, PanUpdatedEventArgs e)
    {
        if (Content.Scale == 1)
        {
            return;
        }

        switch (e.StatusType)
        {
            case GestureStatus.Running:

                double newX = (e.TotalX * Scale) + xOffset;
                double newY = (e.TotalY * Scale) + yOffset;

                double width = (Content.Width * Content.Scale);
                double height = (Content.Height * Content.Scale);

                bool canMoveX = width > Application.Current.MainPage.Width;
                bool canMoveY = height > Application.Current.MainPage.Height;

                if (canMoveX)
                {
                    double minX = (width - (Application.Current.MainPage.Width / 2)) * -1;
                    double 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)
                {
                    double minY = (height - (Application.Current.MainPage.Height / 2)) * -1;
                    double 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;
        }
    }
}`
blackadder1000 commented 3 years ago

I am experiencing the same problem, is there a solution?