Olá, neste post irei demonstrar como você pode implementar zoom nas imagens em suas aplicações Xamarin.Forms de uma maneira fácil e rápida utilizando custom renderer.
Comece criando a classe estática chamada “DoubleExtensions” no projeto compartilhado.
DoubleExtensions.cs
using System; | |
namespace DemoZoomImage | |
{ | |
public static class DoubleExtensions | |
{ | |
public static double Clamp(this double self, double min, double max) | |
{ | |
return Math.Min(max, Math.Max(self, min)); | |
} | |
} | |
} |
Em seguida crie a classe “PinchToZoomContainer” em seu projeto compartilhado, ela será responsável em capturar o GestureStatus e aplicar o zoom na imagem.
PinchToZoomContainer.cs
using System; | |
using Xamarin.Forms; | |
namespace DemoZoomImage | |
{ | |
public class PinchToZoomContainer : ContentView | |
{ | |
double currentScale = 1; | |
double startScale = 1; | |
double xOffset = 0; | |
double yOffset = 0; | |
public PinchToZoomContainer() | |
{ | |
var 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 = targetX.Clamp(–Content.Width * (currentScale – 1), 0); | |
Content.TranslationY = targetY.Clamp(–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; | |
} | |
} | |
} | |
} |
Xaml
Para utilizar no arquivo xaml, adicione uma Image dentro do PinchToZoomContainer.Content como demonstrado a seguir.
<?xml version="1.0" encoding="utf-8" ?> | |
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" | |
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" | |
xmlns:local="clr-namespace:DemoZoomImage" | |
x:Class="DemoZoomImage.MainPage"> | |
<Grid Padding="20"> | |
<local:PinchToZoomContainer> | |
<local:PinchToZoomContainer.Content> | |
<Image Source="wallpaper.jpg"/> | |
</local:PinchToZoomContainer.Content> | |
</local:PinchToZoomContainer> | |
</Grid> | |
</ContentPage> |
Resultado
Esse e todos os exemplos deste blog encontram-se disponíveis no GitHub.