Icons with gradient colors - react-native

Is there any way I can add gradient colors to Icons in react-native / expo?
I want to make icons like those :

Tried this variant using MaskedView and LinearGradient packages https://github.com/react-native-linear-gradient/react-native-linear-gradient/issues/198#issuecomment-590821900. I use this snippet with Icon from native-base and this solution works perfectly for me.
import React from 'react'
import { Text, View, StyleSheet } from 'react-native'
import Icon from 'react-native-vector-icons/MaterialCommunityIcons'
import LinearGradient from 'react-native-linear-gradient'
import MaskedView from '#react-native-community/masked-view'
const size = 40
export function PowerOff({ ...rest }) {
return (
<View style={{ width: size }} {...rest}>
<MaskedView
style={{ flex: 1, flexDirection: 'row', height: size }}
maskElement={
<View
style={{
backgroundColor: 'transparent',
justifyContent: 'center',
alignItems: 'center',
}}>
<Icon
name="power"
size={size}
color="white"
style={styles.shadow}
/>
</View>
}>
<LinearGradient
colors={['#F7C650', 'rgba(247, 198, 80, 0.71)']}
style={{ flex: 1 }}
/>
</MaskedView>
</View>
)
}
const styles = StyleSheet.create({
shadow: {
shadowColor: 'black',
shadowOpacity: 0.5,
shadowRadius: 5,
shadowOffset: {
width: 0,
height: 1,
},
},
})

Related

Flex is not splitting components equally in react native

I'm trying to make a layout like this:
In order to do so, I've made two components named HalfWidthFullHeightCard and HalfWithHalfHeightCard.
I've created the HalfWidthFullHeightCell component as?
<TouchableOpacity onPress={pressEvent}>
<ImageBackground
source={sourcePath}
imageStyle={{ borderRadius: 8, resizeMode: 'cover', width: '100%' }}
style={styles.halfWidthCard}>
<Text style={styles.halfWidthCardHeading}>{heading}</Text>
<Text style={styles.halfWidthCardText}>{cardText}</Text>
</ImageBackground>
</TouchableOpacity>
...
halfWidthCard: {
backgroundColor: colors.brightYellow,
marginBottom: 10,
borderRadius: 8,
},
Based on the cardText the width of the card is calculated automatically and in the halfWidthCardText StyleSheet I've only had padding: 10
Next for HalfWithHalfHeightCard everything is the same except for the styling which is:
...
smallHalfWidthCard: {
backgroundColor: colors.brightYellow,
borderRadius: 8,
marginBottom: 10
},
smallHalfWidthCardHeading: {
padding: 10,
},
smallHalfWidthCardText: {
padding: 10,
},
Where I'm putting both of these components together I'm doing:
<ScrollView contentContainerStyle={{padding: 15}}>
<View style={{flexDirection: 'row',}}>
<HalfWidthFullHeightCell />
<View>
<HalfWithHalfHeightCell />
<HalfWithHalfHeightCell />
</View>
</View>
</ScrollView>
Now there are two problems:
Consider the gray area as the width of the device. The HalfWidthFullHeightCard takes 100% of the space and
The HalfWithHalfHeightCard are outside of the screen and also not of the same height as HalfWidthFullHeightCard.
So, how can I make these components flexible so that they adapt to the layout as screen size changes?
I would have made it like this
import * as React from 'react';
import { Text, View, StyleSheet, Dimensions } from 'react-native';
const ScreenWidth = Dimensions.get('window').width;
export default function App() {
return (
<View style={styles.container}>
<View style={styles.WholeBox}>
<View style={styles.Block}></View>
<View style={{ flex: 1 }}>
<View style={styles.Block}></View>
<View style={styles.Block}></View>
</View>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
backgroundColor: '#ecf0f1',
},
WholeBox: {
width: ScreenWidth,
height: 300,
flexDirection: 'row',
},
Block: {
flex: 1,
backgroundColor: '#DDA73A',
margin: 6,
borderRadius: 8,
},
});
Working Example Here

How can I force content within modal to be 100% the height of the modal?

I am trying to use flexbox to make the content within a Modalize view go to 100% of the Modal view. Currently, it's only going to the height of the content, and not the modal.
With this code:
<Modalize
// onOpen={onOpen}
onOpened={() => console.log("ONOPEN")}
ref={modalizeRef}
modalStyle={{ flex: 1,
backgroundColor: 'yellow',
shadowColor: '#000', shadowOffset: { width: 0, height: 6 }, shadowOpacity: 0.45, shadowRadius: 16,
}}
alwaysOpen={85}
handlePosition="inside"
>
<View style={{ flex: 1, backgroundColor: 'green' }}>
<Text>
Data here
</Text>
</View>
</Modalize>
It looks like this:
How can I make it so the green background fills the entire height of the modal?
Use Dimensions to set the height.
Sample Example: Expo Snack
import * as React from 'react';
import { Text, View, StyleSheet, Dimensions } from 'react-native';
import Constants from 'expo-constants';
import { Modalize } from 'react-native-modalize';
const window = Dimensions.get('screen');
export default function App() {
const modalizeRef = React.useRef();
return (
<View style={styles.container}>
<Modalize
// onOpen={onOpen}
onOpened={() => console.log('ONOPEN')}
ref={modalizeRef}
modalStyle={{
flex: 1,
backgroundColor: 'yellow',
shadowColor: '#000',
shadowOffset: { width: 0, height: 6 },
shadowOpacity: 0.45,
shadowRadius: 16,
}}
alwaysOpen={85}
handlePosition="inside">
<View style={{ height: window.height * 0.85, backgroundColor: 'green' }}>
<Text>Data here</Text>
</View>
</Modalize>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
});

Making part of a touchable transparent with React-Native

I would like to make part of a Touchable traslucid, i.e, to be able to see the background behind it.
A possible hack is to use MaskedView and draw my background again, inside the Touchable, as the children prop to MaskedView. However, this only works for a limited number of scenarios. Here it is working:
However, as soon as I add some margin, for example, things get out of phase:
A couple clarifications, just in case:
My real intention is to use a gradient which goes between opposite corners of the screen. In that case, things don't work even in the simple scenario I presented.
I know why this hack doesn't work, but I haven't been able to come up with anything better
Here is a MWE, using a view instead of an image, so that I don't need to bundle the png file:
import React from 'react';
import {
View,
TouchableOpacity,
} from 'react-native';
import MaskedView from '#react-native-community/masked-view';
import LinearGradient from 'react-native-linear-gradient';
export default function () {
return (
<LinearGradient start={{x: 0, y: 0}} end={{x: 1, y: 0}}
colors={['red', 'blue', 'green']}
style={
{flex: 1,
alignItems: 'stretch',
justifyContent: 'center'}
}>
<TouchableOpacity>
<View style={
{height: 100,
alignItems: 'stretch',
justifyContent: 'center',
backgroundColor: 'white',
borderRadius: 30,
//marginLeft: 50, // -> if you uncomment this line, the translucid effect is ruined
}
}>
<MaskedView
style={{height: '100%', backgroundColor: 'yellow',
alignItems: 'stretch', justifyContent: 'center',
}}
maskElement={
<View style={{flex: 1, backgroundColor: 'transparent',
alignItems: 'center', justifyContent: 'center',
}}>
<View style={{width: 300, height: '100%', backgroundColor: 'black'}}/>
</View>
}
>
<LinearGradient start={{x: 0, y: 0}} end={{x: 1, y: 0}}
colors={['red', 'blue', 'green']}
style={{height: '100%'}}
/>
</MaskedView>
</View>
</TouchableOpacity>
</LinearGradient>
);
}
Here's an expo snack to illustrate my comment: https://snack.expo.io/SkCNR7Iqr
The idea is, rather than rendering and then hiding content, just don't render anything there in the first place. This will render the white ends within the bounds of the button. The wrapper uses overflow: 'hidden' to ensure that the Touchable effect will only appear within the bounded borderRadius (more noticeable with TouchableHighlight), and it will ensure that the white ends and any other content in it will stay within the bounded borderRadius.
import * as React from 'react';
import { Text, View, StyleSheet, TouchableOpacity } from 'react-native'
import { LinearGradient } from 'expo-linear-gradient'
export default class App extends React.Component {
render() {
return (
<LinearGradient
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 0 }}
colors={['red', 'blue', 'green']}
style={styles.gradient}>
<View style={styles.wrapper}>
<TouchableOpacity style={styles.touch}>
<View style={styles.end} />
<View style={styles.content} />
<View style={styles.end} />
</TouchableOpacity>
</View>
</LinearGradient>
);
}
}
const styles = StyleSheet.create({
gradient: {
flex: 1,
justifyContent: 'center'
},
wrapper: {
height: 100,
borderRadius: 30,
overflow: 'hidden',
marginLeft: 50,
flexDirection: 'row',
},
touch: {
flexDirection: 'row',
flex: 1,
},
end: {
width: 50,
backgroundColor: 'white',
height: '100%',
},
content: {
flex: 1,
}
});

React navigation- Wrap button in TabBar

I'm new in React Native and i'm trying to do the TabBar in the image. My problem is to put a button in the tabbar. If someone can help me or have an idea to create this tabbar it could be really nice.
THX
you can check
this link. One of the props to pass TabNavigator is tabBarComponent. If you do not want the default styling or have to make custom tabBar you can specify the how the component should look.
In your case this should work.
import React from 'react';
import {View, Text, TouchableOpacity, Dimensions} from 'react-native';
import {TabNavigator} from 'react-navigation';
import Tab1Screen from '../components/tab1Screen';
import Tab2Screen from '../components/tab2Screen';
var {height, width} = Dimensions.get('window');
const mainRoutes = TabNavigator({
Tab1: {screen: Tab1Screen},
Tab2: {screen: Tab2Screen}
},
{
tabBarComponent:({navigation}) => (
<View style={{flex: 0.1, borderColor: 'green', borderWidth: 1}}>
<View style={{flexDirection:'row', justifyContent: 'space-around', alignItems: 'center', paddingTop: 15}}>
<View style={{width: 40, height: 40, borderRadius: 20, borderColor: 'red', borderWidth: 1, position: 'absolute', left: width/2.5, bottom:13 }}></View>
<TouchableOpacity onPress={() => navigation.navigate('Tab1')}>
<Text>Tab1</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => navigation.navigate('Tab2')}>
<Text>Tab2</Text>
</TouchableOpacity>
</View>
</View>
)});
export default mainRoutes;
I had to do something similar. I'm using React Navigation v5 and in my case, the button had to execute a custom action instead of navigating to a tab. So this is what I did:
import styles from './styles';
// Other needed imports...
// ...
<Tab.Screen
name="Add Recipe"
component={() => null}
options={{
tabBarButton: () => (
<TouchableOpacity
style={styles.addIconWrapper}
onPress={() => {
// Your custom action here
}}
>
<View style={styles.addIconBackground}>
<Image source={assets.add} style={styles.addIconImage} />
</View>
</TouchableOpacity>
),
}}
/>;
And inside styles.js:
// ...
addIconWrapper: {
width: '20%',
justifyContent: 'center',
alignItems: 'center',
},
addIconBackground: {
marginTop: -30,
backgroundColor: '#85c349',
borderColor: 'white',
shadowOffset: { width: 2, height: 2 },
shadowColor: '#999',
shadowOpacity: 0.5,
borderRadius: 1000,
width: 42,
height: 42,
justifyContent: 'center',
alignItems: 'center',
},
addIconImage: {
tintColor: 'white',
},
Final result

Draw horizontal rule in React Native

I've tried react-native-hr package - doesn't work for me nor on Android nor on iOS.
Following code is also not suitable because it renders three dots at the end
<Text numberOfLines={1}}>
______________________________________________________________
</Text>
You could simply use an empty View with a bottom border.
<View
style={{
borderBottomColor: 'black',
borderBottomWidth: StyleSheet.hairlineWidth,
}}
/>
I was able to draw a separator with flexbox properties even with a text in the center of line.
<View style={{flexDirection: 'row', alignItems: 'center'}}>
<View style={{flex: 1, height: 1, backgroundColor: 'black'}} />
<View>
<Text style={{width: 50, textAlign: 'center'}}>Hello</Text>
</View>
<View style={{flex: 1, height: 1, backgroundColor: 'black'}} />
</View>
One can use margin in order to change the width of a line and place it center.
import { StyleSheet } from 'react-native;
<View style = {styles.lineStyle} />
const styles = StyleSheet.create({
lineStyle:{
borderWidth: 0.5,
borderColor:'black',
margin:10,
}
});
if you want to give margin dynamically then you can use Dimension width.
I recently had this problem.
<Text style={styles.textRegister}> ──────── Register With ────────</Text>
with this result:
I did it like this. Hope this helps
<View style={styles.hairline} />
<Text style={styles.loginButtonBelowText1}>OR</Text>
<View style={styles.hairline} />
for style:
hairline: {
backgroundColor: '#A2A2A2',
height: 2,
width: 165
},
loginButtonBelowText1: {
fontFamily: 'AvenirNext-Bold',
fontSize: 14,
paddingHorizontal: 5,
alignSelf: 'center',
color: '#A2A2A2'
},
You can also try react-native-hr-component
npm i react-native-hr-component --save
Your code:
import Hr from 'react-native-hr-component'
//..
<Hr text="Some Text" fontSize={5} lineColor="#eee" textPadding={5} textStyles={yourCustomStyles} hrStyles={yourCustomHRStyles} />
This is in React Native (JSX) code, updated to today:
<View style = {styles.viewStyleForLine}></View>
const styles = StyleSheet.create({
viewStyleForLine: {
borderBottomColor: "black",
borderBottomWidth: StyleSheet.hairlineWidth,
alignSelf:'stretch',
width: "100%"
}
})
you can use either alignSelf:'stretch' or width: "100%" both should work...
and,
borderBottomWidth: StyleSheet.hairlineWidth
here StyleSheet.hairlineWidth is the thinnest,
then,
borderBottomWidth: 1,
and so on to increase thickness of the line.
Creating a reusable Line component worked for me:
import React from 'react';
import { View } from 'react-native';
export default function Line() {
return (
<View style={{
height: 1,
backgroundColor: 'rgba(255, 255, 255 ,0.3)',
alignSelf: 'stretch'
}} />
)
}
Now, Import and use Line anywhere:
<Line />
import { View, Dimensions } from 'react-native'
var { width, height } = Dimensions.get('window')
// Create Component
<View style={{
borderBottomColor: 'black',
borderBottomWidth: 0.5,
width: width - 20,}}>
</View>
You can use native element divider.
Install it with:
npm install --save react-native-elements
# or with yarn
yarn add react-native-elements
import { Divider } from 'react-native-elements'
Then go with:
<Divider style={{ backgroundColor: 'blue' }} />
Source
Why don't you do something like this?
<View
style={{
borderBottomWidth: 1,
borderBottomColor: 'black',
width: 400,
}}
/>
Maybe you should try using react-native-hr something like this:
<Hr lineColor='#b3b3b3'/>
documentation: https://www.npmjs.com/package/react-native-hr
import {Dimensions} from 'react-native'
const { width, height } = Dimensions.get('window')
<View
style={{
borderBottomColor: '#1D3E5E',
borderBottomWidth: 1,
width : width ,
}}
/>
This is how i solved divider with horizontal lines and text in the midddle:
<View style={styles.divider}>
<View style={styles.hrLine} />
<Text style={styles.dividerText}>OR</Text>
<View style={styles.hrLine} />
</View>
And styles for this:
import { Dimensions, StyleSheet } from 'react-native'
const { width } = Dimensions.get('window')
const styles = StyleSheet.create({
divider: {
flexDirection: 'row',
alignItems: 'center',
marginTop: 10,
},
hrLine: {
width: width / 3.5,
backgroundColor: 'white',
height: 1,
},
dividerText: {
color: 'white',
textAlign: 'center',
width: width / 8,
},
})
Just create a View component which has small height.
<View style={{backgroundColor:'black', height:10}}/>
If you have a solid background (like white), this could be your solution:
<View style={container}>
<View style={styles.hr} />
<Text style={styles.or}>or</Text>
</View>
const styles = StyleSheet.create({
container: {
flex: 0,
backgroundColor: '#FFFFFF',
width: '100%',
},
hr: {
position: 'relative',
top: 11,
borderBottomColor: '#000000',
borderBottomWidth: 1,
},
or: {
width: 30,
fontSize: 14,
textAlign: 'center',
alignSelf: 'center',
backgroundColor: '#FFFFFF',
},
});
Another approach:
import { View } from 'react-native';
import { Divider, Text } from 'react-native-paper';
const MyComponent = () => (
<View>
<Text>Lemon</Text>
<Divider />
<Text>Mango</Text>
<Divider />
</View>
);
export default MyComponent;
I use this component. It has two props: 1. Number of dash need. 2. dashWidth. and use it like this:
<Line dashedCount={Math.floor(screenWidth / 12)} dashWidth={8} />
type TLine = {
dashedCount: number;
dashWidth: number;
};
function Line({ dashedCount, dashWidth }: TLine) {
const Dash = ({ dashWidth }) => (
<View
style={{
height: 1,
backgroundColor: 'rgba(255, 255, 255 ,0.3)',
alignSelf: 'stretch',
width: dashWidth
}}
/>
);
const dashed = Array(dashedCount).fill(<Dash dashWidth={dashWidth} />);
return (
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between'
}}
>
{dashed}
</View>
);
}
You can use the View like this to render a horizontal rule:
<View style={{ backgroundColor : "your color", height : 1 }} />
For horizontal line in React native<Text style={{ height:1,width:"100%",backgroundColor:"black",margin:5}}></Text>
Use an empty View and give it CSS styles,
In the View, put an empty Text for the view not to be ignored as seen in the snippet below
<View style={{ height: 1, width: "100%",backgroundColor: "black",}}><Text></Text></View>
You can use this with native base package
<Flex alignItems='center' justifyContent='center' direction='row'>
<Divider width={150} mx="5" />
<Text>OR</Text>
<Divider width={150} mx="5" />
</Flex>
just add the following code to get your desired result :
<View style={{ borderBottomColor: 'black', borderBottomWidth: 1, }} />