How to make triple outline border in React Native - react-native

Can anybody tell me how to do this kind of triple border design in React Native?

Wrap 3 different views to get different borders.
import React, { Component } from "react";
import { StyleSheet, Text, View, SafeAreaView } from "react-native";
export default class Example extends Component {
render() {
return (
<SafeAreaView style={styles.container}>
<View style={{ borderWidth: 1, borderRadius: 5, borderColor: 'red', width: "90%" }}>
<View style={{ borderWidth: 1, borderRadius: 10, borderColor: 'green', width: "100%" }}>
<View style={{ borderWidth: 1, borderRadius: 15, borderColor: 'blue', width: "100%" }}>
<Text style={{alignSelf: 'center'}}>Search</Text>
</View>
</View>
</View>
</SafeAreaView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 100,
justifyContent: "center",
alignItems: "center"
}
});
This not be the optimal solution. Change this accoding to requirement.
Hope this helps you. Feel free for doubts.

Related

TouchableOpacity outside parent View in absolute positive not works react native

I was making Picker component but what I found is Touchable Opacity in absolute positions outside from it's parent view not works.
const App = () => {
const data = [2, 3, 4, 23]
const [isOpen, setIsOpen] = useState(true);
return (
<View style={{ flex: 1, backgroundColor: 'white', justifyContent: 'center', alignItems: 'center' }}>
<TouchableOpacity style={styles.container} onPress={setIsOpen.bind(null, true)} disabled={isOpen}>
<Text>3</Text>
<Image source={require('./assets/downArrow2.png')} />
{
isOpen && (
<View style={styles.optionsContainer}>
{
data.map((number, index) => (
<View key={index}>
<TouchableOpacity onPress={() => { setIsOpen(false) }}>
<View style={{ padding: 10, paddingRight: 40 }}>
<Text>{number}</Text>
</View>
</TouchableOpacity>
<View style={{ height: 1, width: '100%', backgroundColor: 'white' }} />
</View>
))
}
</View>
)
}
</TouchableOpacity>
</View>
)
}
const styles = StyleSheet.create({
container: {
width: 48,
paddingVertical: 8,
paddingRight: 5,
paddingLeft: 8,
borderWidth: 1,
borderColor: 'grey',
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
position: 'relative'
},
optionsContainer:
position: 'absolute',
top: -1,
left: -1,
backgroundColor: 'grey'
}
})
So, There is outer TouchableOpacity Component & inside we are mapping many TouchableOpacity Component where children are in Absolute View.
TouchableOpacity inside it's parent's view works, but not Works outside Parent View with absolute position. Is their someOne to help me out with it???
It even Not works with TouchableNativeFeedback
Using TouchableOpacity from react-native-gesture-handler solves the issue of absolute position touches. However, it leads to some styling issues such as the overflow "visible" property not working.
So what you can do is that, for the parent TouchableOpacity you can use react-native's TouchableOpacity and for children you can use react-native-gesture-handler's TouchableOpacity to get the touch to work even when positioned absolutely.
This is the updates code. Please note the imports.
import { useState } from 'react';
import {View, StyleSheet, Text, TouchableOpacity as TouchableRN} from 'react-native';
import {TouchableOpacity} from 'react-native-gesture-handler'
const App = () => {
const data = [2, 3, 4, 23]
const [isOpen, setIsOpen] = useState(false);
return (
<View style={{ flex: 1, backgroundColor: 'white', justifyContent: 'center', alignItems: 'center' }}>
<TouchableRN style={styles.container} onPress={setIsOpen.bind(null, true)} disabled={isOpen}>
<Text>3</Text>
<Image source={require('./assets/downArrow2.png')} />
{
isOpen && (
<View style={styles.optionsContainer}>
{
data.map((number, index) => (
<View key={index}>
<TouchableOpacity onPress={() => { setIsOpen(false) }}>
<View style={{ padding: 10, paddingRight: 40 }}>
<Text>{number}</Text>
</View>
</TouchableOpacity>
<View style={{ height: 1, width: '100%', backgroundColor: 'white' }} />
</View>
))
}
</View>
)
}
</TouchableRN>
</View>
)
}
const styles = StyleSheet.create({
container: {
width: 48,
paddingVertical: 8,
paddingRight: 5,
paddingLeft: 8,
borderWidth: 1,
borderColor: 'grey',
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
position: 'relative'
},
optionsContainer: {
position: 'absolute',
top: -1,
left: -1,
backgroundColor: 'grey'
}
})
export default App;

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

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,
}
});

Is it possible to place one <View> over another in react-native?

I want to place one <View> over another in react-native. Here is my code:
<View style={styles.container}>
<View style={styles.vimgProduct}>
<Image style={styles.imgProduct} source={{uri: "http://www.unclesamsjamms.com/unclesamcash7.jpg"}}/>
</View>
<View style={styles.vNewView}>
</View>
</View>`
and here is my style:
container: {
flex: 1,
paddingTop: 65,
backgroundColor: "#F5FCFF"
},
vimgProduct: {
paddingTop: 20,
justifyContent: 'center',
alignItems: 'center'
},
vNewView: {
height: 400,
paddingVertical: 20,
marginTop: -60,
marginHorizontal: 40,
borderWidth: 3,
borderColor: "black",
borderRadius: 15,
flexDirection: "row",
justifyContent: 'center',
alignItems: 'center'
}
My problem now is, that the View with Image is over my "vNewView" but the border of "vNewView" is in foreground and overlaps my "vimgProduct".
I want that my vNewView is in background and my vimgProduct is in foreground. How can I achieve this? In HTML/CSS it works with zIndex I think.
Could you help me please here? Would be great!
best regards,
Alban
To achieve similar functionality to z-index in react native, you simply need to place your components in the order that they are intended to be layered. For example, if you have three components in a row, then the second will overlay the first, and the third will overlay the second, so on and so forth.
For what you are doing, maybe try placing the vNewView as the first item in the view and use position: 'absolute' .
I'd here is an overlay container that you can use to overlay your views:
import React, { ReactElement } from 'react';
import { View, StyleSheet, ViewStyle, StyleProp } from 'react-native';
type OverlayContainerProps = {
back?: ReactElement;
front?: ReactElement;
backViewStyle?: StyleProp<ViewStyle>;
frontViewStyle?: StyleProp<ViewStyle>;
containerStyle?: StyleProp<ViewStyle>;
};
export default function OverlayContainer({
back,
front,
backViewStyle,
frontViewStyle,
containerStyle,
}: OverlayContainerProps): ReactElement {
return (
<View style={[styles.container, containerStyle]}>
<View style={backViewStyle}>{back}</View>
<View style={[styles.front, frontViewStyle]}>{front}</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignContent: 'center',
alignItems: 'center',
justifyContent: 'center',
},
front: {
position: 'absolute',
zIndex: 1,
},
});
Credit where it is due, I got my inspiration for this approach from seeing this bit of code: https://github.com/onmyway133/blog/issues/254

In React Native, how do I put a view on top of another view, with part of it lying outside the bounds of the view behind?

I'm trying to make a layout as per below with React Native.
How do I specify the position of B relative to A?
With iOS Interface Builder and autoconstraints, this can very explicitly be done and is a breeze. It's not so obvious how one might achieve this with React Native.
Add the following style to the "floating" view:
position: 'absolute'
You may also need to add a top and left value for positioning.
The above solutions were not working for me. I solved it by creating a View with the same background colour as the parent and added negative margin to move the image upwards.
<ScrollView style={{ backgroundColor: 'blue' }}>
<View
style={{
width: '95%',
paddingLeft: '5%',
marginTop: 80,
height: 800,
}}>
<View style={{ backgroundColor: 'white' }}>
<Thumbnail square large source={{uri: uri}} style={{ marginTop: -30 }}/>
<Text>Some Text</Text>
</View>
</View>
</ScrollView>
and I got the following result.
You can use zIndex for placing a view on top of another. It works like the CSS z-index property - components with a larger zIndex will render on top.
You can refer: Layout Props
Snippet:
<ScrollView>
<StatusBar backgroundColor="black" barStyle="light-content" />
<Image style={styles.headerImage} source={{ uri: "http://www.artwallpaperhi.com/thumbnails/detail/20140814/cityscapes%20buildings%20hong%20kong_www.artwallpaperhi.com_18.jpg" }}>
<View style={styles.back}>
<TouchableOpacity>
<Icons name="arrow-back" size={25} color="#ffffff" />
</TouchableOpacity>
</View>
<Image style={styles.subHeaderImage} borderRadius={55} source={{ uri: "https://upload.wikimedia.org/wikipedia/commons/thumb/1/14/Albert_Einstein_1947.jpg/220px-Albert_Einstein_1947.jpg" }} />
</Image>
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "white"
},
headerImage: {
height: height(150),
width: deviceWidth
},
subHeaderImage: {
height: 110,
width: 110,
marginTop: height(35),
marginLeft: width(25),
borderColor: "white",
borderWidth: 2,
zIndex: 5
},
You can use this OverlayContainer. The trick is to use absolute with 100% size. Check below an example:
// #flow
import React from 'react'
import { View, StyleSheet } from 'react-native'
type Props = {
behind: React.Component,
front: React.Component,
under: React.Component
}
// Show something on top of other
export default class OverlayContainer extends React.Component<Props> {
render() {
const { behind, front, under } = this.props
return (
<View style={styles.container}>
<View style={styles.center}>
<View style={styles.behind}>
{behind}
</View>
{front}
</View>
{under}
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
height: '100%',
justifyContent: 'center',
},
center: {
width: '100%',
height: '100%',
alignItems: 'center',
justifyContent: 'center',
},
behind: {
alignItems: 'center',
justifyContent: 'center',
position: 'absolute',
left: 0,
top: 0,
width: '100%',
height: '100%'
}
})
import React, {Component} from 'react';
import {StyleSheet, View} from 'react-native';
export default class App extends Component {
render() {
return (
<View>// you need to wrap the two Views an another View
<View style={styles.box1}></View>
<View style={styles.box2}></View>
</View>
);
}
}
const styles = StyleSheet.create({
box1:{
height:100,
width:100,
backgroundColor:'red'
},
box2:{
height:100,
width:100,
backgroundColor:'green',
position: 'absolute',
top:10,
left:30
},
});
You can use react-native-view-overflow plugin for placing a view on top of another. It works like the CSS z-index property.
import ViewOverflow from 'react-native-view-overflow';
<ViewOverflow />
<View style={[styles2.cardBox, { marginTop: 50 }]}>
<View style={[styles2.cardItem]} >
<Text style={styles2.cardHeader}>userList</Text>
</View>
<View style={[styles2.cardContent]}>
<Text style={styles2.text}>overflow: "visible"</Text>
</View>
<View style={[styles2.cardItemFooter]} >
<Text style={styles2.cardTextFooter}>...</Text>
</View>
</View>
</ViewOverflow>
const styles2 = StyleSheet.create({
cardBox: {
borderLeftWidth: 0,
borderTopWidth: 0,
backgroundColor: "transparent",
borderWidth: 1,
borderColor: "#d0d0d0",
width: '94%',
alignSelf: 'center',
height: 200,
position: "relative",
borderRadius: 15,
overflow: "visible" // doesn't do anything
},
cardContent: {
textAlign: "right",
backgroundColor: "transparent",
marginTop: 15,
alignSelf: 'flex-end',
padding: 5,
},
cardHeader: {
color: '#fff',
fontFamily: 'Vazir',
fontSize: 12
},
cardItem: {
backgroundColor: "#3c4252",
borderRadius: 3,
position: "absolute",
top: -10,
right: -5,
width: 50,
height: 20,
paddingRight: 5,
},
})
The easiest way to achieve this is with a negative margin.
const deviceWidth = RN.Dimensions.get('window').width
a: {
alignItems: 'center',
backgroundColor: 'blue',
width: deviceWidth,
},
b: {
marginTop: -16,
marginStart: 20,
},
You can use elevation property for Android if you don't mind the shadow.
{
elevation:1
}
Try this:
style = {{position: 'absolute', bottom: 20, left: 20, elevation: 100}}
Based on the example above i've created a component which stacks all childeren on top of each other. You could even nest OverlayContainers inside OverlayContainers.
Usage:
<OverlayContainer>
<View style={{backgroundColor:'red', width:150, height: 150}}></View>
<View style={{backgroundColor:'yellow', width:50, height: 50}}></View>
<Text>Just some text</Text>
</OverlayContainer>
Output:
import React, { FC, PropsWithChildren } from 'react'
import { StyleSheet, View } from 'react-native'
export const OverlayContainer: FC<PropsWithChildren<unknown>> = (props) => {
return (
<View style={styles.container}>
{props.children.map((child, index) => (
<View style={styles.child} key={index}>
{child}
</View>
))}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
height: '100%',
},
child: {
position: 'absolute',
left: 0,
top: 0,
width: '100%',
height: '100%'
}
})
<SafeAreaView style={{ flex: 1 }} >
<View style={{ height: Dimensions.get('window').height / 2, backgroundColor: 'blue', justifyContent: 'center' }}>
<Text style={{ fontSize: 25, alignSelf: 'center' }} >A</Text>
<View style={{ justifyContent: 'center', height: 100, width: 100, backgroundColor: 'yellow', position: 'absolute', left: 20, top: Dimensions.get('window').height / 2 - 70 }}>
<Text style={{ fontSize: 22, alignSelf: 'center' }} >B</Text>
</View>
</View>
</SafeAreaView>