[Android] fixes Picker list showing up incorrectly when focus is set on other control...
authorPavel Yakovlev <v-payako@microsoft.com>
Wed, 5 Dec 2018 00:54:00 +0000 (03:54 +0300)
committerRui Marinho <me@ruimarinho.net>
Wed, 5 Dec 2018 00:54:00 +0000 (00:54 +0000)
* [Android] fixes Picker list shows up, when focus is set on other controls

* - fixes Picker outside the cell, when you tap on the adjacent EditBox
- address comments

* [Android] added automated UItest

* [Android] added automated test in the carousel

* correct namespace UITest

* fix uitest

* fix uitest #2

* [Controls] Add test for #4494

* minor formating

Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue4187.cs [new file with mode: 0644]
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems
Xamarin.Forms.Platform.Android/AppCompat/PickerRenderer.cs
Xamarin.Forms.Platform.Android/IPickerRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Android/Renderers/DatePickerRenderer.cs
Xamarin.Forms.Platform.Android/Renderers/PickerEditText.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Android/Renderers/PickerRenderer.cs
Xamarin.Forms.Platform.Android/Renderers/TimePickerRenderer.cs
Xamarin.Forms.Platform.Android/VisualElementRenderer.cs
Xamarin.Forms.Platform.Android/Xamarin.Forms.Platform.Android.csproj

diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue4187.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue4187.cs
new file mode 100644 (file)
index 0000000..7839c83
--- /dev/null
@@ -0,0 +1,201 @@
+using System;
+using System.Collections.Generic;
+using Xamarin.Forms.CustomAttributes;
+using Xamarin.Forms.Internals;
+
+#if UITEST
+using NUnit.Framework;
+using System.Threading;
+#endif
+
+namespace Xamarin.Forms.Controls.Issues
+{
+       [Preserve(AllMembers = true)]
+       [Issue(IssueTracker.Github, 4187, "Picker list shows up, when focus is set on other controls", PlatformAffected.Android)]
+       public class Issue4187 : TestCarouselPage
+       {
+               protected override void Init()
+               {
+                       var items = new List<Issue4187Model>
+                       {
+                               new Issue4187Model
+                               {
+                                       Label = "Label 1",
+                                       PickerSource = new List<string> {"Flower", "Harvest", "Propagation", "Vegetation"},
+                                       Text = "Text 1",
+                                       Date = DateTime.Now
+                               },
+                               new Issue4187Model
+                               {
+                                       Label = "Label 2",
+                                       PickerSource = new List<string> {"1", "2", "3", "4"},
+                                       Text = "Text 2",
+                                       Date = DateTime.Now.AddDays(1)
+                               }
+                       };
+                       var listView = new ListView
+                       {
+                               VerticalOptions = LayoutOptions.FillAndExpand,
+                               HasUnevenRows = true,
+                               ItemsSource = items,
+                               ItemTemplate = new DataTemplate(() => GetViewCell())
+                       };
+
+                       var tableView = new TableView
+                       {
+                               BackgroundColor = Color.Wheat,
+                               HasUnevenRows = true,
+                               RowHeight = 100
+                       };
+                       tableView.Root = new TableRoot
+                       {
+                               new TableSection
+                               {
+                                       GetViewCell(),
+                                       GetViewCell(),
+                               }
+                       };
+                       tableView.BindingContext = new Issue4187Model
+                       {
+                               Label = "Label 1",
+                               PickerSource = new List<string> { "Flower", "Harvest", "Propagation", "Vegetation" },
+                               Text = "Text 1",
+                               Date = DateTime.Now
+                       };
+
+                       Children.Add(new ContentPage
+                       {
+                               Content = new StackLayout
+                               {
+                                       Children = {
+                                               GenerateNewPicker(),
+                                               listView
+                                       }
+                               }
+                       });
+
+                       Children.Add(new ContentPage
+                       {
+                               BackgroundColor = Color.Red,
+                               Content = new StackLayout
+                               {
+                                       Children = { GenerateNewPicker(), tableView }
+                               }
+                       });
+
+                       Children.Add(new ContentPage
+                       {
+                               BackgroundColor = Color.Blue,
+                               Content = new StackLayout
+                               {
+                                       Children = { GenerateNewPicker() }
+                               }
+                       });
+               }
+
+               static ViewCell GetViewCell()
+               {
+                       var label = new Label { Text = "Status" };
+                       label.SetBinding(Label.TextProperty, new Binding(nameof(Issue4187Model.Label)));
+                       var picker = new Picker();
+                       picker.SetBinding(Picker.ItemsSourceProperty, new Binding(nameof(Issue4187Model.PickerSource)));
+
+                       var datePicker = new DatePicker();
+                       datePicker.SetBinding(DatePicker.DateProperty, new Binding(nameof(Issue4187Model.Date)));
+
+                       var entry = new Entry();
+                       entry.SetBinding(Entry.TextProperty, new Binding(nameof(Issue4187Model.Text)));
+
+                       return new ViewCell
+                       {
+                               View = new StackLayout
+                               {
+                                       BackgroundColor = Color.Pink,
+                                       Children = {
+                                               label,
+                                               picker,
+                                               datePicker,
+                                               new TimePicker(),
+                                               entry
+                                       }
+                               }
+                       };
+               }
+
+               Picker GenerateNewPicker()
+               {
+                       var picker = new Picker();
+                       for (int i = 1; i < 100; i++)
+                               picker.Items.Add($"item {i}");
+                       return picker;
+               }
+
+               [Preserve(AllMembers = true)]
+               class Issue4187Model
+               {
+                       public string Label { get; set; }
+                       public List<string> PickerSource { get; set; }
+                       public string Text { get; set; }
+                       public DateTime Date { get; set; }
+               }
+
+#if UITEST && __ANDROID__
+               [Test]
+               public void Issue4187Test()
+               {
+                       RunningApp.WaitForElement("Text 1");
+                       Assert.AreEqual(7, RunningApp.Query(q => q.TextField().Class("PickerEditText")).Length, "picker count");
+                       TapOnPicker(1);
+                       Assert.IsTrue(DialogIsOpened(), "#1");
+                       RunningApp.Tap("Text 2");
+                       Assert.IsFalse(DialogIsOpened(), "#2");
+                       TapOnPicker(3);
+                       Assert.IsTrue(DialogIsOpened(), "#3");
+                       RunningApp.Tap("Text 1");
+                       Assert.IsFalse(DialogIsOpened(), "#5");
+
+                       // Carousel - first page
+                       RunningApp.Back();
+                       RunningApp.ScrollUp();
+                       TapOnPicker(0);
+                       Assert.IsTrue(DialogIsOpened(), "Carousel - #1");
+
+                       // Red page
+                       RunningApp.SwipeRightToLeft();
+                       Assert.IsFalse(DialogIsOpened(), "Carousel - #2");
+                       TapOnPicker(0);
+                       Assert.IsTrue(DialogIsOpened(), "Carousel - #3");
+
+                       // Blue page
+                       RunningApp.SwipeRightToLeft();
+                       Assert.IsFalse(DialogIsOpened(), "Carousel - #4");
+                       TapOnPicker(0);
+                       Assert.IsTrue(DialogIsOpened(), "Carousel - #5");
+               }
+
+               void TapOnPicker(int index)
+               {
+                       var picker = RunningApp.Query(q => q.TextField().Class("PickerEditText"))[index];
+                       var location = picker.Rect;
+                       RunningApp.TapCoordinates(location.X + 10, location.Y + location.Height / 2);
+               }
+
+               bool DialogIsOpened()
+               {
+                       Thread.Sleep(1500);
+                       var frameLayouts = RunningApp.Query(q => q.Class("FrameLayout"));
+                       foreach (var layout in frameLayouts)
+                       {
+                               if (layout.Rect.X > 0 && layout.Rect.Y > 0 && layout.Description.Contains(@"id/content"))
+                               {
+                                       // close dialog
+                                       RunningApp.Back();
+                                       Thread.Sleep(1500);
+                                       return true;
+                               }
+                       }
+                       return false;
+               }
+#endif
+       }
+}
\ No newline at end of file
index f65145b..ff2a172 100644 (file)
     <Compile Include="$(MSBuildThisFileDirectory)Issue1236.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Issue1259.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Issue1267.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)Issue4187.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Issue1305.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Issue1329.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Issue1384.cs" />
index fd04acc..90e7508 100644 (file)
@@ -1,30 +1,20 @@
 using Android.App;
-using Android.Content.Res;
-using Android.Text;
 using Android.Util;
-using Android.Widget;
 using System;
 using System.Collections.Specialized;
 using System.ComponentModel;
 using System.Linq;
 using Android.Content;
-using Object = Java.Lang.Object;
-using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
-using System.Collections.Generic;
-using Android.Views;
+using Android.Widget;
 
 namespace Xamarin.Forms.Platform.Android.AppCompat
 {
-       public class PickerRenderer : ViewRenderer<Picker, EditText>
+       public class PickerRenderer : ViewRenderer<Picker, EditText>, IPickerRenderer
        {
                AlertDialog _dialog;
                bool _disposed;
                TextColorSwitcher _textColorSwitcher;
 
-               HashSet<Keycode> availableKeys = new HashSet<Keycode>(new[] {
-                       Keycode.Tab, Keycode.Forward, Keycode.Back, Keycode.DpadDown, Keycode.DpadLeft, Keycode.DpadRight, Keycode.DpadUp
-               });
-
                public PickerRenderer(Context context) : base(context)
                {
                        AutoPackage = false;
@@ -38,7 +28,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
 
                protected override EditText CreateNativeControl()
                {
-                       return new EditText(Context);
+                       return new PickerEditText(Context, this);
                }
 
                protected override void Dispose(bool disposing)
@@ -63,17 +53,11 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
                                ((INotifyCollectionChanged)e.NewElement.Items).CollectionChanged += RowsCollectionChanged;
                                if (Control == null)
                                {
-                                       EditText textField = CreateNativeControl();
-                                       textField.Focusable = true;
-                                       textField.Clickable = true;
-                                       textField.Tag = this;
-                                       textField.InputType = InputTypes.Null;
-                                       textField.KeyPress += TextFieldKeyPress;
-                                       textField.SetOnClickListener(PickerListener.Instance);
+                                       var textField = CreateNativeControl();
 
                                        var useLegacyColorManagement = e.NewElement.UseLegacyColorManagement();
                                        _textColorSwitcher = new TextColorSwitcher(textField.TextColors, useLegacyColorManagement);
-                                       
+
                                        SetNativeControl(textField);
                                }
                                UpdateFont();
@@ -84,24 +68,6 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
                        base.OnElementChanged(e);
                }
 
-               void TextFieldKeyPress(object sender, KeyEventArgs e)
-               {
-                       if (availableKeys.Contains(e.KeyCode))
-                       {
-                               e.Handled = false;
-                               return;
-                       }
-                       e.Handled = true;
-                       OnClick();
-               }
-
-               internal override void OnNativeFocusChanged(bool hasFocus)
-               {
-                       base.OnNativeFocusChanged(hasFocus);
-                       if (hasFocus)
-                               OnClick();
-               }
-
                protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
                {
                        base.OnElementPropertyChanged(sender, e);
@@ -121,7 +87,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
                        base.OnFocusChangeRequested(sender, e);
 
                        if (e.Focus)
-                               OnClick();
+                               CallOnClick();
                        else if (_dialog != null)
                        {
                                _dialog.Hide();
@@ -131,7 +97,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
                        }
                }
 
-               void OnClick()
+               void IPickerRenderer.OnClick()
                {
                        Picker model = Element;
                        if (_dialog == null)
@@ -143,7 +109,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
                                        builder.SetItems(items, (s, e) => ((IElementController)model).SetValueFromRenderer(Picker.SelectedIndexProperty, e.Which));
 
                                        builder.SetNegativeButton(global::Android.Resource.String.Cancel, (o, args) => { });
-                                       
+
                                        ((IElementController)Element).SetValueFromRenderer(VisualElement.IsFocusedPropertyKey, true);
 
                                        _dialog = builder.Create();
@@ -185,20 +151,5 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
                {
                        _textColorSwitcher?.UpdateTextColor(Control, Element.TextColor);
                }
-
-               class PickerListener : Object, IOnClickListener
-               {
-                       #region Statics
-
-                       public static readonly PickerListener Instance = new PickerListener();
-
-                       #endregion
-
-                       public void OnClick(global::Android.Views.View v)
-                       {
-                               var renderer = v.Tag as PickerRenderer;
-                               renderer?.OnClick();
-                       }
-               }
        }
 }
\ No newline at end of file
diff --git a/Xamarin.Forms.Platform.Android/IPickerRenderer.cs b/Xamarin.Forms.Platform.Android/IPickerRenderer.cs
new file mode 100644 (file)
index 0000000..fb7e6f0
--- /dev/null
@@ -0,0 +1,7 @@
+namespace Xamarin.Forms.Platform.Android
+{
+       public interface IPickerRenderer
+       {
+               void OnClick();
+       }
+}
\ No newline at end of file
index 54a3e61..7b2d911 100644 (file)
@@ -1,29 +1,18 @@
 using System;
-using System.Collections.Generic;
 using System.ComponentModel;
 using Android.App;
 using Android.Content;
-using Android.Content.Res;
-using Android.Text;
 using Android.Util;
-using Android.Views;
 using Android.Widget;
-using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
-using AView = Android.Views.View;
-using Object = Java.Lang.Object;
 
 namespace Xamarin.Forms.Platform.Android
 {
-       public class DatePickerRenderer : ViewRenderer<DatePicker, EditText>
+       public class DatePickerRenderer : ViewRenderer<DatePicker, EditText>, IPickerRenderer
        {
                DatePickerDialog _dialog;
                bool _disposed;
                TextColorSwitcher _textColorSwitcher;
 
-               HashSet<Keycode> availableKeys = new HashSet<Keycode>(new[] {
-                       Keycode.Tab, Keycode.Forward, Keycode.Back, Keycode.DpadDown, Keycode.DpadLeft, Keycode.DpadRight, Keycode.DpadUp
-               });
-
                public DatePickerRenderer(Context context) : base(context)
                {
                        AutoPackage = false;
@@ -62,7 +51,7 @@ namespace Xamarin.Forms.Platform.Android
 
                protected override EditText CreateNativeControl()
                {
-                       return new EditText(Context) { Focusable = true, Clickable = true, Tag = this };
+                       return new PickerEditText(Context, this);
                }
 
                protected override void OnElementChanged(ElementChangedEventArgs<DatePicker> e)
@@ -73,9 +62,6 @@ namespace Xamarin.Forms.Platform.Android
                        {
                                var textField = CreateNativeControl();
 
-                               textField.SetOnClickListener(TextFieldClickHandler.Instance);
-                               textField.InputType = InputTypes.Null;
-                               textField.KeyPress += TextFieldKeyPress;
                                SetNativeControl(textField);
 
                                var useLegacyColorManagement = e.NewElement.UseLegacyColorManagement();
@@ -90,24 +76,6 @@ namespace Xamarin.Forms.Platform.Android
                        UpdateTextColor();
                }
 
-               void TextFieldKeyPress(object sender, KeyEventArgs e)
-               {
-                       if (availableKeys.Contains(e.KeyCode))
-                       {
-                               e.Handled = false;
-                               return;
-                       }
-                       e.Handled = true;
-                       OnTextFieldClicked();
-               }
-
-               internal override void OnNativeFocusChanged(bool hasFocus)
-               {
-                       base.OnNativeFocusChanged(hasFocus);
-                       if (hasFocus)
-                               OnTextFieldClicked();
-               }
-
                protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
                {
                        base.OnElementPropertyChanged(sender, e);
@@ -129,7 +97,7 @@ namespace Xamarin.Forms.Platform.Android
                        base.OnFocusChangeRequested(sender, e);
 
                        if (e.Focus)
-                               OnTextFieldClicked();
+                               CallOnClick();
                        else if (_dialog != null)
                        {
                                _dialog.Hide();
@@ -168,7 +136,7 @@ namespace Xamarin.Forms.Platform.Android
                        }
                }
 
-               void OnTextFieldClicked()
+               void IPickerRenderer.OnClick()
                {
                        if (_dialog != null && _dialog.IsShowing)
                        {
@@ -225,15 +193,5 @@ namespace Xamarin.Forms.Platform.Android
                {
                        _textColorSwitcher?.UpdateTextColor(Control, Element.TextColor);
                }
-
-               class TextFieldClickHandler : Object, IOnClickListener
-               {
-                       public static readonly TextFieldClickHandler Instance = new TextFieldClickHandler();
-
-                       public void OnClick(AView v)
-                       {
-                               ((DatePickerRenderer)v.Tag).OnTextFieldClicked();
-                       }
-               }
        }
 }
\ No newline at end of file
diff --git a/Xamarin.Forms.Platform.Android/Renderers/PickerEditText.cs b/Xamarin.Forms.Platform.Android/Renderers/PickerEditText.cs
new file mode 100644 (file)
index 0000000..55326c6
--- /dev/null
@@ -0,0 +1,82 @@
+using Android.Content;
+using Android.Views;
+using Android.Widget;
+using Android.Text;
+using Java.Lang;
+using System.Collections.Generic;
+using Android.Graphics;
+using Android.Runtime;
+
+namespace Xamarin.Forms.Platform.Android
+{
+       public class PickerEditText : EditText
+       {
+               readonly static HashSet<Keycode> availableKeys = new HashSet<Keycode>(new[] {
+                       Keycode.Tab, Keycode.Forward, Keycode.Back, Keycode.DpadDown, Keycode.DpadLeft, Keycode.DpadRight, Keycode.DpadUp
+               });
+
+               System.WeakReference<IPickerRenderer> rendererRef;
+
+               internal bool FromFocusSearch;
+
+               public PickerEditText(Context context, IPickerRenderer pickerRenderer) : base(context)
+               {
+                       Focusable = true;
+                       Clickable = true;
+                       InputType = InputTypes.Null;
+                       KeyPress += OnKeyPress;
+                       rendererRef = new System.WeakReference<IPickerRenderer>(pickerRenderer);
+                       SetOnClickListener(PickerListener.Instance);
+               }
+
+               protected override void OnFocusChanged(bool gainFocus, [GeneratedEnum] FocusSearchDirection direction, Rect previouslyFocusedRect)
+               {
+                       base.OnFocusChanged(gainFocus, direction, previouslyFocusedRect);
+                       if (gainFocus && FromFocusSearch)
+                               CallOnClick();
+                       FromFocusSearch = false;
+               }
+
+               void OnKeyPress(object sender, KeyEventArgs e)
+               {
+                       if (availableKeys.Contains(e.KeyCode))
+                       {
+                               e.Handled = false;
+                               return;
+                       }
+                       e.Handled = true;
+                       CallOnClick();
+               }
+
+               public override bool OnTouchEvent(MotionEvent e)
+               {
+                       if (e.Action == MotionEventActions.Up && !IsFocused)
+                               RequestFocus();
+                       return base.OnTouchEvent(e); // raises the OnClick event if focus is already received
+               }
+
+               protected override void Dispose(bool disposing)
+               {
+                       if (disposing)
+                       {
+                               KeyPress -= OnKeyPress;
+                               rendererRef = null;
+                       }
+                       base.Dispose(disposing);
+               }
+
+               class PickerListener : Object, IOnClickListener
+               {
+                       public static readonly PickerListener Instance = new PickerListener();
+
+                       public void OnClick(global::Android.Views.View v)
+                       {
+                               if (v is PickerEditText picker)
+                               {
+                                       picker.rendererRef.TryGetTarget(out IPickerRenderer renderer);
+                                       renderer?.OnClick();
+                               }
+                       }
+               }
+       }
+}
\ No newline at end of file
index e2ca3c6..bb4fd63 100644 (file)
@@ -1,5 +1,4 @@
 using Android.App;
-using Android.Content.Res;
 using Android.Util;
 using Android.Views;
 using Android.Widget;
@@ -7,27 +6,17 @@ using System;
 using System.Collections.Specialized;
 using System.ComponentModel;
 using System.Linq;
-using ADatePicker = Android.Widget.DatePicker;
-using ATimePicker = Android.Widget.TimePicker;
-using Object = Java.Lang.Object;
 using Orientation = Android.Widget.Orientation;
 using Android.Content;
-using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
-using System.Collections.Generic;
-using Android.Text;
 
 namespace Xamarin.Forms.Platform.Android
 {
-       public class PickerRenderer : ViewRenderer<Picker, EditText>
+       public class PickerRenderer : ViewRenderer<Picker, EditText>, IPickerRenderer
        {
                AlertDialog _dialog;
                bool _isDisposed;
                TextColorSwitcher _textColorSwitcher;
 
-               HashSet<Keycode> availableKeys = new HashSet<Keycode>(new[] {
-                       Keycode.Tab, Keycode.Forward, Keycode.Back, Keycode.DpadDown, Keycode.DpadLeft, Keycode.DpadRight, Keycode.DpadUp
-               });
-
                public PickerRenderer(Context context) : base(context)
                {
                        AutoPackage = false;
@@ -54,7 +43,7 @@ namespace Xamarin.Forms.Platform.Android
 
                protected override EditText CreateNativeControl()
                {
-                       return new EditText(Context) { Focusable = true, Clickable = true, Tag = this };
+                       return new PickerEditText(Context, this);
                }
 
                protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
@@ -68,16 +57,13 @@ namespace Xamarin.Forms.Platform.Android
                                if (Control == null)
                                {
                                        var textField = CreateNativeControl();
-                                       textField.SetOnClickListener(PickerListener.Instance);
-                                       textField.InputType = InputTypes.Null;
-                                       textField.KeyPress += TextFieldKeyPress;
 
                                        var useLegacyColorManagement = e.NewElement.UseLegacyColorManagement();
                                        _textColorSwitcher = new TextColorSwitcher(textField.TextColors, useLegacyColorManagement);
 
                                        SetNativeControl(textField);
                                }
-                               
+
                                UpdateFont();
                                UpdatePicker();
                                UpdateTextColor();
@@ -86,24 +72,6 @@ namespace Xamarin.Forms.Platform.Android
                        base.OnElementChanged(e);
                }
 
-               void TextFieldKeyPress(object sender, KeyEventArgs e)
-               {
-                       if (availableKeys.Contains(e.KeyCode))
-                       {
-                               e.Handled = false;
-                               return;
-                       }
-                       e.Handled = true;
-                       OnClick();
-               }
-
-               internal override void OnNativeFocusChanged(bool hasFocus)
-               {
-                       base.OnNativeFocusChanged(hasFocus);
-                       if (hasFocus)
-                               OnClick();
-               }
-
                protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
                {
                        base.OnElementPropertyChanged(sender, e);
@@ -123,7 +91,7 @@ namespace Xamarin.Forms.Platform.Android
                        base.OnFocusChangeRequested(sender, e);
 
                        if (e.Focus)
-                               OnClick();
+                               CallOnClick();
                        else if (_dialog != null)
                        {
                                _dialog.Hide();
@@ -132,7 +100,7 @@ namespace Xamarin.Forms.Platform.Android
                        }
                }
 
-               void OnClick()
+               void IPickerRenderer.OnClick()
                {
                        Picker model = Element;
 
@@ -212,19 +180,5 @@ namespace Xamarin.Forms.Platform.Android
                {
                        _textColorSwitcher?.UpdateTextColor(Control, Element.TextColor);
                }
-
-               class PickerListener : Object, IOnClickListener
-               {
-                       public static readonly PickerListener Instance = new PickerListener();
-
-                       public void OnClick(global::Android.Views.View v)
-                       {
-                               var renderer = v.Tag as PickerRenderer;
-                               if (renderer == null)
-                                       return;
-
-                               renderer.OnClick();
-                       }
-               }
        }
 }
\ No newline at end of file
index c952fd5..ac0ddca 100644 (file)
@@ -3,27 +3,17 @@ using System.ComponentModel;
 using Android.App;
 using Android.Content;
 using Android.Util;
-using Android.Widget;
 using Android.Text.Format;
 using ATimePicker = Android.Widget.TimePicker;
-using Object = Java.Lang.Object;
-using AView = Android.Views.View;
 using Android.OS;
-using Android.Views;
-using System.Collections.Generic;
-using Android.Text;
+using Android.Widget;
 
 namespace Xamarin.Forms.Platform.Android
 {
-       public class TimePickerRenderer : ViewRenderer<TimePicker, EditText>, TimePickerDialog.IOnTimeSetListener
+       public class TimePickerRenderer : ViewRenderer<TimePicker, EditText>, TimePickerDialog.IOnTimeSetListener, IPickerRenderer
        {
                AlertDialog _dialog;
                TextColorSwitcher _textColorSwitcher;
-                
-
-               HashSet<Keycode> availableKeys = new HashSet<Keycode>(new[] {
-                       Keycode.Tab, Keycode.Forward, Keycode.Back, Keycode.DpadDown, Keycode.DpadLeft, Keycode.DpadRight, Keycode.DpadUp
-               });
 
                bool Is24HourView
                {
@@ -57,7 +47,7 @@ namespace Xamarin.Forms.Platform.Android
 
                protected override EditText CreateNativeControl()
                {
-                       return new EditText(Context) { Focusable = true, Clickable = true, Tag = this };
+                       return new PickerEditText(Context, this);
                }
 
                protected override void OnElementChanged(ElementChangedEventArgs<TimePicker> e)
@@ -68,9 +58,6 @@ namespace Xamarin.Forms.Platform.Android
                        {
                                var textField = CreateNativeControl();
 
-                               textField.SetOnClickListener(TimePickerListener.Instance);
-                               textField.InputType = InputTypes.Null;
-                               textField.KeyPress += TextFieldKeyPress;
                                SetNativeControl(textField);
 
                                var useLegacyColorManagement = e.NewElement.UseLegacyColorManagement();
@@ -85,24 +72,6 @@ namespace Xamarin.Forms.Platform.Android
                                Control.TextAlignment = global::Android.Views.TextAlignment.ViewStart;
                }
 
-               void TextFieldKeyPress(object sender, KeyEventArgs e)
-               {
-                       if (availableKeys.Contains(e.KeyCode))
-                       {
-                               e.Handled = false;
-                               return;
-                       }
-                       e.Handled = true;
-                       OnClick();
-               }
-
-               internal override void OnNativeFocusChanged(bool hasFocus)
-               {
-                       base.OnNativeFocusChanged(hasFocus);
-                       if (hasFocus)
-                               OnClick();
-               }
-
                protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
                {
                        base.OnElementPropertyChanged(sender, e);
@@ -120,7 +89,7 @@ namespace Xamarin.Forms.Platform.Android
                        base.OnFocusChangeRequested(sender, e);
 
                        if (e.Focus)
-                               OnClick();
+                               CallOnClick();
                        else if (_dialog != null)
                        {
                                _dialog.Hide();
@@ -143,7 +112,7 @@ namespace Xamarin.Forms.Platform.Android
                        return dialog;
                }
 
-               void OnClick()
+               void IPickerRenderer.OnClick()
                {
                        if (_dialog != null && _dialog.IsShowing)
                        {
@@ -178,19 +147,5 @@ namespace Xamarin.Forms.Platform.Android
                {
                        _textColorSwitcher?.UpdateTextColor(Control, Element.TextColor);
                }
-
-               class TimePickerListener : Object, IOnClickListener
-               {
-                       public static readonly TimePickerListener Instance = new TimePickerListener();
-
-                       public void OnClick(AView v)
-                       {
-                               var renderer = v.Tag as TimePickerRenderer;
-                               if (renderer == null)
-                                       return;
-
-                               renderer.OnClick();
-                       }
-               }
        }
 }
index a956d23..b5d04f1 100644 (file)
@@ -165,6 +165,10 @@ namespace Xamarin.Forms.Platform.Android
                                control = (renderer as ITabStop)?.TabStop;
                        } while (!(control?.Focusable == true || ++attempt >= maxAttempts));
 
+                       // when the user focuses on picker show a popup dialog
+                       if (control is PickerEditText picker)
+                               picker.FromFocusSearch = true;
+
                        return control;
                }
 
index 553059c..46d9f7a 100644 (file)
     <Compile Include="IBorderVisualElementRenderer.cs" />
     <Compile Include="IDeviceInfoProvider.cs" />
     <Compile Include="ITabStop.cs" />
+    <Compile Include="IPickerRenderer.cs" />
+    <Compile Include="Renderers\PickerEditText.cs" />
     <Compile Include="Renderers\FormsWebViewClient.cs" />
     <Compile Include="Renderers\IImageViewHandler.cs" />
     <Compile Include="InnerGestureListener.cs" />