How to Make View Filled in at Certain Intervals? - css

I am currently attempting to create a bar that fills in based on arrays of numbers that are fed to it out of 1440 (for minutes in a day). For instance, if [3, 400] was inputted, the view would fill in the area corresponding to 3-400 minutes with some color.
I'm not sure where to start here, since the only idea I have had is to fill the parent view with 1440 other views which I can then fill based on the input, which certainly would not be a great idea. Any help would be much appreciated.

I think I figured it out. This was my solution:
import React from 'react'
import { StyleSheet, View, Text } from 'react-native'
export default function TimeAvailabilityIndicator() {
const testArray = [[130, 210], [1000, 1300], [500, 800]]
const minuteToPercentageConverter = (minute) => {
return (minute * 100) / 1440
}
return (
<View style={styles.parentView}>
{testArray.map(time => {
return <View
style={{
position: 'absolute',
left: minuteToPercentageConverter(time[0]) + '%',
right: (100 - minuteToPercentageConverter(time[1])) + '%',
height: 16,
backgroundColor: 'red'
}}
/>
})}
</View>
)
}
const styles = StyleSheet.create({
parentView: {
borderColor: 'black',
borderWidth: 2,
height: 20,
marginTop: 10,
position: 'relative'
}
})

Related

How do i dynamically resize buttons in a row based off the number of buttons in a row in React Native

I'm currently trying to dynamically display different rows of buttons that are evenly spaced out from each other. In my code, two rows have five buttons each, and the third row has only two buttons. Since both buttons are being created using the same component, I was wondering if there was any CSS to help me do this properly.
Currently, here is the code for my the button component:
const NodesOptionButton = (props) => {
const styles = StyleSheet.create({
bold: {
fontWeight: '800',
},
textWrapper: {
width: 60,
height: 60,
borderWidth: 1,
borderStyle: 'solid',
borderColor: '#000',
padding: 12,
marginVertical: 8,
backgroundColor: props.isActive ? '#000' : '#fff',
alignItems: 'center',
justifyContent: 'center',
},
activeTextColor: {
color: '#fff',
}
});
And I'm rendering the three rows of button through this code:
const NPage = (props) => {
const styles = StyleSheet.create({
nodeOptionsContainer: {
flexDirection:'row',
backgroundColor:'red',
display: 'flex',
justifyContent: 'space-evenly',
},
});
//lots of code with logic
return (
<React.Fragment>
<View style={styles.nodeOptionsContainer}>
{nodeNumberOptions}
</View>
<View style={styles.nodeOptionsContainer}>
{clincallyOccultOptions}
</View>
<View style={styles.nodeOptionsContainer}>
{MSIOptions}
</View>
</React.Fragment>
)
Is there any suggestions, or would I have to create a new component for that specific button? Thanks!
You want the two last buttons to take up the whole row? You can always try to add:
flex-grow: 1
to your button component.
If you want your buttons to always take up the whole row, you should just need to add flex: 1 to your Button component root View, and you don't need space-evenly in the parent.
If that's not the case, maybe you should post a pic of the desired design and the current design with problem. It helps understand.
p.s: another tip for performance...define your style outside your component.

What is the proper way to change only one element in in css but the others remains

I have an element has these CSS properties, applied with Stylesheet option of react-native
const styles = StyleSheet.create({
card: {
marginTop: 30,
marginLeft: 50,
marginRight: 50,
padding: 20,
backgroundColor: '#74C8AF',
borderRadius: 10,
flex: 1,
flexDirection: 'column',
},
})
I want to implement this "card" property to all my cards but just want to alter only backgroundColor property unique to each card. Is there any way to handle this just in one card object, without setting different card objects for each individual?
I tried to change style like this but it discards whole object and only applies backgroundcolor
<Card style={styles.card, {backgroundColor:"#9932cc"}}>
//...
</Card>
use like this
<Card style={[styles.card, {backgroundColor:"#9932cc"}]}>
instead of
<Card style={styles.card, {backgroundColor:"#9932cc"}}>
I usually do something along the lines of:
<View style={this.jewelStyle()} />
jewelStyle = function(options) {
return {
borderRadius: 12,
background: randomColor(),
}
}
Every time View is rendered, a new style object will be instantiated with a random color associated with it. Of course, this means that the colors will change every time the component is re-rendered, which is perhaps not what you want. Instead, you could do something like this:
var myColor = randomColor()
<View style={jewelStyle(myColor)} />
jewelStyle = function(myColor) {
return {
borderRadius: 10,
background: myColor,
}
}

How to use percentage padding top and bottom in React Native?

I am trying to achieve dynamic padding top and bottom. I am aware that paddingTop and paddingBottom with % will use the width of the container and I am fine with that.
Unfortunately when I do set the paddingTop to any value with %, it sets the paddingBottom to the same value. Basically paddingTop: '5%', paddingBottom: '0%' will give me equal 5% paddings on both sides.
If I set paddingBottom to any % value - it's just being added to the value that came form the top. So: paddingTop: '5%', paddingBottom: '10%' results in paddingBottom equal to 15%...
I checked the same solution in a web project and there it works as expected.
The snack presenting the problem:
https://snack.expo.io/BJ9-2t8LB
The problem is on both Android and iOS.
How to solve it?
Apply the value to the child container to be applied, not to the parent container.
I have modified the answer according to the conditions you want. You should send Bottom's territory to the parent's container. Because they interact with each other in their child's container, they must be independent.
import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
export default class App extends React.Component {
render() {
return (
<View style={styles.wrapper}>
<View style={styles.inner}>
<View style={{ backgroundColor: 'yellow' }}>
<Text>TOP</Text>
</View>
</View>
<View style={{ backgroundColor: 'red', }}><Text>BOTTOM</Text></View>
</View>
);
}
}
const styles = StyleSheet.create({
wrapper: {
flex:1,
paddingLeft: 24,
paddingRight: 24,
backgroundColor: 'green',
paddingBottom:"5%"
},
inner: {
flex:1,
justifyContent: 'space-between',
backgroundColor: 'blue',
marginTop:"10%"
},
});
That is strange behavior, you should bring it up as an issue to react-native.
In the meantime, a workaround would be applying marginTop and marginBottom to the inner View, instead of paddingTop and paddingBottom to the wrapper View.
const styles = StyleSheet.create({
ayz:{
marginTop:"15%",
backgroundColor:'pink',
alignItems:'center',
justifyContent:'center',
},
asd:{
color:'white',
fontSize:50,
fontWeight:'bold'
}
});

Custom shape for border radius image in React-Native

I want to reproduce that style in my component (the border bottom).
I am basically loading a rectangular image, then I want to rounded it at the bottom.
I think about :
border-bottom-right-radius and left, but it is not accurate with the custom shape of the screen.
transform scaleX, but it scale the image proportion (obviously)
create a white image with the custom shape and load it at the bottom of the screen, but I want to add a shadow at the bottom of the image... With a white image I could not do that...
Is there a way to do that in a proper style with React-Native ?
Thank you !
This is possible, but it's a little tricky. The idea is you need to create a "mask" of sorts that you can apply the shape to. After doing that you can put the image as a child of the mask element so that it will essentially mask the area you want. It's probably possible to do it with a dynamic size, but I didn't take the time to come up with that solution, i'll leave that to you ;)
Hopefully this'll get you going in the right direction though.
First lets setup the app structure
class App extends Component {
render() {
return (
<View style={styles.app}>
<Mask />
</View>
);
}
}
Pretty straightforward, just a basic app with a mask component. I made it a component so you can pass props to it in the future (like the image uri for instance).
Then the mask component
const logoUri = `http://66.media.tumblr.com/86b941b3445b80a518ea51208f48ab35/tumblr_ntpi99a6Pl1uounv1o1_500.png`;
const Mask = (props) => (
<View style={styles.maskContainer}>
<View style={styles.mask}>
<Image
source={{ uri: logoUri }}
style={styles.img}
/>
</View>
</View>
)
The maskContainer is a positioning element to help center the image.
The mask uses the oval style approach but to get the edges to not round like border radius, we have to scale it 2x
The img style needs to reverse the scaling so that the image itself is not warped :)
const styles = StyleSheet.create({
app: {
marginHorizontal: "auto",
maxWidth: 500,
backgroundColor: "#e0e0e0",
width: 700,
height: 700
},
mask: {
width: 200,
height: 470,
borderBottomLeftRadius: 100,
borderBottomRightRadius: 100,
overflow: "hidden",
transform: [{ scaleX: 2 }]
},
img: {
height: 470,
width: 299,
left: 25,
position: "absolute",
transform: [{ scaleX: 0.5 }, { translate: "-50%" }]
},
maskContainer: {
position: "absolute",
left: "50%",
transform: [{ translate: "-50%" }]
}
});
See it working on this fiddle!
#John Ruddell's answer is very helpful.
I am able to design this by creating a mask and applied through SVG path. So, you need to install 2 libraries.
react-native-svg (expo install react-native-svg)
react-native-masked-view (npm install --save #react-native-community/masked-view)
Following code respect the aspect ratio of image. So, you need the set the aspect ratio of your image and adjust the value of curveAdjustment in order to achieve your desired sharpness of curve.
import React from "react";
import {
Image,
View,
StyleSheet,
Text,
useWindowDimensions,
} from "react-native";
import MaskedView from "#react-native-community/masked-view";
import Svg, { Path } from "react-native-svg";
const logoUri = `http://66.media.tumblr.com/86b941b3445b80a518ea51208f48ab35/tumblr_ntpi99a6Pl1uounv1o1_500.png`;
function SplashScreen(props) {
const windowWidth = useWindowDimensions().width;
const imageAspectWidth = 375;
const imageAspectHeight = 332;
const curveAdjustment = 40;
const maskHeight = (imageAspectHeight / imageAspectWidth) * windowWidth;
const scaleFactor = imageAspectWidth / imageAspectHeight;
const scaledHeight = scaleFactor * maskHeight;
const controlPointX = windowWidth / 2.0;
const controlPointY = scaledHeight + curveAdjustment;
const curveCenterPointY = (controlPointY - maskHeight) / 2;
return (
<View style={styles.main}>
<MaskedView
style={[
styles.mask,
{
height: controlPointY - curveCenterPointY,
},
]}
maskElement={
<Svg height="100%" width="100%">
<Path
d={`M0 0 L${windowWidth} 0 L${windowWidth} ${maskHeight} Q${controlPointX} ${controlPointY} 0 ${maskHeight} Z`}
fill={"#fff"}
/>
</Svg>
}
>
<Image source={{ uri: logoUri }} style={styles.image} />
</MaskedView>
<Text>{"Tag line"}</Text>
</View>
);
}
const styles = StyleSheet.create({
image: {
flex: 1,
resizeMode: "stretch",
},
main: {
flex: 1,
},
mask: {
backgroundColor: "orange",
width: "100%",
},
});
export default SplashScreen;
Final result
Yep. clip-path property!
Just add:
clip-path: circle(69.3% at 50% 30%)
To your class and it will work.
if you want to create it yourself, there's a generator here:
https://bennettfeely.com/clippy/

React Native - why padding does not work?

Why padding never works in React Native? I have 10px padding in the image and the text box below:
const styles = StyleSheet.create({
container: {
marginTop: 75,
alignItems: 'center'
},
image: {
width: 107,
height: 165,
padding: 10,
backgroundColor:'blue'
},
description: {
padding: 20,
margin: 10,
fontSize: 15,
color: '#656565',
backgroundColor:'red'
}
});
Result:
Any ideas why? Did I miss something?
Use this for padding:
function padding(a, b, c, d) {
return {
paddingTop: a,
paddingRight: b ? b : a,
paddingBottom: c ? c : a,
paddingLeft: d ? d : (b ? b : a)
}
}
In practice
<Text style={{...padding(10, 20, 10, 5), color: "black"}}>Some text</Text>
Android with React Native tends to not like padding, unless it has a border. A temporary fix would be to change all of your "paddingXXX" to "marginXXX" to get the approximate styling you want.
const styles = StyleSheet.create({
container: {
marginTop: 75,
alignItems: 'center'
},
image: {
width: 107,
height: 165,
margin: 10,
backgroundColor:'blue'
},
description: {
margin: 30,
fontSize: 15,
color: '#656565',
backgroundColor:'red'
}
});
It's a really bad workaround, but I have yet to see a concise fix to it. As far as I know, there is an issue on the Git repo but hasn't been fixed yet.
padding issue for android is fixed in react-native v0.31.0 version.
for more details you can go to react-natvie release changelog https://github.com/facebook/react-native/releases
Another factor to consider is flexbox being used everywhere. Flexbox can take away bottom padding from what I have found, so wrapping in another View might be necessary.
referring to https://stackoverflow.com/a/55724273/12962610 answer
improved version:
export const padding = (a, b, c, d) => ({
paddingTop: a,
paddingRight: b ?? a,
paddingBottom: c ?? a,
paddingLeft: d ?? b ?? a,
})
Padding in react native only accepts a number and not any other character.
Eg:
<TextInput placeholder="Enter Text" style={{padding: 30}} />
Similar to https://stackoverflow.com/a/55724273, but can be done in a more concise manner with default arguments.
/**
* Padding utility function that mimics padding syntax in web
* https://developer.mozilla.org/en-US/docs/Web/CSS/padding
*/
export function padding(
top: number | string | null,
right: number | string | null = top,
bottom: number | string | null = top,
left: number | string | null = right
) {
return {
paddingTop: top ?? undefined,
paddingRight: right ?? undefined,
paddingBottom: bottom ?? undefined,
paddingLeft: left ?? undefined,
};
}
<Text>
{` ${description} `}
</Text>
Adding space before and after like above helped me in most cases. Very helpful when you have nested 'Text' tags.
Use this for padding:
<View style={styles.textPadding}>
<Text>balablabla</Text>
</View>
textPadding: {
color: '#fff',
fontSize: 25,
fontWeight: 'bold',
backgroundColor: "#FFA679",
paddingVertical: 20,
paddingHorizontal: 20,
textAlign: "center"
},
If You are having issues and using margin is not an option, consider replacing View with Button or some other component that fixes the problem for You.
I am using ReactXP and for some reason, using Styles.createButtonStyle with ReactXp's Button worked, and Styles.createViewStyle with View did not.
Padding in react native only accepts a number and not any other character.
Eg:
<TextInput placeholder="Enter Text" style={{padding: 30}} />
I have solution for your problem. Try this:
<Text>
<View style={{padding: 20, backgroundColor: 'red'}}>
<Text style={{color: 'white'}}>Description</Text>
</View>
</Text>

Resources