Reputation: 334
I'm trying to create a dashboard layout from a react-native project. The idea is to keep most of the code similar for Android, iOS and Web only the layout or navigation style will change. But I find making this type of layout in web is easy but to make it responsive without re-rendering is difficult.
I have achieved this by manually calculating the windows heigh and width by following the code
Dimensions.get('window').width
Dimensions.get('window').height
and by eventListener keep updating the state so that it re-renders the whole page again and again.
Dimensions.addEventListener("change", this.updateScreen);
Is there a way I can simply use some % value to fill up the screen. Right now if I use % it squeezed to a child View
size. I even tried flex:1
with alignSelf:stretch
, alignItem:stretch
, width:'100%'
etc but no luck.
For a while, let's talk about center row (image attached) it contain 3 columns. I want left and right block (Menu & Call to Action) to be 300px each. Now if I'm on 1000px width monitor my Content block should be (1000 - (300+300)) 400px. if monitor is 1200px then Content block will be (1200 - (300+300)) 600px.
Upvotes: 3
Views: 1233
Reputation: 2342
I made this exactly for the same reasons:
https://www.npmjs.com/package/react-native-animated-layout
Demos:
Expo snack: https://snack.expo.dev/@mehmetkaplan/react-native-animated-layout
Web demo: https://mehmetkaplan.github.io/react-native-animated-layout/
It takes layouts as inputs and using the Width / Height ratio of the screen, decides which layout to use.
And within each layout, you define top, right, bottom, left of each screen using the coordinates between 0 and 1. (Because browser resizing changes the coordinates of each View and you want views to stay exact relative places.)
import React, { useState, useEffect } from 'react';
import { Text, View } from 'react-native';
import ReactNativeAnimatedLayout from 'react-native-animated-layout';
export default function App() {
const [rerender, setRerender] = useState(0);
const redView = <View style={{ backgroundColor: 'red', height: '100%', width: '100%', }}><Text>{"I am the red view"}</Text></View>;
const greenView = <View style={{ backgroundColor: 'green', height: '100%', width: '100%', overflow: 'hidden'}}>
<Text>{"I am the green view and my contents overflow. Because of the overflow prop, the over-flown content is hidden."}</Text><Text>{"0"}</Text><Text>{"1"}</Text><Text>{"2"}</Text><Text>{"3"}</Text><Text>{"4"}</Text><Text>{"5"}</Text><Text>{"6"}</Text><Text>{"7"}</Text><Text>{"8"}</Text><Text>{"9"}</Text><Text>{"10"}</Text><Text>{"11"}</Text><Text>{"12"}</Text><Text>{"13"}</Text><Text>{"14"}</Text><Text>{"15"}</Text><Text>{"16"}</Text><Text>{"17"}</Text><Text>{"18"}</Text><Text>{"19"}</Text><Text>{"20"}</Text><Text>{"21"}</Text><Text>{"22"}</Text><Text>{"23"}</Text><Text>{"24"}</Text><Text>{"25"}</Text><Text>{"26"}</Text><Text>{"27"}</Text><Text>{"28"}</Text><Text>{"29"}</Text>
</View>;
const blueView = <View style={{ backgroundColor: 'blue', height: '100%', width: '100%', }}><Text>{"I am the blue view"}</Text></View>;
const layouts = [
{
validAfterWHRatio: 0,
validBeforeWHRatio: 0.9,
views: [
{ top: 0, bottom: 0.5, left: 0, right: 1, children: redView },
{ top: 0.75, bottom: 1, left: 0, right: 1, children: blueView },
{ top: 0.5, bottom: 0.75, left: 0, right: 1, children: greenView },
]
},
{
validAfterWHRatio: 1 / 0.62,
validBeforeWHRatio: 999, // infinity
views: [
{ top: 0, bottom: 1, left: 0, right: 0.5, children: redView },
{ top: 0.5, bottom: 1, left: 0.5, right: 1, children: blueView },
{ top: 0, bottom: 0.5, left: 0.5, right: 1, children: greenView },
]
},
{
defaultFlag: true,
views: [
{ top: 0.16, bottom: 0.84, left: 0.16, right: 0.5, children: redView },
{ top: 0.50, bottom: 0.84, left: 0.5, right: 0.84, children: blueView },
{ top: 0.16, bottom: 0.50, left: 0.5, right: 0.84, children: greenView },
]
},
];
useEffect(() => {
let nextRerender = rerender + 1;
setRerender(nextRerender);
}, []); // when we want to re-render
return <ReactNativeAnimatedLayout
layouts={layouts}
rerender={rerender}
/>;
}
Note: This approach may be useful especially for PWAs. If you need to use scroll bars, they should be inside one of the views, probably "the" content view.
Upvotes: 0
Reputation: 1829
I hope this doesn't come too late.
<View style={{ flex: 1 }}>
<View style={{ height: 100, backgroundColor: 'red' }} />
<View style={{ flex: 1, backgroundColor: 'gray', flexDirection: 'row' }}>
<View style={{ width: 100, backgroundColor: 'green' }} />
<View style={{ flex: 1, backgroundColor: 'blue' }} />
<View style={{ width: 100, backgroundColor: 'green' }} />
</View>
<View style={{ height: 100, backgroundColor: 'red' }} />
</View>
This is the result from the above code.
You don't need to do percentage calculations at all; just structure it in 2 layers of flex layout.
For the components that should not stretch, state their width. For the rest, specify the flex value.
If you insist on using 1 layer to handle it all, then we shall discuss again.
Cheers.
Upvotes: 3