diff --git a/ReactWindows/ReactNative/ReactNative.csproj b/ReactWindows/ReactNative/ReactNative.csproj index 45dc1dbee9f..f1fc0501fe5 100644 --- a/ReactWindows/ReactNative/ReactNative.csproj +++ b/ReactWindows/ReactNative/ReactNative.csproj @@ -272,7 +272,9 @@ + + @@ -362,6 +364,7 @@ + diff --git a/ReactWindows/ReactNative/Touch/TouchHandler.cs b/ReactWindows/ReactNative/Touch/TouchHandler.cs index 77227e2d2f4..e347e885fe7 100644 --- a/ReactWindows/ReactNative/Touch/TouchHandler.cs +++ b/ReactWindows/ReactNative/Touch/TouchHandler.cs @@ -46,10 +46,13 @@ private void OnPointerPressed(object sender, PointerRoutedEventArgs e) } var reactView = GetReactViewFromView(e.OriginalSource as UIElement); + var reactTag = reactView.GetReactCompoundView().GetReactTagAtPoint(reactView, + e.GetCurrentPoint(reactView).Position); + if (reactView != null && _view.CapturePointer(e.Pointer)) { var pointer = new ReactPointer(); - pointer.Target = reactView.GetTag(); + pointer.Target = reactTag; pointer.PointerId = e.Pointer.PointerId; pointer.Identifier = ++_pointerIDs; pointer.ReactView = reactView; diff --git a/ReactWindows/ReactNative/UIManager/DependencyObjectExtensions.cs b/ReactWindows/ReactNative/UIManager/DependencyObjectExtensions.cs index 7bbd14b8494..8ace3fe8997 100644 --- a/ReactWindows/ReactNative/UIManager/DependencyObjectExtensions.cs +++ b/ReactWindows/ReactNative/UIManager/DependencyObjectExtensions.cs @@ -11,6 +11,7 @@ public static class DependencyObjectExtensions { private static readonly ConditionalWeakTable s_properties = new ConditionalWeakTable(); + private static readonly IReactCompoundView s_defaultCompoundView = new ReactDefaultCompoundView(); /// /// Sets the pointer events for the view. @@ -44,6 +45,46 @@ public static PointerEvents GetPointerEvents(this DependencyObject view) return elementData.PointerEvents.Value; } + /// + /// Associates an implementation of IReactCompoundView with the view. + /// + /// The view. + /// The implementation of IReactCompoundView. + public static void SetReactCompoundView(this DependencyObject view, IReactCompoundView compoundView) + { + if (view == null) + throw new ArgumentNullException(nameof(view)); + + s_properties.GetOrCreateValue(view).CompoundView = compoundView; + } + + /// + /// Gets the implementation of IReactCompoundView associated with the view. + /// + /// The view. + /// + /// The implementation of IReactCompoundView associated with the view. Defaults to + /// an instance of ReactDefaultCompoundView when no other implementation has been + /// provided. + /// + public static IReactCompoundView GetReactCompoundView(this DependencyObject view) + { + if (view == null) + throw new ArgumentNullException(nameof(view)); + + var elementData = default(DependencyObjectData); + if (s_properties.TryGetValue(view, out elementData)) + { + var compoundView = elementData.CompoundView; + if (compoundView != null) + { + return compoundView; + } + } + + return s_defaultCompoundView; + } + internal static void SetTag(this DependencyObject view, int tag) { if (view == null) @@ -115,6 +156,8 @@ class DependencyObjectData public PointerEvents? PointerEvents { get; set; } public int? Tag { get; set; } + + public IReactCompoundView CompoundView { get; set; } } } } diff --git a/ReactWindows/ReactNative/UIManager/IReactCompoundView.cs b/ReactWindows/ReactNative/UIManager/IReactCompoundView.cs new file mode 100644 index 00000000000..7c97ff99731 --- /dev/null +++ b/ReactWindows/ReactNative/UIManager/IReactCompoundView.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Windows.Foundation; +using Windows.UI.Xaml; + +namespace ReactNative.UIManager +{ + /// + /// Interface consisting of methods which are relevant to views which contain + /// visuals that have react tags but are not rendered using UIElements. + /// + public interface IReactCompoundView + { + /// + /// Returns the react tag rendered at point in reactView. The view + /// is not expected to do hit testing on its UIElement descendants. Rather, + /// this is useful for views which are composed of visuals that are associated + /// with react tags but the visuals are not UIElements. + /// + /// The react view to do hit testing within. + /// The point to hit test in coordinates that are relative to the view. + /// The react tag rendered at point in reactView. + int GetReactTagAtPoint(UIElement reactView, Point point); + } +} diff --git a/ReactWindows/ReactNative/UIManager/ReactDefaultCompoundView.cs b/ReactWindows/ReactNative/UIManager/ReactDefaultCompoundView.cs new file mode 100644 index 00000000000..25daaddb1e4 --- /dev/null +++ b/ReactWindows/ReactNative/UIManager/ReactDefaultCompoundView.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Windows.Foundation; +using Windows.UI.Xaml; + +namespace ReactNative.UIManager +{ + class ReactDefaultCompoundView : IReactCompoundView + { + public int GetReactTagAtPoint(UIElement reactView, Point point) + { + return reactView.GetTag(); + } + } +} diff --git a/ReactWindows/ReactNative/Views/Text/ReactTextCompoundView.cs b/ReactWindows/ReactNative/Views/Text/ReactTextCompoundView.cs new file mode 100644 index 00000000000..58c65f1edcf --- /dev/null +++ b/ReactWindows/ReactNative/Views/Text/ReactTextCompoundView.cs @@ -0,0 +1,22 @@ +using ReactNative.UIManager; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Windows.Foundation; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; + +namespace ReactNative.Views.Text +{ + class ReactTextCompoundView : IReactCompoundView + { + public int GetReactTagAtPoint(UIElement reactView, Point point) + { + var richTextBlock = reactView.As(); + var textPointer = richTextBlock.GetPositionFromPoint(point); + return textPointer.Parent.GetTag(); + } + } +} diff --git a/ReactWindows/ReactNative/Views/Text/ReactTextViewManager.cs b/ReactWindows/ReactNative/Views/Text/ReactTextViewManager.cs index e5755c165b1..a46ee3ef435 100644 --- a/ReactWindows/ReactNative/Views/Text/ReactTextViewManager.cs +++ b/ReactWindows/ReactNative/Views/Text/ReactTextViewManager.cs @@ -13,6 +13,7 @@ namespace ReactNative.Views.Text /// public class ReactTextViewManager : ViewParentManager { + private static readonly IReactCompoundView s_compoundView = new ReactTextCompoundView(); private const double DefaultFontSize = 15; /// @@ -162,6 +163,7 @@ protected override RichTextBlock CreateViewInstance(ThemedReactContext reactCont }; richTextBlock.Blocks.Add(new Paragraph()); + richTextBlock.SetReactCompoundView(s_compoundView); return richTextBlock; }