Xamarin Formsのマウスイベントが少ない話の続き
前回書かなかったレンダラの実装。今回は実際に書いたコードを張り付けるだけの簡単なお仕事なので前回の話と微妙に違う。
まず共通部分。
public interface IClickableView { bool CallClick(); bool CallPointerDown(); bool CallPointerUp(); } public class ClickableView : global::Xamarin.Forms.BoxView, IClickableView { public static readonly BindableProperty IsPointerDownProperty = BindableProperty.Create(nameof(IsPointerDown), typeof(bool), typeof(ClickableView), default(bool), propertyChanged: (bindable, oldValue, newValue) => ((ClickableView)bindable).IsPointerDown = (bool)newValue); public bool IsPointerDown { get { return (bool)GetValue(IsPointerDownProperty); } set { SetValue(IsPointerDownProperty, value); } } public static readonly BindableProperty ForegroundColorProperty = BindableProperty.Create(nameof(ForegroundColor), typeof(Color), typeof(ClickableView), default(Color), propertyChanged: (bindable, oldValue, newValue) => ((ClickableView)bindable).ForegroundColor = (Color)newValue); public Color ForegroundColor { get { return (Color)GetValue(ForegroundColorProperty); } set { SetValue(ForegroundColorProperty, value); } } public event EventHandler<EventArgs> Clicked; public event EventHandler<EventArgs> PointerDown; public event EventHandler<EventArgs> PointerUp; bool IClickableView.CallClick() { Clicked?.Invoke(this, EventArgs.Empty); return Clicked != null; } bool IClickableView.CallPointerDown() { IsPointerDown = true; PointerDown?.Invoke(this, EventArgs.Empty); return PointerDown != null; } bool IClickableView.CallPointerUp() { IsPointerDown = false; PointerUp?.Invoke(this, EventArgs.Empty); return PointerUp != null; } }
プラットフォーム個別実装でandroid。
public class ClickableViewHelper { public class Helper<T> where T : Android.Views.View, IVisualElementRenderer { private IClickableView target; public Helper(T renderer) { renderer.ElementChanged += (s, e) => { if (e.NewElement == null) { // 後片付け必要? return; } else { target = e.NewElement as IClickableView; System.Diagnostics.Debug.Assert(target != null); renderer.Touch += (snder, ev) => { var pointerIndex = ((int)ev.Event.Action) >> ((int)MotionEventActions.PointerIndexShift) & ((int)MotionEventActions.PointerIndexMask); switch (ev.Event.Action & MotionEventActions.Mask) { case MotionEventActions.Down: ev.Handled = target.CallPointerDown(); break; case MotionEventActions.Up: ev.Handled = target.CallPointerUp(); if(new Rectangle( 0, 0, renderer.Width, renderer.Height).Contains( ev.Event.GetX(), ev.Event.GetY())) { target.CallClick(); } break; case MotionEventActions.Cancel: break; } }; } }; } } public static Helper<T> Create<T>(T renderer) where T : Android.Views.View, IVisualElementRenderer { return new Helper<T>(renderer); } } public class ClickableViewRenderer : BoxRenderer { private object helper; public ClickableViewRenderer() { helper = ClickableViewHelper.Create(this); } }
UWPはこちら。
public class ClickableViewHelper { public class Helper<T> where T : Windows.UI.Xaml.Controls.Panel, IVisualElementRenderer { private IClickableView target; public Helper(T renderer) { renderer.ElementChanged += (s, e) => { if (e.NewElement == null) { // 後片付け必要? return; } else { target = e.NewElement as IClickableView; System.Diagnostics.Debug.Assert(target != null); renderer.PointerPressed += (sender, ev) => { renderer.CapturePointer(ev.Pointer); target?.CallPointerDown(); }; renderer.PointerReleased += (sender, ev) => { renderer.ReleasePointerCapture(ev.Pointer); if (target != null) { target.CallPointerUp(); var pt = ev.GetCurrentPoint(renderer); if ((0 <= pt.Position.X) && (pt.Position.X <= renderer.ActualWidth) && (0 <= pt.Position.Y) && (pt.Position.Y <= renderer.ActualHeight)) { target.CallClick(); } } }; } }; } } public static Helper<T> Create<T>(T renderer) where T : Windows.UI.Xaml.Controls.Panel, IVisualElementRenderer { return new Helper<T>(renderer); } } public class ClickableViewRenderer : BoxViewRenderer { private object helper; public ClickableViewRenderer() { helper = ClickableViewHelper.Create(this); } }