Toma Radu-Petrescu
Toma Radu-Petrescu

Reputation: 2262

How to round button before rendering?

I want to create a button component that will automatically have rounded corners, no matter its dimension.

As you know, to achieve rounded corners, one way to achieve it is to specify the border radius as half of the height of the button.

The way I implemented is that in the custom component I use the onLayout function like this:

 onLayout(event: LayoutChangeEvent) {
    const { height } = event.nativeEvent.layout;
    this.setState({ borderRadius: height / 2 });
  }

The problem is that the button will initially appear on screen as a rectangle and only after a millisecond, it will round the corners causing a flicker.

My guess is that onLayout is called after the component renders.

How would one go about implementing this? Thanks!

Upvotes: 7

Views: 2561

Answers (3)

Hristo Eftimov
Hristo Eftimov

Reputation: 15703

You can use the lifecycle method componentWillMount() to calculate the border radius:

componentWillMount() {
    const { height } = Dimensions.get('window');
    radius = height / 2;
}

This method is only called one time, which is before the initial render. Since this method is called before render().

And then, you can style your button using the calculated radius:

<TouchableOpacity
    style={[styles.button, { borderRadius: radius }]}
    onPress={() => alert('Hello World!') }
>

Here is a working demo.

Upvotes: 0

samgrigg
samgrigg

Reputation: 11

To do this precisely, you would need to know the size that the string would take up once rendered. I wasn't able to find a React Native API for this (and I'm assuming you couldn't either), but I know both Android and iOS have such APIs. So therefore the solution would be to create a native module (https://facebook.github.io/react-native/docs/native-modules-android.html) for in iOS and Android which exposes a method called "measureText" or something. Then in each native class you'd use the corresponding API:

I haven't actually tried this so I'm curious if something like this ends up working. Cheers!

Upvotes: 0

Hend El-Sahli
Hend El-Sahli

Reputation: 6742

Before the borderRadius is calculated, you could return transparent button, this would prevent this flickering effect...

// you pass radius, and height from component state

const MyButton = ({ radius, height }) => {
   if (radius === null) return <View style={{ backgroundColor: transparent }}>...</View>

else return <View style={{ borderRadius: radius, backgroundColor: 'red' }}>...</View>;
};

Upvotes: 1

Related Questions