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

Commit

Permalink
[iOS] Fix issue using TapGesture (#11419) fixes #10623 fixes #12685 f…
Browse files Browse the repository at this point in the history
…ixes #13020

* Added repro sample

* Fixed the issue

* Update Issue11050.xaml.cs

* Updated issue 10626. Replaced Color by Brush.

* Fixed build error

* Fixed build error

* Added Issue12685 test

* Changes in text format

* Fix rebase error

Co-authored-by: Samantha Houts <samhouts@users.noreply.github.com>
Co-authored-by: E.Z. Hart <hartez@gmail.com>
Co-authored-by: Rui Marinho <me@ruimarinho.net>
  • Loading branch information
4 people committed Dec 4, 2020
1 parent c80a908 commit fdb0dac
Show file tree
Hide file tree
Showing 4 changed files with 364 additions and 2 deletions.
@@ -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" });

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;
}
}
}
@@ -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
}
}
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
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

0 comments on commit fdb0dac

Please sign in to comment.