react-native-morph-card 0.1.13 → 0.1.15

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.
@@ -114,48 +114,86 @@ class MorphCardSourceView(context: Context) : ReactViewGroup(context) {
114
114
  val bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888)
115
115
  val canvas = Canvas(bitmap)
116
116
 
117
- // Track state to restore: (view, hadClipToOutline, savedRoundingParams)
118
- data class ViewState(val view: View, val hadClip: Boolean, val roundingParams: Any?)
119
- val savedStates = mutableListOf<ViewState>()
117
+ // Track Fresco views to restore rounding after capture
118
+ data class FrescoState(val view: View, val hierarchy: Any, val roundingParams: Any)
119
+ val frescoStates = mutableListOf<FrescoState>()
120
+ // Track views whose clipToOutline was disabled
121
+ val clippedViews = mutableListOf<View>()
120
122
 
121
- fun disableClipping(view: View) {
122
- val hadClip = view.clipToOutline
123
- var savedRounding: Any? = null
123
+ // Map of Fresco views to their hierarchy (for drawing drawable directly)
124
+ val frescoViews = mutableMapOf<View, Any>()
124
125
 
126
+ fun prepareView(view: View) {
125
127
  // Disable outline clipping
126
- if (hadClip) {
128
+ if (view.clipToOutline) {
129
+ clippedViews.add(view)
127
130
  view.clipToOutline = false
128
131
  }
129
132
 
130
- // Disable Fresco RoundingParams on DraweeView (React Native Image components).
131
- // Uses reflection to avoid a compile-time dependency on Fresco.
133
+ // Detect Fresco DraweeView and disable rounding
132
134
  try {
133
135
  val getHierarchy = view.javaClass.getMethod("getHierarchy")
134
136
  val hierarchy = getHierarchy.invoke(view)
135
137
  if (hierarchy != null) {
136
138
  val getRounding = hierarchy.javaClass.getMethod("getRoundingParams")
137
- savedRounding = getRounding.invoke(hierarchy)
138
- if (savedRounding != null) {
139
+ val rounding = getRounding.invoke(hierarchy)
140
+ if (rounding != null) {
139
141
  val roundingClass = Class.forName("com.facebook.drawee.generic.RoundingParams")
140
142
  val setRounding = hierarchy.javaClass.getMethod("setRoundingParams", roundingClass)
141
143
  setRounding.invoke(hierarchy, null)
144
+ frescoStates.add(FrescoState(view, hierarchy, rounding))
145
+ frescoViews[view] = hierarchy
146
+ Log.d(TAG, "captureSnapshot: disabled Fresco rounding on ${view.width}x${view.height}")
142
147
  }
143
148
  }
144
149
  } catch (_: Exception) {}
145
150
 
146
- if (hadClip || savedRounding != null) {
147
- savedStates.add(ViewState(view, hadClip, savedRounding))
148
- }
149
-
150
151
  if (view is ViewGroup) {
151
152
  for (i in 0 until view.childCount) {
152
- disableClipping(view.getChildAt(i))
153
+ prepareView(view.getChildAt(i))
153
154
  }
154
155
  }
155
156
  }
156
157
 
157
158
  for (i in 0 until childCount) {
158
- disableClipping(getChildAt(i))
159
+ prepareView(getChildAt(i))
160
+ }
161
+
162
+ // Draw children. For Fresco views, draw the top-level drawable directly
163
+ // (since the internal drawable is rebuilt when roundingParams changes).
164
+ fun drawView(view: View, c: Canvas) {
165
+ val hierarchy = frescoViews[view]
166
+ if (hierarchy != null) {
167
+ try {
168
+ val getTopDrawable = hierarchy.javaClass.getMethod("getTopLevelDrawable")
169
+ val drawable = getTopDrawable.invoke(hierarchy) as? android.graphics.drawable.Drawable
170
+ if (drawable != null) {
171
+ drawable.setBounds(0, 0, view.width, view.height)
172
+ drawable.invalidateSelf()
173
+ drawable.draw(c)
174
+ Log.d(TAG, "captureSnapshot: drew Fresco drawable directly ${view.width}x${view.height}")
175
+ return
176
+ }
177
+ } catch (_: Exception) {}
178
+ }
179
+
180
+ if (view is ViewGroup) {
181
+ // Draw background
182
+ view.background?.let { bg ->
183
+ bg.setBounds(0, 0, view.width, view.height)
184
+ bg.draw(c)
185
+ }
186
+ for (i in 0 until view.childCount) {
187
+ val child = view.getChildAt(i)
188
+ if (child.visibility != VISIBLE) continue
189
+ c.save()
190
+ c.translate(child.left.toFloat(), child.top.toFloat())
191
+ drawView(child, c)
192
+ c.restore()
193
+ }
194
+ } else {
195
+ view.draw(c)
196
+ }
159
197
  }
160
198
 
161
199
  for (i in 0 until childCount) {
@@ -163,26 +201,21 @@ class MorphCardSourceView(context: Context) : ReactViewGroup(context) {
163
201
  if (child.visibility != VISIBLE) continue
164
202
  canvas.save()
165
203
  canvas.translate(child.left.toFloat(), child.top.toFloat())
166
- child.draw(canvas)
204
+ drawView(child, canvas)
167
205
  canvas.restore()
168
206
  }
169
207
 
170
- // Restore all view states
171
- for (state in savedStates) {
172
- if (state.hadClip) {
173
- state.view.clipToOutline = true
174
- }
175
- if (state.roundingParams != null) {
176
- try {
177
- val getHierarchy = state.view.javaClass.getMethod("getHierarchy")
178
- val hierarchy = getHierarchy.invoke(state.view)
179
- if (hierarchy != null) {
180
- val roundingClass = Class.forName("com.facebook.drawee.generic.RoundingParams")
181
- val setRounding = hierarchy.javaClass.getMethod("setRoundingParams", roundingClass)
182
- setRounding.invoke(hierarchy, state.roundingParams)
183
- }
184
- } catch (_: Exception) {}
185
- }
208
+ // Restore clipToOutline
209
+ for (view in clippedViews) {
210
+ view.clipToOutline = true
211
+ }
212
+ // Restore Fresco rounding params
213
+ for (state in frescoStates) {
214
+ try {
215
+ val roundingClass = Class.forName("com.facebook.drawee.generic.RoundingParams")
216
+ val setRounding = state.hierarchy.javaClass.getMethod("setRoundingParams", roundingClass)
217
+ setRounding.invoke(state.hierarchy, state.roundingParams)
218
+ } catch (_: Exception) {}
186
219
  }
187
220
 
188
221
  return bitmap
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-morph-card",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "description": "Native card-to-modal morph transition for React Native. iOS App Store-style expand animation.",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",