react-native-fast-image 9.2.2 → 9.3.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 +36 -7
- package/android/src/main/java/com/dylanvann/fastimage/FastImageBlur.java +18 -5
- package/android/src/main/java/com/dylanvann/fastimage/FastImageRequestListener.java +5 -1
- package/android/src/main/java/com/dylanvann/fastimage/FastImageSharedDownloads.java +64 -19
- package/android/src/main/java/com/dylanvann/fastimage/FastImageSourceSize.java +22 -0
- package/android/src/main/java/com/dylanvann/fastimage/FastImageSvg.java +27 -0
- package/android/src/main/java/com/dylanvann/fastimage/FastImageSvgRenderer.java +10 -0
- package/android/src/main/java/com/dylanvann/fastimage/FastImageViewConverter.java +5 -0
- package/android/src/main/java/com/dylanvann/fastimage/FastImageViewManager.java +1 -1
- package/android/src/main/java/com/dylanvann/fastimage/FastImageViewWithUrl.java +157 -14
- package/dist/index.cjs.js +50 -18
- package/dist/index.cjs.js.flow +3 -0
- package/dist/index.cjs.web.js +241 -130
- package/dist/index.cjs.web.js.flow +3 -0
- package/dist/index.d.ts +36 -6
- package/dist/index.js +50 -18
- package/dist/index.js.flow +3 -0
- package/dist/index.web.js +243 -132
- package/dist/index.web.js.flow +3 -0
- package/dist/objectFit.d.ts +3 -0
- package/ios/FastImage/FFFDownsampledImage.h +8 -0
- package/ios/FastImage/FFFDownsampledImage.m +16 -0
- package/ios/FastImage/FFFastImageView.h +7 -1
- package/ios/FastImage/FFFastImageView.m +10 -5
- package/ios/FastImage/FFFastImageViewManager.m +3 -1
- package/ios/FastImage/RCTConvert+FFFastImage.h +3 -0
- package/ios/FastImage/RCTConvert+FFFastImage.m +11 -0
- package/package.json +1 -1
|
@@ -9,6 +9,7 @@ import android.annotation.SuppressLint;
|
|
|
9
9
|
import android.content.Context;
|
|
10
10
|
import android.graphics.Bitmap;
|
|
11
11
|
import android.graphics.Canvas;
|
|
12
|
+
import android.graphics.Matrix;
|
|
12
13
|
import android.graphics.Paint;
|
|
13
14
|
import android.graphics.PorterDuff;
|
|
14
15
|
import android.graphics.PorterDuffXfermode;
|
|
@@ -60,6 +61,9 @@ class FastImageViewWithUrl extends AppCompatImageView implements ReactPointerEve
|
|
|
60
61
|
public FastImageViewWithUrl(Context context, @Nullable RequestManager requestManager) {
|
|
61
62
|
super(context);
|
|
62
63
|
this.requestManager = requestManager;
|
|
64
|
+
// An image larger than the view (objectFit none) is cropped to it,
|
|
65
|
+
// also when the view doesn't clip its content (overflow visible).
|
|
66
|
+
setCropToPadding(true);
|
|
63
67
|
}
|
|
64
68
|
|
|
65
69
|
// FastImage sends "none" when it has pointerEvents="box-none" (the image
|
|
@@ -609,19 +613,134 @@ class FastImageViewWithUrl extends AppCompatImageView implements ReactPointerEve
|
|
|
609
613
|
// as React Native's Image does. The view fills with it (FIT_XY).
|
|
610
614
|
private boolean mRepeat = false;
|
|
611
615
|
|
|
616
|
+
// The scale type for resizeMode, which Glide decodes the image for and the
|
|
617
|
+
// blur scales with. For scale-down (CENTER_INSIDE) and none (CENTER) the
|
|
618
|
+
// view is MATRIX: it lays the image out itself (see updateImageMatrix).
|
|
619
|
+
// Starts as ImageView's.
|
|
620
|
+
private ScaleType mResizeScaleType = ScaleType.FIT_CENTER;
|
|
621
|
+
|
|
622
|
+
// resizeMode center: CENTER_INSIDE as ImageView draws it, an image smaller
|
|
623
|
+
// than the view at its size in pixels on the screen (scale-down: in dp).
|
|
624
|
+
private boolean mInPixels = false;
|
|
625
|
+
|
|
626
|
+
// The scale type the image on screen is laid out for (see
|
|
627
|
+
// applyResizeMode).
|
|
628
|
+
private ScaleType mLayoutScaleType = ScaleType.FIT_CENTER;
|
|
629
|
+
|
|
612
630
|
// Glide crops or fits the bitmap for the scale type when it loads, so a
|
|
613
631
|
// new resizeMode needs a reload to take effect (#762).
|
|
614
|
-
public void setResizeMode(ScaleType scaleType, boolean repeat) {
|
|
615
|
-
if (scaleType ==
|
|
616
|
-
|
|
632
|
+
public void setResizeMode(ScaleType scaleType, boolean repeat, boolean inPixels) {
|
|
633
|
+
if (scaleType == mResizeScaleType && repeat == mRepeat && inPixels == mInPixels) return;
|
|
634
|
+
mResizeScaleType = scaleType;
|
|
635
|
+
mInPixels = inPixels;
|
|
617
636
|
mRepeat = repeat;
|
|
618
637
|
mNeedsReload = true;
|
|
638
|
+
// A loaded image on screen was cropped or fitted for the old scale
|
|
639
|
+
// type: it keeps its layout until the image for the new one is ready
|
|
640
|
+
// (onImageLoaded), or the load fails. Laid out for the new one, a
|
|
641
|
+
// cover crop would be stretched to the image's own size.
|
|
642
|
+
if (mShownRequest == null) applyResizeMode();
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
// Lays the view out for resizeMode.
|
|
646
|
+
private void applyResizeMode() {
|
|
647
|
+
mLayoutScaleType = mResizeScaleType;
|
|
648
|
+
setScaleType(!mInPixels && (mResizeScaleType == ScaleType.CENTER_INSIDE || mResizeScaleType == ScaleType.CENTER)
|
|
649
|
+
? ScaleType.MATRIX
|
|
650
|
+
: mResizeScaleType);
|
|
651
|
+
updateImageMatrix();
|
|
619
652
|
}
|
|
620
653
|
|
|
621
654
|
// Repeats what the view shows (the loaded image, and defaultSource).
|
|
622
655
|
@Override
|
|
623
656
|
public void setImageDrawable(@Nullable Drawable drawable) {
|
|
624
657
|
super.setImageDrawable(mRepeat ? tiled(drawable) : drawable);
|
|
658
|
+
updateImageMatrix();
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
@Override
|
|
662
|
+
protected boolean setFrame(int l, int t, int r, int b) {
|
|
663
|
+
boolean changed = super.setFrame(l, t, r, b);
|
|
664
|
+
updateImageMatrix();
|
|
665
|
+
return changed;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// The loaded image's own size in pixels (as onLoad has it), and its scale
|
|
669
|
+
// (a bundled image's, so it's its size in points; 1 for others, as on
|
|
670
|
+
// iOS), for scale-down and none. 0 until it's known.
|
|
671
|
+
private int mImageWidth = 0;
|
|
672
|
+
private int mImageHeight = 0;
|
|
673
|
+
private double mImageScale = 1;
|
|
674
|
+
// The loading source's scale.
|
|
675
|
+
private double mLoadingScale = 1;
|
|
676
|
+
@Nullable
|
|
677
|
+
private Matrix mImageMatrix;
|
|
678
|
+
|
|
679
|
+
// The loading image's own size, from FastImageRequestListener as it's
|
|
680
|
+
// ready (null until a local image's has been read).
|
|
681
|
+
void onImageSize(@Nullable int[] size) {
|
|
682
|
+
mImageWidth = size != null ? size[0] : 0;
|
|
683
|
+
mImageHeight = size != null ? size[1] : 0;
|
|
684
|
+
mImageScale = mLoadingScale;
|
|
685
|
+
updateImageMatrix();
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
// Pixels on screen per pixel of the loaded image at its own size: an image
|
|
689
|
+
// is its size in pixels in dp (a bundled one in points, its pixels divided
|
|
690
|
+
// by its scale), as on iOS.
|
|
691
|
+
private float imageDensity() {
|
|
692
|
+
return (float) (getResources().getDisplayMetrics().density / mImageScale);
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
// The same for the loading image.
|
|
696
|
+
private float loadingDensity() {
|
|
697
|
+
return (float) (getResources().getDisplayMetrics().density / mLoadingScale);
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
// scale-down: the image at its own size, centered, or scaled down
|
|
701
|
+
// uniformly to fit if that's larger than the view. Glide decodes it no
|
|
702
|
+
// larger than that (CenterInside), and it's drawn at this size. none: the
|
|
703
|
+
// image at its own size, centered, whatever its size (cropped by the view;
|
|
704
|
+
// Glide decodes it at its size). defaultSource (a resource) is already at
|
|
705
|
+
// its size on screen.
|
|
706
|
+
private void updateImageMatrix() {
|
|
707
|
+
if (getScaleType() != ScaleType.MATRIX) return;
|
|
708
|
+
Drawable drawable = getDrawable();
|
|
709
|
+
if (drawable == null) return;
|
|
710
|
+
int drawableWidth = drawable.getIntrinsicWidth();
|
|
711
|
+
int drawableHeight = drawable.getIntrinsicHeight();
|
|
712
|
+
float viewWidth = getWidth() - getPaddingLeft() - getPaddingRight();
|
|
713
|
+
float viewHeight = getHeight() - getPaddingTop() - getPaddingBottom();
|
|
714
|
+
if (mImageMatrix == null) mImageMatrix = new Matrix();
|
|
715
|
+
Matrix matrix = mImageMatrix;
|
|
716
|
+
if (drawableWidth <= 0 || drawableHeight <= 0 || viewWidth <= 0 || viewHeight <= 0) {
|
|
717
|
+
matrix.reset();
|
|
718
|
+
setImageMatrix(matrix);
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
721
|
+
float width;
|
|
722
|
+
float height;
|
|
723
|
+
if (drawable == mDefaultSource) {
|
|
724
|
+
width = drawableWidth;
|
|
725
|
+
height = drawableHeight;
|
|
726
|
+
} else if (mImageWidth > 0 && mImageHeight > 0) {
|
|
727
|
+
width = mImageWidth * imageDensity();
|
|
728
|
+
height = mImageHeight * imageDensity();
|
|
729
|
+
} else {
|
|
730
|
+
// Its size isn't known yet (a local image's is read after it
|
|
731
|
+
// loads): Glide decoded it at its size unless it's larger than
|
|
732
|
+
// the view, which shows it scaled down to fit either way.
|
|
733
|
+
width = drawableWidth * imageDensity();
|
|
734
|
+
height = drawableHeight * imageDensity();
|
|
735
|
+
}
|
|
736
|
+
float fit = mLayoutScaleType == ScaleType.CENTER
|
|
737
|
+
? 1
|
|
738
|
+
: Math.min(1, Math.min(viewWidth / width, viewHeight / height));
|
|
739
|
+
width *= fit;
|
|
740
|
+
height *= fit;
|
|
741
|
+
matrix.setScale(width / drawableWidth, height / drawableHeight);
|
|
742
|
+
matrix.postTranslate(Math.round((viewWidth - width) / 2), Math.round((viewHeight - height) / 2));
|
|
743
|
+
setImageMatrix(matrix);
|
|
625
744
|
}
|
|
626
745
|
|
|
627
746
|
@Nullable
|
|
@@ -668,7 +787,9 @@ class FastImageViewWithUrl extends AppCompatImageView implements ReactPointerEve
|
|
|
668
787
|
// pixelated, and the blur. A blurred animated image shows its first frame,
|
|
669
788
|
// as on iOS.
|
|
670
789
|
private RequestOptions renderingOptions(Object model) {
|
|
671
|
-
FastImageBlur blur = mBlurRadius > 0
|
|
790
|
+
FastImageBlur blur = mBlurRadius > 0
|
|
791
|
+
? new FastImageBlur(mBlurRadius, mRepeat ? null : mResizeScaleType, mInPixels ? 1 : loadingDensity())
|
|
792
|
+
: null;
|
|
672
793
|
RequestOptions options;
|
|
673
794
|
if (mRepeat) {
|
|
674
795
|
// Decoded at its own size, or scaled down to fit the view if it's
|
|
@@ -690,7 +811,15 @@ class FastImageViewWithUrl extends AppCompatImageView implements ReactPointerEve
|
|
|
690
811
|
if (blur != null) options = options.optionalTransform(blur);
|
|
691
812
|
} else {
|
|
692
813
|
options = FastImageSourceSize.scaleTypeOptions(
|
|
693
|
-
|
|
814
|
+
mResizeScaleType, FastImageSourceSize.capture(mResizeScaleType, model), blur);
|
|
815
|
+
boolean ownSize = mResizeScaleType == ScaleType.CENTER_INSIDE || mResizeScaleType == ScaleType.CENTER;
|
|
816
|
+
// scale-down and none show it at its own size in dp: an SVG is
|
|
817
|
+
// drawn at that size, so it's sharp (not with a blur, which hides
|
|
818
|
+
// the difference).
|
|
819
|
+
if (ownSize && !mInPixels && blur == null) {
|
|
820
|
+
options = options.set(FastImageSvg.DENSITY, loadingDensity())
|
|
821
|
+
.set(FastImageSvg.FITS, mResizeScaleType == ScaleType.CENTER_INSIDE);
|
|
822
|
+
}
|
|
694
823
|
}
|
|
695
824
|
return blur != null ? options.dontAnimate() : options;
|
|
696
825
|
}
|
|
@@ -708,12 +837,13 @@ class FastImageViewWithUrl extends AppCompatImageView implements ReactPointerEve
|
|
|
708
837
|
// have).
|
|
709
838
|
private boolean mRestarting = false;
|
|
710
839
|
|
|
711
|
-
// The request for the image the view shows
|
|
712
|
-
//
|
|
713
|
-
//
|
|
714
|
-
//
|
|
715
|
-
//
|
|
716
|
-
//
|
|
840
|
+
// The request for the image the view shows (from when it has loaded until
|
|
841
|
+
// another image or defaultSource replaces it), and the one loading. A new
|
|
842
|
+
// source starts with the shown one as a thumbnail, from the cache only, so
|
|
843
|
+
// the image stays until the new one has loaded instead of flashing blank
|
|
844
|
+
// (#747), also if the source changes again meanwhile. This is Glide's safe
|
|
845
|
+
// way to do that: the previous bitmap can't be kept in the view itself,
|
|
846
|
+
// since Glide reuses it once its request is cleared.
|
|
717
847
|
@Nullable
|
|
718
848
|
private RequestBuilder<Drawable> mShownRequest;
|
|
719
849
|
@Nullable
|
|
@@ -751,6 +881,8 @@ class FastImageViewWithUrl extends AppCompatImageView implements ReactPointerEve
|
|
|
751
881
|
void onImageLoaded() {
|
|
752
882
|
mLoadEnded = true;
|
|
753
883
|
endProgress();
|
|
884
|
+
// Before the view shows it (the target does once this returns).
|
|
885
|
+
applyResizeMode();
|
|
754
886
|
mShownRequest = mLoadingRequest;
|
|
755
887
|
mShownWidth = mLoadingWidth;
|
|
756
888
|
mShownHeight = mLoadingHeight;
|
|
@@ -905,6 +1037,7 @@ class FastImageViewWithUrl extends AppCompatImageView implements ReactPointerEve
|
|
|
905
1037
|
void onImageFailed(boolean hadThumbnail) {
|
|
906
1038
|
mLoadEnded = true;
|
|
907
1039
|
endProgress();
|
|
1040
|
+
applyResizeMode();
|
|
908
1041
|
mShownRequest = null;
|
|
909
1042
|
if (!hadThumbnail) return;
|
|
910
1043
|
final int load = mLoadCount;
|
|
@@ -961,15 +1094,17 @@ class FastImageViewWithUrl extends AppCompatImageView implements ReactPointerEve
|
|
|
961
1094
|
mRestarting = false;
|
|
962
1095
|
mLoadCount++;
|
|
963
1096
|
// A fade in progress carries on, as on iOS: into the next image if it
|
|
964
|
-
// shows at once, and a next image that fades starts from it.
|
|
1097
|
+
// shows at once, and a next image that fades starts from it. The
|
|
1098
|
+
// image on screen stays the shown one while the next loads (as its
|
|
1099
|
+
// thumbnail, or a copy), so a change before then keeps it too.
|
|
965
1100
|
RequestBuilder<Drawable> shownRequest = mShownRequest;
|
|
966
|
-
mShownRequest = null;
|
|
967
1101
|
mLoadingRequest = null;
|
|
968
1102
|
mBaseRequest = null;
|
|
969
1103
|
mModel = null;
|
|
970
1104
|
|
|
971
1105
|
// Nothing to show.
|
|
972
1106
|
if (mSource == null && mDefaultSource == null) {
|
|
1107
|
+
mShownRequest = null;
|
|
973
1108
|
// Cancel existing requests.
|
|
974
1109
|
clearView(requestManager);
|
|
975
1110
|
|
|
@@ -980,6 +1115,9 @@ class FastImageViewWithUrl extends AppCompatImageView implements ReactPointerEve
|
|
|
980
1115
|
return;
|
|
981
1116
|
}
|
|
982
1117
|
|
|
1118
|
+
mLoadingScale = mSource != null && mSource.hasKey("__packager_asset")
|
|
1119
|
+
? Math.max(number(mSource, "scale", 1), 0.01)
|
|
1120
|
+
: 1;
|
|
983
1121
|
//final GlideUrl glideUrl = FastImageViewConverter.getGlideUrl(view.getContext(), mSource);
|
|
984
1122
|
final FastImageSource imageSource = FastImageViewConverter.hasUri(mSource)
|
|
985
1123
|
? FastImageViewConverter.getImageSource(getContext(), mSource)
|
|
@@ -995,6 +1133,7 @@ class FastImageViewWithUrl extends AppCompatImageView implements ReactPointerEve
|
|
|
995
1133
|
FastImageEvents.send(this, REACT_ON_ERROR_EVENT, event);
|
|
996
1134
|
FastImageEvents.sendLoadEnd(this, error);
|
|
997
1135
|
|
|
1136
|
+
mShownRequest = null;
|
|
998
1137
|
// Cancel existing requests.
|
|
999
1138
|
clearView(requestManager);
|
|
1000
1139
|
|
|
@@ -1053,7 +1192,11 @@ class FastImageViewWithUrl extends AppCompatImageView implements ReactPointerEve
|
|
|
1053
1192
|
RequestBuilder<Drawable> builder = base.clone().apply(renderingOptions(model));
|
|
1054
1193
|
RequestBuilder<Drawable> request = builder.clone();
|
|
1055
1194
|
|
|
1056
|
-
|
|
1195
|
+
// Only defaultSource: it replaces the image.
|
|
1196
|
+
if (model == null) {
|
|
1197
|
+
meanwhile = null;
|
|
1198
|
+
mShownRequest = null;
|
|
1199
|
+
}
|
|
1057
1200
|
boolean thumbnail = shownRequest != null && model != null && meanwhile == null;
|
|
1058
1201
|
// After the clone: loading the image that's showing again (at a
|
|
1059
1202
|
// new size, or with another blur) doesn't fade it in again. Over a
|
package/dist/index.cjs.js
CHANGED
|
@@ -46,30 +46,61 @@ const cacheControl = {
|
|
|
46
46
|
cacheOnly: "cacheOnly"
|
|
47
47
|
};
|
|
48
48
|
//#endregion
|
|
49
|
-
//#region src/
|
|
50
|
-
|
|
51
|
-
if (!defaultSource) return null;
|
|
52
|
-
if (react_native.Platform.OS === "android") {
|
|
53
|
-
const resolved = react_native.Image.resolveAssetSource(defaultSource);
|
|
54
|
-
if (resolved) return resolved.uri;
|
|
55
|
-
return null;
|
|
56
|
-
}
|
|
57
|
-
return defaultSource;
|
|
58
|
-
};
|
|
59
|
-
function tintColorFromStyle(style) {
|
|
49
|
+
//#region src/objectFit.ts
|
|
50
|
+
function fromStyle(style, key) {
|
|
60
51
|
if (Array.isArray(style)) {
|
|
61
52
|
for (let i = style.length - 1; i >= 0; i--) {
|
|
62
|
-
const found =
|
|
53
|
+
const found = fromStyle(style[i], key);
|
|
63
54
|
if (found !== void 0) return found;
|
|
64
55
|
}
|
|
65
56
|
return;
|
|
66
57
|
}
|
|
67
58
|
if (typeof style === "number") {
|
|
68
59
|
const flattened = react_native.StyleSheet.flatten(style);
|
|
69
|
-
return flattened ? flattened
|
|
60
|
+
return flattened ? flattened[key] : void 0;
|
|
70
61
|
}
|
|
71
|
-
return style && typeof style === "object" ? style
|
|
62
|
+
return style && typeof style === "object" ? style[key] : void 0;
|
|
63
|
+
}
|
|
64
|
+
const RESIZE_MODE_FIT = {
|
|
65
|
+
contain: "contain",
|
|
66
|
+
cover: "cover",
|
|
67
|
+
stretch: "fill",
|
|
68
|
+
center: "center",
|
|
69
|
+
repeat: "repeat"
|
|
70
|
+
};
|
|
71
|
+
const FITS = {
|
|
72
|
+
fill: true,
|
|
73
|
+
contain: true,
|
|
74
|
+
cover: true,
|
|
75
|
+
none: true,
|
|
76
|
+
"scale-down": true
|
|
77
|
+
};
|
|
78
|
+
function resolveObjectFit(objectFit, style, resizeMode) {
|
|
79
|
+
var _RESIZE_MODE_FIT$resi;
|
|
80
|
+
const fit = objectFit != null ? objectFit : fromStyle(style, "objectFit");
|
|
81
|
+
if (fit && FITS[fit] === true) return fit;
|
|
82
|
+
return (_RESIZE_MODE_FIT$resi = RESIZE_MODE_FIT[resizeMode]) !== null && _RESIZE_MODE_FIT$resi !== void 0 ? _RESIZE_MODE_FIT$resi : "cover";
|
|
72
83
|
}
|
|
84
|
+
//#endregion
|
|
85
|
+
//#region src/index.tsx
|
|
86
|
+
const resolveDefaultSource = (defaultSource) => {
|
|
87
|
+
if (!defaultSource) return null;
|
|
88
|
+
if (react_native.Platform.OS === "android") {
|
|
89
|
+
const resolved = react_native.Image.resolveAssetSource(defaultSource);
|
|
90
|
+
if (resolved) return resolved.uri;
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
return defaultSource;
|
|
94
|
+
};
|
|
95
|
+
const NATIVE_RESIZE_MODE = {
|
|
96
|
+
fill: "stretch",
|
|
97
|
+
contain: "contain",
|
|
98
|
+
cover: "cover",
|
|
99
|
+
none: "none",
|
|
100
|
+
"scale-down": "scale-down",
|
|
101
|
+
center: "center",
|
|
102
|
+
repeat: "repeat"
|
|
103
|
+
};
|
|
73
104
|
function loopCount(loop) {
|
|
74
105
|
if (loop === void 0) return -1;
|
|
75
106
|
if (loop === true) return 0;
|
|
@@ -111,7 +142,7 @@ function withoutCache(source) {
|
|
|
111
142
|
const { cache: _cache, ...rest } = source || {};
|
|
112
143
|
return rest;
|
|
113
144
|
}
|
|
114
|
-
function FastImageBase({ source, defaultSource, tintColor, onLoadStart, onProgress, onLoad, onError, onLoadEnd, style, fallback, children, resizeMode = "cover", loop, transition, forwardedRef, onLayout, pointerEvents, hitSlop, onStartShouldSetResponder, onStartShouldSetResponderCapture, onMoveShouldSetResponder, onMoveShouldSetResponderCapture, onResponderGrant, onResponderReject, onResponderStart, onResponderMove, onResponderEnd, onResponderRelease, onResponderTerminationRequest, onResponderTerminate, onTouchStart, onTouchMove, onTouchEnd, onTouchCancel, onTouchEndCapture, ...viewProps }) {
|
|
145
|
+
function FastImageBase({ source, defaultSource, tintColor, onLoadStart, onProgress, onLoad, onError, onLoadEnd, style, fallback, children, objectFit, resizeMode = "cover", loop, transition, forwardedRef, onLayout, pointerEvents, hitSlop, onStartShouldSetResponder, onStartShouldSetResponderCapture, onMoveShouldSetResponder, onMoveShouldSetResponderCapture, onResponderGrant, onResponderReject, onResponderStart, onResponderMove, onResponderEnd, onResponderRelease, onResponderTerminationRequest, onResponderTerminate, onTouchStart, onTouchMove, onTouchEnd, onTouchCancel, onTouchEndCapture, ...viewProps }) {
|
|
115
146
|
const { onClick, ...props } = viewProps;
|
|
116
147
|
const fallbackResult = (0, react.useRef)(void 0);
|
|
117
148
|
const wrapperProps = {
|
|
@@ -141,7 +172,8 @@ function FastImageBase({ source, defaultSource, tintColor, onLoadStart, onProgre
|
|
|
141
172
|
...props,
|
|
142
173
|
pointerEvents: pointerEvents === "box-none" ? "none" : void 0
|
|
143
174
|
};
|
|
144
|
-
const resolvedTintColor = tintColor != null ? tintColor :
|
|
175
|
+
const resolvedTintColor = tintColor != null ? tintColor : fromStyle(style, "tintColor");
|
|
176
|
+
const mode = NATIVE_RESIZE_MODE[resolveObjectFit(objectFit, style, resizeMode)];
|
|
145
177
|
if (fallback) {
|
|
146
178
|
const cleanedSource = typeof source === "number" ? source : Array.isArray(source) ? source.map(withoutCache) : withoutCache(source);
|
|
147
179
|
const resolvedSource = react_native.Image.resolveAssetSource(cleanedSource);
|
|
@@ -179,7 +211,7 @@ function FastImageBase({ source, defaultSource, tintColor, onLoadStart, onProgre
|
|
|
179
211
|
error: "Failed to load the image"
|
|
180
212
|
});
|
|
181
213
|
}),
|
|
182
|
-
resizeMode
|
|
214
|
+
resizeMode: mode === "none" || mode === "scale-down" ? "center" : mode
|
|
183
215
|
}), children);
|
|
184
216
|
}
|
|
185
217
|
const sources = Array.isArray(source) ? source.length === 1 ? void 0 : source : void 0;
|
|
@@ -205,7 +237,7 @@ function FastImageBase({ source, defaultSource, tintColor, onLoadStart, onProgre
|
|
|
205
237
|
onFastImageLoad: onLoad,
|
|
206
238
|
onFastImageError: onError,
|
|
207
239
|
onFastImageLoadEnd: onLoadEnd && ((event) => onLoadEnd(loadResult(event.nativeEvent))),
|
|
208
|
-
resizeMode
|
|
240
|
+
resizeMode: mode
|
|
209
241
|
}), children);
|
|
210
242
|
}
|
|
211
243
|
const FastImageMemo = (0, react.memo)(FastImageBase);
|
package/dist/index.cjs.js.flow
CHANGED
|
@@ -49,6 +49,7 @@ export type CacheControl = $ReadOnly<{|
|
|
|
49
49
|
|}>
|
|
50
50
|
|
|
51
51
|
export type ResizeModes = $Values<ResizeMode>
|
|
52
|
+
export type ObjectFit = 'fill' | 'contain' | 'cover' | 'none' | 'scale-down'
|
|
52
53
|
export type Priorities = $Values<Priority>
|
|
53
54
|
export type CacheControls = $Values<CacheControl>
|
|
54
55
|
|
|
@@ -123,6 +124,8 @@ export type FastImageProps = $ReadOnly<{|
|
|
|
123
124
|
defaultSource?: ?number,
|
|
124
125
|
|
|
125
126
|
tintColor?: number | string,
|
|
127
|
+
objectFit?: ?ObjectFit,
|
|
128
|
+
// Deprecated: use objectFit.
|
|
126
129
|
resizeMode?: ?ResizeModes,
|
|
127
130
|
fallback?: ?boolean,
|
|
128
131
|
recyclingKey?: ?string,
|