Track tap gestures

This commit is contained in:
Frank A. Krueger 2017-12-09 20:39:10 -08:00
parent 0b60b4c800
commit 88a4798acb
3 changed files with 201 additions and 5 deletions

169
Ooui.Forms/EventTracker.cs Normal file
View File

@ -0,0 +1,169 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using Xamarin.Forms;
using NativeView = Ooui.Element;
namespace Ooui.Forms
{
public class EventTracker
{
readonly NotifyCollectionChangedEventHandler _collectionChangedHandler;
readonly Dictionary<IGestureRecognizer, NativeGestureRecognizer> _gestureRecognizers = new Dictionary<IGestureRecognizer, NativeGestureRecognizer> ();
readonly IVisualElementRenderer _renderer;
bool _disposed;
NativeView _handler;
public EventTracker (IVisualElementRenderer renderer)
{
if (renderer == null)
throw new ArgumentNullException (nameof (renderer));
_collectionChangedHandler = ModelGestureRecognizersOnCollectionChanged;
_renderer = renderer;
_renderer.ElementChanged += OnElementChanged;
}
ObservableCollection<IGestureRecognizer> ElementGestureRecognizers {
get {
if (_renderer?.Element is View)
return ((View)_renderer.Element).GestureRecognizers as ObservableCollection<IGestureRecognizer>;
return null;
}
}
public void Dispose ()
{
if (_disposed)
return;
_disposed = true;
foreach (var kvp in _gestureRecognizers) {
RemoveGestureRecognizer (_handler, kvp.Value);
kvp.Value.Dispose ();
}
_gestureRecognizers.Clear ();
if (ElementGestureRecognizers != null)
ElementGestureRecognizers.CollectionChanged -= _collectionChangedHandler;
_handler = null;
}
void ModelGestureRecognizersOnCollectionChanged (object sender, NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs)
{
LoadRecognizers ();
}
void OnElementChanged (object sender, VisualElementChangedEventArgs e)
{
if (e.OldElement != null) {
// unhook
var oldView = e.OldElement as View;
if (oldView != null) {
var oldRecognizers = (ObservableCollection<IGestureRecognizer>)oldView.GestureRecognizers;
oldRecognizers.CollectionChanged -= _collectionChangedHandler;
}
}
if (e.NewElement != null) {
// hook
if (ElementGestureRecognizers != null) {
ElementGestureRecognizers.CollectionChanged += _collectionChangedHandler;
LoadRecognizers ();
}
}
}
void LoadRecognizers ()
{
if (ElementGestureRecognizers == null)
return;
foreach (var recognizer in ElementGestureRecognizers) {
if (_gestureRecognizers.ContainsKey (recognizer))
continue;
var nativeRecognizer = GetNativeRecognizer (recognizer);
if (nativeRecognizer != null) {
AddGestureRecognizer (_handler, nativeRecognizer);
_gestureRecognizers[recognizer] = nativeRecognizer;
}
}
var toRemove = _gestureRecognizers.Keys.Where (key => !ElementGestureRecognizers.Contains (key)).ToArray ();
foreach (var gestureRecognizer in toRemove) {
var uiRecognizer = _gestureRecognizers[gestureRecognizer];
_gestureRecognizers.Remove (gestureRecognizer);
RemoveGestureRecognizer (_handler, uiRecognizer);
uiRecognizer.Dispose ();
}
}
protected virtual NativeGestureRecognizer GetNativeRecognizer (IGestureRecognizer recognizer)
{
if (recognizer == null)
return null;
var weakRecognizer = new WeakReference (recognizer);
var weakEventTracker = new WeakReference (this);
var tapRecognizer = recognizer as TapGestureRecognizer;
if (tapRecognizer != null) {
var returnAction = new TargetEventHandler ((s, e) => {
var tapGestureRecognizer = weakRecognizer.Target as TapGestureRecognizer;
var eventTracker = weakEventTracker.Target as EventTracker;
var view = eventTracker?._renderer?.Element as View;
if (tapGestureRecognizer != null && view != null)
tapGestureRecognizer.SendTapped (view);
});
var uiRecognizer = new NativeGestureRecognizer {
EventType = "click",
Handler = returnAction,
};
return uiRecognizer;
}
return null;
}
static void AddGestureRecognizer (Element element, NativeGestureRecognizer recognizer)
{
element.AddEventListener (recognizer.EventType, recognizer.Handler);
}
static void RemoveGestureRecognizer (Element element, NativeGestureRecognizer recognizer)
{
element.RemoveEventListener (recognizer.EventType, recognizer.Handler);
}
public void LoadEvents (NativeView handler)
{
if (_disposed)
throw new ObjectDisposedException (null);
_handler = handler;
OnElementChanged (this, new VisualElementChangedEventArgs (null, _renderer.Element));
}
protected class NativeGestureRecognizer : IDisposable
{
public string EventType;
public TargetEventHandler Handler;
public void Dispose ()
{
}
}
}
}

View File

@ -57,6 +57,10 @@ namespace Ooui.Forms
MessagingCenter.Unsubscribe<Page, ActionSheetArguments> (this, Page.ActionSheetSignalName);
MessagingCenter.Unsubscribe<Page, AlertArguments> (this, Page.AlertSignalName);
MessagingCenter.Unsubscribe<Page, bool> (this, Page.BusySetSignalName);
DisposeModelAndChildrenRenderers (Page);
//foreach (var modal in _modals)
//DisposeModelAndChildrenRenderers (modal);
}
public static IVisualElementRenderer CreateRenderer (VisualElement element)
@ -110,7 +114,29 @@ namespace Ooui.Forms
void HandleChildRemoved (object sender, ElementEventArgs e)
{
throw new NotImplementedException ();
var view = e.Element;
DisposeModelAndChildrenRenderers (view);
}
void DisposeModelAndChildrenRenderers (Xamarin.Forms.Element view)
{
IVisualElementRenderer renderer;
foreach (VisualElement child in view.Descendants ()) {
renderer = GetRenderer (child);
child.ClearValue (RendererProperty);
if (renderer != null) {
//renderer.NativeView.RemoveFromSuperview ();
renderer.Dispose ();
}
}
renderer = GetRenderer ((VisualElement)view);
if (renderer != null) {
//renderer.NativeView.RemoveFromSuperview ();
renderer.Dispose ();
}
view.ClearValue (RendererProperty);
}
void AddChild (VisualElement view)

View File

@ -38,6 +38,7 @@ namespace Ooui.Forms
VisualElementRendererFlags _flags = VisualElementRendererFlags.AutoPackage | VisualElementRendererFlags.AutoTrack;
EventTracker _events;
VisualElementPackager _packager;
VisualElementTracker _tracker;
@ -107,10 +108,10 @@ namespace Ooui.Forms
_packager.Load ();
}
//if (AutoTrack && _events == null) {
// _events = new EventTracker (this);
// _events.LoadEvents (this);
//}
if (AutoTrack && _events == null) {
_events = new EventTracker (this);
_events.LoadEvents (this);
}
element.PropertyChanged += _propertyChangedHandler;
}