|
4 | 4 | using ReactNative.UIManager.Events;
|
5 | 5 | using System;
|
6 | 6 | using System.Collections.Generic;
|
| 7 | +using Windows.Foundation; |
7 | 8 | using Windows.UI.Xaml;
|
8 | 9 | using Windows.UI.Xaml.Input;
|
| 10 | +using Windows.UI.Xaml.Media; |
9 | 11 |
|
10 | 12 | namespace ReactNative.Touch
|
11 | 13 | {
|
@@ -45,8 +47,7 @@ private void OnPointerPressed(object sender, PointerRoutedEventArgs e)
|
45 | 47 | throw new InvalidOperationException("A pointer with this ID already exists.");
|
46 | 48 | }
|
47 | 49 |
|
48 |
| - var reactView = GetReactViewFromView(e.OriginalSource as UIElement); |
49 |
| - |
| 50 | + var reactView = GetReactViewFromPoint(e.GetCurrentPoint(_view).Position); |
50 | 51 | if (reactView != null && _view.CapturePointer(e.Pointer))
|
51 | 52 | {
|
52 | 53 | var reactTag = reactView.GetReactCompoundView().GetReactTagAtPoint(reactView,
|
@@ -123,31 +124,38 @@ private int IndexOfPointerWithId(uint pointerId)
|
123 | 124 | return -1;
|
124 | 125 | }
|
125 | 126 |
|
126 |
| - private UIElement GetReactViewFromView(DependencyObject originalSource) |
| 127 | + private UIElement GetReactViewFromPoint(Point point) |
127 | 128 | {
|
128 |
| - var viewHierarchy = RootViewHelper.GetReactViewHierarchy(originalSource); |
129 |
| - if (viewHierarchy.Count == 0) |
130 |
| - { |
131 |
| - return null; |
132 |
| - } |
| 129 | + var sources = VisualTreeHelper.FindElementsInHostCoordinates(point, _view); |
| 130 | + |
| 131 | + // Get the first React view that does not have pointer events set |
| 132 | + // to 'none' or 'box-none', and is not a child of a view with |
| 133 | + // 'box-only' or 'none' settings for pointer events. |
133 | 134 |
|
134 |
| - var target = -1; |
135 |
| - for (var i = 0; i < viewHierarchy.Count; ++i) |
| 135 | + // TODO: use pooled data structure |
| 136 | + var isBoxOnlyCache = new Dictionary<UIElement, bool>(); |
| 137 | + foreach (var source in sources) |
136 | 138 | {
|
137 |
| - var view = viewHierarchy[i]; |
138 |
| - var pointerEvents = view.GetPointerEvents(); |
139 |
| - if (pointerEvents != PointerEvents.None && pointerEvents != PointerEvents.BoxNone) |
| 139 | + if (!source.HasTag()) |
| 140 | + { |
| 141 | + continue; |
| 142 | + } |
| 143 | + |
| 144 | + var pointerEvents = source.GetPointerEvents(); |
| 145 | + if (pointerEvents == PointerEvents.None || pointerEvents == PointerEvents.BoxNone) |
140 | 146 | {
|
141 |
| - target = i; |
| 147 | + continue; |
142 | 148 | }
|
143 | 149 |
|
144 |
| - if (pointerEvents == PointerEvents.BoxOnly || pointerEvents == PointerEvents.None) |
| 150 | + var viewHierarchy = RootViewHelper.GetReactViewHierarchy(source); |
| 151 | + var isBoxOnly = IsBoxOnlyWithCache(viewHierarchy, isBoxOnlyCache); |
| 152 | + if (!isBoxOnly) |
145 | 153 | {
|
146 |
| - break; |
| 154 | + return source; |
147 | 155 | }
|
148 | 156 | }
|
149 | 157 |
|
150 |
| - return target < 0 ? null : viewHierarchy[target]; |
| 158 | + return null; |
151 | 159 | }
|
152 | 160 |
|
153 | 161 | private void UpdatePointerForEvent(ReactPointer pointer, PointerRoutedEventArgs e)
|
@@ -184,6 +192,42 @@ private void DispatchTouchEvent(TouchEventType touchEventType, List<ReactPointer
|
184 | 192 | .DispatchEvent(touchEvent);
|
185 | 193 | }
|
186 | 194 |
|
| 195 | + private static bool IsBoxOnlyWithCache(IEnumerable<UIElement> hierarchy, IDictionary<UIElement, bool> cache) |
| 196 | + { |
| 197 | + var enumerator = hierarchy.GetEnumerator(); |
| 198 | + |
| 199 | + // Skip the first element (only checking ancestors) |
| 200 | + if (!enumerator.MoveNext()) |
| 201 | + { |
| 202 | + return false; |
| 203 | + } |
| 204 | + |
| 205 | + return IsBoxOnlyWithCacheRecursive(enumerator, cache); |
| 206 | + } |
| 207 | + |
| 208 | + private static bool IsBoxOnlyWithCacheRecursive(IEnumerator<UIElement> enumerator, IDictionary<UIElement, bool> cache) |
| 209 | + { |
| 210 | + if (!enumerator.MoveNext()) |
| 211 | + { |
| 212 | + return false; |
| 213 | + } |
| 214 | + |
| 215 | + var currentView = enumerator.Current; |
| 216 | + var isBoxOnly = default(bool); |
| 217 | + if (!cache.TryGetValue(currentView, out isBoxOnly)) |
| 218 | + { |
| 219 | + var pointerEvents = currentView.GetPointerEvents(); |
| 220 | + |
| 221 | + isBoxOnly = pointerEvents == PointerEvents.BoxOnly |
| 222 | + || pointerEvents == PointerEvents.None |
| 223 | + || IsBoxOnlyWithCacheRecursive(enumerator, cache); |
| 224 | + |
| 225 | + cache.Add(currentView, isBoxOnly); |
| 226 | + } |
| 227 | + |
| 228 | + return isBoxOnly; |
| 229 | + } |
| 230 | + |
187 | 231 | class TouchEvent : Event
|
188 | 232 | {
|
189 | 233 | private readonly TouchEventType _touchEventType;
|
|
0 commit comments