Search code examples
react-nativeborderreact-native-stylesheet

React-Native: Mask image with a bottom radius


How do I make the border bottom radius in an image?

And how can I mask the image to the green area?

Image here

I've tried the following codes, but I can't get the radius ratio in the image I've shared above

View Code:

<View style={styles.wrapper}>
    <View style={styles.welcomeWrapper}>
        <View style={styles.welcomeImageWrapper}>
            <Image style={{width:'100%'}} source={require('../assets/images/test-slide.jpg')}/>
        </View>
    </View>
    <View style={{
        height: 100,
        backgroundColor: colors.white,
        justifyContent: 'flex-end',
        alignItems: 'center'
    }}>
       <Text style={{marginBottom:50,fontSize:18,fontFamily:'Montserrat-Regular'}}>Deneme Text </Text>
    </View>
</View>

Style Code:

wrapper:{
    flex:1,
    display: 'flex',
    backgroundColor:colors.white,
},
welcomeWrapper:{
    flex:1,
    justifyContent:'center',   
    backgroundColor:colors.green01,
    overflow: 'hidden',
    position:'relative',
    width:'100%',
    borderBottomRightRadius:Dimensions.get('window').width/100*50,
    borderBottomLeftRadius:Dimensions.get('window').width/100*50,
},

Solution

  • Seeing the shape of your image mask, I think you should use something like react-native-svg to create a real image mask.

    Steps:

    1. Set the background image in a View with a position: absolute, so that your image is always in the background and can be masked

    2. Add react-native-svg to your project, for instance with yarn add react-native-svg, and link the library using react-native link. Finally, re-launch the metro bundler and compile your app (run-android or run-ios).

    3. Design the svg mask (I used ) and add it to the container's View, the mask should have the same backgroundColor as your text container.

    4. A bit of styling using react's flexbox layout to be able to have almost the same look on every device. In this example, the mask takes 5/6 of the screen height as my mask flex number is 5 and my text flex is 1

    So, this is what I ended up with:

    import * as React from 'react';
    import { Dimensions, Image, StyleSheet, Text, View } from 'react-native';
    import { Path, Svg } from 'react-native-svg';
    
    const mask = {
      width: Dimensions.get('window').width,
      height: 50,
      bgColor: '#ecf0f1',
    };
    
    const styles = StyleSheet.create({
      container: {
        flex: 1,
        alignItems: 'center',
        justifyContent: 'flex-end',
      },
      image: {
        position: 'absolute',
      },
      mask: {
        flex: 5,
        justifyContent: 'flex-end',
      },
      textContainer: {
        flex: 1,
        width: '100%',
        alignItems: 'center',
        justifyContent: 'center',
        backgroundColor: mask.bgColor,
      },
      text: {
        fontSize: 50,
        textAlign: 'center',
      }
    });
    
    const App = () => (
      <View style={styles.container}>
        <Image style={styles.image} source={require('./assets/image.jpg')} />
        <View style={styles.mask}>
          <Svg width={mask.width} height={mask.height}>
            <Path
              fill={mask.bgColor}
              d={`M 0 0 L 0 ${mask.height} L ${mask.width} ${mask.height} L ${mask.width} 0 A ${mask.width / 2} ${mask.height / 2} 0 0 1 ${mask.width / 2} ${mask.height / 2} A ${mask.width / 2} ${mask.height / 2} 0 0 1 0 0 z `} />
          </Svg>
        </View>
        <View style={styles.textContainer}>
          <Text style={styles.text}>Text</Text>
        </View>
      </View>
    );
    
    export default App;
    

    And here is the result in an Android emulator

    Result in android emulator

    Hope this helps!

    Link to snack: https://snack.expo.io/BJlZgpuB7 (but my image does not load on snack :( )