React-native: TouchableNativeFeedback's ripples aren't affected by borderRadius on Android 9

Created on 16 Mar 2016  路  38Comments  路  Source: facebook/react-native

This is a bit of a problem when creating buttons with borderRadius and TouchableNativeFeedback, and the ripples extend out. I'm not an expert but I suppose setNativeBackground needs to get the corner radius when making the mask for the RippleDrawable and setBorderRadius may need to remake the background drawable somehow.

Bug TouchableNativeFeedback Android

Most helpful comment

FWIW, as of 0.30, the ripple effect works with respect to the borderRadius of its parent , but it requires its borderless argument to be set to true.
Eg:

<View style={{borderRadius: 24, backgroundColor: '#F66', width: 48,height: 48}}> <TouchableNativeFeedback background={TouchableNativeFeedback.Ripple('#AAF', true)}> [snip] </TouchableNativeFeedback> </View>
If this is the intented effect, it should probably be made explicit, and added to the documentation. It it's a side effect (no pun intented), #6515 still makes sense.

All 38 comments

Attached the following images to represent graphically what is proposed

before
after

Images were taken from Michael Evans Blog - Android Ripples With Rounded Corners

It's supposed to be implemented in https://github.com/facebook/react-native/pull/6515 but I can't make it work :/

I realize that PR got reverted

FWIW, as of 0.30, the ripple effect works with respect to the borderRadius of its parent , but it requires its borderless argument to be set to true.
Eg:

<View style={{borderRadius: 24, backgroundColor: '#F66', width: 48,height: 48}}> <TouchableNativeFeedback background={TouchableNativeFeedback.Ripple('#AAF', true)}> [snip] </TouchableNativeFeedback> </View>
If this is the intented effect, it should probably be made explicit, and added to the documentation. It it's a side effect (no pun intented), #6515 still makes sense.

@reyesr OMG thank you so much for this! 馃憤

@reyesr IT WORKS!!! Thank you so much buddy!! :raised_hands:

Looks like this is resolved. Feel free to open a new issue if you're still having troubles with it

Re-opening since this issue has re-surfaced on Android P.

Just to illustrate from Android P:

screenshot_20180820-124834_2

@reyesr thank you..yet it worked for me after I added a View inside TochableNativeFeedback with the same parent style .. like:
test button


0.55 + Android Pie = The ripple is not affected by the borderRadius.
Tried all the variations (View from outside, View from inside, both).

This issue was never solved, the solution given in a comment above is a hack.

Any updates on the issue?

<View style={{ borderRadius: 5, overflow: 'hidden' }}>
  <TouchableNativeFeedback onPress={() => {}} background={TouchableNativeFeedback.Ripple('red')}>
    {'CLICK CLICK'}
  </TouchableNativeFeedback>
</View>

You guys should try to wrap your TouchableNativeFeedback in a view with a border-radius and an hidden overflow.

@balthazar , wrapping the touchable hides the effect of borderless ripple. This is undesired in Floating Action Buttons components.

@aMarCruz I'm not talking about borderless ripples here, as my example shows.

I've been trying the button issue with https://github.com/kmagiera/react-native-gesture-handler. Looks like it works correctly using the buttons from the library on Android P:

ripple-p

For me it works when I set in TouchableRipple.js the useForeground true + borderless false

  disabled={disabled}
          useForeground={true}
          background={
            background != null
              ? background
              : TouchableNativeFeedback.Ripple(calculatedRippleColor, false)
          }

Also on e.g. the FAB its needs an overflow: 'hidden' style. Works for me on both iOS and Android!

  touchable: {
    borderRadius: 28,
    overflow: 'hidden',
  },

I'm running the latest Android (9 Pie)

Thanks @RichardLindhout

If anyone is still experiencing this on the latest release please submit a new issue

@rickhanlonii That's a workaround which we can't use if oveflow: hidden is not desirable. The behavior is still different between Android versions and buggy.

@satya164 do you think we should keep this open so contributors need to read though the whole thread from 2016 to understand what the current status is or should we file a new issue with the current state of the bug and no superfluous/outdated information?

@rickhanlonii someone can open a new issue, but this issue lists some workarounds which are useful to people coming from google, which is better than a new empty issue imo, given that this thread is quite short. there are also people subscribed to this issue who won't get the notifications for the new issue.

It's 2019 and I can't create a touchable element with border radius which works on both platforms without using dirty hacks.

I poked around with this a bit. One solution is to change the mask on the ripple drawable to be a ShapeDrawable with a corner radius. So instead of:

https://github.com/facebook/react-native/blob/cbf1b39c662eeede356214ba276a105604b75bb2/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactDrawableHelper.java#L78-L86

ColorDrawable is just a rectangle, but it can be replaced with a ShapeDrawable that uses a RoundRectShape. So you could do:

private static Drawable getRippleMask() {
    // Border radii
    float[] outerRadii = new float[] { 12f, 12f, 12f, 12f, 12f, 12f, 12f, 12f };

    RoundRectShape r = new RoundRectShape(outerRadii, null, null);

    ShapeDrawable shapeDrawable = new ShapeDrawable(r);
    shapeDrawable.getPaint().setColor(Color.WHITE);

    return shapeDrawable;
  }

  public static Drawable createDrawableFromJSDescription(Context context, ReadableMap drawableDescriptionDict) {
  // Later on
  return new RippleDrawable(colorStateList, null, mask);
}

This works!

Screenshot_1561043846

However it needs to:

  1. Account for border-width (the mask should only apply to the edge of the border)
  2. Account for the actual border radius

So I think I _might_ have a fix for this! I just need to figure out how to pass the border and corner radius fields ReactDrawableHelper.

I sent out a possible fix for this here:
https://github.com/facebook/react-native/pull/25342

Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as a "Discussion" or add it to the "Backlog" and I will leave it open. Thank you for your contributions.

Unfortunately, the commit that was supposed to fix this issue introduced a major regression and we had to roll it back.

I am reopening this issue as it's still the case. Hopefully, prior work by @nhunzaker can be helpful to work on a fix once again.

My fix to this was to add overflow:'hidden' and the needed borderRadius to the parent view containing the TouchableNativeFeedback and then add useForeground={true} to the TouchableNativeFeedback :)

For me it works when I set in TouchableRipple.js the useForeground true + borderless false

  disabled={disabled}
          useForeground={true}
          background={
            background != null
              ? background
              : TouchableNativeFeedback.Ripple(calculatedRippleColor, false)
          }

Also on e.g. the FAB its needs an overflow: 'hidden' style. Works for me on both iOS and Android!

  touchable: {
    borderRadius: 28,
    overflow: 'hidden',
  },

I'm running the latest Android (9 Pie)

I was first :-P

@RichardLindhout Hahahaha, nice one :D

FWIW, as of 0.30, the ripple effect works with respect to the borderRadius of its parent , but it requires its borderless argument to be set to true.
Eg:

<View style={{borderRadius: 24, backgroundColor: '#F66', width: 48,height: 48}}> <TouchableNativeFeedback background={TouchableNativeFeedback.Ripple('#AAF', true)}> [snip] </TouchableNativeFeedback> </View>
If this is the intented effect, it should probably be made explicit, and added to the documentation. It it's a side effect (no pun intented), #6515 still makes sense.

This causes the ripple to completely ignore the size of the button:

Button

My fix to this was to add overflow:'hidden' and the needed borderRadius to the parent view containing the TouchableNativeFeedback and then add useForeground={true} to the TouchableNativeFeedback :)

This was also the working solution for me. But what if I want the ripples in the background and not in the foreground??

Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as a "Discussion" or add it to the "Backlog" and I will leave it open. Thank you for your contributions.

FWIW, as of 0.30, the ripple effect works with respect to the borderRadius of its parent , but it requires its borderless argument to be set to true.
Eg:
<View style={{borderRadius: 24, backgroundColor: '#F66', width: 48,height: 48}}> <TouchableNativeFeedback background={TouchableNativeFeedback.Ripple('#AAF', true)}> [snip] </TouchableNativeFeedback> </View>
If this is the intented effect, it should probably be made explicit, and added to the documentation. It it's a side effect (no pun intented), #6515 still makes sense.

This causes the ripple to completely ignore the size of the button:

Button

My fix to this was to add overflow:'hidden' and the needed borderRadius to the parent view containing the TouchableNativeFeedback and then add useForeground={true} to the TouchableNativeFeedback :)

This was also the working solution for me. But what if I want the ripples in the background and not in the foreground??

Hi,

I don't know if do you have still a problem, but this is how I'm using it ( "react-native": "0.62.2",):

    buttonShape: {
        borderRadius: 50,
        overflow: 'hidden',
    },
    button: {
        backgroundColor:  'green',
        height: 80,
        width: 80,
    },

[...]

            <View style={styles.buttonShape}>
                <TouchableFeedback>
                    <View style={styles.button}>
                        <Text>
                            Floating btn
                        </Text>
                    </View>
                </TouchableFeedback>
            </View>

Same problem in Pressable =\

I tried every possible ways to make it work on Pressable and this problem still persist. Are there any solutions for 0.63.2 yet?

For me it works when I set in TouchableRipple.js the useForeground true + borderless false

  disabled={disabled}
          useForeground={true}
          background={
            background != null
              ? background
              : TouchableNativeFeedback.Ripple(calculatedRippleColor, false)
          }

Also on e.g. the FAB its needs an overflow: 'hidden' style. Works for me on both iOS and Android!

  touchable: {
    borderRadius: 28,
    overflow: 'hidden',
  },

I'm running the latest Android (9 Pie)

This still works but it's in the hidden comments now..

The <Pressable> doesn't have a useForeground prop, how are we supposed to show ripple effects with buttons that have backgrounds (such as a LinearGradient) in a Pressable?

Was this page helpful?
0 / 5 - 0 ratings