Skip to content
This repository was archived by the owner on May 1, 2024. It is now read-only.

[iOS] Fix issue using TapGesture #11419

Merged
merged 10 commits into from
Dec 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;
using Xamarin.Forms.Shapes;

#if UITEST
using Xamarin.Forms.Core.UITests;
using Xamarin.UITest;
using NUnit.Framework;
#endif

namespace Xamarin.Forms.Controls.Issues
{
#if UITEST
[Category(UITestCategories.Shape)]
#endif
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Github, 10623, "Tap Gesture not working on iOS [Bug]", PlatformAffected.iOS)]
public class Issue10623 : TestContentPage
{
public Issue10623()
{
Device.SetFlags(new List<string>(Device.Flags ?? new List<string>()) { "Shapes_Experimental" });
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

think we don't need this right?


var layout = new StackLayout();

var instructions = new Label
{
Padding = 12,
BackgroundColor = Color.Black,
TextColor = Color.White,
Text = "Tap the rating control. If you can modify the number of selected stars, the test has passed."
};

var rating = new RatingControl
{
Size = 30,
Max = 5,
FillColor = Brush.Gold,
StrokeColor = Brush.Silver,
StrokeThickness = 2,
HorizontalOptions = LayoutOptions.Center
};

layout.Children.Add(instructions);
layout.Children.Add(rating);

Content = layout;
}

protected override void Init()
{
Title = "Issue 10623";
}
}

public class RatingControl : StackLayout
{
public RatingControl()
{
Orientation = StackOrientation.Horizontal;
}

public static BindableProperty RatingProperty = BindableProperty.Create(nameof(Rating), typeof(double), typeof(RatingControl), 0.0, BindingMode.OneWay, propertyChanged: (bindable, newValue, oldValue) =>
{
var control = (RatingControl)bindable;

if (newValue != oldValue)
{
control.Draw();
}
});

readonly List<Point> _originalFullStarPoints = new List<Point>()
{
new Point(96,1.12977573),
new Point(66.9427701,60.0061542),
new Point(1.96882894,69.4474205),
new Point(48.9844145,115.27629),
new Point(37.8855403,179.987692),
new Point(96,149.435112),
new Point(154.11446,179.987692),
new Point(143.015586,115.27629),
new Point(190.031171,69.4474205),
new Point(125.05723,60.0061542),
new Point(96,1.12977573),
};

readonly List<Point> _originalHalfStarPoints = new List<Point>()
{
new Point(96,1.12977573),
new Point(66.9427701,60.0061542),
new Point(1.96882894,69.4474205),
new Point(48.9844145,115.27629),
new Point(37.8855403,179.987692),
new Point(96,149.435112),
new Point(96,1.12977573)
};

readonly PointCollection _fullStarPoints = new PointCollection();
readonly PointCollection _halfStarPoints = new PointCollection();

double _ratio;

private void Draw()
{
Children.Clear();

var newRatio = Size / 200;

if (newRatio != _ratio)
{
_ratio = newRatio;

CalculatePoints(_fullStarPoints, _originalFullStarPoints);
CalculatePoints(_halfStarPoints, _originalHalfStarPoints);
}


for (var i = 1; i <= Max; i++)
{
if (Rating >= i)
{
Children.Add(GetFullStar());
}
else if (Rating > i - 1)
{
Children.Add(GetHalfStar());
}
else
{
Children.Add(GetEmptyStar());
}
}

UpdateTapGestureRecognizers();
}

private void CalculatePoints(PointCollection calculated, List<Point> original)
{
calculated.Clear();

foreach (var point in original)
{
var x = point.X * _ratio;
var y = point.Y * _ratio;

var p = new Point(x, y);

calculated.Add(p);
}
}

private Polygon GetFullStar()
{
var fullStar = new Polygon()
{
Points = _fullStarPoints,
Fill = FillColor,
StrokeThickness = StrokeThickness,
Stroke = StrokeColor
};

return fullStar;
}

private Grid GetHalfStar()
{
var grid = new Grid();

var halfStar = new Polygon()
{
Points = _halfStarPoints,
Fill = _fillColor,
Stroke = Brush.Transparent,
StrokeThickness = 0,
};

var emptyStar = new Polygon()
{
Points = _fullStarPoints,
StrokeThickness = StrokeThickness,
Stroke = StrokeColor
};

grid.Children.Add(halfStar);
grid.Children.Add(emptyStar);

return grid;
}

private Polygon GetEmptyStar()
{
var emptyStar = new Polygon()
{
Points = _fullStarPoints,
StrokeThickness = StrokeThickness,
Stroke = StrokeColor
};

return emptyStar;
}

private void Set<T>(ref T field, T newValue)
{
if (!EqualityComparer<T>.Default.Equals(field, newValue))
{
field = newValue;
Draw();
}
}

public double Rating
{
get => (double)GetValue(RatingProperty);
set => SetValue(RatingProperty, value);
}

int _max = 5;
public int Max
{
get => _max;
set => Set(ref _max, value);
}


Brush _fillColor = Brush.Yellow;
public Brush FillColor
{
get => _fillColor;
set => Set(ref _fillColor, value);
}

Brush _strokeColor = Brush.Black;
public Brush StrokeColor
{
get => _strokeColor;
set => Set(ref _strokeColor, value);
}

double _strokeThickness = 0;
public double StrokeThickness
{
get => _strokeThickness;
set => Set(ref _strokeThickness, value);
}

double _size = 50;
public double Size
{
get => _size;
set => Set(ref _size, value);
}

private void UpdateTapGestureRecognizers()
{
foreach (var star in Children)
{
if (!star.GestureRecognizers.Any())
{
var recognizer = new TapGestureRecognizer();
recognizer.Tapped += TapGestureRecognizer_Tapped;
star.GestureRecognizers.Add(recognizer);
}
}
}

private void TapGestureRecognizer_Tapped(object sender, EventArgs e)
{
var star = (View)sender;

var index = Children.IndexOf(star);

Rating = index + 1;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
using System;
using System.ComponentModel;
using System.Windows.Input;
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;
using Xamarin.Forms.Shapes;

#if UITEST
using Xamarin.UITest;
using NUnit.Framework;
using Xamarin.Forms.Core.UITests;
#endif

namespace Xamarin.Forms.Controls.Issues
{
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Github, 12685, "[iOs][Bug] TapGestureRecognizer in Path does not work on iOS", PlatformAffected.iOS)]
#if UITEST
[NUnit.Framework.Category(Core.UITests.UITestCategories.Github10000)]
[NUnit.Framework.Category(UITestCategories.Shape)]
#endif
public partial class Issue12685 : TestContentPage
{
const string ResetStatus = "Path touch event not fired, touch path above.";
const string ClickedStatus = "Path was clicked, click reset button to start over.";

protected override void Init()
{
var layout = new StackLayout();
var statusLabel = new Label
{
AutomationId = "LabelValue",
Text = ResetStatus,
};

var lgb = new LinearGradientBrush();
lgb.GradientStops.Add(new GradientStop(Color.White, 0));
lgb.GradientStops.Add(new GradientStop(Color.Orange, 1));

var pathGeometry = new PathGeometry();
PathFigureCollectionConverter.ParseStringToPathFigureCollection(pathGeometry.Figures, "M0,0 V300 H300 V-300 Z");

var path = new Path
{
Data = pathGeometry,
Fill = lgb
};

var touch = new TapGestureRecognizer
{
Command = new Command(_ => statusLabel.Text = ClickedStatus),
};
path.GestureRecognizers.Add(touch);

var resetButton = new Button
{
Text = "Reset",
Command = new Command(_ => statusLabel.Text = ResetStatus),
};

layout.Children.Add(path);
layout.Children.Add(statusLabel);
layout.Children.Add(resetButton);

Content = layout;
}

#if UITEST
[Test]
public void ShapesPathReceiveGestureRecognizers()
{
var testLabel = RunningApp.WaitForFirstElement("LabelValue");
Assert.AreEqual(ResetStatus, testLabel.ReadText());
var pathRect = testLabel.Rect;
RunningApp.TapCoordinates(pathRect.X + 100, pathRect.Y-100);
Assert.AreEqual(ClickedStatus, RunningApp.WaitForFirstElement("LabelValue").ReadText());
}
#endif
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1633,7 +1633,8 @@
<Compile Include="$(MSBuildThisFileDirectory)Issue11938.xaml.cs">
<DependentUpon>Issue11938.xaml</DependentUpon>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Issue11496.xaml.cs">
<Compile Include="$(MSBuildThisFileDirectory)Issue10623.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue11496.xaml.cs" >
<DependentUpon>Issue11496.xaml</DependentUpon>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Issue11209.xaml.cs">
Expand All @@ -1653,6 +1654,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Issue8988.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue12084.xaml.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue12512.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue12685.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue12642.cs" />
</ItemGroup>
<ItemGroup>
Expand Down
3 changes: 2 additions & 1 deletion Xamarin.Forms.Platform.iOS/EventTracker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,8 @@ bool ShouldReceiveTouch(UIGestureRecognizer recognizer, UITouch touch)
return false;
}

if (touch.View.IsDescendantOfView(_renderer.NativeView) && touch.View.GestureRecognizers?.Length > 0)
if (touch.View.IsDescendantOfView(_renderer.NativeView) &&
(touch.View.GestureRecognizers?.Length > 0 || _renderer.NativeView.GestureRecognizers?.Length > 0))
{
return true;
}
Expand Down