Make border-radius greater than half of height

Viewed 672

I want to make a "rounded bottom" component, without using a ImageBackground, like this: enter image description here

I tried to use a combination of <LinearGradient/>, but to simplify the code in this question, I used <View/> instead.

Here is my code:

import React from 'react'
import { Dimensions, StyleSheet, View } from 'react-native'

export default class App extends React.Component {
  constructor(props) {
    super(props)
  }

  render() {
    return (
      <View style={classes.container}>
        <View style={classes.block} />
        <View style={classes.roundedBlock} />
      </View>
    )
  }
}

const classes = StyleSheet.create({
  container: {
    flex: 1,
    marginTop: 30,
  },
  block: {
    height: 135,
    backgroundColor: 'red',
  },
  roundedBlock: {
    height: 15,
    backgroundColor: 'red',
    width: Dimensions.get('window').width,
    borderBottomLeftRadius: Dimensions.get('window').width / 2,
    borderBottomRightRadius: Dimensions.get('window').width / 2,
  }
})

This code is available for tests purpose on Expo Snack

Here is the result:

enter image description here

As you can see, the borderRadius is limited to 7.5px, which is half of the height of the block, instead of half of the width as demanded.

Is there a way to override this limit? If no, is there a way to achieve what I want?

1 Answers

You can use ART from react-native to draw whatever you want to draw. Some unofficial docs https://github.com/react-native-china/react-native-ART-doc/blob/master/doc.md. Please check the Expo Snack or code below.

import React from 'react';
import { Dimensions, StyleSheet, View, ART } from 'react-native';

const {
  Surface,
  Shape,
  Path,
  RadialGradient,
  Pattern,
  Transform,
  LinearGradient,
} = ART;
const width = Dimensions.get('window').width;
export default class App extends React.Component {
  constructor(props) {
    super(props);
  }

  getPathRect = () => {
    const x = width;
    const y = 0;
    const radius = 1000;

    return ART.Path()
      .moveTo(x, y)
      .lineTo(x - width, y)
      .lineTo(x - width, y + width / 2)
      .lineTo(x, y + width / 2)
      .close();
  };

  getPathArc = () => {
    const x = width;
    const y = 0;
    const radius = 1000;
    return ART.Path()
      .moveTo(x, y + width / 2)
      .arc(-x, 0, radius, radius)
      .close();
  };

  gradient = () => {
    return new LinearGradient(
      {
        '.01': 'blue', // blue in 1% position
        '1': 'red', // opacity white in 100% position
      },
      '0',
      '0',
      width,
      '0'
    );
  };

  render() {
    return (
      <View style={classes.container}>
        <Surface width={width} height={width}>
          <Shape
            d={this.getPathRect()}
            fill={this.gradient()}
            // stroke="red"
            strokeWidth="1"
            strokeCap="butt"
            strokeJoin="bevel"
          />
          <Shape
            d={this.getPathArc()}
            fill={this.gradient()}
            // stroke="red"
            strokeWidth="1"
            strokeCap="butt"
            strokeJoin="bevel"
          />
        </Surface>
      </View>
    );
  }
}

const classes = StyleSheet.create({
  container: {
    flex: 1,
    marginTop: 30,
  },
});
Related