1+ package com .sensorsdata .analytics .utils ;
2+
3+ import android .graphics .Matrix ;
4+ import android .graphics .PointF ;
5+ import android .graphics .Rect ;
6+ import android .view .View ;
7+ import android .view .ViewGroup ;
8+ import com .facebook .react .bridge .JSApplicationIllegalArgumentException ;
9+ import com .facebook .react .bridge .UiThreadUtil ;
10+ import com .facebook .react .touch .ReactHitSlopView ;
11+ import com .facebook .react .uimanager .PointerEvents ;
12+ import com .facebook .react .uimanager .ReactCompoundView ;
13+ import com .facebook .react .uimanager .ReactCompoundViewGroup ;
14+ import com .facebook .react .uimanager .ReactPointerEventsView ;
15+
16+ public class RNTouchTargetHelper {
17+ private static final float [] mEventCoords = new float [2 ];
18+ private static final Matrix mInverseMatrix = new Matrix ();
19+ private static final float [] mMatrixTransformCoords = new float [2 ];
20+ private static final PointF mTempPoint = new PointF ();
21+
22+ public static int findTargetTagForTouch (float eventX , float eventY , ViewGroup viewGroup ) {
23+ return findTargetTagAndCoordinatesForTouch (eventX , eventY , viewGroup , mEventCoords );
24+ }
25+
26+ public static int findTargetTagAndCoordinatesForTouch (float eventX , float eventY , ViewGroup viewGroup , float [] viewCoords ) {
27+ UiThreadUtil .assertOnUiThread ();
28+ int targetTag = viewGroup .getId ();
29+ viewCoords [0 ] = eventX ;
30+ viewCoords [1 ] = eventY ;
31+ View nativeTargetView = findTouchTargetView (viewCoords , viewGroup );
32+ if (nativeTargetView == null ) {
33+ return targetTag ;
34+ }
35+ View reactTargetView = findClosestReactAncestor (nativeTargetView );
36+ if (reactTargetView != null ) {
37+ return getTouchTargetForView (reactTargetView , viewCoords [0 ], viewCoords [1 ]);
38+ }
39+ return targetTag ;
40+ }
41+
42+ public static View findClosestReactAncestor (View view ) {
43+ while (view != null && view .getId () <= 0 ) {
44+ view = (View ) view .getParent ();
45+ }
46+ return view ;
47+ }
48+
49+ public static View findTouchTargetView (float [] eventCoords , ViewGroup viewGroup ) {
50+ for (int i = viewGroup .getChildCount () - 1 ; i >= 0 ; i --) {
51+ View child = viewGroup .getChildAt (i );
52+ PointF childPoint = mTempPoint ;
53+ if (isTransformedTouchPointInView (eventCoords [0 ], eventCoords [1 ], viewGroup , child , childPoint )) {
54+ float restoreX = eventCoords [0 ];
55+ float restoreY = eventCoords [1 ];
56+ eventCoords [0 ] = childPoint .x ;
57+ eventCoords [1 ] = childPoint .y ;
58+ View targetView = findTouchTargetViewWithPointerEvents (eventCoords , child );
59+ if (targetView != null ) {
60+ return targetView ;
61+ }
62+ eventCoords [0 ] = restoreX ;
63+ eventCoords [1 ] = restoreY ;
64+ }
65+ }
66+ return viewGroup ;
67+ }
68+
69+ private static boolean isTransformedTouchPointInView (float x , float y , ViewGroup parent , View child , PointF outLocalPoint ) {
70+ float localX = (((float ) parent .getScrollX ()) + x ) - ((float ) child .getLeft ());
71+ float localY = (((float ) parent .getScrollY ()) + y ) - ((float ) child .getTop ());
72+ Matrix matrix = child .getMatrix ();
73+ if (!matrix .isIdentity ()) {
74+ float [] localXY = mMatrixTransformCoords ;
75+ localXY [0 ] = localX ;
76+ localXY [1 ] = localY ;
77+ Matrix inverseMatrix = mInverseMatrix ;
78+ matrix .invert (inverseMatrix );
79+ inverseMatrix .mapPoints (localXY );
80+ localX = localXY [0 ];
81+ localY = localXY [1 ];
82+ }
83+ if ((child instanceof ReactHitSlopView ) && ((ReactHitSlopView ) child ).getHitSlopRect () != null ) {
84+ Rect hitSlopRect = ((ReactHitSlopView ) child ).getHitSlopRect ();
85+ if (localX < ((float ) (-hitSlopRect .left )) || localX >= ((float ) ((child .getRight () - child .getLeft ()) + hitSlopRect .right )) || localY < ((float ) (-hitSlopRect .top )) || localY >= ((float ) ((child .getBottom () - child .getTop ()) + hitSlopRect .bottom ))) {
86+ return false ;
87+ }
88+ outLocalPoint .set (localX , localY );
89+ return true ;
90+ } else if (localX < 0.0f || localX >= ((float ) (child .getRight () - child .getLeft ())) || localY < 0.0f || localY >= ((float ) (child .getBottom () - child .getTop ()))) {
91+ return false ;
92+ } else {
93+ outLocalPoint .set (localX , localY );
94+ return true ;
95+ }
96+ }
97+
98+ private static View findTouchTargetViewWithPointerEvents (float [] eventCoords , View view ) {
99+ PointerEvents pointerEvents = view instanceof ReactPointerEventsView ? ((ReactPointerEventsView ) view ).getPointerEvents () : PointerEvents .AUTO ;
100+ if (pointerEvents == PointerEvents .NONE ) {
101+ return null ;
102+ }
103+ if (pointerEvents == PointerEvents .BOX_ONLY ) {
104+ return view ;
105+ }
106+ if (pointerEvents == PointerEvents .BOX_NONE ) {
107+ if (view instanceof ViewGroup ) {
108+ View targetView = findTouchTargetView (eventCoords , (ViewGroup ) view );
109+ if (targetView != view ) {
110+ return targetView ;
111+ }
112+ if (!(view instanceof ReactCompoundView ) || ((ReactCompoundView ) view ).reactTagForTouch (eventCoords [0 ], eventCoords [1 ]) == view .getId ()) {
113+ return null ;
114+ }
115+ return view ;
116+ }
117+ return null ;
118+ } else if (pointerEvents != PointerEvents .AUTO ) {
119+ StringBuilder stringBuilder = new StringBuilder ();
120+ stringBuilder .append ("Unknown pointer event type: " );
121+ stringBuilder .append (pointerEvents .toString ());
122+ throw new JSApplicationIllegalArgumentException (stringBuilder .toString ());
123+ } else if ((!(view instanceof ReactCompoundViewGroup ) || !((ReactCompoundViewGroup ) view ).interceptsTouchEvent (eventCoords [0 ], eventCoords [1 ])) && (view instanceof ViewGroup )) {
124+ return findTouchTargetView (eventCoords , (ViewGroup ) view );
125+ } else {
126+ return view ;
127+ }
128+ }
129+
130+ public static int getTouchTargetForView (View targetView , float eventX , float eventY ) {
131+ if (targetView instanceof ReactCompoundView ) {
132+ return ((ReactCompoundView ) targetView ).reactTagForTouch (eventX , eventY );
133+ }
134+ return targetView .getId ();
135+ }
136+ }
0 commit comments