facebook / react-native

A framework for building native applications using React
https://reactnative.dev
MIT License
119.46k stars 24.37k forks source link

[Android] skew transform not working #27649

Open usrbowe opened 4 years ago

usrbowe commented 4 years ago

Steps To Reproduce

  1. Try to set skewX for View component: transforms: [{ skewX: '45deg' }}
  2. Doesn't change the skew of View on Android (works on iOS)

Describe what you expected to happen:

Basically skewX doesn't apply any skew on the view on Android. Here is comparison between iOS/Android:

also skewY doesn't render same as on iOS (which looks more correct)

Screenshot 2020-01-02 at 2 13 00 PM

React Native version:

System:
    OS: macOS Mojave 10.14.6
    CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
    Memory: 1.50 GB / 16.00 GB
    Shell: 5.3 - /bin/zsh
  Binaries:
    Node: 12.13.0 - ~/.nvm/versions/node/v12.13.0/bin/node
    Yarn: 1.19.1 - ~/.yarn/bin/yarn
    npm: 6.12.0 - ~/.nvm/versions/node/v12.13.0/bin/npm
  SDKs:
    iOS SDK:
      Platforms: iOS 13.2, DriverKit 19.0, macOS 10.15, tvOS 13.2, watchOS 6.1
    Android SDK:
      API Levels: 25, 28, 29
      Build Tools: 28.0.3, 29.0.2
      System Images: android-28 | Google Play Intel x86 Atom, android-29 | Google APIs Intel x86 Atom
  IDEs:
    Android Studio: 3.5 AI-191.8026.42.35.5977832
    Xcode: 11.3/11C29 - /usr/bin/xcodebuild
  npmPackages:
    react: 16.9.0 => 16.9.0 
    react-native: 0.61.5 => 0.61.5

Related issues

Snack demo

https://snack.expo.io/@usrbowe2/e9b920

Resources

In case anyone interested, here is the source code for skew code:

  1. This is called for SkewX: MatrixMathHelper.applySkewX(helperMatrix, convertToRadians(transform, transformType)); in file: Libraries/StyleSheet/processTransform.js
  2. Which laters uses this matrix helper to apply transformation: https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/uimanager/MatrixMathHelper.java
MarekJavurek commented 4 years ago

This is real problem!

HarshitMadhav commented 4 years ago

I faced this issue too in android but for iOS, it is working fine.

JX0829 commented 4 years ago

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 commented 4 years ago

@JX0829 As of now I have searched a lot for workarounds but found nothing. Sadly, I had to remove skew for android.

DaniAkash commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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...

ramyma commented 3 years ago

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:

anroid-skew-not-working

However it works on iOS as described in the original issue:

ios-skew-working

Can we reopen this issue as it seems like the applied fix didn't resolve the reported issue?

ghaschel commented 3 years ago

I'm still facing this issue. SkewY works, skewX doesn't. Skew works properly on iOS but it doesn't on android

kelset commented 3 years ago

reopening for now.

@ramyma @ghaschel can either of you try if it still repros with RN 65 RC2?

ghaschel commented 3 years ago

I'll take a look as soon as I can. But just in advance, it is still not working on your documentation using the next version

ghaschel commented 3 years ago

@kelset it still happens.

This is when using skewX on android (nothing happens): image

and this is when happens when using skewY on android (as visible, the view is not skewed, but instead, rotated): image

Btw: This IS on RN 65 RC2

ramyma commented 3 years ago

I would like to point out that it seems like on Android the skew y operation is doing a bit of rotation as well if you compare it to the iOS result (which I think should be the correct result).

So, on Android, skew x is not working at all, and skew y is doing something but not the intended result.

Podlipny commented 3 years ago

did anyone figure out how to make skewX work on Android? We are currently running 0.64.2 and skewX still doesn't work.

danieldulcettiBN commented 3 years ago

Hello to everyone! Any news about this problem? I'm using RN 0.65.1 and skewX still doesn't work.

Any workaround would be fine.

MFQuraishi commented 2 years ago

One solution can be to use a combination of rotates (x,y,z) to produce a similar effect.

It will not be exactly similar to Skew but with some trial and error we can produce something similar.

Eg. <View style={{ transform: [ { rotateZ: "345deg" } ] }}> <View style={[styles.box, { transform: [ { rotateX: "30deg" }, { rotateY: "330deg" }, { rotateZ: "30deg" } ] }]}>

Rotate X,Y,Z (similar to skew)
       </View>

rvuyyuru1 commented 2 years ago

still not wroking... any solution ?

thlindustries commented 2 years ago

Here's an example: Err ... Err

DieTime commented 2 years ago

Version 0.70.5, skewX still doesn't work

itsramiel commented 1 year ago

Is this issue abandoned?

thlindustries commented 1 year ago

Is this issue abandoned?

Definitely not, the problem stills there :/

javache commented 1 year ago

The root cause here is that Android does not natively support a skew property. The way we apply transforms is to decompose them and set the individual view properties: https://github.com/facebook/react-native/blob/main/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java#L431-L447

Suggestions welcome on how to achieve the desired behaviour in Android.

DieTime commented 1 year ago

It sounds like it is not possible at the moment to achieve the expected behaviour. Android View doesn't even provide the setTransformation(Matrix) method to do the skew.

github-actions[bot] commented 1 year ago

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.

itsramiel commented 1 year ago

Still valid

brent-charlton commented 1 year ago

still having this problem

GNUGradyn commented 1 year ago

I found another workaround but it's a bit difficult to implement and might not work for all use cases. In my case I was trying to make a "register" ribbon. What I did is make the view way too wide, rotate it 45 degrees, and put it in another view that with overflow: hidden. Note you will need to do some math to figure out what the width of the outer view should be, because it wont account for the fact the inner view is rotated 45 degrees. Here is my implementation for reference

interface RibbonProps {
    text: string
    color: string
    textColor: string,
    styles?: StyleProp<ViewStyle>
}

function toRadians (angle: number): number {
    return angle * (Math.PI / 180);
}

const Ribbon: React.FC<RibbonProps> = (props: RibbonProps) => {

    const [ribbonWidth, setRibbonWidth] = React.useState(1); // cant be 0 or we'll try to divide by 0
    const [ribbonHeight, setRibbonHeight] = React.useState(1); // cant be 0 or we'll try to divide by 0
    const [containerWidth, setContainerWidth] = React.useState(1); // cant be 0 or we'll try to divide by 0
    const [containerHeight, setContainerHeight] = React.useState(1); // cant be 0 or we'll try to divide by 0

    const onBannerLayout = (event: LayoutChangeEvent) => {
        const { height, width } = event.nativeEvent.layout;
        setRibbonHeight(height);
        setRibbonWidth(width);
    }

    const onContainerLayout = (event: LayoutChangeEvent) => {
        const { height, width } = event.nativeEvent.layout;
        setContainerHeight(height);
        setContainerWidth(width);
    }

    const styles = StyleSheet.create({
        ribbon: {
            transform: [{ rotate: '45deg' }],
            alignItems: "center",
            justifyContent: "center",
            width: "1000%",
        },
        container: {
            overflow: "hidden",
            alignItems: "center",
            justifyContent: "center",
            flex: 1,
            width: ((ribbonHeight / Math.sin(toRadians(45))) + (containerHeight / Math.tan(toRadians(45))))
        }
    });

    return (
        <View style={[styles.container, props.styles]} onLayout={onContainerLayout}>
            <View style={[styles.ribbon, { backgroundColor: props.color }]} onLayout={onBannerLayout}>
                <AppText style={{ color: props.textColor, padding: 0 }}>{props.text}</AppText>
            </View>
        </View>
    );
};

export default Ribbon;
likeSo commented 9 months ago

As of today, 2024.2.21, the skew transform still not working, in the official documentation! skewX not working at all! skewY looks like only a rotate ? 😓😓😓 WX20240221-102237@2x

zane-commeatio commented 7 months ago

2024 and still same issue :(

MaxGraey commented 5 months ago

It looks like view.setSkewX and view.setSkewY doesn't apply here:

https://github.com/facebook/react-native/blob/main/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java#L545

However, Android's View doesn't have setSkewX and setSkewY methods

But it has setTransformation (as part of View > dispatchProvideStructure) which can apply the whole Matrix. This requires API level 23. https://developer.android.com/reference/android/view/ViewStructure#setTransformation(android.graphics.Matrix)

For such case, we even don't need to perform matrix decomposition.

Update: Another option is override getChildStaticTransformation like suggested here

delventhalz commented 2 months ago

Still seeing this exact issue with react-native 0.74.5 almost five years later. If this is not going to be fixed due to Android's lack of a native skew implementation, then it seems to me like skewX and skewY should become iOS-only properties and marked as such in the documentation.

bumjin1013 commented 1 month ago

same.. 0.74.3