react-native-morph-card 0.1.14 → 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,55 +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
124
-
125
- Log.d(TAG, "captureSnapshot: visiting ${view.javaClass.name} clipToOutline=$hadClip size=${view.width}x${view.height}")
123
+ // Map of Fresco views to their hierarchy (for drawing drawable directly)
124
+ val frescoViews = mutableMapOf<View, Any>()
126
125
 
126
+ fun prepareView(view: View) {
127
127
  // Disable outline clipping
128
- if (hadClip) {
128
+ if (view.clipToOutline) {
129
+ clippedViews.add(view)
129
130
  view.clipToOutline = false
130
131
  }
131
132
 
132
- // Disable Fresco RoundingParams on DraweeView (React Native Image components).
133
- // Uses reflection to avoid a compile-time dependency on Fresco.
133
+ // Detect Fresco DraweeView and disable rounding
134
134
  try {
135
135
  val getHierarchy = view.javaClass.getMethod("getHierarchy")
136
136
  val hierarchy = getHierarchy.invoke(view)
137
137
  if (hierarchy != null) {
138
- Log.d(TAG, "captureSnapshot: found hierarchy ${hierarchy.javaClass.name}")
139
138
  val getRounding = hierarchy.javaClass.getMethod("getRoundingParams")
140
- savedRounding = getRounding.invoke(hierarchy)
141
- Log.d(TAG, "captureSnapshot: roundingParams=$savedRounding")
142
- if (savedRounding != null) {
139
+ val rounding = getRounding.invoke(hierarchy)
140
+ if (rounding != null) {
143
141
  val roundingClass = Class.forName("com.facebook.drawee.generic.RoundingParams")
144
142
  val setRounding = hierarchy.javaClass.getMethod("setRoundingParams", roundingClass)
145
143
  setRounding.invoke(hierarchy, null)
146
- Log.d(TAG, "captureSnapshot: disabled Fresco rounding")
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}")
147
147
  }
148
148
  }
149
- } catch (e: Exception) {
150
- Log.d(TAG, "captureSnapshot: reflection skip for ${view.javaClass.simpleName}: ${e.javaClass.simpleName}")
151
- }
152
-
153
- if (hadClip || savedRounding != null) {
154
- savedStates.add(ViewState(view, hadClip, savedRounding))
155
- }
149
+ } catch (_: Exception) {}
156
150
 
157
151
  if (view is ViewGroup) {
158
152
  for (i in 0 until view.childCount) {
159
- disableClipping(view.getChildAt(i))
153
+ prepareView(view.getChildAt(i))
160
154
  }
161
155
  }
162
156
  }
163
157
 
164
158
  for (i in 0 until childCount) {
165
- 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
+ }
166
197
  }
167
198
 
168
199
  for (i in 0 until childCount) {
@@ -170,26 +201,21 @@ class MorphCardSourceView(context: Context) : ReactViewGroup(context) {
170
201
  if (child.visibility != VISIBLE) continue
171
202
  canvas.save()
172
203
  canvas.translate(child.left.toFloat(), child.top.toFloat())
173
- child.draw(canvas)
204
+ drawView(child, canvas)
174
205
  canvas.restore()
175
206
  }
176
207
 
177
- // Restore all view states
178
- for (state in savedStates) {
179
- if (state.hadClip) {
180
- state.view.clipToOutline = true
181
- }
182
- if (state.roundingParams != null) {
183
- try {
184
- val getHierarchy = state.view.javaClass.getMethod("getHierarchy")
185
- val hierarchy = getHierarchy.invoke(state.view)
186
- if (hierarchy != null) {
187
- val roundingClass = Class.forName("com.facebook.drawee.generic.RoundingParams")
188
- val setRounding = hierarchy.javaClass.getMethod("setRoundingParams", roundingClass)
189
- setRounding.invoke(hierarchy, state.roundingParams)
190
- }
191
- } catch (_: Exception) {}
192
- }
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) {}
193
219
  }
194
220
 
195
221
  return bitmap
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-morph-card",
3
- "version": "0.1.14",
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",