Not getting accurate screen height and width with Dimensions in react native - react-native
I am trying to use Dimensions to get device screen height and width.
Below is my code:
return (
<SafeAreaView style={styles.safeAreaView}>
<View style={styles.mainContainer}>
</View>
<View style={styles.footerContainer}>
<Text>Hello</Text>
</View>
</SafeAreaView>
);
And this the style which I am using:
const styles = StyleSheet.create({
mainContainer: {
height: (Dimensions.get('window').height / 100) * 80,
backgroundColor: "blue",
},
footerContainer: {
top: (Dimensions.get('window').height / 100) * 80,
height: (Dimensions.get('window').height / 100) * 20,
width: Dimensions.get('window').width / 100 * 100,
backgroundColor: "yellow",
position: "absolute",
justifyContent: "flex-end"
}
});
OUTPUT
As you can see I am not able to see the <Text>Hello</Text>.
I am doing basic mathematics with (Dimensions.get('window').height / 100) * 80. I am taking total height of the screen, dividing it by hundred and then multiplying the result with the required number: this will give me the percentage height of the screen. I don't want to use flex. I want to go forward with the process which I am following. I just want to know why my Hello text is going below the screen.
It works on some device but not on another. It works in Pixel4 emulator, but not on Pixel3 emulator. If my dimensions calculation is right, then why is it not working on all the devices??
"why is it not working on all the devices??" - this is because Dimensions.get('...').height is currently buggy in Android see this issue.
To get WINDOW_HEIGHT_NO_STATUS_BAR and STATUS_BAR_HEIGHT (so window full height = WINDOW_HEIGHT_NO_STATUS_BAR + STATUS_BAR_HEIGHT)
I used this code:
import { getStatusBarHeight } from 'react-native-status-bar-height'
import { initialWindowMetrics } from 'react-native-safe-area-context'
export const STATUS_BAR_HEIGHT = getStatusBarHeight()
export const WINDOW_HEIGHT_NO_STATUS_BAR = Platform.OS !== 'ios' && Dimensions.get('screen').height !== Dimensions.get('window').height && STATUS_BAR_HEIGHT > 24
? Dimensions.get('screen').height - STATUS_BAR_HEIGHT
: STATUS_BAR_HEIGHT > 24
? Dimensions.get('window').height - STATUS_BAR_HEIGHT
: Dimensions.get('window').height + initialWindowMetrics.insets.bottom === Dimensions.get('screen').height
? Dimensions.get('window').height - STATUS_BAR_HEIGHT
: Dimensions.get('window').height
Related
Setting card height programmatically in React Native
In my React Native app, I want to display cards using simple <View>'s that will have a set height to begin with and display two lines of text. If the text is longer than two lines, I want to display a "more" button which will expand the height of the view to fit all the text when clicked. My question is how to determine/calculate the height? The approach I'm thinking is to use two different style classes and programmatically switch them but I'm not sure how to dynamically figure out the height of the <View> so that all the text would fit into it, however long it may be. const cardStyle = this.props.moreButtonClicked ? "card-long" : "card-std"; return ( <View style={cardStyle}> <Text> { this.props.cardContent.length <= 120 ? this.props.cardContent : this.props.moreButtonClicked ? this.props.cardContent : this.props.cardContent.substring(0, 119) } </Text> </View> ); Specifically, how do I figure out the right height for my card-long style class? Or is there a better approach to handling this? Thanks.
You can determine text height before rendering the text by using this library: https://github.com/aMarCruz/react-native-text-size Here is an example: import rnTextSize, { TSFontSpecs } from 'react-native-text-size' type Props = {} type State = { width: number, height: number } // On iOS 9+ will show 'San Francisco' and 'Roboto' on Android const fontSpecs: TSFontSpecs = { fontFamily = undefined, fontSize = 24, fontStyle = 'italic', fontWeight = 'bold', } const text = 'I ❤️ rnTextSize' class Test extends Component<Props, State> { state = { width: 0, height: 0, } async componentDidMount() { const width = Dimensions.get('window').width * 0.8 const size = await rnTextSize.measure({ text, // text to measure, can include symbols width, // max-width of the "virtual" container ...fontSpecs, // RN font specification }) this.setState({ width: size.width, height: size.height }) } // The result is reversible render() { const { width, height } = this.state return ( <View style={{ padding: 12 }}> <Text style={{ width, height, ...fontSpecs }}> {text} </Text> </View> ) } }
React Native Image component with "{width: 100%, height: auto}" gets dislocated when using margin
I have an Image component that has width from Dimensions.get('window').width, and height that is calculated using this formula: { //not the real code, but it works exactly like this. width: Dimensions.get('window').width, height: actualImageHeight*(Dimensions.get('window').width/actualImageWidth) } It basically closely emulates how width: 100%, height: auto works in css. and it works well until i added margins to it, which causes the image to get dislocated like this: Dislocated Bear I have also tried to use PixelRatio.getPixelSizeForLayoutSize(margin*2) to try taking account the margin, which makes the new formula look like this: { //not the real code, but it works exactly like this. width: Dimensions.get('window').width-PixelRatio.getPixelSizeForLayoutSize(margin*2), height: actualImageHeight*((Dimensions.get('window').width-PixelRatio.getPixelSizeForLayoutSize(margin*2))/actualImageWidth) } and the result is almost, there, but still slightly dislocated: Slightly Dislocated Bear Which makes me think that Dimensions isn't a good reference for width. So how do I emulate width: 100%, height: auto that doesn't use Dimensions? Is it possible to use width: 100% as a reference to use in the formula?
import React from 'react'; import {SafeAreaView,View,Dimensions,Image,} from 'react-native'; const {width, height} = Dimensions.get('window'); const actualImageHeight = 200; const actualImageWidth = 300; const Test = props => { return ( <SafeAreaView style={{flex: 1}}> <View style={{ width: width, height: actualImageHeight * (width / actualImageWidth), borderRadius: 6, borderWidth: 1, borderColor: '#f1f1f1', overflow: 'hidden', backgroundColor: 'red', padding: 12, }}> <Image style={{flex: 1, width: null, height: null}} source={{uri: 'https://picsum.photos/200/300'}} /> </View> </SafeAreaView> ); }; when you place calculated width and height to any view if you place margin in styles it will dislocated the view because while rendering the view margin also considered. Better to wrap image with view.
I still continued the idea of subtracting the width with the margins, and I managed to make it work. Simply by doing Dimensions.get('window').width-(margin*2) will make it work. So final code is: { width: Dimensions.get('window').width-(margin*2), height: actualImageHeight*(Dimensions.get('window').width-(margin*2)/actualImageWidth) } The result: Bears Full code of the component: import React, { useState, useEffect } from "react"; import { Dimensions, Image } from "react-native"; interface AnotherCardProps { thumbnail: string; margin?: number; column?: number; maxHeight?: number; minHeight?: number; } const AnotherCard: React.FC<AnotherCardProps> = (props) => { const [imageSize, setImageSize] = useState({ width: 0, height: 0, ratio: 0 }); const margin = props.margin || 0; const column = props.column || 1; const newWidth = Dimensions.get("window").width / column - margin * 2; const maxHeight = props.maxHeight || newWidth * 1.5; const minHeight = props.minHeight || newWidth; useEffect(() => { Image.getSize(props.thumbnail, (w, h) => setImageSize({ width: w, height: h, ratio: newWidth / w, }) ); }); return ( <Image style={{ borderRadius: 20, margin: margin, flex: 1, width: newWidth, height: imageSize.height * imageSize.ratio < minHeight ? minHeight : imageSize.height * imageSize.ratio > maxHeight ? maxHeight : imageSize.height * imageSize.ratio, resizeMode: "cover", }} source={{ uri: props.thumbnail, }} /> ); }; export default AnotherCard;
React native, view got cut off when rendered in flat list
So, I'm currently working on the react native project, I trying to add a tooltip component which once user tap the item in Flatlist. it will triggered this tooltip that have several options. The problem is now it got cut off even I set the 'position' to be 'absolute' with x,y position. Is there anyway I can overcome this problem? I tried with the zIndex as well, but still not work out. Here is the tooltip component that I implemented. export function Tooltip({ children, x, y, height, width, isVisible = false, component, }: TooltipProps) { const [myWidth, setW] = useState(0) const [myHeight, setH] = useState(0) function onLayout({ nativeEvent: { layout: {width, height}, }, }: LayoutChangeEvent) { setW(width) setH(height) } return ( <View> {children} {isVisible && ( <View onLayout={onLayout} style={{ elevation: 5, borderWidth: 1, backgroundColor: 'white', position: 'absolute', top: (height - componentHeight * 2) / 2 + y, left: (width - componentWidth) / 2 + x, }}> {component} </View> )} </View> ) } Here is the image in the app, (I need to blur out items there, sorry for inconvenience)
Tty to make parent view is SafeAreaView. return(<SafeAreaView><YourComponent/></SafeAreaView>) May be that can help.
React-Native: How to add full screen Lottie animation
I am using linear gradient from lottie, the code is working fine with ios but in android its not fitting to full screen, there is some kind of padding between gradient and the view. On ios its working fine...i tried many ways, buy including padding to 0 and even margin to -20, but nothing worked...any solution? import React, { Component } from 'react'; import { Text, StyleSheet, View, Platform, Dimensions } from 'react-native'; import SignInScreen from './src/screens/auth/SignInScreen'; import Animation from 'lottie-react-native'; import anim from './assets/gradient_animated_background.json'; const height = Dimensions.get('window').height + 20; const width = Dimensions.get('window').width + 20; export default class App extends Component { componentDidMount() { this.animation.play(); } render() { return ( <View style={styles.container}> <Animation ref={animation => { this.animation = animation; }} style={{ backgroundColor: 'red', height: '100%', width: '100%' }} loop={true} source={Platform.OS === 'ios' ? anim : 'gradient_animated_background.json'} /> </View> ); } } const styles = StyleSheet.create({ container: { backgroundColor: 'blue', flex: 1, }, welcome: { fontSize: 20, textAlign: 'center', margin: 10, color: '#ffffff' } }); The animation, and when ever i keep changing the width and height..it forcefully tries to maintain the aspect radio...(not sure though) {"v":"4.6.10","fr":15,"ip":0,"op":155,"w":1080,"h":1920,"nm":"background","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[540,960,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[1160,880]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":0},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect"},{"ty":"st","c":{"a":0,"k":[0.9960784,0.7843137,0.145098,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"gf","o":{"a":0,"k":100},"r":1,"g":{"p":3,"k":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":0,"s":[0,0.511,0.89,0.283,0.5,0.334,0.873,0.583,1,0.156,0.857,0.882],"e":[0,0.726,0.283,0.89,0.5,0.441,0.356,0.886,1,0.156,0.429,0.882]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":31,"s":[0,0.726,0.283,0.89,0.5,0.441,0.356,0.886,1,0.156,0.429,0.882],"e":[0,0.89,0.283,0.283,0.5,0.886,0.553,0.219,1,0.882,0.823,0.156]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":61,"s":[0,0.89,0.283,0.283,0.5,0.886,0.553,0.219,1,0.882,0.823,0.156],"e":[0,0,0.312,0.737,0.5,0.078,0.597,0.754,1,0.156,0.882,0.771]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":91,"s":[0,0,0.312,0.737,0.5,0.078,0.597,0.754,1,0.156,0.882,0.771],"e":[0,0.51,0.89,0.282,0.5,0.333,0.873,0.582,1,0.157,0.855,0.882]},{"t":120}]}},"s":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":0,"s":[-430.769,-404.573],"e":[23.726,-364.48],"to":[75.7491683959961,6.68213844299316],"ti":[-123.915840148926,-8.51547145843506]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":31,"s":[23.726,-364.48],"e":[312.726,-353.48],"to":[123.915840148926,8.51547145843506],"ti":[-1.00208830833435,-1.83333337306976]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":61,"s":[312.726,-353.48],"e":[29.739,-353.48],"to":[1.00208830833435,1.83333337306976],"ti":[120.055290222168,0.60746711492538]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":91,"s":[29.739,-353.48],"e":[-407.606,-357.125],"to":[-120.055290222168,-0.60746711492538],"ti":[72.8907089233398,0.60746711492538]},{"t":120}]},"e":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":0,"s":[374.412,342.611],"e":[22.822,357.191],"to":[-58.5984153747559,2.42986845970154],"ti":[132.520950317383,-7.89707231521606]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":31,"s":[22.822,357.191],"e":[-420.714,389.994],"to":[-132.520950317383,7.89707231521606],"ti":[-4.68509674072266,-7.89707231521606]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":61,"s":[-420.714,389.994],"e":[50.932,404.573],"to":[4.68509674072266,7.89707231521606],"ti":[-132.918350219727,4.25226974487305]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":91,"s":[50.932,404.573],"e":[376.797,364.48],"to":[132.918350219727,-4.25226974487305],"ti":[-54.3107261657715,6.68213844299316]},{"t":120}]},"t":1,"nm":"Gradient Fill 1","mn":"ADBE Vector Graphic - G-Fill"},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[93.29,219.491],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":155,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":2,"ty":1,"nm":"Deep Red Solid 1","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[540,960,0]},"a":{"a":0,"k":[540,960,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"sw":1080,"sh":1920,"sc":"#be2a2a","ip":0,"op":155,"st":0,"bm":0,"sr":1}]}
What you are missing is the resizeMode, which is not specified on the documentation page, but if you look at the source you'll find it. Here's something that works if you don't care to lose a few pixels: import React, { Component } from 'react'; import { StyleSheet, View, Dimensions } from 'react-native'; import LottieView from 'lottie-react-native'; import { anim } from './assets/animation.json'; const { height, width } = Dimensions.get('window') export default class App extends Component { componentDidMount() { this.animation.play(); } render() { return ( <View style={styles.container}> <LottieView ref={animation => { this.animation = animation; }} style={{ width: width + 10, height: height, marginLeft: - 5 }} resizeMode='cover' loop={true} source={anim} /> </View> ); } } const styles = StyleSheet.create({ container: { backgroundColor: 'blue', flex: 1, }, }); Notice that I've exported the asset a bit differently since I tried this on https://snack.expo.io and for some reason they don't like JSON files 😁, so now the assets look something /assets/animation.json.js export const anim = {"v":"4.6.10","fr":15,"ip":0,"op":155,"w":1080,"h":1920,"nm":"background","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[540,960,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[1160,880]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":0},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect"},{"ty":"st","c":{"a":0,"k":[0.9960784,0.7843137,0.145098,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":6},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"gf","o":{"a":0,"k":100},"r":1,"g":{"p":3,"k":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":0,"s":[0,0.511,0.89,0.283,0.5,0.334,0.873,0.583,1,0.156,0.857,0.882],"e":[0,0.726,0.283,0.89,0.5,0.441,0.356,0.886,1,0.156,0.429,0.882]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":31,"s":[0,0.726,0.283,0.89,0.5,0.441,0.356,0.886,1,0.156,0.429,0.882],"e":[0,0.89,0.283,0.283,0.5,0.886,0.553,0.219,1,0.882,0.823,0.156]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":61,"s":[0,0.89,0.283,0.283,0.5,0.886,0.553,0.219,1,0.882,0.823,0.156],"e":[0,0,0.312,0.737,0.5,0.078,0.597,0.754,1,0.156,0.882,0.771]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":91,"s":[0,0,0.312,0.737,0.5,0.078,0.597,0.754,1,0.156,0.882,0.771],"e":[0,0.51,0.89,0.282,0.5,0.333,0.873,0.582,1,0.157,0.855,0.882]},{"t":120}]}},"s":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":0,"s":[-430.769,-404.573],"e":[23.726,-364.48],"to":[75.7491683959961,6.68213844299316],"ti":[-123.915840148926,-8.51547145843506]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":31,"s":[23.726,-364.48],"e":[312.726,-353.48],"to":[123.915840148926,8.51547145843506],"ti":[-1.00208830833435,-1.83333337306976]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":61,"s":[312.726,-353.48],"e":[29.739,-353.48],"to":[1.00208830833435,1.83333337306976],"ti":[120.055290222168,0.60746711492538]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":91,"s":[29.739,-353.48],"e":[-407.606,-357.125],"to":[-120.055290222168,-0.60746711492538],"ti":[72.8907089233398,0.60746711492538]},{"t":120}]},"e":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":0,"s":[374.412,342.611],"e":[22.822,357.191],"to":[-58.5984153747559,2.42986845970154],"ti":[132.520950317383,-7.89707231521606]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":31,"s":[22.822,357.191],"e":[-420.714,389.994],"to":[-132.520950317383,7.89707231521606],"ti":[-4.68509674072266,-7.89707231521606]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":61,"s":[-420.714,389.994],"e":[50.932,404.573],"to":[4.68509674072266,7.89707231521606],"ti":[-132.918350219727,4.25226974487305]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":91,"s":[50.932,404.573],"e":[376.797,364.48],"to":[132.918350219727,-4.25226974487305],"ti":[-54.3107261657715,6.68213844299316]},{"t":120}]},"t":1,"nm":"Gradient Fill 1","mn":"ADBE Vector Graphic - G-Fill"},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[93.29,219.491],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":155,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":2,"ty":1,"nm":"Deep Red Solid 1","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[540,960,0]},"a":{"a":0,"k":[540,960,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"sw":1080,"sh":1920,"sc":"#be2a2a","ip":0,"op":155,"st":0,"bm":0,"sr":1}]}
So the first answer raised an important point (adding resizeMode="cover"). But that's not enough, If you test across several screens sizes, you might still find unwanted margins and spaces. I had this issue too, Here's the simple solution: Get the dimensions of the lottie file (e.g 300 X 600) Set width only, then use aspectRatio to determine the height. (must) Set flexGrow = 1 (must) e.g <LottieView style={{ width: 300, aspectRatio: 300 / 600, flexGrow: 1, alignSelf: 'center', }} resizeMode="cover" ref={animation=> { this.animation = animation; }} source={require ('./assets/animation.json')} autoPlay={false} loop={false} /> I guess the problem arises because you cant use width and height at the same time in the styling of the Lottie view. So an easy workaround is to use the width and aspectRatio Good luck!
Creating CSS circles in react-native
I'm having some trouble creating CSS circles in react-native. The following works in iPhone 6 Plus but in all the other iPhones, they become diamonds. circle: { height: 30, width: 30, borderRadius: 30, } Now if I use PixelRatio on borderRadius it works in everything but iPhone 6 plus. iPhone 6 plus renders it as boxes with rounded corners. circle: { height: 30, width: 30, borderRadius: 30 / PixelRatio.get(), }
Your border radius should be a half of width and your height. like below: circle: { width: 44, height: 44, borderRadius: 44/2 }
None of these fit my needs, if you need a responsive circle you can try using my solution: Step 1: Import Dimensions (and other used elements) from react native (or add to existing imports list) import { Dimensions, TouchableHighlight, Text } from 'react-native'; Step 2: Add your touchable element (you can calculate width or height of a device) <TouchableHighlight style = {{ borderRadius: Math.round(Dimensions.get('window').width + Dimensions.get('window').height) / 2, width: Dimensions.get('window').width * 0.5, height: Dimensions.get('window').width * 0.5, backgroundColor:'#f00', justifyContent: 'center', alignItems: 'center' }} underlayColor = '#ccc' onPress = { () => alert('Yaay!') } > <Text> Mom, look, I am a circle! </Text> </TouchableHighlight> Step 3: Enjoy your responsive circled element
borderRadius should be half the side of the square. So 15 in your case - no matter what pixel ratio the device has. It works with 30 / PixelRatio.get() only for 2x retina devices, cause the result is 15. Then for iPhone 6 Plus, you indeed get a rounded box because the result is 10 (pixel ratio is 3). I'm surprised your saying it worked on iPhone 6 Plus with 30 for a 30x30 square.
If you want to make a circle that will work on any device the only thing that you should do is to give the same height and width the same value and then give the borderRadius a really high value I personally give it 1000 so it will big enough for most of the cases circle :{ height : 30 , width :30, borderRadius: 1000, }
Since borderRadius style expects number as a value you can't use borderRadius: 50%. To make circle all you have to do is use your image width/height and devide it with 2. Read more here: https://github.com/refinery29/react-native-cheat-sheet
Basically just need to apply same height, width and in borderRadius have to divided by 2 E.g. height : 50, width :50 borderRadius : 50/2 Just Circle var circle = { height: 30, width: 30, borderRadius: 15 } Responsive Circle with Device Height var circle = { height: Dimensions.get('window').height * 0.1, width: Dimensions.get('window').height * 0.1, borderRadius: Math.round((Dimensions.get('window').height + Dimensions.get('window').width) / 2) } Responsive Circle with Device Width var circle = { height: Dimensions.get('window').width * 0.1, width: Dimensions.get('window').width * 0.1, borderRadius: Math.round((Dimensions.get('window').height + Dimensions.get('window').width) / 2) } Example Code import React, { useEffect, useState, useRef } from 'react' import { Dimensions, SafeAreaView, StyleSheet, Text, View } from 'react-native' const { height, width } = Dimensions.get('window') function roundOff(v) { return Math.round(v) } function dimensions() { var _borderRadius = roundOff((height + width) / 2), _height = roundOff(height), _width = roundOff(width) return { _borderRadius, _height, _width } } export default function ResponsiveCircle() { return ( <SafeAreaView style={styles.container}> <View style={styles.circleView}> <Text style={styles.text}> Responsive{'\n'}Circle </Text> </View> </SafeAreaView> ) } const commonStyles = { alignItems: 'center', justifyContent: 'center', } const styles = StyleSheet.create({ container: { flex: 1, ...commonStyles }, circleView: { height: dimensions()._height * 0.2, width: dimensions()._height * 0.2, borderRadius: dimensions()._borderRadius, backgroundColor: 'tan', ...commonStyles }, text: { textAlign: 'center', lineHeight: 25, color: 'black', fontWeight: 'bold' } })
I've been using the styled-components package to style my React Native components and the easiest solution I've found is to set the border radius to a size in px larger than half of the width that the circle will ever have. It'll then default to the equivalent of a 50% border-radius for any size smaller than that.
onLayout worked for me. Calculate width and height to maintain 1:1 aspect ratio, then set borderRadius to width/2 const [circleSytle, setCircleStytle] = useState(); ... function calCircleStyle(layoutEvent) { let {width, height} = layoutEvent.nativeEvent.layout; let dim = width > height ? width : height; setCircleStyle({width:dim, height:dim, borderRadius:dim/2}); } Then apply it to your view like this: <View onLayout={calCircleStyle} style={circleStyle}> ... </View> Btw, can anyone explain why borderRadius:1000 is bad?