Stack Masked View to Make Curved Card React Native - reactjs

Anyone know how to make card like this using view only?
desired result
Currently I'm still using SVG combined with view, but I'm curious if this result can be achieved using view only method.
I've searching about masked-view in react native using this library
https://github.com/react-native-masked-view/masked-view
but I have a gradle issue when I'm trying to build the app.
And apparently this issue hasn't solved yet.
https://github.com/react-native-masked-view/masked-view/issues/89
Current Result using SVG
current result
Component :
<View style={styles.card}>
<Image
source={{
uri:
'https://media.istockphoto.com/vectors/flat-cityscape-with-blue-sky-white-clouds-and-sun-modern-city-skyline-vector-id931139544?s=612x612',
}}
style={[
styles.cardImage,
{
justifyContent: 'center',
marginTop: 0,
resizeMode: 'cover',
},
]}
/>
{/* <View style={[styles.cardImage, {}]} /> */}
<View
style={{
position: 'absolute',
bottom: 60,
}}>
<SvgExclude color={'#FFF'} />
</View>
<View style={[styles.cardDescription, {}]}>
<Text>
Kota Indonesia dan Keunikannya
</Text>
</View>
</View>
Style :
const styles = StyleSheet.create({
card: {
marginTop: 16,
width: windowWidth - 32,
marginHorizontal: 16,
backgroundColor: '#FFF',
height: 179,
borderRadius: 16,
elevation: 2,
overflow: 'hidden',
},
cardImage: {
width: '100%',
height: 134,
backgroundColor: 'black',
position: 'absolute',
top: 0,
},
cardDescription: {
height: 60,
width: windowWidth - 32,
borderBottomEndRadius: 16,
borderBottomStartRadius: 16,
borderTopEndRadius: 16,
backgroundColor: '#FFF',
position: 'absolute',
bottom: 0,
padding: 12,
},
});
SVG :
import * as React from 'react';
import Svg, {Path} from 'react-native-svg';
function SvgExclude(props) {
return (
<Svg
width={16}
height={16}
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}>
<Path
fillRule="evenodd"
clipRule="evenodd"
d="M0 0c0 8.837 7.163 16 16 16H0V0z"
fill={props.color}
/>
</Svg>
);
}
export default SvgExclude;
Thankyou..

I tried it on snack please have a look at it. I'm using View only for this design.
import * as React from 'react';
import { View } from 'react-native';
export default function App() {
return (
<View style={{
alignSelf:'center',
marginTop:100
width:300,
height:250,
backgroundColor:'red',
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 5,
borderRadius:10
}}>
<View style={{
position:'absolute',
bottom:0,
height:100,
width:'100%',
backgroundColor:'white',
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 10,
},
shadowOpacity: 0.5,
shadowRadius: 13.84,
elevation: 10,
borderBottomLeftRadius:10,
borderBottomRightRadius:10,
borderTopRightRadius:10,
}}>
<View style={{
position:'abolute',
backgroundColor:'red',
top:0,
width:'100%',
height:20,
borderBottomLeftRadius:20
}}>
</View>
</View>
</View>
);
}

Related

Flex value for main view causing all of my content to dissapear

I am working on a react native coffee app and trying to create the lay out where I have
the header
the scrollable container holding my coffee
a footer with a text input
a '+' icon to add the coffees to the container
Currently the flex value of my main 'View' is causing my entire app to push to the top of the screen and i have no idea why. I can set the height and width to 100% without flex and i can fill the screen but then i cannot configure my footer properly (+ i know this is bad practice..)
What am i doing wrong with my styles?
const Main = () => {
return(
<View style={styles.container}>
<View style={styles.header}>
<Text style={styles.headerText}> List of Coffee </Text>
</View>
<ScrollView styles={styles.scrollContainer}>
</ScrollView>
<View styles={styles.footer}>
<TextInput
styles={styles.textInput}
placeholder="add your latest coffee here"
placeholderTextColor="#EEE">
</TextInput>
</View>
<TouchableOpacity style={styles.addButton}>
<Text style={styles.addButtonText}>+</Text>
</TouchableOpacity>
</View>
);};
const styles = StyleSheet.create({
container: {
flex:1,
flexDirection:"column",
backgroundColor: 'grey',
},
footer: {
position: 'absolute',
bottom: 10,
left: 10,
right: 10,
backgroundColor: 'white',
zIndex: 9,
},
header: {
backgroundColor: 'black',
alignItems: 'center',
justifyContent: 'center',
borderBottomWidth: 10,
borderBottomColor: 'yellow' ,
paddingTop: 20,
},
headerText: {
color: 'white',
fontSize: 36,
padding: 26,
fontWeight: "500",
fontFamily: 'Helvetica',
},
scrollContainer:{
marginBottom: 100,
},
textInput: {
alignSelf: 'stretch',
color: 'black',
padding:20,
backgroundColor: 'black',
borderTopWidth: 2,
borderTopColor: 'black',
fontSize: 32,
},
addButton: {
position: 'absolute',
zIndex: 11,
right: 20,
bottom: 100,
backgroundColor: 'black',
width: 80,
height: 80,
borderRadius: 50,
justifyContent: 'center',
alignItems: 'center',
} ,
addButtonText:{
color: '#FFD700',
fontSize: 36,
fontWeight: '700',
},
});
export default Main;

How to add button near bubble Gifted Chat?

I've been using the GitedChat library and I want to add a button next to Bubble on the right "Reply".How do I do that?
Example Image
Bubble.JS
import React from 'react';
import {Bubble} from 'react-native-gifted-chat';
export const renderBubble = props => {
return (
<Bubble
{...props}
wrapperStyle={{
left: {
backgroundColor: '#FFFFFF',
display: 'flex',
flexDirection: 'row',
borderBottomLeftRadius: 0,
},
right: {
backgroundColor: '#1D4ED8',
left: 0,
marginBottom: 15,
borderBottomRightRadius: 0,
},
}}
tickStyle={{color: 'red'}}
/>
);
};
Just renderBubble and create Image on right side
renderBubble(props) {
return (
<View
style={{ flex: 1, flexDirection: 'row'}}>
<Bubble
{...props}
/>
<Image
style={{
width: 30,
height: 30,
marginTop: 'auto',
bottom: 0,
}}
source={{
uri:
'https://icons-for-free.com/iconfiles/png/512/next+reply+icon-1320165657413388724.png',
}}
/>
</View>
);}

ripple effect leaking at corners as if Pressable button has a borderRadius

I'm using Pressable for buttons after referring this docs pressable docs
Now I want to add ripple effect to the button but it is not working properly.
<Pressable
android_ripple={{color: 'red', borderless: false}}
style={{backgroundColor: 'blue',borderRadius : 10}}>
<Text style={{alignSelf: 'center'}}>Button</Text>
</Pressable>
Ripple effect don't have border radius if button has radius.
it looks awkward that ripple effect corners go out of the curved radius.
Snack demonstrating the problem: https://snack.expo.dev/6U8dxxzLx
Nothing worked for me, So I solved this myself.
pressable should be wrapped in a view
view must have margin not padding
border radius must be on view not on pressable
pressable component must have padding not margin
then add ripple by android_ripple={{color: 'black', borderless: true}} to pressable.
<View style={styles.buttonView}>
<Pressable
onPress={() => {}}
android_ripple={{color: 'black', borderless: true}}
style={styles.loginButton}>
<Text style={styles.buttonText}>Login</Text>
</Pressable>
</View>
buttonView: {
alignSelf: 'stretch',
justifyContent: 'center',
borderRadius: 10,
elevation: 25,
margin: 10,
},
loginButton: {
height: 50,
backgroundColor: '#0f4c75',
padding: 10,
alignItems: 'center',
justifyContent: 'center',
},
buttonText: {
color: 'white',
fontSize: 16,
textTransform: 'uppercase',
fontFamily: 'sans-serif-light',
},
Update:-
Floating pressable component with ripple leakage fixed
<View style={{
position: 'absolute',
bottom: 250,
borderRadius: 50,
overflow: 'hidden',
alignSelf: 'center'
}}>
<Pressable
style={{
height: 60,
width: 60,
borderRadius: 50,
backgroundColor: 'red',
justifyContent: 'center',
alignItems: 'center',
elevation: 4,
}}
android_ripple={{
color: 'black',
}}
onPress={() => { console.log('om') }}>
<Text>O</Text>
</Pressable>
</View>
You can wrap pressable into View and pass borderRadius:10 and overflow:'hidden' to View style.
<View style={{ borderRadius: 10, overflow: 'hidden' }}>
<Pressable
android_ripple={{ color: 'red', borderless: false, }}
style={{ backgroundColor: 'blue', borderRadius: 10 }}>
<Text style={{ alignSelf: 'center' }}>Button</Text>
</Pressable>
</View>
Turns out the other solution don't cover all edge cases... I needed to wrap the view 2 times to manage elevation and shadow on iOS. (The button is in absolute position also).
export const PNFloatingButton = ({ children, ...props }) => {
return (
<View style={thisStyles.shadow}>
<View style={thisStyles.parentContainer}>
<Pressable style={thisStyles.button}
android_ripple={{ borderless: false, color: "#0F0" }}>
<Text>Button</Text>
</PNPressable>
</View>
</View>
)
}
const thisStyles = StyleSheet.create({
shadow: {
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.4,
shadowRadius: 4,
width: 56,
height: 56,
position: 'absolute',
elevation: 2,
right: 0,
bottom: 0,
},
button: {
padding: 4,
backgroundColor: "#F00",
},
parentContainer: {
// Pressable has issues with borderRadius on the ripple on android
overflow: "hidden",
borderRadius: 40,
},
})
For those that are using the Button element I found a simple workaround. Since this problem happens always when border od the button is changed (like became rounded) I just pass to the containerStyle of the button all the props + my button border radius. I add also the overflow property with hidden attribute.
Some little context: myButtonStyle is the style I want to apply to that button. If it's null, I'll apply a default style. Same for myContainerStyle.
The function inplemented before return():
function fixRippleBorder() {
const borderRadius = myButtonStyle
? EStyleSheet.flatten(myButtonStyle).borderRadius
: EStyleSheet.flatten(defaultButtonStyle).borderRadius;
return {
borderRadius: borderRadius,
overflow: 'hidden',
};
}
The button itself:
<Button
containerStyle={[
myContainerStyle ?? defaultContainerStyle,
fixRippleBorder(),
]}
buttonStyle={myButtonStyle ?? defaultButtonStyle}
...
You can add the style overFlow: 'hidden' to a view that wraps around your pressable object as long as that view also contains your borderRadius. Below is an example of a file I worked on recently that does this
import React from 'react';
import {Pressable, View, Text, StyleSheet, Platform} from 'react-native';
export default function CategoryGridTile({title, color, onPress}) {
return (
<View style={styles.gridItem}>
<Pressable
android_ripple={{color: '#ccc'}}
style={({pressed}) => [
styles.button,
pressed ? styles.buttonPressed : null,
]}
onPress={onPress}>
<View style={[styles.innerContainer, {backgroundColor: color}]}>
<Text style={styles.title}>{title}</Text>
</View>
</Pressable>
</View>
);
}
const styles = StyleSheet.create({
gridItem: {
flex: 1,
margin: 16,
height: 150,
borderRadius: 8,
elevation: 4,
backgroundColor: 'white',
shadowColor: 'black',
shadowOpacity: 0.25,
shadowOffset: {width: 0, height: 2},
shadowRadius: 8,
overflow: 'hidden',
},
button: {
flex: 1,
},
buttonPressed: {
opacity: 0.5,
},
innerContainer: {
flex: 1,
padding: 16,
borderRadius: 8,
justifyContent: 'center',
alignItems: 'center',
},
title: {
fontWeight: 'bold',
fontSize: 18,
},
});

React Native Scrollview keyboardshouldpersisttaps not working for ios

I have a Login screen where I wrap the entire component with ScrollView and apply keyboardshouldpersisttaps prop as always. The prop seems to work fine on android but not on ios, on tapping the textInput, it gets hidden under keyboard.
Below is my code for the login screen
<View>
<ScrollView
style={styles.scrollviewStyle}
keyboardShouldPersistTaps="always">
<View style={styles.topContainerStyle}>
<View style={styles.padding}>
<Text style={styles.skipTextStyle}>SKIP</Text>
<Image source={BlackLogo} style={styles.logoStyle} />
</View>
</View>
<Image source={PreLoginImage} style={styles.preLoginImageStyle} />
<View style={styles.padding}>
<Text style={styles.getStartedTextStyle}>Let's Get started</Text>
<View style={styles.bottomContainer}>
<TextInput
// onChangeText={mobile => this.onMobileEnter(mobile)}
style={{ height: 40, borderColor: 'gray', borderWidth: 1 }}
value={this.state.mobile}
maxLength={10}
onCodeChange={this.onCodeChange}
/>
<TouchableHighlight
disabled={!this.state.mobile ? true : false}
onPress={() => this.onProceedPress()}
style={
!this.state.mobile
? styles.disabledContinueButtonStyles
: styles.continueButtonStyles
}>
<Text
style={{
alignSelf: 'center',
fontFamily: 'Roboto-Medium',
fontSize: 16,
marginTop: 18,
color: '#FFFFFF',
}}>
CONTINUE
</Text>
</TouchableHighlight>
</View>
<Text style={styles.termsStyle}>
By continuing, you agree to Remedico's terms of use and privacy
Policy.
</Text>
</View>
</ScrollView>
</View>
);
}
}
const styles = StyleSheet.create({
topContainerStyle: {
backgroundColor: '#F4EBE4',
height: deviceHeight * 0.4,
},
logoStyle: {
width: 139,
height: 45,
resizeMode: 'contain',
top: 123,
},
padding: {
padding: 24,
},
preLoginImageStyle: {
width: 178,
height: 167,
position: 'absolute',
top: deviceHeight * 0.2,
left: deviceWidth * 0.5,
},
getStartedTextStyle: {
paddingTop: 60,
fontFamily: 'Ubuntu-Medium',
fontSize: 20,
},
skipTextStyle: {
left: deviceWidth - 80,
fontFamily: 'Roboto-Medium',
fontSize: 16,
},
bottomContainer: {
paddingTop: 32,
},
continueButtonStyles: {
marginTop: 84.5,
borderRadius: 25,
backgroundColor: '#00ACC1',
height: 55,
},
disabledContinueButtonStyles: {
marginTop: 84.5,
borderRadius: 25,
backgroundColor: '#CCCCCC',
height: 55,
},
termsStyle: {
fontFamily: 'Roboto-Regular',
fontSize: 12,
paddingTop: 32,
color: '#808080',
},
scrollviewStyle: {
backgroundColor: '#FFF',
height: deviceHeight,
},
// activityIndicatorStyle:{
// marginTop: 84.5
// },
});
Please do suggest why is it so, and how will it be working on ios, any suggestion would be a help,thanks in advance.
I don't think keyboardshouldpersisttaps props of ScrollView will solve your problem. This props will only dismiss the keyboard when you press on the container view.
Please check ref: https://reactnative.dev/docs/scrollview#keyboardshouldpersisttaps
I suggest you to use https://github.com/APSL/react-native-keyboard-aware-scroll-view for your problem.
Hope that help. :)

Building Image Card in React Native

I'm trying to build a simple image card component in React Native and got some problems. This is my component now (It's available for you on snack):
I can't find a way to set border only on the top of the image on the card, keeping the bottom border flat.
Desired form:
The Image component doesn't seen to be rendered from the top showing the model's face, instead it's getting centered showing her body.
Here it's the original image for comparison:
Use this code. Added overflow: "hidden" to the View and removed borderRadius for Image. Tested in IOS.
import * as React from 'react';
import { Text, View, Image } from "react-native";
export default class RootComponent extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
<View style={{ backgroundColor: "#eee", borderRadius: 10, overflow: "hidden" }}>
<View>
<Image
source={require("./assets/h4.jpg")}
style={{
height: 135,
width: 155
}}
/>
</View>
<View style={{ padding: 10, width: 155 }}>
<Text>Title</Text>
<Text style={{ color: "#777", paddingTop: 5 }}>
Description of the image
</Text>
</View>
</View>
</View>
);
}
}
By removing the height from the <Image> and setting it in its parent view, the image will be shown from the top.
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
<View style={{ backgroundColor: "#eee", borderRadius: 10, overflow: 'hidden' }}>
<View style={{ height: 135, width: 155, overflow: 'hidden' }}>
<Image
source={require("./assets/h4.jpg")}
style={{
width: 155
}}
/>
</View>
<View style={{ padding: 10, width: 155 }}>
<Text>Title</Text>
<Text style={{ color: "#777", paddingTop: 5 }}>
Description of the image
</Text>
</View>
</View>
</View>
You can directly do it with borderTopLeftRadius and borderTopRightRadius in a Card.
<Card
containerStyle={styles.boxCon}
featuredTitle={title}
image={{
uri: urlToImage
}}
imageStyle={{ borderTopLeftRadius: 10, borderTopRightRadius: 10 }}
>
const styles = {
boxCon: {
margin: 15,
marginHorizontal: 10,
marginBottom: 17.5,
borderColor: '#FFFFFF',
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.3,
shadowRadius: 5,
elevation: 5,
borderRadius: 10
}
};

Resources