summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Xamarin.Forms.ControlGallery.Android/Resources/drawable/oasis.jpgbin27478 -> 125291 bytes
-rw-r--r--Xamarin.Forms.ControlGallery.WP8/oasis.jpgbin27246 -> 125291 bytes
-rw-r--r--Xamarin.Forms.ControlGallery.iOS/oasis.jpgbin27478 -> 125291 bytes
-rw-r--r--Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla44096.cs188
-rw-r--r--Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla44176.cs184
-rw-r--r--Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla46458.cs125
-rw-r--r--Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla53445.cs109
-rw-r--r--Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/InputTransparentIssue.cs38
-rw-r--r--Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/InputTransparentTests.cs204
-rw-r--r--Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems6
-rw-r--r--Xamarin.Forms.Core.UITests.Shared/UITestCategories.cs2
-rw-r--r--Xamarin.Forms.Platform.Android/AppCompat/FrameRenderer.cs26
-rw-r--r--Xamarin.Forms.Platform.Android/Platform.cs44
-rw-r--r--Xamarin.Forms.Platform.Android/Renderers/BoxRenderer.cs19
-rw-r--r--Xamarin.Forms.Platform.Android/Renderers/ImageRenderer.cs14
-rw-r--r--Xamarin.Forms.Platform.Android/Renderers/LabelRenderer.cs14
-rw-r--r--Xamarin.Forms.Platform.Android/Renderers/MotionEventHelper.cs53
-rw-r--r--Xamarin.Forms.Platform.Android/VisualElementRenderer.cs28
-rw-r--r--Xamarin.Forms.Platform.Android/Xamarin.Forms.Platform.Android.csproj1
-rw-r--r--Xamarin.Forms.Platform.WinRT/VisualElementRenderer.cs2
20 files changed, 991 insertions, 66 deletions
diff --git a/Xamarin.Forms.ControlGallery.Android/Resources/drawable/oasis.jpg b/Xamarin.Forms.ControlGallery.Android/Resources/drawable/oasis.jpg
index 078a6e09..e0be19c8 100644
--- a/Xamarin.Forms.ControlGallery.Android/Resources/drawable/oasis.jpg
+++ b/Xamarin.Forms.ControlGallery.Android/Resources/drawable/oasis.jpg
Binary files differ
diff --git a/Xamarin.Forms.ControlGallery.WP8/oasis.jpg b/Xamarin.Forms.ControlGallery.WP8/oasis.jpg
index e0c15afc..e0be19c8 100644
--- a/Xamarin.Forms.ControlGallery.WP8/oasis.jpg
+++ b/Xamarin.Forms.ControlGallery.WP8/oasis.jpg
Binary files differ
diff --git a/Xamarin.Forms.ControlGallery.iOS/oasis.jpg b/Xamarin.Forms.ControlGallery.iOS/oasis.jpg
index 078a6e09..e0be19c8 100644
--- a/Xamarin.Forms.ControlGallery.iOS/oasis.jpg
+++ b/Xamarin.Forms.ControlGallery.iOS/oasis.jpg
Binary files differ
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla44096.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla44096.cs
new file mode 100644
index 00000000..91ef39a4
--- /dev/null
+++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla44096.cs
@@ -0,0 +1,188 @@
+using Xamarin.Forms.CustomAttributes;
+using Xamarin.Forms.Internals;
+
+#if UITEST
+using Xamarin.Forms.Core.UITests;
+using Xamarin.UITest;
+using NUnit.Framework;
+#endif
+
+namespace Xamarin.Forms.Controls.Issues
+{
+#if UITEST
+ [Category(UITestCategories.IsEnabled)]
+#endif
+
+ [Preserve(AllMembers = true)]
+ [Issue(IssueTracker.Bugzilla, 44096, "Grid, StackLayout, and ContentView still participate in hit testing on Android after IsEnabled is set to false", PlatformAffected.Android)]
+ public class Bugzilla44096 : TestContentPage
+ {
+ bool _flag;
+
+ protected override void Init()
+ {
+ var result = new Label
+ {
+ Text = "Original"
+ };
+
+ var grid = new Grid
+ {
+ IsEnabled = true,
+ WidthRequest = 250,
+ HeightRequest = 50,
+ AutomationId = "grid"
+ };
+ AddTapGesture(result, grid);
+
+ var contentView = new ContentView
+ {
+ IsEnabled = true,
+ WidthRequest = 250,
+ HeightRequest = 50,
+ AutomationId = "contentView"
+ };
+ AddTapGesture(result, contentView);
+
+ var stackLayout = new StackLayout
+ {
+ IsEnabled = true,
+ WidthRequest = 250,
+ HeightRequest = 50,
+ AutomationId = "stackLayout"
+ };
+ AddTapGesture(result, stackLayout);
+
+ var color = new Button
+ {
+ Text = "Toggle colors",
+ Command = new Command(() =>
+ {
+ if (!_flag)
+ {
+ grid.BackgroundColor = Color.Red;
+ contentView.BackgroundColor = Color.Blue;
+ stackLayout.BackgroundColor = Color.Yellow;
+ }
+ else
+ {
+ grid.BackgroundColor = Color.Default;
+ contentView.BackgroundColor = Color.Default;
+ stackLayout.BackgroundColor = Color.Default;
+ }
+
+ _flag = !_flag;
+ }),
+ AutomationId = "color"
+ };
+
+ var disabled = new Button
+ {
+ Text = "Disabled",
+ Command = new Command(() =>
+ {
+ grid.IsEnabled = false;
+ contentView.IsEnabled = false;
+ stackLayout.IsEnabled = false;
+
+ result.Text = "Original";
+ }),
+ AutomationId = "disabled"
+ };
+
+ var parent = new StackLayout
+ {
+ Spacing = 10,
+ Orientation = StackOrientation.Vertical,
+ HorizontalOptions = LayoutOptions.Center,
+ VerticalOptions = LayoutOptions.Center,
+ Children =
+ {
+ color,
+ disabled,
+ result,
+ grid,
+ contentView,
+ stackLayout
+ }
+ };
+
+ Content = parent;
+ }
+
+ void AddTapGesture(Label result, View view)
+ {
+ var tapGestureRecognizer = new TapGestureRecognizer
+ {
+ Command = new Command(() =>
+ {
+ result.Text = "Child";
+ })
+ };
+ view.GestureRecognizers.Add(tapGestureRecognizer);
+ }
+
+#if UITEST
+ [Test]
+ public void Test()
+ {
+ RunningApp.WaitForElement(q => q.Marked("grid"));
+ RunningApp.Tap(q => q.Marked("grid"));
+ RunningApp.WaitForElement(q => q.Marked("Child"));
+
+ RunningApp.WaitForElement(q => q.Marked("contentView"));
+ RunningApp.Tap(q => q.Marked("contentView"));
+ RunningApp.WaitForElement(q => q.Marked("Child"));
+
+ RunningApp.WaitForElement(q => q.Marked("stackLayout"));
+ RunningApp.Tap(q => q.Marked("stackLayout"));
+ RunningApp.WaitForElement(q => q.Marked("Child"));
+
+ RunningApp.WaitForElement(q => q.Marked("color"));
+ RunningApp.Tap(q => q.Marked("color"));
+
+ RunningApp.WaitForElement(q => q.Marked("grid"));
+ RunningApp.Tap(q => q.Marked("grid"));
+ RunningApp.WaitForElement(q => q.Marked("Child"));
+
+ RunningApp.WaitForElement(q => q.Marked("contentView"));
+ RunningApp.Tap(q => q.Marked("contentView"));
+ RunningApp.WaitForElement(q => q.Marked("Child"));
+
+ RunningApp.WaitForElement(q => q.Marked("stackLayout"));
+ RunningApp.Tap(q => q.Marked("stackLayout"));
+ RunningApp.WaitForElement(q => q.Marked("Child"));
+
+ RunningApp.WaitForElement(q => q.Marked("disabled"));
+ RunningApp.Tap(q => q.Marked("disabled"));
+
+ RunningApp.WaitForElement(q => q.Marked("grid"));
+ RunningApp.Tap(q => q.Marked("grid"));
+ RunningApp.WaitForElement(q => q.Marked("Original"));
+
+ RunningApp.WaitForElement(q => q.Marked("contentView"));
+ RunningApp.Tap(q => q.Marked("contentView"));
+ RunningApp.WaitForElement(q => q.Marked("Original"));
+
+ RunningApp.WaitForElement(q => q.Marked("stackLayout"));
+ RunningApp.Tap(q => q.Marked("stackLayout"));
+ RunningApp.WaitForElement(q => q.Marked("Original"));
+
+ RunningApp.WaitForElement(q => q.Marked("color"));
+ RunningApp.Tap(q => q.Marked("color"));
+
+ RunningApp.WaitForElement(q => q.Marked("grid"));
+ RunningApp.Tap(q => q.Marked("grid"));
+ RunningApp.WaitForElement(q => q.Marked("Original"));
+
+ RunningApp.WaitForElement(q => q.Marked("contentView"));
+ RunningApp.Tap(q => q.Marked("contentView"));
+ RunningApp.WaitForElement(q => q.Marked("Original"));
+
+ RunningApp.WaitForElement(q => q.Marked("stackLayout"));
+ RunningApp.Tap(q => q.Marked("stackLayout"));
+ RunningApp.WaitForElement(q => q.Marked("Original"));
+ }
+#endif
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla44176.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla44176.cs
new file mode 100644
index 00000000..9a2e519c
--- /dev/null
+++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla44176.cs
@@ -0,0 +1,184 @@
+using Xamarin.Forms.CustomAttributes;
+using Xamarin.Forms.Internals;
+
+#if UITEST
+using Xamarin.Forms.Core.UITests;
+using Xamarin.UITest;
+using NUnit.Framework;
+#endif
+
+namespace Xamarin.Forms.Controls.Issues
+{
+#if UITEST
+ [Category(UITestCategories.InputTransparent)]
+#endif
+
+ [Preserve(AllMembers = true)]
+ [Issue(IssueTracker.Bugzilla, 44176, "InputTransparent fails if BackgroundColor not explicitly set on Android", PlatformAffected.Android)]
+ public class Bugzilla44176 : TestContentPage
+ {
+ bool _flag;
+
+ protected override void Init()
+ {
+ var result = new Label();
+
+ var grid = new Grid
+ {
+ InputTransparent = true,
+ WidthRequest = 250,
+ HeightRequest = 50,
+ AutomationId = "grid"
+ };
+ AddTapGesture(result, grid);
+
+ var contentView = new ContentView
+ {
+ InputTransparent = true,
+ WidthRequest = 250,
+ HeightRequest = 50,
+ AutomationId = "contentView"
+ };
+ AddTapGesture(result, contentView);
+
+ var stackLayout = new StackLayout
+ {
+ InputTransparent = true,
+ WidthRequest = 250,
+ HeightRequest = 50,
+ AutomationId = "stackLayout"
+ };
+ AddTapGesture(result, stackLayout);
+
+ var color = new Button
+ {
+ Text = "Toggle colors",
+ Command = new Command(() =>
+ {
+ if (!_flag)
+ {
+ grid.BackgroundColor = Color.Red;
+ contentView.BackgroundColor = Color.Blue;
+ stackLayout.BackgroundColor = Color.Yellow;
+ }
+ else
+ {
+ grid.BackgroundColor = Color.Default;
+ contentView.BackgroundColor = Color.Default;
+ stackLayout.BackgroundColor = Color.Default;
+ }
+
+ _flag = !_flag;
+ }),
+ AutomationId = "color"
+ };
+
+ var nonTransparent = new Button
+ {
+ Text = "Non-transparent",
+ Command = new Command(() =>
+ {
+ grid.InputTransparent = false;
+ contentView.InputTransparent = false;
+ stackLayout.InputTransparent = false;
+ }),
+ AutomationId = "nontransparent"
+ };
+
+ var parent = new StackLayout
+ {
+ Spacing = 10,
+ Orientation = StackOrientation.Vertical,
+ HorizontalOptions = LayoutOptions.Center,
+ VerticalOptions = LayoutOptions.Center,
+ Children =
+ {
+ color,
+ nonTransparent,
+ result,
+ grid,
+ contentView,
+ stackLayout
+ }
+ };
+ AddTapGesture(result, parent, true);
+
+ Content = parent;
+ }
+
+ void AddTapGesture(Label result, View view, bool isParent = false)
+ {
+ var tapGestureRecognizer = new TapGestureRecognizer
+ {
+ Command = new Command(() =>
+ {
+ result.Text = !isParent ? "Child" : "Parent";
+ })
+ };
+ view.GestureRecognizers.Add(tapGestureRecognizer);
+ }
+
+#if UITEST
+ [Test]
+ public void Test()
+ {
+ RunningApp.WaitForElement(q => q.Marked("grid"));
+ RunningApp.Tap(q => q.Marked("grid"));
+ RunningApp.WaitForElement(q => q.Marked("Parent"));
+
+ RunningApp.WaitForElement(q => q.Marked("contentView"));
+ RunningApp.Tap(q => q.Marked("contentView"));
+ RunningApp.WaitForElement(q => q.Marked("Parent"));
+
+ RunningApp.WaitForElement(q => q.Marked("stackLayout"));
+ RunningApp.Tap(q => q.Marked("stackLayout"));
+ RunningApp.WaitForElement(q => q.Marked("Parent"));
+
+ RunningApp.WaitForElement(q => q.Marked("color"));
+ RunningApp.Tap(q => q.Marked("color"));
+
+ RunningApp.WaitForElement(q => q.Marked("grid"));
+ RunningApp.Tap(q => q.Marked("grid"));
+ RunningApp.WaitForElement(q => q.Marked("Parent"));
+
+ RunningApp.WaitForElement(q => q.Marked("contentView"));
+ RunningApp.Tap(q => q.Marked("contentView"));
+ RunningApp.WaitForElement(q => q.Marked("Parent"));
+
+ RunningApp.WaitForElement(q => q.Marked("stackLayout"));
+ RunningApp.Tap(q => q.Marked("stackLayout"));
+ RunningApp.WaitForElement(q => q.Marked("Parent"));
+
+ RunningApp.WaitForElement(q => q.Marked("nontransparent"));
+ RunningApp.Tap(q => q.Marked("nontransparent"));
+
+ RunningApp.WaitForElement(q => q.Marked("grid"));
+ RunningApp.Tap(q => q.Marked("grid"));
+ RunningApp.WaitForElement(q => q.Marked("Child"));
+
+ RunningApp.WaitForElement(q => q.Marked("contentView"));
+ RunningApp.Tap(q => q.Marked("contentView"));
+ RunningApp.WaitForElement(q => q.Marked("Child"));
+
+ RunningApp.WaitForElement(q => q.Marked("stackLayout"));
+ RunningApp.Tap(q => q.Marked("stackLayout"));
+ RunningApp.WaitForElement(q => q.Marked("Child"));
+
+ RunningApp.WaitForElement(q => q.Marked("color"));
+ RunningApp.Tap(q => q.Marked("color"));
+
+ RunningApp.WaitForElement(q => q.Marked("grid"));
+ RunningApp.Tap(q => q.Marked("grid"));
+ RunningApp.WaitForElement(q => q.Marked("Child"));
+
+ RunningApp.WaitForElement(q => q.Marked("contentView"));
+ RunningApp.Tap(q => q.Marked("contentView"));
+ RunningApp.WaitForElement(q => q.Marked("Child"));
+
+ RunningApp.WaitForElement(q => q.Marked("stackLayout"));
+ RunningApp.Tap(q => q.Marked("stackLayout"));
+ RunningApp.WaitForElement(q => q.Marked("Child"));
+ }
+#endif
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla46458.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla46458.cs
new file mode 100644
index 00000000..8863770f
--- /dev/null
+++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla46458.cs
@@ -0,0 +1,125 @@
+using Xamarin.Forms.CustomAttributes;
+using Xamarin.Forms.Internals;
+
+#if UITEST
+using Xamarin.Forms.Core.UITests;
+using Xamarin.UITest;
+using NUnit.Framework;
+#endif
+
+namespace Xamarin.Forms.Controls.Issues
+{
+#if UITEST
+ [Category(UITestCategories.InputTransparent)]
+ [Category(UITestCategories.IsEnabled)]
+#endif
+
+ [Preserve(AllMembers = true)]
+ [Issue(IssueTracker.Bugzilla, 46458, "Grid.IsEnabled property is not working", PlatformAffected.Android)]
+ public class Bugzilla46458 : TestContentPage
+ {
+ protected override void Init()
+ {
+ var parentGrid = new Grid
+ {
+ BackgroundColor = Color.Yellow
+ };
+ parentGrid.RowDefinitions.Add(new RowDefinition());
+ parentGrid.RowDefinitions.Add(new RowDefinition());
+
+ var grid = new Grid
+ {
+ IsEnabled = false,
+ BackgroundColor = Color.Red
+ };
+
+ grid.RowDefinitions.Add(new RowDefinition());
+ grid.RowDefinitions.Add(new RowDefinition());
+ grid.RowDefinitions.Add(new RowDefinition());
+
+ var label = new Label
+ {
+ HorizontalOptions = LayoutOptions.Center,
+ Text = "Success"
+ };
+ Grid.SetRow(label, 0);
+ grid.Children.Add(label);
+
+ var entry = new Entry
+ {
+ HorizontalOptions = LayoutOptions.Center,
+ HeightRequest = 50,
+ WidthRequest = 250,
+ Placeholder = "Placeholder",
+ AutomationId = "entry"
+ };
+ Grid.SetRow(entry, 1);
+ entry.Focused += (sender, args) => { label.Text = "Fail"; };
+ grid.Children.Add(entry);
+
+ var button = new Button
+ {
+ WidthRequest = 250,
+ HeightRequest = 50,
+ BackgroundColor = Color.Black,
+ TextColor = Color.White,
+ Text = "Click",
+ HorizontalOptions = LayoutOptions.Center,
+ Command = new Command(() => { label.Text = "Fail"; }),
+ AutomationId = "button"
+ };
+ Grid.SetRow(button, 2);
+ grid.Children.Add(button);
+
+ parentGrid.Children.Add(grid);
+ Grid.SetRow(grid, 1);
+
+ var button1 = new Button
+ {
+ WidthRequest = 250,
+ HeightRequest = 50,
+ BackgroundColor = Color.Black,
+ TextColor = Color.White,
+ Text = "Test transparency",
+ HorizontalOptions = LayoutOptions.Center,
+ AutomationId = "button1"
+ };
+ button1.Command = new Command((sender) =>
+ {
+ grid.IsEnabled = true;
+ grid.InputTransparent = true;
+ button1.Text = "Clicked";
+ });
+ Grid.SetRow(button1, 0);
+ parentGrid.Children.Add(button1);
+
+ Content = parentGrid;
+ }
+
+#if UITEST
+ [Test]
+ public void Issue1Test()
+ {
+ RunningApp.WaitForElement(q => q.Marked("entry"));
+ RunningApp.Tap(q => q.Marked("entry"));
+ RunningApp.WaitForElement(q => q.Marked("Success"));
+
+ RunningApp.WaitForElement(q => q.Marked("button"));
+ RunningApp.Tap(q => q.Marked("button"));
+ RunningApp.WaitForElement(q => q.Marked("Success"));
+
+ RunningApp.WaitForElement(q => q.Marked("button1"));
+ RunningApp.Tap(q => q.Marked("button1"));
+ RunningApp.WaitForElement(q => q.Marked("Clicked"));
+
+ RunningApp.WaitForElement(q => q.Marked("entry"));
+ RunningApp.Tap(q => q.Marked("entry"));
+ RunningApp.WaitForElement(q => q.Marked("Success"));
+
+ RunningApp.WaitForElement(q => q.Marked("button"));
+ RunningApp.Tap(q => q.Marked("button"));
+ RunningApp.WaitForElement(q => q.Marked("Success"));
+ }
+#endif
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla53445.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla53445.cs
new file mode 100644
index 00000000..a9c5f5ab
--- /dev/null
+++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla53445.cs
@@ -0,0 +1,109 @@
+using Xamarin.Forms.CustomAttributes;
+using Xamarin.Forms.Internals;
+
+#if UITEST
+using NUnit.Framework;
+using Xamarin.Forms.Core.UITests;
+#endif
+
+namespace Xamarin.Forms.Controls.Issues
+{
+#if UITEST
+ [Category(UITestCategories.IsEnabled)]
+#endif
+
+ [Preserve(AllMembers = true)]
+ [Issue(IssueTracker.Bugzilla, 53445, "Setting Grid.IsEnabled to false does not disable child controls", PlatformAffected.All)]
+ public class Bugzilla53445 : TestContentPage
+ {
+ protected override void Init()
+ {
+ var layout = new StackLayout { VerticalOptions = LayoutOptions.Fill, Spacing = 20 };
+
+ var status = new Label { Text = "Success" };
+
+ var instructions = new Label { Text = "Disable all of the layouts by clicking the Toggle button. Then click the buttons inside each layout. If the status changes from Success to Fail, this test has failed." };
+
+ var grid = new Grid
+ {
+ BackgroundColor = Color.Blue,
+ IsEnabled = true,
+ WidthRequest = 250,
+ HeightRequest = 50,
+ AutomationId = "grid"
+ };
+
+ var gridButton = new Button { AutomationId = "gridbutton", Text = "Test", WidthRequest = 50 };
+ grid.Children.Add(gridButton);
+ gridButton.Clicked += (sender, args) => status.Text = "Fail";
+
+ var contentView = new ContentView
+ {
+ BackgroundColor = Color.Green,
+ IsEnabled = true,
+ WidthRequest = 250,
+ HeightRequest = 50,
+ AutomationId = "contentView"
+ };
+
+ var contentViewButton = new Button { AutomationId = "contentviewbutton", Text = "Test", WidthRequest = 50 };
+ contentView.Content = contentViewButton;
+ contentViewButton.Clicked += (sender, args) => status.Text = "Fail";
+
+ var stackLayout = new StackLayout
+ {
+ BackgroundColor = Color.Orange,
+ IsEnabled = true,
+ WidthRequest = 250,
+ HeightRequest = 50,
+ AutomationId = "stackLayout"
+ };
+
+ var stackLayoutButton = new Button { AutomationId = "stacklayoutbutton", Text = "Test", WidthRequest = 50 };
+ stackLayout.Children.Add(stackLayoutButton);
+ stackLayoutButton.Clicked += (sender, args) => status.Text = "Fail";
+
+ var toggleButton = new Button { AutomationId = "toggle", Text = $"Toggle IsEnabled (currently {grid.IsEnabled})" };
+ toggleButton.Clicked += (sender, args) =>
+ {
+ grid.IsEnabled = !grid.IsEnabled;
+ contentView.IsEnabled = !contentView.IsEnabled;
+ stackLayout.IsEnabled = !stackLayout.IsEnabled;
+ toggleButton.Text = $"Toggle IsEnabled (currently {grid.IsEnabled})";
+ };
+
+ layout.Children.Add(instructions);
+ layout.Children.Add(status);
+ layout.Children.Add(toggleButton);
+ layout.Children.Add(grid);
+ layout.Children.Add(contentView);
+ layout.Children.Add(stackLayout);
+
+ Content = layout;
+ }
+
+
+#if UITEST
+ [Test]
+ public void Test()
+ {
+ RunningApp.WaitForElement(q => q.Marked("Success"));
+
+ // Disable the layouts
+ RunningApp.Tap(q => q.Marked("toggle"));
+
+ // Tap the grid button; the event should not fire and the label should not change
+ RunningApp.Tap(q => q.Marked("gridbutton"));
+ RunningApp.WaitForElement(q => q.Marked("Success"));
+
+ // Tap the contentview button; the event should not fire and the label should not change
+ RunningApp.Tap(q => q.Marked("contentviewbutton"));
+ RunningApp.WaitForElement(q => q.Marked("Success"));
+
+ // Tap the stacklayout button; the event should not fire and the label should not change
+ RunningApp.Tap(q => q.Marked("stacklayoutbutton"));
+ RunningApp.WaitForElement(q => q.Marked("Success"));
+ }
+#endif
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/InputTransparentIssue.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/InputTransparentIssue.cs
deleted file mode 100644
index 86effcdc..00000000
--- a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/InputTransparentIssue.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-using System;
-
-using Xamarin.Forms.CustomAttributes;
-using Xamarin.Forms.Internals;
-
-#if UITEST
-using Xamarin.UITest;
-using NUnit.Framework;
-#endif
-
-namespace Xamarin.Forms.Controls.Issues
-{
-
- [Preserve (AllMembers = true)]
- [Issue (IssueTracker.Github, 30000, "InputTransparentIssue")]
- public class InputTransparentIssue : TestContentPage
- {
- protected override void Init ()
- {
- var abs = new AbsoluteLayout();
- var box = new BoxView { Color = Color.Red };
- var label = new Label { BackgroundColor = Color.Green , InputTransparent = true };
- abs.Children.Add(box, new Rectangle(0, 0, 1, 1), AbsoluteLayoutFlags.All);
- abs.Children.Add(label, new Rectangle(0, 0, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize), AbsoluteLayoutFlags.PositionProportional);
- label.Text = DateTime.Now.ToString();
- box.GestureRecognizers.Add(new TapGestureRecognizer
- {
- Command = new Command(() =>
- {
- label.Text = DateTime.Now.ToString();
- })
- });
- Image img = new Image { Source = ImageSource.FromFile("oasis.jpg"), InputTransparent = true };
- abs.Children.Add(img, new Rectangle(.5, .5, .5, .5), AbsoluteLayoutFlags.All);
- Content = abs ;
- }
- }
-}
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/InputTransparentTests.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/InputTransparentTests.cs
new file mode 100644
index 00000000..1d23f149
--- /dev/null
+++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/InputTransparentTests.cs
@@ -0,0 +1,204 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using Xamarin.Forms.CustomAttributes;
+using Xamarin.Forms.Internals;
+
+#if UITEST
+using Xamarin.Forms.Core.UITests;
+using Xamarin.UITest;
+using NUnit.Framework;
+#endif
+
+namespace Xamarin.Forms.Controls.Issues
+{
+#if UITEST
+ [Category(UITestCategories.InputTransparent)]
+#endif
+
+ [Preserve(AllMembers = true)]
+ [Issue(IssueTracker.None, 8675309, "Test InputTransparent true/false on various controls")]
+ public class InputTransparentTests : TestNavigationPage
+ {
+ const string TargetAutomationId = "inputtransparenttarget";
+ ContentPage _menu;
+
+#if UITEST
+ [Test, TestCaseSource(nameof(TestCases))]
+ public void VerifyInputTransparent(string menuItem)
+ {
+ var results = RunningApp.WaitForElement(q => q.Marked(menuItem));
+
+ if(results.Length > 1)
+ {
+ var rect = results.First(r => r.Class.Contains("Button")).Rect;
+
+ RunningApp.TapCoordinates( rect.CenterX, rect.CenterY );
+ }
+ else
+ {
+ RunningApp.Tap(q => q.Marked(menuItem));
+ }
+
+ // Find the start label
+ RunningApp.WaitForElement(q => q.Marked("Start"));
+
+ // Find the control we're testing
+ var result = RunningApp.WaitForElement(q => q.Marked(TargetAutomationId));
+ var target = result.First().Rect;
+
+ // Tap the control
+ var y = target.CenterY;
+
+ // In theory we want to tap the center of the control. But Stepper lays out differently than the other controls,
+ // (it doesn't center vertically within its layout), so we need to adjust for it until someone fixes it
+ if (menuItem == "Stepper")
+ {
+ y = target.Y;
+ }
+
+ RunningApp.TapCoordinates(target.CenterX, y);
+
+ if(menuItem == nameof(DatePicker) || menuItem == nameof(TimePicker))
+ {
+ // These controls show a pop-up which we have to cancel/done out of before we can continue
+#if __ANDROID__
+ var cancelButtonText = "Cancel";
+#elif __IOS__
+ var cancelButtonText = "Done";
+#else
+ var cancelButtonText = "Cancel";
+#endif
+ RunningApp.WaitForElement(q => q.Marked(cancelButtonText));
+ RunningApp.Tap(q => q.Marked(cancelButtonText));
+ }
+
+ // Since InputTransparent is set to false, the start label should not have changed
+ RunningApp.WaitForElement(q => q.Marked("Start"));
+
+ // Switch to InputTransparent == true
+ RunningApp.Tap(q => q.Marked("Toggle"));
+
+ // Tap the control
+ RunningApp.TapCoordinates(target.CenterX, target.CenterY);
+
+ // Since InputTransparent is set to true, the start label should now show a single tap
+ RunningApp.WaitForElement(q => q.Marked("Taps registered: 1"));
+ }
+#endif
+
+ ContentPage CreateTestPage(View view)
+ {
+ var layout = new Grid();
+ layout.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
+ layout.RowDefinitions.Add(new RowDefinition());
+
+ var abs = new AbsoluteLayout();
+ var box = new BoxView { Color = Color.BlanchedAlmond };
+
+ var label = new Label { BackgroundColor = Color.Chocolate, Text = "Start", Margin = 5 };
+
+ var taps = 0;
+
+ abs.Children.Add(box, new Rectangle(0, 0, 1, 1), AbsoluteLayoutFlags.All);
+
+ abs.Children.Add(label, new Rectangle(0, 0, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize), AbsoluteLayoutFlags.PositionProportional);
+
+ box.GestureRecognizers.Add(new TapGestureRecognizer
+ {
+ Command = new Command(() =>
+ {
+ taps += 1;
+ label.Text = $"Taps registered: {taps}";
+ })
+ });
+
+ view.InputTransparent = false;
+ abs.Children.Add(view, new Rectangle(.5, .5, .5, .5), AbsoluteLayoutFlags.All);
+
+ var toggleButton = new Button { AutomationId = "Toggle", Text = $"Toggle InputTransparent (now {view.InputTransparent})" };
+ toggleButton.Clicked += (sender, args) =>
+ {
+ view.InputTransparent = !view.InputTransparent;
+ toggleButton.Text = $"Toggle InputTransparent (now {view.InputTransparent})";
+ };
+
+ layout.Children.Add(toggleButton);
+ layout.Children.Add(abs);
+
+ Grid.SetRow(abs, 1);
+
+ return new ContentPage {Content = layout};
+ }
+
+ Button MenuButton(string label, Func<View> view)
+ {
+ var button = new Button { Text = label };
+
+ var testView = view();
+ testView.AutomationId = TargetAutomationId;
+
+ button.Clicked += (sender, args) => PushAsync(CreateTestPage(testView));
+
+ return button;
+ }
+
+ IEnumerable<string> TestCases
+ {
+ get
+ {
+ return (BuildMenu().Content as Layout).InternalChildren.SelectMany(
+ element => (element as Layout).InternalChildren.Select(view => (view as Button).Text));
+ }
+ }
+
+ ContentPage BuildMenu()
+ {
+ if (_menu != null)
+ {
+ return _menu;
+ }
+
+ var layout = new Grid
+ {
+ VerticalOptions = LayoutOptions.Fill, HorizontalOptions = LayoutOptions.Fill,
+ ColumnDefinitions = new ColumnDefinitionCollection { new ColumnDefinition(), new ColumnDefinition() }
+ };
+
+ var col1 = new StackLayout();
+ layout.Children.Add(col1);
+ Grid.SetColumn(col1, 0);
+
+ var col2 = new StackLayout();
+ layout.Children.Add(col2);
+ Grid.SetColumn(col2, 1);
+
+ col1.Children.Add(MenuButton(nameof(Image), () => new Image { Source = ImageSource.FromFile("oasis.jpg") }));
+ col1.Children.Add(MenuButton(nameof(Frame), () => new Frame { BackgroundColor = Color.DarkGoldenrod }));
+ col1.Children.Add(MenuButton(nameof(Entry), () => new Entry()));
+ col1.Children.Add(MenuButton(nameof(Editor), () => new Editor()));
+ col1.Children.Add(MenuButton(nameof(Button), () => new Button { Text = "Test" }));
+ col1.Children.Add(MenuButton(nameof(Label), () => new Label
+ {
+ LineBreakMode = LineBreakMode.WordWrap,
+ Text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
+ }));
+ col1.Children.Add(MenuButton(nameof(SearchBar), () => new SearchBar()));
+
+ col2.Children.Add(MenuButton(nameof(DatePicker), () => new DatePicker()));
+ col2.Children.Add(MenuButton(nameof(TimePicker), () => new TimePicker()));
+ col2.Children.Add(MenuButton(nameof(Slider), () => new Slider()));
+ col2.Children.Add(MenuButton(nameof(Switch), () => new Switch()));
+ col2.Children.Add(MenuButton(nameof(Stepper), () => new Stepper()));
+ col2.Children.Add(MenuButton(nameof(BoxView), () => new BoxView { BackgroundColor = Color.DarkMagenta, WidthRequest = 100, HeightRequest = 100 }));
+
+ return new ContentPage { Content = layout };
+ }
+
+ protected override void Init()
+ {
+ PushAsync(BuildMenu());
+ }
+ }
+}
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems
index 326d1323..ced1ef52 100644
--- a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems
+++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems
@@ -155,6 +155,8 @@
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla43867.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla43735.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla43783.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Bugzilla44096.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Bugzilla44176.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla44453.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla51536.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla44940.cs" />
@@ -170,6 +172,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla45330.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla44955.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla45743.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Bugzilla46458.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla46494.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla44476.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla46630.cs" />
@@ -187,6 +190,7 @@
<SubType>Code</SubType>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla52266.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Bugzilla53445.cs" />
<Compile Include="$(MSBuildThisFileDirectory)CarouselAsync.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla34561.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla34727.cs" />
@@ -196,7 +200,7 @@
<DependentUpon>Bugzilla38416.xaml</DependentUpon>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)FailImageSource.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)InputTransparentIssue.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)InputTransparentTests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)IsInvokeRequiredRaceCondition.cs" />
<Compile Include="$(MSBuildThisFileDirectory)IsPasswordToggleTest.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue1023.cs" />
diff --git a/Xamarin.Forms.Core.UITests.Shared/UITestCategories.cs b/Xamarin.Forms.Core.UITests.Shared/UITestCategories.cs
index 28a6fff4..c5168d7c 100644
--- a/Xamarin.Forms.Core.UITests.Shared/UITestCategories.cs
+++ b/Xamarin.Forms.Core.UITests.Shared/UITestCategories.cs
@@ -30,6 +30,8 @@
public const string ToolbarItem = "ToolbarItem";
public const string WebView = "WebView";
public const string Maps = "Maps";
+ public const string InputTransparent = "InputTransparent";
+ public const string IsEnabled = "IsEnabled";
public const string ManualReview = "ManualReview";
}
diff --git a/Xamarin.Forms.Platform.Android/AppCompat/FrameRenderer.cs b/Xamarin.Forms.Platform.Android/AppCompat/FrameRenderer.cs
index 7c40ea80..d0ed345d 100644
--- a/Xamarin.Forms.Platform.Android/AppCompat/FrameRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/AppCompat/FrameRenderer.cs
@@ -31,6 +31,8 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
VisualElementTracker _visualElementTracker;
NotifyCollectionChangedEventHandler _collectionChangeHandler;
+ bool _inputTransparent;
+
public FrameRenderer() : base(Forms.Context)
{
_tapGestureHandler = new TapGestureHandler(() => Element);
@@ -69,6 +71,16 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
}
}
+ public override bool OnTouchEvent(MotionEvent e)
+ {
+ if (_inputTransparent)
+ {
+ return false;
+ }
+
+ return base.OnTouchEvent(e);
+ }
+
void IOnClickListener.OnClick(AView v)
{
_tapGestureHandler.OnSingleClick();
@@ -83,14 +95,16 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
ScaleGestureDetectorCompat.SetQuickScaleEnabled(_scaleDetector.Value, true);
handled = _scaleDetector.Value.OnTouchEvent(e);
}
-
+
if (_gestureDetector.IsValueCreated && _gestureDetector.Value.Handle == IntPtr.Zero)
{
// This gesture detector has already been disposed, probably because it's on a cell which is going away
return handled;
}
- return _gestureDetector.Value.OnTouchEvent(e) || handled;
+ // It's very important that the gesture detection happen first here
+ // if we check handled first, we might short-circuit and never check for tap/pan
+ return _gestureDetector.Value.OnTouchEvent(e) || handled;
}
VisualElement IVisualElementRenderer.Element => Element;
@@ -202,6 +216,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
UpdateShadow();
UpdateBackgroundColor();
UpdateCornerRadius();
+ UpdateInputTransparent();
SubscribeGestureRecognizers(e.NewElement);
}
}
@@ -235,6 +250,13 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
UpdateBackgroundColor();
else if (e.PropertyName == Frame.CornerRadiusProperty.PropertyName)
UpdateCornerRadius();
+ else if (e.PropertyName == VisualElement.InputTransparentProperty.PropertyName)
+ UpdateInputTransparent();
+ }
+
+ void UpdateInputTransparent()
+ {
+ _inputTransparent = Element.InputTransparent;
}
void SubscribeGestureRecognizers(VisualElement element)
diff --git a/Xamarin.Forms.Platform.Android/Platform.cs b/Xamarin.Forms.Platform.Android/Platform.cs
index ca0b9708..0fc287c9 100644
--- a/Xamarin.Forms.Platform.Android/Platform.cs
+++ b/Xamarin.Forms.Platform.Android/Platform.cs
@@ -1024,6 +1024,50 @@ namespace Xamarin.Forms.Platform.Android
internal class DefaultRenderer : VisualElementRenderer<View>
{
+ bool _notReallyHandled;
+ internal void NotifyFakeHandling()
+ {
+ _notReallyHandled = true;
+ }
+
+ public override bool DispatchTouchEvent(MotionEvent e)
+ {
+ #region
+ // Normally dispatchTouchEvent feeds the touch events to its children one at a time, top child first,
+ // (and only to the children in the hit-test area of the event) stopping as soon as one of them has handled
+ // the event.
+
+ // But to be consistent across the platforms, we don't want this behavior; if an element is not input transparent
+ // we don't want an event to "pass through it" and be handled by an element "behind/under" it. We just want the processing
+ // to end after the first non-transparent child, regardless of whether the event has been handled.
+
+ // This is only an issue for a couple of controls; the interactive controls (switch, button, slider, etc) already "handle" their touches
+ // and the events don't propagate to other child controls. But for image, label, and box that doesn't happen. We can't have those controls
+ // lie about their events being handled because then the events won't propagate to *parent* controls (e.g., a frame with a label in it would
+ // never get a tap gesture from the label). In other words, we *want* parent propagation, but *do not want* sibling propagation. So we need to short-circuit
+ // base.DispatchTouchEvent here, but still return "false".
+
+ // Duplicating the logic of ViewGroup.dispatchTouchEvent and modifying it slightly for our purposes is a non-starter; the method is too
+ // complex and does a lot of micro-optimization. Instead, we provide a signalling mechanism for the controls which don't already "handle" touch
+ // events to tell us that they will be lying about handling their event; they then return "true" to short-circuit base.DispatchTouchEvent.
+
+ // The container gets this message and after it gets the "handled" result from dispatchTouchEvent,
+ // it then knows to ignore that result and return false/unhandled. This allows the event to propagate up the tree.
+ #endregion
+
+ _notReallyHandled = false;
+
+ var result = base.DispatchTouchEvent(e);
+
+ if (result && _notReallyHandled)
+ {
+ // If the child control returned true from its touch event handler but signalled that it was a fake "true", leave the event unhandled
+ // so parent controls have the opportunity
+ return false;
+ }
+
+ return result;
+ }
}
#region IPlatformEngine implementation
diff --git a/Xamarin.Forms.Platform.Android/Renderers/BoxRenderer.cs b/Xamarin.Forms.Platform.Android/Renderers/BoxRenderer.cs
index 380d4018..aa19d81c 100644
--- a/Xamarin.Forms.Platform.Android/Renderers/BoxRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/Renderers/BoxRenderer.cs
@@ -5,7 +5,7 @@ namespace Xamarin.Forms.Platform.Android
{
public class BoxRenderer : VisualElementRenderer<BoxView>
{
- bool _isInViewCell;
+ readonly MotionEventHelper _motionEventHelper = new MotionEventHelper();
public BoxRenderer()
{
@@ -16,26 +16,15 @@ namespace Xamarin.Forms.Platform.Android
{
if (base.OnTouchEvent(e))
return true;
- return !Element.InputTransparent && !_isInViewCell;
+
+ return _motionEventHelper.HandleMotionEvent(Parent);
}
protected override void OnElementChanged(ElementChangedEventArgs<BoxView> e)
{
base.OnElementChanged(e);
- if (e.NewElement != null)
- {
- var parent = e.NewElement.Parent;
- while (parent != null)
- {
- if (parent is ViewCell)
- {
- _isInViewCell = true;
- break;
- }
- parent = parent.Parent;
- }
- }
+ _motionEventHelper.UpdateElement(e.NewElement);
UpdateBackgroundColor();
}
diff --git a/Xamarin.Forms.Platform.Android/Renderers/ImageRenderer.cs b/Xamarin.Forms.Platform.Android/Renderers/ImageRenderer.cs
index e18d4b95..fee05f1b 100644
--- a/Xamarin.Forms.Platform.Android/Renderers/ImageRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/Renderers/ImageRenderer.cs
@@ -3,6 +3,7 @@ using System.ComponentModel;
using System.IO;
using System.Threading.Tasks;
using Android.Graphics;
+using Android.Views;
using AImageView = Android.Widget.ImageView;
using Xamarin.Forms.Internals;
@@ -11,8 +12,7 @@ namespace Xamarin.Forms.Platform.Android
public class ImageRenderer : ViewRenderer<Image, AImageView>
{
bool _isDisposed;
-
- IElementController ElementController => Element as IElementController;
+ readonly MotionEventHelper _motionEventHelper = new MotionEventHelper();
public ImageRenderer()
{
@@ -44,6 +44,8 @@ namespace Xamarin.Forms.Platform.Android
SetNativeControl(view);
}
+ _motionEventHelper.UpdateElement(e.NewElement);
+
UpdateBitmap(e.OldElement);
UpdateAspect();
}
@@ -117,5 +119,13 @@ namespace Xamarin.Forms.Platform.Android
((IVisualElementController)Element).NativeSizeChanged();
}
}
+
+ public override bool OnTouchEvent(MotionEvent e)
+ {
+ if (base.OnTouchEvent(e))
+ return true;
+
+ return _motionEventHelper.HandleMotionEvent(Parent);
+ }
}
} \ No newline at end of file
diff --git a/Xamarin.Forms.Platform.Android/Renderers/LabelRenderer.cs b/Xamarin.Forms.Platform.Android/Renderers/LabelRenderer.cs
index c544a239..ab1a6a35 100644
--- a/Xamarin.Forms.Platform.Android/Renderers/LabelRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/Renderers/LabelRenderer.cs
@@ -4,8 +4,8 @@ using Android.Content.Res;
using Android.Graphics;
using Android.Text;
using Android.Util;
+using Android.Views;
using Android.Widget;
-using AColor = Android.Graphics.Color;
namespace Xamarin.Forms.Platform.Android
{
@@ -23,6 +23,8 @@ namespace Xamarin.Forms.Platform.Android
FormsTextView _view;
bool _wasFormatted;
+ readonly MotionEventHelper _motionEventHelper = new MotionEventHelper();
+
public LabelRenderer()
{
AutoPackage = false;
@@ -97,6 +99,8 @@ namespace Xamarin.Forms.Platform.Android
if (e.OldElement.HorizontalTextAlignment != e.NewElement.HorizontalTextAlignment || e.OldElement.VerticalTextAlignment != e.NewElement.VerticalTextAlignment)
UpdateGravity();
}
+
+ _motionEventHelper.UpdateElement(e.NewElement);
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
@@ -217,5 +221,13 @@ namespace Xamarin.Forms.Platform.Android
_lastSizeRequest = null;
}
+
+ public override bool OnTouchEvent(MotionEvent e)
+ {
+ if (base.OnTouchEvent(e))
+ return true;
+
+ return _motionEventHelper.HandleMotionEvent(Parent);
+ }
}
} \ No newline at end of file
diff --git a/Xamarin.Forms.Platform.Android/Renderers/MotionEventHelper.cs b/Xamarin.Forms.Platform.Android/Renderers/MotionEventHelper.cs
new file mode 100644
index 00000000..4ed06d26
--- /dev/null
+++ b/Xamarin.Forms.Platform.Android/Renderers/MotionEventHelper.cs
@@ -0,0 +1,53 @@
+using Android.Views;
+
+namespace Xamarin.Forms.Platform.Android
+{
+ internal class MotionEventHelper
+ {
+ VisualElement _element;
+ bool _isInViewCell;
+
+ public bool HandleMotionEvent(IViewParent parent)
+ {
+ if (_isInViewCell || _element.InputTransparent)
+ {
+ return false;
+ }
+
+ var renderer = parent as Platform.DefaultRenderer;
+ if (renderer == null)
+ {
+ return false;
+ }
+
+ // Let the container know that we're "fake" handling this event
+ renderer.NotifyFakeHandling();
+
+ return true;
+ }
+
+ public void UpdateElement(VisualElement element)
+ {
+ _isInViewCell = false;
+ _element = element;
+
+ if (_element == null)
+ {
+ return;
+ }
+
+ // Determine whether this control is inside a ViewCell;
+ // we don't fake handle the events because ListView needs them for row selection
+ var parent = _element.Parent;
+ while (parent != null)
+ {
+ if (parent is ViewCell)
+ {
+ _isInViewCell = true;
+ break;
+ }
+ parent = parent.Parent;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Platform.Android/VisualElementRenderer.cs b/Xamarin.Forms.Platform.Android/VisualElementRenderer.cs
index 7f5c7f91..8f6722c3 100644
--- a/Xamarin.Forms.Platform.Android/VisualElementRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/VisualElementRenderer.cs
@@ -92,14 +92,20 @@ namespace Xamarin.Forms.Platform.Android
public override bool OnInterceptTouchEvent(MotionEvent ev)
{
- if (Element.InputTransparent && Element.IsEnabled)
- return false;
+ if (!Element.IsEnabled || (Element.InputTransparent && Element.IsEnabled))
+ return true;
return base.OnInterceptTouchEvent(ev);
}
bool AView.IOnTouchListener.OnTouch(AView v, MotionEvent e)
{
+ if (!Element.IsEnabled)
+ return true;
+
+ if (Element.InputTransparent)
+ return false;
+
var handled = false;
if (_pinchGestureHandler.IsPinchSupported)
{
@@ -116,7 +122,11 @@ namespace Xamarin.Forms.Platform.Android
return handled;
}
- return _gestureDetector.Value.OnTouchEvent(e) || handled;
+ // It's very important that the gesture detection happen first here
+ // if we check handled first, we might short-circuit and never check for tap/pan
+ handled = _gestureDetector.Value.OnTouchEvent(e) || handled;
+
+ return handled;
}
VisualElement IVisualElementRenderer.Element => Element;
@@ -191,8 +201,6 @@ namespace Xamarin.Forms.Platform.Android
SoundEffectsEnabled = false;
}
- InputTransparent = Element.InputTransparent;
-
// must be updated AFTER SetOnClickListener is called
// SetOnClickListener implicitly calls Clickable = true
UpdateGestureRecognizers(true);
@@ -215,6 +223,7 @@ namespace Xamarin.Forms.Platform.Android
SetContentDescription();
SetFocusable();
+ UpdateInputTransparent();
Performance.Stop();
}
@@ -305,14 +314,14 @@ namespace Xamarin.Forms.Platform.Android
{
if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
UpdateBackgroundColor();
- else if (e.PropertyName == VisualElement.InputTransparentProperty.PropertyName)
- InputTransparent = Element.InputTransparent;
else if (e.PropertyName == Accessibility.HintProperty.PropertyName)
SetContentDescription();
else if (e.PropertyName == Accessibility.NameProperty.PropertyName)
SetContentDescription();
else if (e.PropertyName == Accessibility.IsInAccessibleTreeProperty.PropertyName)
SetFocusable();
+ else if (e.PropertyName == VisualElement.InputTransparentProperty.PropertyName)
+ UpdateInputTransparent();
}
protected override void OnLayout(bool changed, int l, int t, int r, int b)
@@ -398,6 +407,11 @@ namespace Xamarin.Forms.Platform.Android
return true;
}
+ void UpdateInputTransparent()
+ {
+ InputTransparent = Element.InputTransparent;
+ }
+
protected void SetPackager(VisualElementPackager packager)
{
_packager = packager;
diff --git a/Xamarin.Forms.Platform.Android/Xamarin.Forms.Platform.Android.csproj b/Xamarin.Forms.Platform.Android/Xamarin.Forms.Platform.Android.csproj
index 29562618..fd894e47 100644
--- a/Xamarin.Forms.Platform.Android/Xamarin.Forms.Platform.Android.csproj
+++ b/Xamarin.Forms.Platform.Android/Xamarin.Forms.Platform.Android.csproj
@@ -174,6 +174,7 @@
<Compile Include="AppCompat\ViewRenderer.cs" />
<Compile Include="Renderers\LocalizedDigitsKeyListener.cs" />
<Compile Include="Renderers\MasterDetailContainer.cs" />
+ <Compile Include="Renderers\MotionEventHelper.cs" />
<Compile Include="Renderers\PageContainer.cs" />
<Compile Include="Renderers\ScrollViewContainer.cs" />
<Compile Include="Renderers\StreamImagesourceHandler.cs" />
diff --git a/Xamarin.Forms.Platform.WinRT/VisualElementRenderer.cs b/Xamarin.Forms.Platform.WinRT/VisualElementRenderer.cs
index e1bf2ef0..a1cc0e44 100644
--- a/Xamarin.Forms.Platform.WinRT/VisualElementRenderer.cs
+++ b/Xamarin.Forms.Platform.WinRT/VisualElementRenderer.cs
@@ -540,6 +540,8 @@ namespace Xamarin.Forms.Platform.WinRT
var control = Control as Control;
if (control != null)
control.IsEnabled = Element.IsEnabled;
+ else
+ IsHitTestVisible = Element.IsEnabled;
}
void UpdateTracker()