From 87482db8d0f42ec117b4beffcd5f7e02082dc391 Mon Sep 17 00:00:00 2001 From: xxrl <837951112@qq.com> Date: Tue, 18 Jul 2023 20:23:11 +0800 Subject: [PATCH] Use animation matrix after android Q --- .../react/uimanager/BaseViewManager.java | 9 ++ .../react/uimanager/MatrixMathHelper.java | 4 + .../react/uimanager/TransformHelper.java | 84 +++++++++++++++++++ 3 files changed, 97 insertions(+) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java index a7970346275fd7..bbd653c3018218 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java @@ -8,6 +8,7 @@ package com.facebook.react.uimanager; import android.graphics.Color; +import android.graphics.Matrix; import android.os.Build; import android.text.TextUtils; import android.view.View; @@ -440,6 +441,14 @@ public void setAccessibilityLiveRegion(@NonNull T view, @Nullable String liveReg } private static void setTransformProperty(@NonNull View view, ReadableArray transforms) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + Matrix matrix = TransformHelper.tryProcessTransformBySkiaMatrix(transforms, + view.getWidth(), view.getHeight()); + if (matrix != null) { + view.setAnimationMatrix(matrix); + return; + } + } sMatrixDecompositionContext.reset(); TransformHelper.processTransform(transforms, sTransformDecompositionArray); MatrixMathHelper.decomposeMatrix(sTransformDecompositionArray, sMatrixDecompositionContext); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/MatrixMathHelper.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/MatrixMathHelper.java index 0d698f7918965e..b93f9e877c44da 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/MatrixMathHelper.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/MatrixMathHelper.java @@ -468,6 +468,10 @@ public static double degreesToRadians(double degrees) { return degrees * Math.PI / 180; } + public static double radiansToDegrees(double radians) { + return radians * 180 / Math.PI; + } + public static void resetIdentityMatrix(double[] matrix) { matrix[1] = matrix[2] = diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/TransformHelper.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/TransformHelper.java index 49d6af12396a01..7db64241ea38f3 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/TransformHelper.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/TransformHelper.java @@ -7,6 +7,8 @@ package com.facebook.react.uimanager; +import android.graphics.Matrix; + import com.facebook.common.logging.FLog; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; @@ -107,4 +109,86 @@ public static void processTransform(ReadableArray transforms, double[] result) { MatrixMathHelper.multiplyInto(result, result, helperMatrix); } } + + + private static double convertToDegrees(ReadableMap transformMap, String key) { + double value; + boolean inRadians = true; + if (transformMap.getType(key) == ReadableType.String) { + String stringValue = transformMap.getString(key); + if (stringValue.endsWith("deg")) { + inRadians = false; + } + if (stringValue.endsWith("rad") || stringValue.endsWith("deg")) { + stringValue = stringValue.substring(0, stringValue.length() - 3); + } + value = Float.parseFloat(stringValue); + } else { + value = transformMap.getDouble(key); + } + return inRadians ? MatrixMathHelper.radiansToDegrees(value) : value; + } + + + public static Matrix tryProcessTransformBySkiaMatrix(ReadableArray transforms, int viewWidth, + int viewHeight) { + Matrix matrix = new Matrix(); + // center of view. + int originX = viewWidth / 2, originY = viewHeight / 2; + + for (int transformIdx = 0, size = transforms.size(); transformIdx < size; transformIdx++) { + ReadableMap transform = transforms.getMap(transformIdx); + String transformType = transform.keySetIterator().nextKey(); + + if ("translate".equals(transformType)) { + ReadableArray value = transform.getArray(transformType); + double x = value.getDouble(0); + double y = value.getDouble(1); + double z = value.size() > 2 ? value.getDouble(2) : 0d; + // Not support translate in z axis. + if (z != 0) { + return null; + } + originX += x; + originY += y; + matrix.postTranslate(PixelUtil.toPixelFromDIP((float) x), PixelUtil.toPixelFromDIP((float) y)); + } else if ("translateX".equals(transformType)) { + double x = transform.getDouble(transformType); + originX += x; + matrix.postTranslate(PixelUtil.toPixelFromDIP(x), 0); + } else if ("translateY".equals(transformType)) { + double y = transform.getDouble(transformType); + originY += y; + matrix.postTranslate(0, PixelUtil.toPixelFromDIP(y)); + } + } + + for (int transformIdx = 0, size = transforms.size(); transformIdx < size; transformIdx++) { + ReadableMap transform = transforms.getMap(transformIdx); + String transformType = transform.keySetIterator().nextKey(); + + if ("rotate".equals(transformType) || "rotateZ".equals(transformType)) { + matrix.postRotate((float) convertToDegrees(transform, transformType), originX, originY); + } else if ("scale".equals(transformType)) { + float scale = (float) transform.getDouble(transformType); + matrix.postScale(scale, scale, originX, originY); + } else if ("scaleX".equals(transformType)) { + matrix.postScale((float) transform.getDouble(transformType), 1, originX, originY); + } else if ("scaleY".equals(transformType)) { + matrix.postScale(1, (float) transform.getDouble(transformType), originX, originY); + } else if ("translate".equals(transformType) || "translateX".equals(transformType) + || "translateY".equals(transformType)) { + // translate has been processed. + } else if ("skewX".equals(transformType)) { + matrix.postSkew((float) convertToRadians(transform, transformType), 0); + } else if ("skewY".equals(transformType)) { + matrix.postSkew(0, (float) convertToRadians(transform, transformType)); + } else { + // matrix, perspective rotateX rotateY + return null; + } + } + return matrix; + } + }