react-native-smooth-clip-view 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -13,12 +13,17 @@ native-owned timing or spring motion without animating Yoga layout. A regular
|
|
|
13
13
|
Reanimated `View` with `overflow: 'hidden'` remains the simpler choice when
|
|
14
14
|
layout-thread work and interruption snapshots are not concerns.
|
|
15
15
|
|
|
16
|
+
## Demo
|
|
17
|
+
|
|
18
|
+
https://github.com/user-attachments/assets/899235b3-de69-46d7-b6db-61bc54d80df8
|
|
19
|
+
|
|
16
20
|
## Requirements
|
|
17
21
|
|
|
18
22
|
- React Native 0.86 or newer with the New Architecture
|
|
19
23
|
- React 19.2 or newer
|
|
20
24
|
- React Native Reanimated 4.5 or newer
|
|
21
25
|
- React Native Worklets 0.10.1 or newer
|
|
26
|
+
- Android API 24 or newer
|
|
22
27
|
|
|
23
28
|
```sh
|
|
24
29
|
npm install react-native-smooth-clip-view react-native-reanimated react-native-worklets
|
package/android/build.gradle
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
buildscript {
|
|
2
2
|
ext.SmoothClipView = [
|
|
3
3
|
kotlinVersion: "2.0.21",
|
|
4
|
-
minSdkVersion:
|
|
4
|
+
minSdkVersion: 24,
|
|
5
5
|
compileSdkVersion: 36,
|
|
6
6
|
targetSdkVersion: 36
|
|
7
7
|
]
|
|
@@ -76,10 +76,7 @@ android {
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
defaultConfig {
|
|
79
|
-
//
|
|
80
|
-
// Keep this as a hard library floor: allowing a consuming root project to
|
|
81
|
-
// override it lower would make the per-corner/continuous path silently
|
|
82
|
-
// unsupported at runtime.
|
|
79
|
+
// API 24-32 clip child drawing directly; API 33+ use path outlines.
|
|
83
80
|
minSdkVersion SmoothClipView.minSdkVersion
|
|
84
81
|
targetSdkVersion getExtOrDefault("targetSdkVersion")
|
|
85
82
|
// C++ resolves SmoothClipView by name and calls its presentation setters via
|
|
@@ -22,7 +22,25 @@ import kotlin.math.abs
|
|
|
22
22
|
import kotlin.math.pow
|
|
23
23
|
|
|
24
24
|
class SmoothClipView(context: ThemedReactContext) : ReactViewGroup(context) {
|
|
25
|
-
private val
|
|
25
|
+
private val clipPath = Path()
|
|
26
|
+
private val supportsPathOutlineClipping =
|
|
27
|
+
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU
|
|
28
|
+
private val clipContainer: ReactViewGroup =
|
|
29
|
+
if (supportsPathOutlineClipping) {
|
|
30
|
+
ReactViewGroup(context)
|
|
31
|
+
} else {
|
|
32
|
+
object : ReactViewGroup(context) {
|
|
33
|
+
override fun dispatchDraw(canvas: Canvas) {
|
|
34
|
+
val saveCount = canvas.save()
|
|
35
|
+
canvas.clipPath(clipPath)
|
|
36
|
+
try {
|
|
37
|
+
super.dispatchDraw(canvas)
|
|
38
|
+
} finally {
|
|
39
|
+
canvas.restoreToCount(saveCount)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
26
44
|
internal val contentContainer = ReactViewGroup(context)
|
|
27
45
|
private var requestedX = 0f
|
|
28
46
|
private var requestedY = 0f
|
|
@@ -54,7 +72,6 @@ class SmoothClipView(context: ThemedReactContext) : ReactViewGroup(context) {
|
|
|
54
72
|
private var clipBottomRightRadius = 0f
|
|
55
73
|
private var clipBottomLeftRadius = 0f
|
|
56
74
|
private var clipCurveCode = CLIP_CURVE_CIRCULAR
|
|
57
|
-
private val clipPath = Path()
|
|
58
75
|
private var boxShadowPath: Path? = null
|
|
59
76
|
private var boxShadowPaint: Paint? = null
|
|
60
77
|
private var clipIsEmpty = true
|
|
@@ -75,17 +92,23 @@ class SmoothClipView(context: ThemedReactContext) : ReactViewGroup(context) {
|
|
|
75
92
|
return
|
|
76
93
|
}
|
|
77
94
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
95
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
96
|
+
// Outline.setRoundRect only accepts integer edges. The raw path
|
|
97
|
+
// keeps sub-pixel coordinates and off-host geometry intact.
|
|
98
|
+
outline.setPath(clipPath)
|
|
99
|
+
} else {
|
|
100
|
+
outline.setEmpty()
|
|
101
|
+
}
|
|
81
102
|
}
|
|
82
103
|
}
|
|
83
104
|
|
|
84
105
|
init {
|
|
85
106
|
clipContainer.addView(contentContainer)
|
|
86
107
|
super.addView(clipContainer)
|
|
87
|
-
|
|
88
|
-
|
|
108
|
+
if (supportsPathOutlineClipping) {
|
|
109
|
+
clipContainer.outlineProvider = clipOutlineProvider
|
|
110
|
+
clipContainer.clipToOutline = true
|
|
111
|
+
}
|
|
89
112
|
clipToOutline = false
|
|
90
113
|
setWillNotDraw(false)
|
|
91
114
|
visibility = INVISIBLE
|
|
@@ -479,7 +502,11 @@ class SmoothClipView(context: ThemedReactContext) : ReactViewGroup(context) {
|
|
|
479
502
|
}
|
|
480
503
|
}
|
|
481
504
|
rebuildBoxShadowPath()
|
|
482
|
-
|
|
505
|
+
if (supportsPathOutlineClipping) {
|
|
506
|
+
clipContainer.invalidateOutline()
|
|
507
|
+
} else {
|
|
508
|
+
clipContainer.invalidate()
|
|
509
|
+
}
|
|
483
510
|
if (requestedShadowEnabled) invalidate()
|
|
484
511
|
}
|
|
485
512
|
|
package/package.json
CHANGED