Skip to content

Commit

Permalink
[iOS] fixes #3525 - add epsilon for float compare and make region imm…
Browse files Browse the repository at this point in the history
…utable
  • Loading branch information
PureWeen committed Aug 24, 2018
1 parent 4222ad2 commit 87e1c75
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 10 deletions.
@@ -0,0 +1,78 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;


#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, 3525, "[iOS] Finicky tap gesture recognition on Spans")]
#if UITEST
[NUnit.Framework.Category(UITestCategories.Gestures)]
#endif
public class Issue3525 : TestContentPage
{
const string kClickCount = "Click Count: ";
const string kClickCountAutomationId = "ClickCount";
const string kLabelTestAutomationId = "SpanningLabel";

protected override void Init()
{
var label = new Label() { Text = kClickCount, AutomationId = kClickCountAutomationId };
Padding = new Thickness(20);
var layout = new StackLayout { Padding = new Thickness(5, 10) };

var formattedString = new FormattedString();
formattedString.Spans.Add(new Span { Text = "Not Clickable, ", ForegroundColor = Color.Red, FontAttributes = FontAttributes.Bold, LineHeight = 1.8 });
formattedString.Spans.Add(new Span { Text = Environment.NewLine });
var span = new Span { Text = "Clickable, " };
int clickCount = 0;
span.GestureRecognizers.Add(new TapGestureRecognizer
{
Command = new Command(() =>
{
clickCount++;
label.Text = $"{kClickCount}{clickCount}";
})
});

formattedString.Spans.Add(span);
formattedString.Spans.Add(new Span { Text = Environment.NewLine });

formattedString.Spans.Add(new Span { Text = "You also cannot click on me sorry about that.", FontAttributes = FontAttributes.Italic, FontSize = Device.GetNamedSize(NamedSize.Small, typeof(Label)) });

layout.Children.Add(new Label { AutomationId = kLabelTestAutomationId, FormattedText = formattedString });
layout.Children.Add(label);

this.Title = "Label Demo - Code";
this.Content = layout;
}

#if UITEST
[Test]
public void SpanRegionClicking()
{
var label = RunningApp.WaitForElement(kLabelTestAutomationId);
var location = label[0].Rect;

var lineHeight = location.Height / 3;
var y = location.Y;
RunningApp.TapCoordinates(location.X, y + lineHeight / 2);
RunningApp.TapCoordinates(location.X + 5, y + lineHeight + 5);
RunningApp.TapCoordinates(location.X, y + (lineHeight * 2));
RunningApp.WaitForElement($"{kClickCount}{1}");

}
#endif
}
}
Expand Up @@ -769,6 +769,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Issue2728.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue1667.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue3012.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue3525.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Bugzilla22229.xaml">
Expand Down
26 changes: 18 additions & 8 deletions Xamarin.Forms.Core/Region.cs
@@ -1,15 +1,26 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace Xamarin.Forms
{
public struct Region
{

// While Regions are currently rectangular, they could in the future be transformed into any shape.
// As such the internals of how it keeps shapes is hidden, so that future internal changes can occur to support shapes
// such as circles if required, without affecting anything else.

IList<Rectangle> Regions { get; set; }
IReadOnlyList<Rectangle> Regions { get; }
readonly Thickness _inflation;

private Region(IList<Rectangle> positions) : this()
{
Regions = new ReadOnlyCollection<Rectangle>(positions);
}

private Region(IList<Rectangle> positions, Thickness inflation) : this(positions)
{
_inflation = inflation;
}

public static Region FromLines(double[] lineHeights, double maxWidth, double startX, double endX, double startY)
{
Expand All @@ -34,7 +45,7 @@ public static Region FromLines(double[] lineHeights, double maxWidth, double sta
else // SingleLine
positions.Add(new Rectangle(startX, lineHeightTotal, endX - startX, lineHeights[i]));

return new Region() { Regions = positions };
return new Region(positions);
}

public bool Contains(Point pt)
Expand All @@ -54,8 +65,6 @@ public bool Contains(double x, double y)
return false;
}

Thickness _inflation;

public Region Deflate()
{
if (_inflation == null)
Expand All @@ -74,6 +83,7 @@ public Region Inflate(double left, double top, double right, double bottom)
if (Regions == null)
return this;

Rectangle[] rectangles = new Rectangle[Regions.Count];
for (int i = 0; i < Regions.Count; i++)
{
var region = Regions[i];
Expand All @@ -87,15 +97,15 @@ public Region Inflate(double left, double top, double right, double bottom)
if (i == Regions.Count - 1) // This is the last line
region.Height += bottom + top;

Regions[i] = region;
rectangles[i] = region;
}

_inflation = new Thickness(_inflation == null ? left : left + _inflation.Left,
var inflation = new Thickness(_inflation == null ? left : left + _inflation.Left,
_inflation == null ? top : top + _inflation.Top,
_inflation == null ? right : right + _inflation.Right,
_inflation == null ? bottom : bottom + _inflation.Bottom);

return this;
return new Region(rectangles, inflation);
}
}
}
7 changes: 5 additions & 2 deletions Xamarin.Forms.Platform.iOS/Extensions/LabelExtensions.cs
Expand Up @@ -74,7 +74,9 @@ public static void RecalculateSpanPositions(this NativeLabel control, Label elem

var yaxis = startRect.Top;
var lineHeights = new List<double>();
while (yaxis < endRect.Bottom)

while( (endRect.Bottom - yaxis) > 0.001 )
//while (yaxis < endRect.Bottom)
{
double lineHeight;
if (yaxis == startRect.Top) // First Line
Expand All @@ -93,7 +95,8 @@ public static void RecalculateSpanPositions(this NativeLabel control, Label elem
yaxis += (float)lineHeight;
}

((ISpatialElement)span).Region = Region.FromLines(lineHeights.ToArray(), finalSize.Width, startRect.X, endRect.X, startRect.Top).Inflate(10);
((ISpatialElement)span).Region = Region.FromLines(lineHeights.ToArray(), finalSize.Width, startRect.X, endRect.X, startRect.Top)
.Inflate(10);

// update current location
currentLocation += length;
Expand Down

0 comments on commit 87e1c75

Please sign in to comment.