You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In case anyone interested, here is the source code for skew code:
This is called for SkewX: MatrixMathHelper.applySkewX(helperMatrix, convertToRadians(transform, transformType)); in file: Libraries/StyleSheet/processTransform.js
i also have this issue, anyone have a workaround? I had search this issue on google, there have many people said use the native canvas have no problem, so whether modify the MatrixMathHelper.java could resolve this issue?
I found this package: https://github.com/wumke/react-native-skewable-view
It skews the shape of the view in android but not images and texts that are inside...
As work around you can also try using canvas, with for example this package: https://github.com/iddan/react-native-canvas#readme. But personally when I try ctx.drawImage(img, width, height) I get an error: "JSON.stringify cannot serialize cyclic structures."
So I'm still facing this problem for images.
The square renders upright. The translateY half of the same array is honored, so the view does receive a transform, but the skewX component is silently dropped. Same result for the CSS-string form transform: 'skewX(-12deg) translateY(8px)'. Tracing the pipeline:
processTransform.js correctly produces { skewX: '-12deg' } in the decomposed array.
Native side, TransformHelper.kt calls MatrixMathHelper.applySkewX, which writes m[4] = tan(radians) into the matrix correctly.
MatrixMathHelper.decomposeMatrix does compute a skew field on MatrixDecompositionContext.
BaseViewManager.java reads only translation, rotationDegrees, and scale from the decomposition context. The skew field is never consumed.
@javache's 2023 explanation still holds: Android View has no setSkewX / setSkewY. @MaxGraey's note in 2025 frames why a clean fix is hard, since polar / SVD decomposition can't disambiguate skew from scale, so an animation crossing the boundary would visibly snap.
Given this has now been documented as a platform limitation for ~6 years across paper and Fabric, would the team accept a documentation-side resolution: marking skewX / skewY as iOS-only on https://reactnative.dev/docs/transforms and emitting a one-time dev warning when those keys are used on Android? @delventhalz proposed this in 2024 and it has community upvotes. It would at least surface the platform divergence at authoring time instead of silently dropping at render time.
Could this be reopened? Happy to send a docs PR + a __DEV__ warning if there's interest.
Reacted by Zané, Pieter De Baets and Zac Delventhal
The only solution is to redesign the entire process architecturally and store the transformations not as a single matrix, but, for example, as a composition of vectors. And only lower to affine 3x3 matrix when needed. The Android versions that support pre-required API for these architectures should be minimum requirement for quite some time now I guess
Show Full Example
structVec2 {
float x = 0.0f;
float y = 0.0f;
};
structRotor2 {
float c = 1.0f;
float s = 0.0f;
...
}
structTransform2D {
...
Mat3x3 toAffineMat() const {
/* <- T * R * Hy * Hx * S */
...
}
}
structVec2 {
float x = 0.0f;
float y = 0.0f;
};
structRotor2 {
float c = 1.0f;
float s = 0.0f;
static Rotor2 fromRadians(float angle) {
return {
.c = std::cos(angle),
.s = std::sin(angle),
};
}
Vec2 apply(Vec2 v) const {
return {
.x = c * v.x - s * v.y,
.y = s * v.x + c * v.y,
};
}
};
structTransform2D {
Vec2 position = {0.0f, 0.0f};
Rotor2 rotor = {};
Vec2 scale = {1.0f, 1.0f};
// skew.x = shear X: x += skew.x * y// skew.y = shear Y: y += skew.y * x
Vec2 skewXY = {0.0f, 0.0f};
Vec2 transform(Vec2 p) const {
// Scale.
p.x *= scale.x;
p.y *= scale.y;
// Sequential skew: Hx then Hy.
p.x += skewXY.x * p.y;
p.y += skewXY.y * p.x;
// Rotation.
p = rotor.apply(p);
// Translation.
p.x += position.x;
p.y += position.y;
return p;
}
Vec2 transformVec(Vec2 v) const {
v.x *= scale.x;
v.y *= scale.y;
v.x += skewXY.x * v.y;
v.y += skewXY.y * v.x;
return rotor.apply(v);
}
Mat3x3 toAffineMat() const {
constfloat tx = position.x;
constfloat ty = position.y;
constfloat c = rotor.c;
constfloat s = rotor.s;
constfloat sx = scale.x;
constfloat sy = scale.y;
constfloat kx = skewXY.x;
constfloat ky = skewXY.y;
// M = T * R * Hy * Hx * Sreturn {
.m00 = sx * (c - s * ky),
.m01 = sy * (c * kx - s * (1.0f + ky * kx)),
.m02 = tx,
.m10 = sx * (s + c * ky),
.m11 = sy * (s * kx + c * (1.0f + ky * kx)),
.m12 = ty,
.m20 = 0.0f,
.m21 = 0.0f,
.m22 = 1.0f,
};
}
};
Thanks for reopening, @javache, and to @quantizor for the fresh repro and the trace through the call site that identified the dropped-skew bug at BaseViewManager.
Want to sanity-check a rendering-fix shape with you before opening a PR.
The dispatch in BaseViewManager.setTransformProperty, after the existing null-transform reset:
isAffine2DTransform rejects matrix, perspective, rotateX, rotateY, and Z-translate; hasSkewTransform is true only for skewX and skewY. So rotate, scale, and translate transforms keep flowing through the View-property code unchanged. buildAffine2DMatrix walks the ops left-to-right with preRotate, preScale, preSkew, and preTranslate around the resolved pivot. Pre-Q silently drops skew, which matches today, so there is no regression.
The working prototype renders correctly on emulator (Android 16, Pixel 8 Pro), with hit testing following via View.getMatrix().
Your #38494 review cited the SDK doc framing setAnimationMatrix as an animation API. androidx.transition.ViewUtilsApi21 calls it via reflection on pre-Q to drive the public Transition API for static transforms, and the API was promoted to public in Q. Is that precedent enough, or is there a deeper concern from #38494 that was not visible in the public thread?
Will open the PR this week unless you flag a reason to hold.
Reacted by Evan Jacobs, zxuhan7 and Zac Delventhal
Activity
MarekJavurek commentedon Jan 3, 2020
This is real problem!
HarshitMadhav commentedon Jan 4, 2020
I faced this issue too in android but for iOS, it is working fine.
JX0829 commentedon Jan 6, 2020
i also have this issue, anyone have a workaround? I had search this issue on google, there have many people said use the native canvas have no problem, so whether modify the MatrixMathHelper.java could resolve this issue?
HarshitMadhav commentedon Jan 6, 2020
@JX0829 As of now I have searched a lot for workarounds but found nothing. Sadly, I had to remove skew for android.
DaniAkash commentedon Feb 9, 2020
A live preview of this issue can be found at the example in https://deploy-preview-1613--react-native.netlify.com/docs/next/transforms
Valegox commentedon Apr 13, 2020
I found this package: https://github.com/wumke/react-native-skewable-view
It skews the shape of the view in android but not images and texts that are inside...
As work around you can also try using canvas, with for example this package: https://github.com/iddan/react-native-canvas#readme. But personally when I try
ctx.drawImage(img, width, height)I get an error: "JSON.stringify cannot serialize cyclic structures."So I'm still facing this problem for images.
Valegox commentedon Apr 13, 2020
For images I just recreated it by myself: I croped 100 same images with ImageEditor and aligned each part in offset to create the one I needed...
Fix skewX on Android and in the JS decomposition (#28862)
Fix skewX on Android and in the JS decomposition (react#28862)
ramyma commentedon Jun 9, 2021
I can see that skew style rules are still not working correctly on Android with RN
v0.64.2.Even the example provided on the transforms documentation page doesn't work:
However it works on iOS as described in the original issue:
Can we reopen this issue as it seems like the applied fix didn't resolve the reported issue?
ghaschel commentedon Jun 22, 2021
I'm still facing this issue. SkewY works, skewX doesn't. Skew works properly on iOS but it doesn't on android
kelset commentedon Jun 23, 2021
reopening for now.
@ramyma @ghaschel can either of you try if it still repros with RN 65 RC2?
38 remaining items
quantizor commentedon May 4, 2026
Just hit this on the latest stable line, sharing a fresh repro since the issue was stale-closed in February.
Confirmed reproducing on:
Minimal vanilla repro, with
skewXarray form, mirrors what's been reported here for years:The square renders upright. The
translateYhalf of the same array is honored, so the view does receive a transform, but theskewXcomponent is silently dropped. Same result for the CSS-string formtransform: 'skewX(-12deg) translateY(8px)'. Tracing the pipeline:processTransform.jscorrectly produces{ skewX: '-12deg' }in the decomposed array.TransformHelper.ktcallsMatrixMathHelper.applySkewX, which writesm[4] = tan(radians)into the matrix correctly.MatrixMathHelper.decomposeMatrixdoes compute askewfield onMatrixDecompositionContext.BaseViewManager.javareads onlytranslation,rotationDegrees, andscalefrom the decomposition context. The skew field is never consumed.@javache's 2023 explanation still holds: Android
Viewhas nosetSkewX/setSkewY. @MaxGraey's note in 2025 frames why a clean fix is hard, since polar / SVD decomposition can't disambiguate skew from scale, so an animation crossing the boundary would visibly snap.Given this has now been documented as a platform limitation for ~6 years across paper and Fabric, would the team accept a documentation-side resolution: marking
skewX/skewYas iOS-only on https://reactnative.dev/docs/transforms and emitting a one-time dev warning when those keys are used on Android? @delventhalz proposed this in 2024 and it has community upvotes. It would at least surface the platform divergence at authoring time instead of silently dropping at render time.Could this be reopened? Happy to send a docs PR + a
__DEV__warning if there's interest.feat(native): dev warning for Android skewX/skewY drop + caller frame…
feat(native-showcase): Android support, virtualized catalog, scroll r…
javache commentedon May 6, 2026
A documentation fix for this and/or warning would definitely be welcome.
MaxGraey commentedon May 6, 2026
The only solution is to redesign the entire process architecturally and store the transformations not as a single matrix, but, for example, as a composition of vectors. And only lower to affine 3x3 matrix when needed. The Android versions that support pre-required API for these architectures should be minimum requirement for quite some time now I guess
Show Full Example
qflen commentedon May 7, 2026
Thanks for reopening, @javache, and to @quantizor for the fresh repro and the trace through the call site that identified the dropped-skew bug at
BaseViewManager.Want to sanity-check a rendering-fix shape with you before opening a PR.
The dispatch in
BaseViewManager.setTransformProperty, after the existing null-transform reset:isAffine2DTransformrejectsmatrix,perspective,rotateX,rotateY, and Z-translate;hasSkewTransformis true only forskewXandskewY. So rotate, scale, and translate transforms keep flowing through the View-property code unchanged.buildAffine2DMatrixwalks the ops left-to-right withpreRotate,preScale,preSkew, andpreTranslatearound the resolved pivot. Pre-Q silently drops skew, which matches today, so there is no regression.The working prototype renders correctly on emulator (Android 16, Pixel 8 Pro), with hit testing following via
View.getMatrix().Your #38494 review cited the SDK doc framing
setAnimationMatrixas an animation API.androidx.transition.ViewUtilsApi21calls it via reflection on pre-Q to drive the public Transition API for static transforms, and the API was promoted to public in Q. Is that precedent enough, or is there a deeper concern from #38494 that was not visible in the public thread?Will open the PR this week unless you flag a reason to hold.
Fix skewX/skewY transforms on Android Q+
Add react#27649 PR screenshots
Add react#27649 PR screenshots
Fix skewX/skewY transforms on Android Q+
tovgroliv commentedon May 26, 2026
What are the updates? When can we expect the fix? Or is it possible to do it locally somehow?
Fix skewX/skewY transforms on Android Q+ (#27649) (#56724)