Issue
I was faced with some weird behavior of TapGestureRecognizer. I have some simple Xamarin page like below
<StackLayout>
<Path
ClassId="BottomCone"
Fill="{AppThemeBinding Dark=#333333, Light=#444444}"
Data="{x:Static local:MainPage.BottomConeGeometry}"
BackgroundColor="Red"
>
<Path.GestureRecognizers>
<TapGestureRecognizer Tapped="BottomConeTapped" />
</Path.GestureRecognizers>
</Path>
</StackLayout>
Though it's actually just some simple closed shape drown with Path element on which I have some handler of tap event. And the problem is that event is firing every time when I'm clicking on Path or its background. Is it possible to not fire the tap event when the tap happened in the background of the path? And fire the event just in case the tap event happened inside a Path element.
Solution
So the shapes have overlapping "bounds" (the rectangle surrounding each shape).
One technique is to have a set of rectangles that approximates each of the shapes. The concept is to make the shapes themselves InputTransparent
, and have an overlapping set of invisible boxes that capture touch.
OverlappingShapeButtonsPage.xaml:
<?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="XFSOAnswers.OverlappingShapeButtonsPage">
<ContentPage.Resources>
<Style TargetType="BoxView">
<!-- Uncomment, to see where OnTapped1 boxes are. -->
<!--<Setter Property="BackgroundColor" Value="Red"/>-->
</Style>
</ContentPage.Resources>
<ContentPage.Content>
<Grid>
<AbsoluteLayout InputTransparent="True">
<Polygon Points="0,0 80,0 0,60" Fill="Green" />
<Polygon Points="80,0 80,60 0,60" Fill="Pink" />
</AbsoluteLayout>
<Grid RowDefinitions="20,20,20" ColumnDefinitions="20,20,20,20"
RowSpacing="0" ColumnSpacing="0">
<Grid.GestureRecognizers>
<TapGestureRecognizer Tapped="OnTapped2" />
</Grid.GestureRecognizers>
<BoxView Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3">
<BoxView.GestureRecognizers>
<TapGestureRecognizer Tapped="OnTapped1" />
</BoxView.GestureRecognizers>
</BoxView>
<BoxView Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2">
<BoxView.GestureRecognizers>
<TapGestureRecognizer Tapped="OnTapped1" />
</BoxView.GestureRecognizers>
</BoxView>
<BoxView Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="1">
<BoxView.GestureRecognizers>
<TapGestureRecognizer Tapped="OnTapped1" />
</BoxView.GestureRecognizers>
</BoxView>
</Grid>
</Grid>
</ContentPage.Content>
</ContentPage>
OverlappingShapeButtonsPage.xaml.cs:
using System;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace XFSOAnswers
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class OverlappingShapeButtonsPage : ContentPage
{
public OverlappingShapeButtonsPage()
{
InitializeComponent();
}
/// <summary>
/// This is called when any of the BoxViews are touched.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void OnTapped1(object sender, EventArgs e)
{
}
/// <summary>
/// This is called when the grid is touched anywhere that is not inside one of the BoxViews.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void OnTapped2(object sender, EventArgs e)
{
}
}
}
Red showing boxes for OnTapped1, approximating Green triangle:
This works reasonably well, because user will tend to touch near the center of the shape they are interested in.
You could refine this by doing simple (x,y) math calculations that approximate the edge between two shapes.
In General, Make sure that you aren't expecting unrealistic precision from user's touch. Primarily, that means that the touch areas should not be too small (more than one in a small area).
Consider these (or similar) guidelines: Optimal Size and Spacing for Mobile Touch.
Answered By - ToolmakerSteve
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.