Quantcast
Channel: Xamarin.Forms — Xamarin Community Forums
Viewing all articles
Browse latest Browse all 91519

Xamarin forms pinch and pan gesture together

$
0
0

Hi,
I spent too much time to check all the post and for searching for code who permit pinch and pan gesture in same time. All the time, for me, there is a bug or a problem with the code. I changed the Microsoft code for have a pinch and pan that work really great.

Create a Content Page
Add the reference :
xmlns:local="clr-namespace:applicationname"

Add image on your form, I put FillAndExpand to be sure that all the layers take all the screen place :

<local:PinchPanContainer.Content HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">

</local:PinchPanContainer.Content>

Create a class name PinchPanContainer.cs. The OnPinchUpdated is a copy-paste in the Microsoft code but I added a bool blnDisableMove to disable the first pan move after a pinch move. On real device, not on simulator, when you pinch gesture some time you pan in same time. This result to pinch gesture that work very well, but at the end your image goes to the wrong location because the panning motion run afterwards. Anyway, on real device you don't see any delay with the pan move. The OnPanUpdated is a combinaison of the Microsoft code and the code in this post : I can't publish a url because I'm a new user and I what to share my code to help others one. I add the scale factor to the Microsoft code and I add my bool blnDisableMove to set this one to false to permit the pan move after the first completition. I also replace the App.ScreenWidth on the Microsoft code because this code doesn't seem to exist anymore. I replace with this Application.Current.MainPage.Width. In my initial code the Application.Current.MainPage.Width and Application.Current.MainPage.Height was Content.Width and Content.Height because I set the to take all the screen and it work really great.

using System;
using Xamarin.Forms;

namespace jardins
{
public class PinchPanContainer : ContentView
{
double currentScale = 1;
double startScale = 1;
double xOffset = 0;
double yOffset = 0;
bool blnDisableMove = false;

    public PinchPanContainer()
    {
        var pinchGesture = new PinchGestureRecognizer();
        pinchGesture.PinchUpdated += OnPinchUpdated;
        GestureRecognizers.Add(pinchGesture);

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

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

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

                if (!blnDisableMove)
                {
                    Content.TranslationX = Math.Max(Math.Min(0, xOffset + (e.TotalX * Scale)), -Math.Abs((Content.Width * Content.Scale) - Application.Current.MainPage.Width));
                    Content.TranslationY = Math.Max(Math.Min(0, yOffset + (e.TotalY * Scale)), -Math.Abs((Content.Height * Content.Scale) - Application.Current.MainPage.Height));
                }

                break;

            case GestureStatus.Completed:

                if (blnDisableMove)
                {
                    blnDisableMove = false;
                    return;
                }
                // Store the translation applied during the pan
                xOffset = Content.TranslationX;
                yOffset = Content.TranslationY;
                break;
        }
    }

    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;
            blnDisableMove = true;
        }
        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 = targetX.Clamp(-Content.Width * (currentScale - 1), 0);
            Content.TranslationY = targetY.Clamp(-Content.Height * (currentScale - 1), 0);

            // Apply scale factor.
            Content.Scale = currentScale;

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

            blnDisableMove = true;
        }
    }
}

}


Viewing all articles
Browse latest Browse all 91519

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>