@granite-js/image 1.0.26 → 1.0.28

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/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # @granite-js/image
2
2
 
3
+ ## 1.0.28
4
+
5
+ ### Patch Changes
6
+
7
+ - 0eb0277: Fix Android GraniteImage rendering when the native provider view is replaced after the parent view is already laid out.
8
+ - 59a4ab7: Reuse the iOS image provider view across source changes.
9
+
10
+ ## 1.0.27
11
+
3
12
  ## 1.0.26
4
13
 
5
14
  ## 1.0.25
@@ -130,11 +130,7 @@ class GraniteImage(context: Context) : FrameLayout(context) {
130
130
  }
131
131
 
132
132
  private fun loadImageIfReady() {
133
- // Remove existing container view
134
- containerView?.let {
135
- removeView(it)
136
- containerView = null
137
- }
133
+ clearContainerView()
138
134
 
139
135
  val provider = providerResolver()
140
136
 
@@ -154,14 +150,8 @@ class GraniteImage(context: Context) : FrameLayout(context) {
154
150
  // Emit load start event
155
151
  emitLoadStart()
156
152
 
157
- // Create new image view from provider
158
153
  val imageView = provider.createImageView(context)
159
- imageView.layoutParams = LayoutParams(
160
- LayoutParams.MATCH_PARENT,
161
- LayoutParams.MATCH_PARENT
162
- )
163
- addView(imageView)
164
- containerView = imageView
154
+ attachContainerView(imageView)
165
155
 
166
156
  // Load image using provider with full options
167
157
  provider.loadImage(
@@ -185,6 +175,44 @@ class GraniteImage(context: Context) : FrameLayout(context) {
185
175
  )
186
176
  }
187
177
 
178
+ private fun attachContainerView(view: View) {
179
+ view.layoutParams = LayoutParams(
180
+ LayoutParams.MATCH_PARENT,
181
+ LayoutParams.MATCH_PARENT
182
+ )
183
+ addView(view)
184
+ containerView = view
185
+ layoutContainerViewIfPossible(view)
186
+ }
187
+
188
+ private fun clearContainerView() {
189
+ containerView?.let {
190
+ removeView(it)
191
+ containerView = null
192
+ }
193
+ }
194
+
195
+ private fun layoutContainerViewIfPossible(view: View) {
196
+ if (width <= 0 || height <= 0) {
197
+ return
198
+ }
199
+
200
+ val widthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY)
201
+ val heightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
202
+ view.measure(widthSpec, heightSpec)
203
+ view.layout(0, 0, width, height)
204
+ }
205
+
206
+ override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
207
+ super.onSizeChanged(w, h, oldw, oldh)
208
+ containerView?.let(::layoutContainerViewIfPossible)
209
+ }
210
+
211
+ override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
212
+ super.onLayout(changed, left, top, right, bottom)
213
+ containerView?.let(::layoutContainerViewIfPossible)
214
+ }
215
+
188
216
  private fun handleLoadCompletion(
189
217
  bitmap: Bitmap?,
190
218
  error: Exception?,
@@ -245,17 +273,15 @@ class GraniteImage(context: Context) : FrameLayout(context) {
245
273
  }
246
274
 
247
275
  errorView.addView(label)
248
- addView(errorView)
249
- containerView = errorView
276
+ attachContainerView(errorView)
250
277
  }
251
278
 
252
279
  fun cleanup() {
253
280
  val provider = providerResolver()
254
281
  containerView?.let {
255
282
  provider?.cancelLoad(it)
256
- removeView(it)
257
283
  }
258
- containerView = null
284
+ clearContainerView()
259
285
  currentUri = null
260
286
  }
261
287
 
@@ -42,6 +42,7 @@ __attribute__((used)) static void _forceIncludeGraniteImageComponentView(void) {
42
42
 
43
43
  @implementation GraniteImageComponentView {
44
44
  UIView *_containerView;
45
+ UIView *_errorView;
45
46
  NSString *_currentUri;
46
47
  UIViewContentMode _currentContentMode;
47
48
  BOOL _needsInitialLoad;
@@ -198,11 +199,7 @@ __attribute__((used)) static void _forceIncludeGraniteImageComponentView(void) {
198
199
 
199
200
  if (shouldReload) {
200
201
  if (_currentUri.length > 0) {
201
- // 다음 runloop으로 지연하여 _eventEmitter 세팅 후 실행
202
- __weak GraniteImageComponentView *weakSelf = self;
203
- dispatch_async(dispatch_get_main_queue(), ^{
204
- [weakSelf loadImageWithProvider];
205
- });
202
+ [self loadImageWithProvider];
206
203
  } else {
207
204
  // URI가 비어있거나 nil인 경우 에러 발생
208
205
  [self showErrorViewWithMessage:@"No URI provided"];
@@ -259,10 +256,6 @@ __attribute__((used)) static void _forceIncludeGraniteImageComponentView(void) {
259
256
 
260
257
  - (void)loadImageWithProvider
261
258
  {
262
- // Remove existing container view
263
- [_containerView removeFromSuperview];
264
- _containerView = nil;
265
-
266
259
  id<GraniteImageProvidable> provider = [[GraniteImageRegistry shared] provider];
267
260
 
268
261
  if (!provider) {
@@ -279,15 +272,21 @@ __attribute__((used)) static void _forceIncludeGraniteImageComponentView(void) {
279
272
  return;
280
273
  }
281
274
 
282
- // Emit load start event
275
+ [_errorView removeFromSuperview];
276
+ _errorView = nil;
277
+
283
278
  [self emitOnLoadStart];
284
279
 
285
- // Create new image view from provider
286
- UIView *imageView = [provider createImageView];
287
- imageView.frame = self.bounds;
288
- imageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
289
- [self addSubview:imageView];
290
- _containerView = imageView;
280
+ UIView *imageView = _containerView;
281
+ if (!imageView) {
282
+ imageView = [provider createImageView];
283
+ imageView.frame = self.bounds;
284
+ imageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
285
+ [self addSubview:imageView];
286
+ _containerView = imageView;
287
+ } else {
288
+ [provider cancelLoadWith:imageView];
289
+ }
291
290
 
292
291
  // Check if provider supports extended loading with callbacks
293
292
  __weak GraniteImageComponentView *weakSelf = self;
@@ -353,6 +352,8 @@ __attribute__((used)) static void _forceIncludeGraniteImageComponentView(void) {
353
352
 
354
353
  - (void)showErrorViewWithMessage:(NSString *)message
355
354
  {
355
+ [_errorView removeFromSuperview];
356
+
356
357
  UIView *errorView = [[UIView alloc] initWithFrame:self.bounds];
357
358
  errorView.backgroundColor = [UIColor redColor];
358
359
  errorView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
@@ -374,7 +375,7 @@ __attribute__((used)) static void _forceIncludeGraniteImageComponentView(void) {
374
375
  ]];
375
376
 
376
377
  [self addSubview:errorView];
377
- _containerView = errorView;
378
+ _errorView = errorView;
378
379
  }
379
380
 
380
381
  - (void)prepareForRecycle
@@ -388,6 +389,8 @@ __attribute__((used)) static void _forceIncludeGraniteImageComponentView(void) {
388
389
 
389
390
  [_containerView removeFromSuperview];
390
391
  _containerView = nil;
392
+ [_errorView removeFromSuperview];
393
+ _errorView = nil;
391
394
  _currentUri = nil;
392
395
  }
393
396
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@granite-js/image",
3
- "version": "1.0.26",
3
+ "version": "1.0.28",
4
4
  "description": "A pluggable React Native image component that lets you use your existing native image loading infrastructure",
5
5
  "type": "module",
6
6
  "main": "./dist/module/index.js",