Browse Source

fixed bug with child views transformation loss

Oleksandr Kucherenko 6 years ago
parent
commit
2a865fa1db

+ 223
- 0
android/src/main/java/fr/greweb/reactnativeviewshot/DebugViews.java View File

1
+package fr.greweb.reactnativeviewshot;
2
+
3
+import android.annotation.TargetApi;
4
+import android.app.Activity;
5
+import android.content.res.Resources;
6
+import android.graphics.Matrix;
7
+import android.os.Build;
8
+import android.support.annotation.NonNull;
9
+import android.support.v4.util.Pair;
10
+import android.util.Log;
11
+import android.view.View;
12
+import android.view.ViewGroup;
13
+import android.widget.TextView;
14
+
15
+import java.util.Locale;
16
+import java.util.Stack;
17
+
18
+import javax.annotation.Nullable;
19
+
20
+import static android.view.View.GONE;
21
+import static android.view.View.INVISIBLE;
22
+import static android.view.View.VISIBLE;
23
+
24
+/**
25
+ * @see <a href="https://gist.github.com/OleksandrKucherenko/054b0331ec791edb39db76bd690ecdb2">Author of the Snippet</a>
26
+ */
27
+@SuppressWarnings("WeakerAccess")
28
+public final class DebugViews {
29
+    /**
30
+     * Chunk of the long log line.
31
+     */
32
+    public static final int LOG_MSG_LIMIT = 200;
33
+    /**
34
+     * Initial matrix without transformations.
35
+     */
36
+    public static final Matrix EMPTY_MATRIX = new Matrix();
37
+
38
+    /**
39
+     * Log long message by chunks
40
+     *
41
+     * @param message message to log.
42
+     */
43
+    @SuppressWarnings("UnusedReturnValue")
44
+    public static int longDebug(@NonNull final String tag, @NonNull final String message) {
45
+        int counter = 0;
46
+
47
+        String msg = message;
48
+
49
+        while (msg.length() > 0) {
50
+            final int endOfLine = msg.indexOf("\n"); // -1, 0, 1
51
+            final int breakPoint = Math.min(endOfLine < 0 ? LOG_MSG_LIMIT : endOfLine + 1, LOG_MSG_LIMIT);
52
+            final int last = Math.min(msg.length(), breakPoint);
53
+            final String out = String.format(Locale.US, "%02d: %s", counter, msg.substring(0, last));
54
+            Log.d(tag, out);
55
+
56
+            msg = msg.substring(last);
57
+            counter++;
58
+        }
59
+
60
+        return counter;
61
+    }
62
+
63
+    /**
64
+     * Print into log activity views hierarchy.
65
+     */
66
+    @NonNull
67
+    public static String logViewHierarchy(@NonNull final Activity activity) {
68
+        final View view = activity.findViewById(android.R.id.content);
69
+
70
+        if (null == view)
71
+            return "Activity [" + activity.getClass().getSimpleName() + "] is not initialized yet. ";
72
+
73
+        return logViewHierarchy(view);
74
+    }
75
+
76
+    /**
77
+     * Print into log view hierarchy.
78
+     */
79
+    @NonNull
80
+    private static String logViewHierarchy(@NonNull final View root) {
81
+        final StringBuilder output = new StringBuilder(8192).append("\n");
82
+        final Resources r = root.getResources();
83
+        final Stack<Pair<String, View>> stack = new Stack<>();
84
+        stack.push(Pair.create("", root));
85
+
86
+        while (!stack.empty()) {
87
+            @NonNull final Pair<String, View> p = stack.pop();
88
+            @NonNull final View v = p.second;
89
+            @NonNull final String prefix = p.first;
90
+
91
+            final boolean isLastOnLevel = stack.empty() || !prefix.equals(stack.peek().first);
92
+            final String graphics = "" + prefix + (isLastOnLevel ? "└── " : "├── ");
93
+
94
+            final String className = v.getClass().getSimpleName();
95
+            final String line = graphics + className + dumpProperties(r, v);
96
+
97
+            output.append(line).append("\n");
98
+
99
+            if (v instanceof ViewGroup) {
100
+                final ViewGroup vg = (ViewGroup) v;
101
+                for (int i = vg.getChildCount() - 1; i >= 0; i--) {
102
+                    stack.push(Pair.create(prefix + (isLastOnLevel ? "    " : "│   "), vg.getChildAt(i)));
103
+                }
104
+            }
105
+        }
106
+
107
+        return output.toString();
108
+    }
109
+
110
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
111
+    @NonNull
112
+    private static String dumpProperties(@NonNull final Resources r, @NonNull final View v) {
113
+        final StringBuilder sb = new StringBuilder();
114
+
115
+        sb.append(" ").append("id=").append(v.getId()).append(resolveIdToName(r, v));
116
+
117
+        switch (v.getVisibility()) {
118
+            case VISIBLE:
119
+                sb.append(", V--");
120
+                break;
121
+            case INVISIBLE:
122
+                sb.append(", -I-");
123
+                break;
124
+            case GONE:
125
+                sb.append(", --G");
126
+                break;
127
+            default:
128
+                sb.append(", ---");
129
+                break;
130
+        }
131
+
132
+        // transformation matrix exists, rotate/scale/skew/translate/
133
+        if (!v.getMatrix().equals(EMPTY_MATRIX)) {
134
+            sb.append(", ").append("matrix=").append(v.getMatrix().toShortString());
135
+
136
+            if (0.0f != v.getRotation() || 0.0f != v.getRotationX() || 0.0f != v.getRotationY()) {
137
+                sb.append(", rotate=[")
138
+                        .append(v.getRotation()).append(",")
139
+                        .append(v.getRotationX()).append(",")
140
+                        .append(v.getRotationY())
141
+                        .append("]");
142
+
143
+                // print pivote only if its not default
144
+                if (v.getWidth() / 2 != v.getPivotX() || v.getHeight() / 2 != v.getPivotY()) {
145
+                    sb.append(", pivot=[")
146
+                            .append(v.getPivotX()).append(",")
147
+                            .append(v.getPivotY())
148
+                            .append("]");
149
+                }
150
+            }
151
+
152
+            if (0.0f != v.getTranslationX() || 0.0f != v.getTranslationY() || 0.0f != v.getTranslationZ()) {
153
+                sb.append(", translate=[")
154
+                        .append(v.getTranslationX()).append(",")
155
+                        .append(v.getTranslationY()).append(",")
156
+                        .append(v.getTranslationZ())
157
+                        .append("]");
158
+            }
159
+
160
+            if (1.0f != v.getScaleX() || 1.0f != v.getScaleY()) {
161
+                sb.append(", scale=[")
162
+                        .append(v.getScaleX()).append(",")
163
+                        .append(v.getScaleY())
164
+                        .append("]");
165
+            }
166
+        }
167
+
168
+        // padding's
169
+        if (0 != v.getPaddingStart() || 0 != v.getPaddingTop() ||
170
+                0 != v.getPaddingEnd() || 0 != v.getPaddingBottom()) {
171
+            sb.append(", ")
172
+                    .append("padding=[")
173
+                    .append(v.getPaddingStart()).append(",")
174
+                    .append(v.getPaddingTop()).append(",")
175
+                    .append(v.getPaddingEnd()).append(",")
176
+                    .append(v.getPaddingBottom())
177
+                    .append("]");
178
+        }
179
+
180
+        // margin's
181
+        final ViewGroup.LayoutParams lp = v.getLayoutParams();
182
+        if (lp instanceof ViewGroup.MarginLayoutParams) {
183
+            final ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) lp;
184
+
185
+            if (0 != mlp.leftMargin || 0 != mlp.topMargin ||
186
+                    0 != mlp.rightMargin || 0 != mlp.bottomMargin) {
187
+                sb.append(", ").append("margin=[")
188
+                        .append(mlp.leftMargin).append(",")
189
+                        .append(mlp.topMargin).append(",")
190
+                        .append(mlp.rightMargin).append(",")
191
+                        .append(mlp.bottomMargin)
192
+                        .append("]");
193
+            }
194
+        }
195
+
196
+        // width, height, size
197
+        sb.append(", position=[").append(v.getLeft()).append(",").append(v.getTop()).append("]");
198
+        sb.append(", size=[").append(v.getWidth()).append(",").append(v.getHeight()).append("]");
199
+
200
+        // texts
201
+        if (v instanceof TextView) {
202
+            final TextView tv = (TextView) v;
203
+
204
+            sb.append(", text=\"").append(tv.getText()).append("\"");
205
+        }
206
+
207
+        return sb.toString();
208
+    }
209
+
210
+    /**
211
+     * @see <a href="https://stackoverflow.com/questions/10137692/how-to-get-resource-name-from-resource-id">Lookup resource name</a>
212
+     */
213
+    @NonNull
214
+    private static String resolveIdToName(@Nullable final Resources r, @NonNull final View v) {
215
+        if (null == r) return "";
216
+
217
+        try {
218
+            return " / " + r.getResourceEntryName(v.getId());
219
+        } catch (Throwable ignored) {
220
+            return "";
221
+        }
222
+    }
223
+}

+ 2
- 1
android/src/main/java/fr/greweb/reactnativeviewshot/RNViewShotModule.java View File

100
                     scaleWidth, scaleHeight, outputFile, resultStreamFormat,
100
                     scaleWidth, scaleHeight, outputFile, resultStreamFormat,
101
                     snapshotContentContainer, reactContext, activity, promise)
101
                     snapshotContentContainer, reactContext, activity, promise)
102
             );
102
             );
103
-        } catch (final Throwable ignored) {
103
+        } catch (final Throwable ex) {
104
+            Log.e(RNVIEW_SHOT, "Failed to snapshot view tag " + tag, ex);
104
             promise.reject(ViewShot.ERROR_UNABLE_TO_SNAPSHOT, "Failed to snapshot view tag " + tag);
105
             promise.reject(ViewShot.ERROR_UNABLE_TO_SNAPSHOT, "Failed to snapshot view tag " + tag);
105
         }
106
         }
106
     }
107
     }

+ 85
- 44
android/src/main/java/fr/greweb/reactnativeviewshot/ViewShot.java View File

5
 import android.graphics.Canvas;
5
 import android.graphics.Canvas;
6
 import android.graphics.Color;
6
 import android.graphics.Color;
7
 import android.graphics.Matrix;
7
 import android.graphics.Matrix;
8
+import android.graphics.Paint;
8
 import android.graphics.Point;
9
 import android.graphics.Point;
9
-import android.graphics.Rect;
10
-import android.graphics.RectF;
11
 import android.net.Uri;
10
 import android.net.Uri;
12
 import android.support.annotation.IntDef;
11
 import android.support.annotation.IntDef;
13
 import android.support.annotation.NonNull;
12
 import android.support.annotation.NonNull;
14
 import android.support.annotation.StringDef;
13
 import android.support.annotation.StringDef;
15
 import android.util.Base64;
14
 import android.util.Base64;
15
+import android.util.Log;
16
 import android.view.TextureView;
16
 import android.view.TextureView;
17
 import android.view.View;
17
 import android.view.View;
18
 import android.view.ViewGroup;
18
 import android.view.ViewGroup;
19
-import android.view.ViewParent;
20
 import android.widget.ScrollView;
19
 import android.widget.ScrollView;
21
 
20
 
22
 import com.facebook.react.bridge.Promise;
21
 import com.facebook.react.bridge.Promise;
34
 import java.util.ArrayList;
33
 import java.util.ArrayList;
35
 import java.util.Arrays;
34
 import java.util.Arrays;
36
 import java.util.Collections;
35
 import java.util.Collections;
36
+import java.util.LinkedList;
37
 import java.util.List;
37
 import java.util.List;
38
 import java.util.Locale;
38
 import java.util.Locale;
39
 import java.util.Set;
39
 import java.util.Set;
42
 
42
 
43
 import javax.annotation.Nullable;
43
 import javax.annotation.Nullable;
44
 
44
 
45
+import static android.view.View.VISIBLE;
46
+
45
 /**
47
 /**
46
  * Snapshot utility class allow to screenshot a view.
48
  * Snapshot utility class allow to screenshot a view.
47
  */
49
  */
48
 public class ViewShot implements UIBlock {
50
 public class ViewShot implements UIBlock {
49
     //region Constants
51
     //region Constants
50
-    static final String ERROR_UNABLE_TO_SNAPSHOT = "E_UNABLE_TO_SNAPSHOT";
52
+    /**
53
+     * Tag fort Class logs.
54
+     */
55
+    private static final String TAG = ViewShot.class.getSimpleName();
56
+    /**
57
+     * Error code that we return to RN.
58
+     */
59
+    public static final String ERROR_UNABLE_TO_SNAPSHOT = "E_UNABLE_TO_SNAPSHOT";
51
     /**
60
     /**
52
      * pre-allocated output stream size for screenshot. In real life example it will eb around 7Mb.
61
      * pre-allocated output stream size for screenshot. In real life example it will eb around 7Mb.
53
      */
62
      */
163
         }
172
         }
164
 
173
 
165
         if (view == null) {
174
         if (view == null) {
175
+            Log.e(TAG, "No view found with reactTag: " + tag, new AssertionError());
166
             promise.reject(ERROR_UNABLE_TO_SNAPSHOT, "No view found with reactTag: " + tag);
176
             promise.reject(ERROR_UNABLE_TO_SNAPSHOT, "No view found with reactTag: " + tag);
167
             return;
177
             return;
168
         }
178
         }
181
             } else if (Results.DATA_URI.equals(result)) {
191
             } else if (Results.DATA_URI.equals(result)) {
182
                 saveToDataUriString(view);
192
                 saveToDataUriString(view);
183
             }
193
             }
184
-        } catch (final Throwable ignored) {
194
+        } catch (final Throwable ex) {
195
+            Log.e(TAG, "Failed to capture view snapshot", ex);
185
             promise.reject(ERROR_UNABLE_TO_SNAPSHOT, "Failed to capture view snapshot");
196
             promise.reject(ERROR_UNABLE_TO_SNAPSHOT, "Failed to capture view snapshot");
186
         }
197
         }
187
     }
198
     }
290
      */
301
      */
291
     private Point captureView(@NonNull final View view, @NonNull final OutputStream os) throws IOException {
302
     private Point captureView(@NonNull final View view, @NonNull final OutputStream os) throws IOException {
292
         try {
303
         try {
304
+            DebugViews.longDebug(TAG, DebugViews.logViewHierarchy(this.currentActivity));
305
+
293
             return captureViewImpl(view, os);
306
             return captureViewImpl(view, os);
294
         } finally {
307
         } finally {
295
             os.close();
308
             os.close();
310
             throw new RuntimeException("Impossible to snapshot the view: view is invalid");
323
             throw new RuntimeException("Impossible to snapshot the view: view is invalid");
311
         }
324
         }
312
 
325
 
313
-        //evaluate real height
326
+        // evaluate real height
314
         if (snapshotContentContainer) {
327
         if (snapshotContentContainer) {
315
             h = 0;
328
             h = 0;
316
             ScrollView scrollView = (ScrollView) view;
329
             ScrollView scrollView = (ScrollView) view;
322
         final Point resolution = new Point(w, h);
335
         final Point resolution = new Point(w, h);
323
         Bitmap bitmap = getBitmapForScreenshot(w, h);
336
         Bitmap bitmap = getBitmapForScreenshot(w, h);
324
 
337
 
338
+        final Paint paint = new Paint();
339
+        paint.setAntiAlias(true);
340
+        paint.setFilterBitmap(true);
341
+        paint.setDither(true);
342
+
343
+        // Uncomment next line if you want to wait attached android studio debugger:
344
+        //   Debug.waitForDebugger();
345
+
325
         final Canvas c = new Canvas(bitmap);
346
         final Canvas c = new Canvas(bitmap);
326
         view.draw(c);
347
         view.draw(c);
327
 
348
 
331
         for (final View child : childrenList) {
352
         for (final View child : childrenList) {
332
             // skip any child that we don't know how to process
353
             // skip any child that we don't know how to process
333
             if (!(child instanceof TextureView)) continue;
354
             if (!(child instanceof TextureView)) continue;
355
+
334
             // skip all invisible to user child views
356
             // skip all invisible to user child views
335
-            if (child.getVisibility() != View.VISIBLE) continue;
357
+            if (child.getVisibility() != VISIBLE) continue;
336
 
358
 
337
             final TextureView tvChild = (TextureView) child;
359
             final TextureView tvChild = (TextureView) child;
338
-            tvChild.setOpaque(false);
360
+            tvChild.setOpaque(false); // <-- switch off background fill
339
 
361
 
340
-            final Point offsets = getParentOffsets(view, child);
341
-            final int left = child.getLeft() + child.getPaddingLeft() + offsets.x;
342
-            final int top = child.getTop() + child.getPaddingTop() + offsets.y;
343
-            final int childWidth = child.getWidth();
344
-            final int childHeight = child.getHeight();
345
-            final Rect source = new Rect(0, 0, childWidth, childHeight);
346
-            final RectF destination = new RectF(left, top, left + childWidth, top + childHeight);
362
+            // NOTE (olku): get re-usable bitmap. TextureView should use bitmaps with matching size,
363
+            // otherwise content of the TextureView will be scaled to provided bitmap dimensions
364
+            final Bitmap childBitmapBuffer = tvChild.getBitmap(getExactBitmapForScreenshot(child.getWidth(), child.getHeight()));
347
 
365
 
348
-            // get re-usable bitmap
349
-            final Bitmap childBitmapBuffer = tvChild.getBitmap(getBitmapForScreenshot(child.getWidth(), child.getHeight()));
366
+            final int countCanvasSave = c.save();
367
+            applyTransformations(c, view, child);
350
 
368
 
351
-            c.save();
352
-            c.setMatrix(concatMatrix(view, child));
353
             // due to re-use of bitmaps for screenshot, we can get bitmap that is bigger in size than requested
369
             // due to re-use of bitmaps for screenshot, we can get bitmap that is bigger in size than requested
354
-            c.drawBitmap(childBitmapBuffer, source, destination, null);
355
-            c.restore();
370
+            c.drawBitmap(childBitmapBuffer, 0, 0, paint);
371
+
372
+            c.restoreToCount(countCanvasSave);
356
             recycleBitmap(childBitmapBuffer);
373
             recycleBitmap(childBitmapBuffer);
357
         }
374
         }
358
 
375
 
380
         return resolution; // return image width and height
397
         return resolution; // return image width and height
381
     }
398
     }
382
 
399
 
383
-    /** Concat all the transformation matrix's from child to parent. */
400
+    /**
401
+     * Concat all the transformation matrix's from parent to child.
402
+     */
384
     @NonNull
403
     @NonNull
385
-    private Matrix concatMatrix(@NonNull final View view, @NonNull final View child){
404
+    @SuppressWarnings("UnusedReturnValue")
405
+    private Matrix applyTransformations(final Canvas c, @NonNull final View root, @NonNull final View child) {
386
         final Matrix transform = new Matrix();
406
         final Matrix transform = new Matrix();
407
+        final LinkedList<View> ms = new LinkedList<>();
387
 
408
 
409
+        // find all parents of the child view
388
         View iterator = child;
410
         View iterator = child;
389
         do {
411
         do {
412
+            ms.add(iterator);
390
 
413
 
391
-            final Matrix m = iterator.getMatrix();
392
-            transform.preConcat(m);
393
-
394
-            iterator = (View)iterator.getParent();
395
-        } while( iterator != view );
414
+            iterator = (View) iterator.getParent();
415
+        } while (iterator != root);
396
 
416
 
397
-        return transform;
398
-    }
399
-
400
-    @NonNull
401
-    private Point getParentOffsets(@NonNull final View view, @NonNull final View child) {
402
-        int left = 0;
403
-        int top = 0;
417
+        // apply transformations from parent --> child order
418
+        Collections.reverse(ms);
404
 
419
 
405
-        View parentElem = (View) child.getParent();
406
-        while (parentElem != null) {
407
-            if (parentElem == view) break;
420
+        for (final View v : ms) {
421
+            c.save();
408
 
422
 
409
-            left += parentElem.getLeft();
410
-            top += parentElem.getTop();
411
-            parentElem = (View) parentElem.getParent();
423
+            // apply each view transformations, so each child will be affected by them
424
+            final float dx = v.getLeft() + ((v != child) ? v.getPaddingLeft() : 0) + v.getTranslationX();
425
+            final float dy = v.getTop() + ((v != child) ? v.getPaddingTop() : 0) + v.getTranslationY();
426
+            c.translate(dx, dy);
427
+            c.rotate(v.getRotation(), v.getPivotX(), v.getPivotY());
428
+            c.scale(v.getScaleX(), v.getScaleY());
429
+
430
+            // compute the matrix just for any future use
431
+            transform.postTranslate(dx, dy);
432
+            transform.postRotate(v.getRotation(), v.getPivotX(), v.getPivotY());
433
+            transform.postScale(v.getScaleX(), v.getScaleY());
412
         }
434
         }
413
 
435
 
414
-        return new Point(left, top);
436
+        return transform;
415
     }
437
     }
416
 
438
 
417
     @SuppressWarnings("unchecked")
439
     @SuppressWarnings("unchecked")
450
     }
472
     }
451
 
473
 
452
     /**
474
     /**
453
-     * Try to find a bitmap for screenshot in reusabel set and if not found create a new one.
475
+     * Try to find a bitmap for screenshot in reusable set and if not found create a new one.
454
      */
476
      */
455
     @NonNull
477
     @NonNull
456
     private static Bitmap getBitmapForScreenshot(final int width, final int height) {
478
     private static Bitmap getBitmapForScreenshot(final int width, final int height) {
457
         synchronized (guardBitmaps) {
479
         synchronized (guardBitmaps) {
458
             for (final Bitmap bmp : weakBitmaps) {
480
             for (final Bitmap bmp : weakBitmaps) {
459
-                if (bmp.getWidth() * bmp.getHeight() <= width * height) {
481
+                if (bmp.getWidth() >= width && bmp.getHeight() >= height) {
482
+                    weakBitmaps.remove(bmp);
483
+                    bmp.eraseColor(Color.TRANSPARENT);
484
+                    return bmp;
485
+                }
486
+            }
487
+        }
488
+
489
+        return Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
490
+    }
491
+
492
+    /**
493
+     * Try to find a bitmap with exact width and height for screenshot in reusable set and if
494
+     * not found create a new one.
495
+     */
496
+    @NonNull
497
+    private static Bitmap getExactBitmapForScreenshot(final int width, final int height) {
498
+        synchronized (guardBitmaps) {
499
+            for (final Bitmap bmp : weakBitmaps) {
500
+                if (bmp.getWidth() == width && bmp.getHeight() == height) {
460
                     weakBitmaps.remove(bmp);
501
                     weakBitmaps.remove(bmp);
461
                     bmp.eraseColor(Color.TRANSPARENT);
502
                     bmp.eraseColor(Color.TRANSPARENT);
462
                     return bmp;
503
                     return bmp;

+ 18
- 2
example/App.js View File

263
         <View ref="empty" collapsable={false} />
263
         <View ref="empty" collapsable={false} />
264
         <View style={styles.experimental} ref="complex" collapsable={false}>
264
         <View style={styles.experimental} ref="complex" collapsable={false}>
265
           <Text style={styles.experimentalTitle}>Experimental Stuff</Text>
265
           <Text style={styles.experimentalTitle}>Experimental Stuff</Text>
266
-          <View ref="transformParent" collapsable={false}>
266
+          <View ref="transformParent" collapsable={false} style={{flex: 1, flexDirection: 'row'}}>
267
               <View ref="transformInner" collapsable={false} style={styles.experimentalTransform}>
267
               <View ref="transformInner" collapsable={false} style={styles.experimentalTransform}>
268
                 <Text ref="transform" >Transform</Text>
268
                 <Text ref="transform" >Transform</Text>
269
                 <ART.Surface ref="surface" width={20} height={20}>
269
                 <ART.Surface ref="surface" width={20} height={20}>
280
                     </ART.Shape>
280
                     </ART.Shape>
281
                 </ART.Surface>
281
                 </ART.Surface>
282
               </View>
282
               </View>
283
+              <View ref="right" style={styles.experimentalTransformV2}>
284
+                <ART.Surface ref="surface2" width={20} height={20}>
285
+                    <ART.Shape
286
+                            x={0}
287
+                            y={10}
288
+                            d='M2.876,10.6499757 L16.375,18.3966817 C16.715,18.5915989 17.011,18.4606545 17.125,18.3956822 C17.237,18.3307098 17.499,18.1367923 17.499,17.746958 L17.499,2.25254636 C17.499,1.86271212 17.237,1.66879457 17.125,1.6038222 C17.011,1.53884983 16.715,1.4079055 16.375,1.60282262 L2.876,9.34952866 C2.537,9.54544536 2.5,9.86930765 2.5,10.000252 C2.5,10.1301967 2.537,10.4550586 2.876,10.6499757 M16.749,20 C16.364,20 15.98,19.8990429 15.629,19.6971288 L2.13,11.9504227 L2.129,11.9504227 C1.422,11.5445953 1,10.8149056 1,10.000252 C1,9.18459879 1.422,8.45590864 2.129,8.04908162 L15.629,0.302375584 C16.332,-0.10245228 17.173,-0.10045313 17.876,0.306373884 C18.579,0.713200898 18.999,1.44089148 18.999,2.25254636 L18.999,17.746958 C18.999,18.5586129 18.579,19.2863035 17.876,19.6931305 C17.523,19.8970438 17.136,20 16.749,20'
289
+                            fill="red"
290
+                            >
291
+                    </ART.Shape>
292
+                </ART.Surface>
293
+              </View>
283
           </View>
294
           </View>
284
           <View ref="svg" collapsable={false}>
295
           <View ref="svg" collapsable={false}>
285
             <SvgUri
296
             <SvgUri
351
     margin: 10
362
     margin: 10
352
   },
363
   },
353
   experimentalTransform: {
364
   experimentalTransform: {
354
-    transform: [{ rotate: '180deg' }]
365
+    transform: [{ rotate: '180deg' }],
366
+    backgroundColor: 'powderblue',
367
+  },
368
+  experimentalTransformV2: {
369
+//    transform: [{ rotate: '180deg' }],
370
+    backgroundColor: 'skyblue',
355
   },
371
   },
356
   p1: {
372
   p1: {
357
     marginBottom: 10,
373
     marginBottom: 10,

+ 8
- 8
example/android/app/build.gradle View File

142
 }
142
 }
143
 
143
 
144
 dependencies {
144
 dependencies {
145
-    compile project(':react-native-svg')
146
-    compile fileTree(dir: "libs", include: ["*.jar"])
145
+    implementation project(':react-native-svg')
146
+    implementation fileTree(dir: "libs", include: ["*.jar"])
147
 
147
 
148
-    compile "com.android.support:appcompat-v7:27.+"
149
-    compile "com.facebook.react:react-native:+"  // From node_modules
148
+    implementation "com.android.support:appcompat-v7:27.+"
149
+    implementation "com.facebook.react:react-native:+"  // From node_modules
150
 
150
 
151
-    compile project(':react-native-view-shot')
152
-    compile project(':gl-react-native')
153
-    compile project(':react-native-maps')
154
-    compile project(':react-native-video')
151
+    implementation project(':react-native-view-shot')
152
+    implementation project(':gl-react-native')
153
+    implementation project(':react-native-maps')
154
+    implementation project(':react-native-video')
155
 }
155
 }
156
 
156
 
157
 // Run this once to be able to run the application with BUCK
157
 // Run this once to be able to run the application with BUCK