Fala, galera!
Tentando manter a periodicidade semanal, chegamos novamente com uma dica rápida de Xamarin.Forms!
A ideia é ser um artigo bem rápido, e todas as dicas ficarão em um único repositório. Se você perdeu algum artigo, veja os que já foram publicados:
- Xamarin Rocket – Parte 01: LineBreakMode
- Xamarin Rocket – Parte 02: alterando o espaço das linhas e colunas do Grid
- Xamarin Rocket – Parte 03: tela cheia, ocultando a barra de status
- Xamarin Rocket – Parte 04: imagens em botões
- Xamarin Rocket – Parte 05: notificação ao alterar a conexão
- Xamarin Rocket – Parte 06: como utilizar o GridLayout
Arrastar, dar zoom e movimento pinça – diversos gestos que fazemos em muitos dos apps do nosso dia a dia.
A utilização de gestos se mostra muito útil, como dar zoom em uma imagem, por exemplo.
Xamarin.Forms dá suporte a diversos gestos muito utilizados, e a implementação dos mesmos é muito simples. Então, sem mais introduções, vamos à alguns deles:
Antes, vamos preparar nosso app adicionando duas propriedades doubles auxiliares no APP.xaml.cs para guardarmos o tamanho da tela:
public partial class App : Application
{
public static double ScreenWidth;
public static double ScreenHeight;
public App()
{
InitializeComponent();
MainPage = new NavigationPage( new MainPage());
}
}
Vamos aos gestos:
PanGesture: o “gesto de panorâmica” é utilizado para detectar a movimentação dos dedos na tela e mover seu conteúdo. Por exemplo, se temos uma imagem maior que a tela, podemos utilizar esse gesto para percorrê-la.
Criaremos uma classe para encapsular o gesto e utilizarmos como controle:
using System;
using Xamarin.Forms;
namespace XamarinRocket.Control.Gestos
{
public class PanContainer : ContentView
{
double x, y;
public PanContainer()
{
var panGesture = new PanGestureRecognizer();
panGesture.PanUpdated += OnPanUpdated;
GestureRecognizers.Add(panGesture);
}
void OnPanUpdated(object sender, PanUpdatedEventArgs e)
{
switch (e.StatusType)
{
case GestureStatus.Running:
Content.TranslationX = Math.Max(Math.Min(0, x + e.TotalX), -Math.Abs(Content.Width - App.ScreenWidth));
Content.TranslationY = Math.Max(Math.Min(0, y + e.TotalY), -Math.Abs(Content.Height - App.ScreenHeight));
break;
case GestureStatus.Completed:
x = Content.TranslationX;
y = Content.TranslationY;
break;
}
}
}
}
O evento OnPanUpdated é atualizado toda vez que movemos o conteúdo (no caso, a imagem).
Agora implementaremos o controle e nossa imagem:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamarinRocket.Views.Gestos.PanGesturePage" xmlns:local="clr-namespace:XamarinRocket.Control.Gestos">
<ContentPage.Content>
<AbsoluteLayout>
<local:PanContainer>
<Image Source="xamarinRocket.png" WidthRequest="1024" HeightRequest="768" />
</local:PanContainer>
</AbsoluteLayout>
</ContentPage.Content>
</ContentPage>
Rodando, podemos mover a imagem:
PinchGesture: o famoso movimento pinça, que utilizamos dois dedos, e o movimento de abrir e fechar. É muito útil para dar zoom em imagens, por exemplo.
Vamos criar uma classe para encapsular o gesto e utilizarmos como controle:
using System;
using Xamarin.Forms;
using Xamarin.Forms.Internals;
namespace XamarinRocket.Control.Gestos
{
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)
{
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 = targetX.Clamp(-Content.Width * (currentScale - 1), 0);
Content.TranslationY = targetY.Clamp(-Content.Height * (currentScale - 1), 0);
Content.Scale = currentScale;
}
if (e.Status == GestureStatus.Completed)
{
xOffset = Content.TranslationX;
yOffset = Content.TranslationY;
}
}
}
}
Também implementaremos o controle na imagem:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamarinRocket.Views.Gestos.PinchGesturePage" xmlns:local="clr-namespace:XamarinRocket.Control.Gestos">
<ContentPage.Content>
<Grid Padding="20">
<local:PinchToZoomContainer>
<local:PinchToZoomContainer.Content>
<Image Source="xamarinRocket.png" />
</local:PinchToZoomContainer.Content>
</local:PinchToZoomContainer>
</Grid>
</ContentPage.Content>
</ContentPage>
Rodando, podemos dar zoom na imagem:
SwipeGesture: o movimento de passar o dedo para executar alguma ação. É possível identificar a direção que o dedo é passado – para cima, para baixo, para direta ou esquerda.
Criaremos uma classe para encapsular o gesto e utilizar como controle:
using System;
using Xamarin.Forms;
namespace XamarinRocket.Control.Gestos
{
public class SwipeContainer : ContentView
{
public event EventHandler<SwipedEventArgs> Swipe;
public SwipeContainer()
{
GestureRecognizers.Add(GetSwipeGestureRecognizer(SwipeDirection.Left));
GestureRecognizers.Add(GetSwipeGestureRecognizer(SwipeDirection.Right));
GestureRecognizers.Add(GetSwipeGestureRecognizer(SwipeDirection.Up));
GestureRecognizers.Add(GetSwipeGestureRecognizer(SwipeDirection.Down));
}
SwipeGestureRecognizer GetSwipeGestureRecognizer(SwipeDirection direction)
{
var swipe = new SwipeGestureRecognizer { Direction = direction };
swipe.Swiped += (sender, e) => Swipe?.Invoke(this, e);
return swipe;
}
}
}
Também vamos implementar o controle em um boxView:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamarinRocket.Views.Gestos.SwipeGesturePage" xmlns:local="clr-namespace:XamarinRocket.Control.Gestos">
<StackLayout Margin="20">
<Label Text="Passe o dedo em qualquer direção no box." />
<local:SwipeContainer Swipe="OnSwiped" HorizontalOptions="Center" VerticalOptions="CenterAndExpand">
<BoxView Color="Teal" WidthRequest="300" HeightRequest="300" />
</local:SwipeContainer>
<Label x:Name="_label" Text="Voce moveu para: "/>
</StackLayout>
</ContentPage>
E no back-end:
using System;
using System.Collections.Generic;
using Xamarin.Forms;
namespace XamarinRocket.Views.Gestos
{
public partial class SwipeGesturePage : ContentPage
{
public SwipeGesturePage()
{
InitializeComponent();
}
void OnSwiped(object sender, SwipedEventArgs e)
{
_label.Text = $"Você moveu para: {e.Direction.ToString()}";
}
}
}
Rodando, podemos testar passando o dedo no box, ou o cursor no emulador:
TapGesture: o gesto de tocar. Com ele, podemos executar algum evento quando é tocado em algum controle na tela, como em uma imagem, por exemplo.
Para utilizar, basta adicionar a propriedade de gesto no controle desejado, como nessa imagem, por exemplo:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamarinRocket.Views.Gestos.TapGesturePage">
<ContentPage.Content>
<StackLayout Padding="20">
<Image HeightRequest="350" WidthRequest="350" Source="xamarinRocket.png" >
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="Image_Tapped" ></TapGestureRecognizer>
</Image.GestureRecognizers>
</Image>
<Label x:Name="lblTapedCount" Text="Você tocou:"/>
</StackLayout>
</ContentPage.Content>
</ContentPage>
Agora, no back-end, vamos implementar um evento para ver quantas vezes foram tocadas na imagem:
using System;
using System.Collections.Generic;
using Xamarin.Forms;
namespace XamarinRocket.Views.Gestos
{
public partial class TapGesturePage : ContentPage
{
int tapCount;
public TapGesturePage()
{
InitializeComponent();
}
public void Image_Tapped(object sender, EventArgs e)
{
tapCount++;
lblTapedCount.Text = String.Format("{0} tap{1}",
tapCount,
tapCount == 1 ? "" : "s");
}
}
}
Rodando, vamos ficar tocando na imagem:
É uma dica bem simples, mas que ajuda muito!
Caso queira baixar o código utilizado no exemplo, acesse este link.
Quer ver outros artigos sobre Xamarin? Clique aqui.
Espero ter ajudado.
Aquele abraço!