diff --git a/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerButtonViewManager.kt b/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerButtonViewManager.kt index fabd819233..59533f54bd 100644 --- a/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerButtonViewManager.kt +++ b/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerButtonViewManager.kt @@ -65,6 +65,26 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager(), R view.borderRadius = borderRadius } + @ReactProp(name = "borderTopLeftRadius") + override fun setBorderTopLeftRadius(view: ButtonViewGroup, borderTopLeftRadius: Float) { + view.borderTopLeftRadius = borderTopLeftRadius + } + + @ReactProp(name = "borderTopRightRadius") + override fun setBorderTopRightRadius(view: ButtonViewGroup, borderTopRightRadius: Float) { + view.borderTopRightRadius = borderTopRightRadius + } + + @ReactProp(name = "borderBottomLeftRadius") + override fun setBorderBottomLeftRadius(view: ButtonViewGroup, borderBottomLeftRadius: Float) { + view.borderBottomLeftRadius = borderBottomLeftRadius + } + + @ReactProp(name = "borderBottomRightRadius") + override fun setBorderBottomRightRadius(view: ButtonViewGroup, borderBottomRightRadius: Float) { + view.borderBottomRightRadius = borderBottomRightRadius + } + @ReactProp(name = "rippleColor") override fun setRippleColor(view: ButtonViewGroup, rippleColor: Int?) { view.rippleColor = rippleColor @@ -115,6 +135,30 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager(), R set(radius) = withBackgroundUpdate { field = radius * resources.displayMetrics.density } + var borderTopLeftRadius = 0f + set(radius) = withBackgroundUpdate { + field = radius * resources.displayMetrics.density + } + var borderTopRightRadius = 0f + set(radius) = withBackgroundUpdate { + field = radius * resources.displayMetrics.density + } + var borderBottomLeftRadius = 0f + set(radius) = withBackgroundUpdate { + field = radius * resources.displayMetrics.density + } + var borderBottomRightRadius = 0f + set(radius) = withBackgroundUpdate { + field = radius * resources.displayMetrics.density + } + + private val hasBorderRadii: Boolean + get() = borderRadius != 0f || + borderTopLeftRadius != 0f || + borderTopRightRadius != 0f || + borderBottomLeftRadius != 0f || + borderBottomRightRadius != 0f + var exclusive = true private var _backgroundColor = Color.TRANSPARENT @@ -139,6 +183,22 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager(), R needBackgroundUpdate = true } + private fun buildBorderRadii(): FloatArray { + // duplicate radius for each corner, as setCornerRadii expects X radius and Y radius for each + return floatArrayOf( + borderTopLeftRadius, + borderTopLeftRadius, + borderTopRightRadius, + borderTopRightRadius, + borderBottomRightRadius, + borderBottomRightRadius, + borderBottomLeftRadius, + borderBottomLeftRadius, + ) + .map { if (it != 0f) it else borderRadius } + .toFloatArray() + } + override fun setBackgroundColor(color: Int) = withBackgroundUpdate { _backgroundColor = color } @@ -188,11 +248,11 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager(), R return false } - private fun updateBackgroundColor(backgroundColor: Int, borderRadius: Float, selectable: Drawable?) { + private fun updateBackgroundColor(backgroundColor: Int, selectable: Drawable?) { val colorDrawable = PaintDrawable(backgroundColor) - if (borderRadius != 0f) { - colorDrawable.setCornerRadius(borderRadius) + if (hasBorderRadii) { + colorDrawable.setCornerRadii(buildBorderRadii()) } val layerDrawable = LayerDrawable(if (selectable != null) arrayOf(colorDrawable, selectable) else arrayOf(colorDrawable)) @@ -216,30 +276,21 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager(), R val selectable = createSelectableDrawable() - if (borderRadius != 0f) { - // Radius-connected lines below ought to be considered - // as a temporary solution. It do not allow to set - // different radius on each corner. However, I suppose it's fairly - // fine for button-related use cases. - // Therefore it might be used as long as: - // 1. ReactViewManager is not a generic class with a possibility to handle another ViewGroup - // 2. There's no way to force native behavior of ReactViewGroup's superclass's onTouchEvent - if (selectable is RippleDrawable) { - val mask = PaintDrawable(Color.WHITE) - mask.setCornerRadius(borderRadius) - selectable.setDrawableByLayerId(android.R.id.mask, mask) - } + if (hasBorderRadii && selectable is RippleDrawable) { + val mask = PaintDrawable(Color.WHITE) + mask.setCornerRadii(buildBorderRadii()) + selectable.setDrawableByLayerId(android.R.id.mask, mask) } if (useDrawableOnForeground && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { foreground = selectable if (_backgroundColor != Color.TRANSPARENT) { - updateBackgroundColor(_backgroundColor, borderRadius, null) + updateBackgroundColor(_backgroundColor, null) } } else if (_backgroundColor == Color.TRANSPARENT && rippleColor == null) { background = selectable } else { - updateBackgroundColor(_backgroundColor, borderRadius, selectable) + updateBackgroundColor(_backgroundColor, selectable) } } diff --git a/example/src/App.tsx b/example/src/App.tsx index 8b7036a9b9..386f9e703d 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -51,6 +51,7 @@ import HoverableIcons from './new_api/hoverable_icons'; import VelocityTest from './new_api/velocityTest'; import EmptyExample from './empty/EmptyExample'; +import RectButtonBorders from './release_tests/rectButton'; interface Example { name: string; @@ -121,6 +122,7 @@ const EXAMPLES: ExamplesSection[] = [ { name: 'MouseButtons', component: MouseButtons }, { name: 'ContextMenu (web only)', component: ContextMenu }, { name: 'PointerType', component: PointerType }, + { name: 'RectButton (borders)', component: RectButtonBorders }, ], }, { diff --git a/example/src/release_tests/rectButton/index.tsx b/example/src/release_tests/rectButton/index.tsx new file mode 100644 index 0000000000..9a5fd2b373 --- /dev/null +++ b/example/src/release_tests/rectButton/index.tsx @@ -0,0 +1,94 @@ +import React from 'react'; +import { StyleSheet, Text, View } from 'react-native'; +import { RectButton } from 'react-native-gesture-handler'; + +export default function RectButtonBorders() { + return ( + +