scaleX doesn't use same dp as width
Description
This
<View style={{width: w}} />
doesn't always equal
<View style={{width: 1, transform: [{scaleX: w}, {translateX: w/2}]}} />
Width isn't always the same. (translateX is a side thing to mimic origin right)
From testing: When Pixel density is 2 on iPhone, iPad, Android tablet/phone: width === scaleX When Pixel density is 1.5, 1.8: width !== scaleX
Which means width is using density-independent pixels, but scaleX isn't?
I've managed to fix this with
// If pixel ratio is 1.5, it's 75% of pixel ratio 2
// w * 0.75
const ratioDiff = PixelRatio.get() / 2;
<View style={{width: 1, transform: [{scaleX: w * ratioDiff}, {translateX: w/2}]}} />
This was only validated on android devices with pixel ratio of 1.5 and 1.88. Will this work for 2+ pixel ratio's?
React Native Version
0.72.5
Output of npx react-native info
System:
OS: macOS 13.5
CPU: (12) arm64 Apple M2 Max
Memory: 64.88 MB / 32.00 GB
Shell:
version: "5.9"
path: /bin/zsh
Binaries:
Node:
version: 20.8.0
path: ~/.nvm/versions/node/v20.8.0/bin/node
Yarn:
version: 1.22.19
path: /usr/local/bin/yarn
npm:
version: 10.1.0
path: ~/.nvm/versions/node/v20.8.0/bin/npm
Watchman:
version: 2023.10.02.00
path: /opt/homebrew/bin/watchman
Managers:
CocoaPods:
version: 1.13.0
path: /usr/local/bin/pod
SDKs:
iOS SDK:
Platforms:
- DriverKit 23.0
- iOS 17.0
- macOS 14.0
- tvOS 17.0
- watchOS 10.0
Android SDK: Not Found
IDEs:
Android Studio: 2022.3 AI-223.8836.35.2231.10811636
Xcode:
version: 15.0/15A240d
path: /usr/bin/xcodebuild
Languages:
Java:
version: 11.0.20.1
path: /usr/bin/javac
Ruby:
version: 3.2.2
path: /Users/gregoirevda/.rbenv/shims/ruby
npmPackages:
"@react-native-community/cli": Not Found
react: Not Found
react-native: Not Found
react-native-macos: Not Found
npmGlobalPackages:
"*react-native*": Not Found
Android:
hermesEnabled: Not found
newArchEnabled: Not found
iOS:
hermesEnabled: Not found
newArchEnabled: Not found
Steps to reproduce
Compare both output on devices with pixel density !== 2
<View style={{width: 100, height: 100, backgroundColor: 'red'}} />
<View style={{height: 100, width: 1, backgroundColor: 'green', transform: [{scaleX: 100}, {translateX: 50}]}} />
Snack, screenshot, or link to a repository
https://snack.expo.dev/@gregoirevda/pixel-density-scalex
| :warning: | Newer Version of React Native is Available! |
|---|---|
| :information_source: | You are on a supported minor version, but it looks like there's a newer patch available - 0.72.6. Please upgrade to the highest patch for your minor or latest and verify if the issue persists (alternatively, create a new project and repro the issue in it). If it does not repro, please let us know so we can close out this issue. This helps us ensure we are looking at issues that still exist in the most recent releases. |
After testing on ldpi, mdpi, hdpi, xhdpi and xxhdpi I realised width !== scaleX only when pixel density is a decimal (could only find decimal dpi on android)
I've changed
const ratioDiff = PixelRatio.get() / 2;
to
const pixelRatio = PixelRatio.get();
const pixelRatioRounded = Math.round(pixelRatio);
const ratioDiff = pixelRatio / pixelRatioRounded;
When running this
const width = 200;
return <View style={{marginLeft: 100, marginTop: 100}}>
<View style={{width: width, height: 100, backgroundColor: 'red'}} />
<View style={{height: 100, width: 1, backgroundColor: 'green', transform: [
{translateX: width/2},
{ scaleX: width }
]}} />
<View style={{height: 100, width: 1, backgroundColor: 'pink', transform: [
{translateX: width/2},
{ scaleX: width * ratioDiff }
]}} />
<Text>{PixelRatio.get()}</Text>
</View>
You notice that the 3th option (pink) always equals the width (red)
@Gregoirevda this worked perfectly, thank you!