fixes #1942 - added a custom call for calling any manually set OnTouchListeners (#2703)

This commit is contained in:
Shane Neuville 2018-05-22 04:53:37 -06:00 коммит произвёл Rui Marinho
Родитель 5787584c86
Коммит 8ed7a287ed
4 изменённых файлов: 122 добавлений и 7 удалений

Просмотреть файл

@ -17,12 +17,15 @@ using Android.Runtime;
using Android.Util;
using AButton = Android.Widget.Button;
using AView = Android.Views.View;
using AViewGroup = Android.Views.ViewGroup;
using Android.OS;
using System.Reflection;
using Android.Text;
using Android.Text.Method;
using Xamarin.Forms.Controls.Issues;
[assembly: ExportRenderer(typeof(Issue1942.CustomGrid), typeof(Issue1942GridRenderer))]
[assembly: ExportRenderer(typeof(Bugzilla31395.CustomContentView), typeof(CustomContentRenderer))]
[assembly: ExportRenderer(typeof(NativeListView), typeof(NativeListViewRenderer))]
[assembly: ExportRenderer(typeof(NativeListView2), typeof(NativeAndroidListViewRenderer))]
@ -605,6 +608,49 @@ namespace Xamarin.Forms.ControlGallery.Android
}
}
public class Issue1942GridRenderer : VisualElementRenderer<Grid>, AView.IOnTouchListener, ViewTreeObserver.IOnGlobalLayoutListener
{
AView _gridChild;
public Issue1942GridRenderer(Context context) : base(context)
{
}
bool AView.IOnTouchListener.OnTouch(AView v, MotionEvent e)
{
((Element.Children.First() as Layout).Children.First() as Label).Text = Issue1942.SuccessString;
ViewGroup.ViewTreeObserver.RemoveOnGlobalLayoutListener(this);
_gridChild.SetOnTouchListener(null);
return true;
}
protected override void OnElementChanged(ElementChangedEventArgs<Grid> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
ViewGroup.ViewTreeObserver.AddOnGlobalLayoutListener(this);
}
}
protected override void Dispose(bool disposing)
{
if(disposing)
{
ViewGroup.ViewTreeObserver.RemoveOnGlobalLayoutListener(this);
_gridChild.SetOnTouchListener(null);
_gridChild = null;
}
base.Dispose(disposing);
}
void ViewTreeObserver.IOnGlobalLayoutListener.OnGlobalLayout()
{
_gridChild = ViewGroup.GetChildAt(0);
_gridChild.SetOnTouchListener(this);
}
}
public static class KeyboardFlagExtensions
{
public static void TestKeyboardFlags(this FormsEditText Control, KeyboardFlags? flags)

Просмотреть файл

@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
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, 1942, "[Android] Attached Touch Listener events do not dispatch to immediate parent Grid Renderer View on Android when Child fakes handled",
PlatformAffected.Android)]
public class Issue1942 : TestContentPage
{
public const string SuccessString = "Success";
public const string ClickMeString = "CLICK ME";
protected override void Init()
{
Content = new CustomGrid()
{
Children =
{
new Grid
{
Children = { new Label() { Text = ClickMeString, BackgroundColor = Color.Blue, HeightRequest = 300, WidthRequest = 300 } }
}
}
};
}
public class CustomGrid : Grid { }
#if UITEST && __ANDROID__
[Test]
public void ClickPropagatesToOnTouchListener()
{
RunningApp.Tap(ClickMeString);
RunningApp.WaitForElement(SuccessString);
}
#endif
}
}

Просмотреть файл

@ -249,6 +249,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Issue1705_2.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue1396.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue1415.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue1942.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue2247.cs" />
<Compile Include="$(MSBuildThisFileDirectory)GroupListViewHeaderIndexOutOfRange.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue1760.cs" />

Просмотреть файл

@ -65,7 +65,7 @@ namespace Xamarin.Forms.Platform.Android
{
_defaultActionBarTitleTextColor = SetDefaultActionBarTitleTextColor();
}
_renderer = new PlatformRenderer(context, this);
if (embedded)
@ -1105,8 +1105,8 @@ namespace Xamarin.Forms.Platform.Android
static int s_id = 0x00000400;
#region Previewer Stuff
internal static readonly BindableProperty PageContextProperty =
internal static readonly BindableProperty PageContextProperty =
BindableProperty.CreateAttached("PageContext", typeof(Context), typeof(Platform), null);
internal Platform(Context context) : this(context, false)
@ -1115,12 +1115,12 @@ namespace Xamarin.Forms.Platform.Android
// the 'embedded' bool parameter so the previewer can find it via reflection
}
internal static void SetPageContext(BindableObject bindable, Context context)
{
internal static void SetPageContext(BindableObject bindable, Context context)
{
// Set a context for this page and its child controls
bindable.SetValue(PageContextProperty, context);
}
static Context GetPreviewerContext(Element element)
{
// Walk up the tree and find the Page this element is hosted in
@ -1139,6 +1139,7 @@ namespace Xamarin.Forms.Platform.Android
internal class DefaultRenderer : VisualElementRenderer<View>
{
bool _notReallyHandled;
IOnTouchListener _touchListener;
[Obsolete("This constructor is obsolete as of version 2.5. Please use DefaultRenderer(Context) instead.")]
public DefaultRenderer()
@ -1207,11 +1208,29 @@ namespace Xamarin.Forms.Platform.Android
// don't consider the event truly "handled" yet.
// Since a child control short-circuited the normal dispatchTouchEvent stuff, this layout never got the chance for
// IOnTouchListener.OnTouch and the OnTouchEvent override to try handling the touches; we'll do that now
return OnTouchEvent(e);
// Any associated Touch Listeners are called from DispatchTouchEvents if all children of this view return false
// So here we are simulating both calls that would have typically been called from inside DispatchTouchEvent
// but were not called due to the fake "true"
result = _touchListener?.OnTouch(this, e) ?? false;
return result || OnTouchEvent(e);
}
return result;
}
public override void SetOnTouchListener(IOnTouchListener l)
{
_touchListener = l;
base.SetOnTouchListener(l);
}
protected override void Dispose(bool disposing)
{
if (disposing)
_touchListener = null;
base.Dispose(disposing);
}
}
#region IPlatformEngine implementation