Open brunolemos opened 6 years ago
Thanks for posting this! It looks like your issue may refer to an older version of React Native. Can you reproduce the issue on the latest stable release?
Thank you for your contributions.
+1
I can reproduce this on the latest stable release.
+1
+1
I was able to solve this from removing overflow: “hidden”
from the Views’ style (on Android). I had been using it to clip the corners of my container View so that the border radius applied to the entire component, but instead I now just have the border radius style on every View in my component.
I have a similar issue, latest RN (0.54) and no overflow: “hidden”
used.
Was hopping the new release will cure that, but it seems it's not the case.
0.55.2 the same works fine on ios
I was able to get overflow: 'hidden'
to work by also adding the style zIndex: 1
to the same element. It seems #3198 was closed.
Apart from child View
s with borders not rotating, the rotated View
's own border is misbehaving too.
Before rotation:
After a 45deg rotation:
This is on 55.3
Just a comment so the facebook bot doesn't mark this as stale
Hey @brunolemos!
Your problem reproduces on React Native ~0.55.2. As evidence, here's a screenshot:
But I also ran your code against React Native master and saw that the rounded border rendering has been fixed. Screenshot:
However, it still looks like clipping is broken (with rounded borders).
Code: https://snack.expo.io/Hyc6HMPxX
Edit: I did some digging around and narrowed it down to the canvas.clipPath
call inside ReactViewGroup.drawdispatchOverflowDraw
. Clipping works perfectly fine if I zero all the radii and use canvas.clipPath. However, if I leave the radii non-zero, it fails. An interesting consequence is that when borderWidth
> borderRadius
, clipping works correctly (because the clipped rectangle won't be rounded at that point).
I'll look into this a bit further.
Yup, so this wasn't a React Native issue; it was an AOSP bug. I just tested clipping in API 26, API 27, and API 28, and verified that it was broken in API 26, and 27, but was working in API 28.
Code: https://snack.expo.io/Skj_iWjxX
React Native v0.55.0 running on my S8 (Android 8.0, API 26):
React Native master, running on API 28 emulator:
So, rounded border rendering works as expected under transformations. Also, clipping works as expected for sufficiently new devices. @hramos, can we close this issue?
@rsnara can we close this issue?
Everything worked fine on react-native@0.49.5
and got broke on 0.51
, so clearly there is some fix to be made here. Unless the fix is released on npm I don't see why this issue should be closed.
Why would you close if everything worked fine on react-native@0.49.5 and got broke on 0.50+? Unless the fix is released on npm I don't see why a bug should be closed.
From my understanding, there were two problems here.
overflow: hidden
for views with non-rounded borders. I'm not completely sure about the history of borders and overflow: hidden
in React Native, but I just tried v0.49.5 and overflow: hidden
doesn't work at all. Child views render on top of their parent's borders, but are clipped to the outer edge of their parent regardless of the overflow
property.
This clipping algorithm worked perfectly fine for rotated views. However, when it was extended to account for rounded borders, it broke due to what I think was an AOSP bug. Whatever the probem was, it was resolved in the latest release of Android. So really, overflow: hidden
is the only thing that's presently broken. Specifically, I think it's broken whenever the inner border edge has a curved corner, which happens when borderRadius > borderWidth
. This problem also only occurs on Android API < 28.
From where I stand, I see two options:
borderWidth
> borderRadius
or to not use borders. This is a bit of a bummer, I know. overflow:hidden
on android devices running API < 28. Maybe this involves adding a nested view so the contents of the border are clipped to the outer edge of the inner view. Or maybe, there's---there probably is---a better solution. I'm really not sure. (What I do know is that we have to be careful about view hierarchy depth on older Android devices, because they can easily run into stack overflow errors. So, maybe the multi-layer solution isn't the best idea?)Previously, I was leaning more toward the first option. That's why I suggested that we should close this issue. But now that I think about it a bit more, I'm not sure what the best approach is. Any thoughts, @shergin?
Edit 1: I'll do some more thorough testing and see if things actually are working.
Edit 2: Hmm.... so it looks like API 28 works perfectly for all cases I've tried, but with borders whose width is specified using border(Top|Left|Bottom|Right)Width
, devices running API 27 and below don't render rotated borders correctly. Sigh...
I've got the same issue. borderRadius doesn't play nice with Animation.
Tagged as a regression so the bot does not close this due to staleness. Thanks @rsnara for the writeup. 0.56.0-rc
should have the fixes you mentioned.
i have a issue when use transform:[{ rotate:'45deg' }]
in react native 56
Closing now that 0.56 has been on npm for a while.
Still seeing this in 0.57 on Android. iOS works fine as originally noted.
@johnyoonh can you open a new issue? This is marked as fix, so we'd need to get more details from you in order to determine if this is the same issue or something else.
I also still have this issue on some devices. Working fine on Android 6.0.1 but not on 8.1.0. Using RN 0.59.4
I also still have this issue on Android 8.0.0(honer EMUI 8.0.0) when i use "overflow:'hidden'" and " transform: [{ rotate: "45deg" }]". It's normal when i use transform-rotate alone.
React And ReactNative Version: "react": "16.8.1", "react-native": "0.59.5",
so why is this closed ? as this clearly still happens. I assume the RN implementation uses clipChildren=true
when a borderRadius
is specified in the Style, and this causes the above mentioned issue.
Im not sure whether it is an Android or React Native issue, but here is what is working using RN 0.59.8: Android 21 - Fine Android 22 - Fine Android 23 - Fine Android 24 - Not working Android 25 - Not working Android 26 - Not working Android 27 - Not working Android 28 - Not working Android Q - Fine
Based on @tominou ‘s table above, this is an OS bug? If that’s the case, is the best option to document this properly with a PR that includes the above table?
Is there any workaround for this? Currently facing it myself on Android 28 and haven't found any success in my searches for a fix.
We are also running into this issue. Tried removing individual border radius widths and sizes, however that breaks specifying different border radius colours for each side on the affect platforms.
Changing this:
const AStyledView = styled.View`
border-top-width: 8;
border-bottom-width: 8;
border-right-width: 8;
border-left-width: 8;
border-top-right-radius: 50;
border-top-left-radius: 50;
border-bottom-left-radius: 50;
border-bottom-right-radius: 50;
border-right-color: yellow;
border-top-color: yellow;
border-left-color: transparent;
border-bottom-color: transparent;
transform: rotateZ(45deg);
`;
To this:
const AStyledView = styled.View`
border-width: 8;
border-radius: 50;
border-right-color: yellow;
border-top-color: yellow;
border-left-color: transparent;
border-bottom-color: transparent;
transform: rotateZ(45deg);
`;
Breaks the separate border colours, they are all black on android. Works on iOS.
Still seen at 0.61.5 and Android SDK 25, but not seen at Android SDK 29, seems using overflow: 'visible'
for the parent view could solve the problem.
I'm trying to prepare a pull request to fix this, would be happy to receive your advice. I think this was caused from: https://github.com/facebook/react-native/blob/b81c8b51fc6fe3c2dece72e3fe500e175613c5d4/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java#L809-L823
Changing the code fixed the issue diplayed in the comment from @RSNara. Issue would reproduce as from your screenshot above. The result is displayed below.
The radii
array of floats [X,Y]
for each corner of the square are the radius distance used to draw the corner. The path
is a square with rounded corners used to clip the canvas available for drawing.
In the below example the clipped Canvas
is displayed in red while the rectangle
displayed in the Canvas
is displayed in blue. If we set [X,Y]
to [0,0]
, we fix this as we do not crop corners (but it is not the solution).
I believe the clipping is caused by using the wrong [X,Y]
values. The [X,Y]
values should be the same used to draw the parent corners.
Issues that I found till now: FIRST-ISSUE: The borderRadius is converted from DPI to Pixels while the original value is in Pixels: https://github.com/facebook/react-native/blob/673cbb3110855c45beb7e340b61e7daf927d9ade/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java#L107-L114
SECOND-ISSUE: I don't see any logic to transform
the mPath
and give it the -10dg
rotation before clipping. I applied the transformation, but seems to not fix the problem. Removing the transform from the View
fixes the problem, so I believe this is connected to transform and clip.
https://github.com/facebook/react-native/blob/b81c8b51fc6fe3c2dece72e3fe500e175613c5d4/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java#L822
THIRD-ISSUE: The issue is caused by using addRoundRect
or drawing the path with lineTo
and quadTo
. The problem is not experienced when using addRect
or removing the rounded corners.
Related Issue https://github.com/facebook/react-native/issues/3198
Unluckily the issues seems to be more complex from my superficial analysis. It may be connected to drawing and clipping shapes with rounded borders with ReactViewBackgroundDrawable
.
canvas.drawRect()
paints the yellow background of the small rectangle
The border is drawn using drawRect
This logic breaks with transform
rotation. Thanks for reading.
The issue is caused from the canvas cropping on a LAYER_TYPE_NONE
on Android Sdk 24-28. Adding the below code to ReactViewGroup.java
fixes the issue. I am preparing a pull request.
// Disable Hardware Accelleration on Views with property overflow hidden
// for SDK 24-28 https://github.com/facebook/react-native/issues/18266
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
&& Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
setLayerType(View.LAYER_TYPE_HARDWARE, null);
}
before canvas.clipPath(mPath)
Result in the example from @RSNara comment before and after the fix.
The issue was caused from clipping
the view that had property overflow: 'hidden'
and LAYER_TYPE_NONE
, in specific drawing an area (mPath
) to crop the canvas from the before mentioned view using a method called addRoundRect
, which would not take in consideration the view rotation previously applied with view.setRotation()
The original expo snack posted from @brunolemos does not reproduce anymore on react-native master, but the issue in the above example from @RSNara still reproduces.
The issue and solution was tested on Physical Devices and Emulators running Android Sdk 24-29, my pull request will explicitly set the layerType
for View
s with property overflow: 'hidden'
on devices running Android 24-28 and avoid this issue.
I am preparing the pull request. Thanks a lot for reading this message :smiley:
This happened in react-native 0.61.0. When set rotate and border Radius and overflow hidden to the parent, the child works fine, but when I set background color to children, parent border radius does not work.
Same shit different day😭
The same problem was found on Samsung S8.
So what the hell shall we do? :/ It's 2021 for God's sake
You could try fixing this by using prop rendertohardwaretextureandroid
with value of true
https://reactnative.dev/docs/view#rendertohardwaretextureandroid
Whether this View should render itself (and all of its children) into a single hardware texture on the GPU.
On Android, this is useful for animations and interactions that only modify opacity, rotation, translation, and/or scale: in those cases, the view doesn't have to be redrawn and display lists don't need to be re-executed. The texture can be re-used and re-composited with different parameters. The downside is that this can use up limited video memory, so this prop should be set back to false at the end of the interaction/animation.
My pr would just enable hardware accelleration on that view after applying the border radius, but you could solve this issue by enabling hardware accelleration on the view in Javascript for Android API N till P
the prop allows you to call setLayerType(HARDWARE)
on each React View
.
https://github.com/facebook/react-native/issues/29312#issuecomment-892405146
You could try fixing this by using prop
rendertohardwaretextureandroid
with value oftrue
https://reactnative.dev/docs/view#rendertohardwaretextureandroid
Whether this View should render itself (and all of its children) into a single hardware texture on the GPU.
On Android, this is useful for animations and interactions that only modify opacity, rotation, translation, and/or scale: in those cases, the view doesn't have to be redrawn and display lists don't need to be re-executed. The texture can be re-used and re-composited with different parameters. The downside is that this can use up limited video memory, so this prop should be set back to false at the end of the interaction/animation.
My pr would just enable hardware accelleration on that view after applying the border radius, but you could solve this issue by enabling hardware accelleration on the view in Javascript for Android API N till P
the prop allows you to call
setLayerType(HARDWARE)
on each ReactView
.
Hi thanks for informing us about this, Looks like your pr isn't merged yet, also would you mind talking about the limitations? Docs are a little unclear. It says turn this off before animation because you can use a limited amount of video memory, we only need it when we have the animation otherwise what's the point?
I reply to @Stevemoretz comment on my post https://github.com/facebook/react-native/issues/18266#issuecomment-892405169
this prop should be set back to false at the end of the interaction/animation.
You just need to enable hardware accelleration for the duration of the animation on the View, as tested in my pr https://github.com/facebook/react-native/pull/28881 it fixes this issue.
you only apply this change for a limited number of Android APIs (from n till p)
CLICK TO OPEN TESTS RESULTS
The solution uses [`setLayerType`](https://developer.android.com/reference/android/view/View#setLayerType(int,%20android.graphics.Paint)) to change the layer to [`LAYER_TYPE_HARDWARE`](https://developer.android.com/reference/android/view/View#LAYER_TYPE_HARDWARE). `setLayerType` specifies the type of layer backing this view. The change is applied only to Views with overflow hidden running on sdk 24-28. The below screenshots are from `RNTester` transformation examples. The screenshot on the left displays how the `clipPath` method crops incorrectly using a `Path` shape without the `transform: { rotate: "30deg" }` effect. The `View` is cropped as if no rotation was applied. The screenshot on the right displays the result after implementing the patch. | **BEFORE** | **AFTER** | |:-------------------------:|:-------------------------:| | | | The below tests performed with `RNTester` Animated examples do not identify any issue when running animations. Gif image quality was reduced to respect github upload limits. Thanks a lot. :smiley: Fabrizio Bertoglio
I reply to @Stevemoretz comment on my post #18266 (comment)
this prop should be set back to false at the end of the interaction/animation.
You just need to enable hardware accelleration for the duration of the animation on the View, as tested in my pr #28881 it fixes this issue.
you only apply this change for a limited number of Android APIs (from n till p)
CLICK TO OPEN TESTS RESULTS The solution uses
setLayerType
to change the layer toLAYER_TYPE_HARDWARE
.setLayerType
specifies the type of layer backing this view.The change is applied only to Views with overflow hidden running on sdk 24-28.
The below screenshots are from
RNTester
transformation examples.The screenshot on the left displays how the
clipPath
method crops incorrectly using aPath
shape without thetransform: { rotate: "30deg" }
effect. TheView
is cropped as if no rotation was applied. The screenshot on the right displays the result after implementing the patch.BEFORE AFTER The below tests performed with
RNTester
Animated examples do not identify any issue when running animations. Gif image quality was reduced to respect github upload limits. Thanks a lot. 😃 Fabrizio Bertoglio
It sounds great but a couple of questions what happens for sdks below 24 and it could be great if you provided a code example, I don't exactly get how to do this use a state and change it before and after animation starts and ends?
Also when do you think your pr get merged?
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.
The issue still persists in React Native 0.73. The solution is to set the renderToHardwareTextureAndroid
prop to true
.
When rotating a component, its children also rotate as expected, except for the
View
s withborderRadius > 0
, which their rounded border does not rotate.Environment
Environment: OS: macOS High Sierra 10.13.3 Node: 8.9.0 Yarn: 1.5.1 npm: 5.7.1 Watchman: 4.9.0 Xcode: Xcode 9.2 Build version 9C40b Android Studio: 3.0 AI-171.4443003
Packages: (wanted => installed) react: ^16.3.0-alpha.1 => 16.3.0-alpha.1 react-native: ^0.54.0 => 0.54.0
Expected Behavior
Borders should rotate like everything else.
Actual Behavior
Steps to Reproduce
[ANDROID] https://snack.expo.io/@brunolemos/react-native---border-radius-rotate-bug
Full Code
```jsx import React, { Component } from 'react'; import { Image, Text, View, StyleSheet } from 'react-native'; import { Constants } from 'expo'; export default class App extends Component { render() { return (Investigating + Related
After more investigation this is what I found:
rotate + borderRadius > 0 + overflow:hidden
bug introduced on 0.50.0; (https://github.com/facebook/react-native/commit/30044fd531c22c4c5e8f1ede206fa7c2c3fd3aa8?)rotate + borderRadius > 0 + borderWidth > 0
bug introduced on 0.51.0; (https://github.com/facebook/react-native/commit/4994d6a389b4e41ba25e802edab5d3fdc9e8a4f1?)Possibly related: