mirror of
https://github.com/status-im/react-native.git
synced 2025-03-01 09:30:33 +00:00
Add support for ImageLoadEvents to RCTImageView
Summary: This diff implements ImageLoadEvents (ON_LOAD, ON_LOAD_END and ON_LOAD_START) in RCTImageView. ON_ERROR and ON_PROGRESS are easy to implement, too, but these 2 are supposed to carry extra information (error message and progress) but ImageLoadEvent doesn't support a payload yet (I'll add them in a separate patch). Reviewed By: ahmedre Differential Revision: D2824772
This commit is contained in:
parent
76abec8894
commit
59fe71caff
@ -14,4 +14,5 @@ import android.graphics.Bitmap;
|
||||
/* package */ interface BitmapUpdateListener {
|
||||
public void onSecondaryAttach(Bitmap bitmap);
|
||||
public void onBitmapReady(Bitmap bitmap);
|
||||
public void onImageLoadEvent(int imageLoadEvent);
|
||||
}
|
||||
|
@ -44,6 +44,11 @@ import com.facebook.imagepipeline.request.ImageRequest;
|
||||
*/
|
||||
public ScaleType getScaleType();
|
||||
|
||||
/**
|
||||
* React tag used for dispatching ImageLoadEvents, or 0 to ignore events.
|
||||
*/
|
||||
public void setReactTag(int reactTag);
|
||||
|
||||
public void setBorderWidth(float borderWidth);
|
||||
|
||||
public float getBorderWidth();
|
||||
|
@ -14,19 +14,23 @@ import javax.annotation.Nullable;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffColorFilter;
|
||||
import android.graphics.drawable.Animatable;
|
||||
|
||||
import com.facebook.drawee.controller.ControllerListener;
|
||||
import com.facebook.drawee.drawable.ScalingUtils.ScaleType;
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchy;
|
||||
import com.facebook.drawee.generic.RoundingParams;
|
||||
import com.facebook.imagepipeline.request.ImageRequest;
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.react.views.image.ImageLoadEvent;
|
||||
import com.facebook.react.views.image.ImageResizeMode;
|
||||
|
||||
/**
|
||||
* DrawImageWithDrawee is DrawCommand that can draw a local or remote image.
|
||||
* It uses DraweeRequestHelper internally to fetch and cache the images.
|
||||
*/
|
||||
/* package */ final class DrawImageWithDrawee extends AbstractDrawCommand implements DrawImage {
|
||||
/* package */ final class DrawImageWithDrawee extends AbstractDrawCommand
|
||||
implements DrawImage, ControllerListener {
|
||||
|
||||
private @Nullable DraweeRequestHelper mRequestHelper;
|
||||
private @Nullable PorterDuffColorFilter mColorFilter;
|
||||
@ -34,6 +38,8 @@ import com.facebook.react.views.image.ImageResizeMode;
|
||||
private float mBorderWidth;
|
||||
private float mBorderRadius;
|
||||
private int mBorderColor;
|
||||
private int mReactTag;
|
||||
private @Nullable FlatViewGroup.InvalidateCallback mCallback;
|
||||
|
||||
@Override
|
||||
public boolean hasImageRequest() {
|
||||
@ -45,7 +51,7 @@ import com.facebook.react.views.image.ImageResizeMode;
|
||||
if (imageRequest == null) {
|
||||
mRequestHelper = null;
|
||||
} else {
|
||||
mRequestHelper = new DraweeRequestHelper(imageRequest);
|
||||
mRequestHelper = new DraweeRequestHelper(imageRequest, this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,6 +104,11 @@ import com.facebook.react.views.image.ImageResizeMode;
|
||||
return mBorderColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReactTag(int reactTag) {
|
||||
mReactTag = reactTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDraw(Canvas canvas) {
|
||||
Assertions.assumeNotNull(mRequestHelper).getDrawable().draw(canvas);
|
||||
@ -105,6 +116,8 @@ import com.facebook.react.views.image.ImageResizeMode;
|
||||
|
||||
@Override
|
||||
public void onAttached(FlatViewGroup.InvalidateCallback callback) {
|
||||
mCallback = callback;
|
||||
|
||||
GenericDraweeHierarchy hierarchy = Assertions.assumeNotNull(mRequestHelper).getHierarchy();
|
||||
|
||||
RoundingParams roundingParams = hierarchy.getRoundingParams();
|
||||
@ -140,6 +153,43 @@ import com.facebook.react.views.image.ImageResizeMode;
|
||||
Assertions.assumeNotNull(mRequestHelper).detach();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSubmit(String id, Object callerContext) {
|
||||
if (mCallback != null && mReactTag != 0) {
|
||||
mCallback.dispatchImageLoadEvent(mReactTag, ImageLoadEvent.ON_LOAD_START);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinalImageSet(
|
||||
String id,
|
||||
@Nullable Object imageInfo,
|
||||
@Nullable Animatable animatable) {
|
||||
if (mCallback != null && mReactTag != 0) {
|
||||
mCallback.dispatchImageLoadEvent(mReactTag, ImageLoadEvent.ON_LOAD_END);
|
||||
mCallback.dispatchImageLoadEvent(mReactTag, ImageLoadEvent.ON_LOAD);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onIntermediateImageSet(String id, @Nullable Object imageInfo) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onIntermediateImageFailed(String id, Throwable throwable) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(String id, Throwable throwable) {
|
||||
if (mCallback != null && mReactTag != 0) {
|
||||
mCallback.dispatchImageLoadEvent(mReactTag, ImageLoadEvent.ON_LOAD_END);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRelease(String id) {
|
||||
}
|
||||
|
||||
private boolean shouldDisplayBorder() {
|
||||
return mBorderColor != 0 || mBorderRadius >= 0.5f;
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ import com.facebook.react.views.image.ImageResizeMode;
|
||||
private @Nullable Path mPathForRoundedBitmap;
|
||||
private @Nullable BitmapShader mBitmapShader;
|
||||
private boolean mForceClip;
|
||||
private int mReactTag;
|
||||
|
||||
@Override
|
||||
public boolean hasImageRequest() {
|
||||
@ -80,6 +81,11 @@ import com.facebook.react.views.image.ImageResizeMode;
|
||||
return mScaleType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReactTag(int reactTag) {
|
||||
mReactTag = reactTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
Bitmap bitmap = Assertions.assumeNotNull(mRequestHelper).getBitmap();
|
||||
@ -148,6 +154,13 @@ import com.facebook.react.views.image.ImageResizeMode;
|
||||
updateBounds(bitmap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onImageLoadEvent(int imageLoadEvent) {
|
||||
if (mReactTag != 0 && mCallback != null) {
|
||||
mCallback.dispatchImageLoadEvent(mReactTag, imageLoadEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/* package */ void updateBounds(Bitmap bitmap) {
|
||||
Assertions.assumeNotNull(mCallback).invalidate();
|
||||
|
||||
|
@ -14,6 +14,7 @@ import android.content.res.Resources;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import com.facebook.drawee.controller.AbstractDraweeControllerBuilder;
|
||||
import com.facebook.drawee.controller.ControllerListener;
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchy;
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
|
||||
import com.facebook.drawee.interfaces.DraweeController;
|
||||
@ -37,10 +38,11 @@ import com.facebook.infer.annotation.Assertions;
|
||||
private final DraweeController mDraweeController;
|
||||
private int mAttachCounter;
|
||||
|
||||
/* package */ DraweeRequestHelper(ImageRequest imageRequest) {
|
||||
/* package */ DraweeRequestHelper(ImageRequest imageRequest, ControllerListener listener) {
|
||||
DraweeController controller = sControllerBuilder
|
||||
.setImageRequest(imageRequest)
|
||||
.setCallerContext(RCTImageView.getCallerContext())
|
||||
.setControllerListener(listener)
|
||||
.build();
|
||||
|
||||
controller.setHierarchy(sHierarchyBuilder.build());
|
||||
|
@ -18,17 +18,21 @@ import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.SystemClock;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewParent;
|
||||
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.bridge.SoftAssertions;
|
||||
import com.facebook.react.touch.CatalystInterceptingViewGroup;
|
||||
import com.facebook.react.touch.OnInterceptTouchEventListener;
|
||||
import com.facebook.react.uimanager.PointerEvents;
|
||||
import com.facebook.react.uimanager.ReactCompoundView;
|
||||
import com.facebook.react.uimanager.ReactPointerEventsView;
|
||||
import com.facebook.react.uimanager.UIManagerModule;
|
||||
import com.facebook.react.views.image.ImageLoadEvent;
|
||||
|
||||
/**
|
||||
* A view that FlatShadowNode hierarchy maps to. Performs drawing by iterating over
|
||||
@ -54,6 +58,18 @@ import com.facebook.react.uimanager.ReactPointerEventsView;
|
||||
view.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
public void dispatchImageLoadEvent(int reactTag, int imageLoadEvent) {
|
||||
FlatViewGroup view = get();
|
||||
if (view == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ReactContext reactContext = ((ReactContext) view.getContext());
|
||||
UIManagerModule uiManagerModule = reactContext.getNativeModule(UIManagerModule.class);
|
||||
uiManagerModule.getEventDispatcher().dispatchEvent(
|
||||
new ImageLoadEvent(reactTag, SystemClock.uptimeMillis(), imageLoadEvent));
|
||||
}
|
||||
}
|
||||
|
||||
private static final ArrayList<FlatViewGroup> LAYOUT_REQUESTS = new ArrayList<>();
|
||||
|
@ -99,6 +99,11 @@ import com.facebook.infer.annotation.Assertions;
|
||||
Assertions.assumeNotNull(mCallback).invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onImageLoadEvent(int imageLoadEvent) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttached(FlatViewGroup.InvalidateCallback callback) {
|
||||
mCallback = callback;
|
||||
|
@ -23,6 +23,7 @@ import com.facebook.imagepipeline.image.CloseableBitmap;
|
||||
import com.facebook.imagepipeline.image.CloseableImage;
|
||||
import com.facebook.imagepipeline.request.ImageRequest;
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.react.views.image.ImageLoadEvent;
|
||||
|
||||
/**
|
||||
* Helper class for DrawImage that helps manage fetch requests through ImagePipeline.
|
||||
@ -54,11 +55,13 @@ import com.facebook.infer.annotation.Assertions;
|
||||
// this is a secondary attach, ignore it, only updating Bitmap boundaries if needed.
|
||||
Bitmap bitmap = getBitmap();
|
||||
if (bitmap != null) {
|
||||
mBitmapUpdateListener.onSecondaryAttach(bitmap);
|
||||
listener.onSecondaryAttach(bitmap);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
listener.onImageLoadEvent(ImageLoadEvent.ON_LOAD_START);
|
||||
|
||||
Assertions.assertCondition(mDataSource == null);
|
||||
Assertions.assertCondition(mImageRef == null);
|
||||
|
||||
@ -150,7 +153,10 @@ import com.facebook.infer.annotation.Assertions;
|
||||
return;
|
||||
}
|
||||
|
||||
Assertions.assumeNotNull(mBitmapUpdateListener).onBitmapReady(bitmap);
|
||||
BitmapUpdateListener listener = Assertions.assumeNotNull(mBitmapUpdateListener);
|
||||
listener.onBitmapReady(bitmap);
|
||||
listener.onImageLoadEvent(ImageLoadEvent.ON_LOAD_END);
|
||||
listener.onImageLoadEvent(ImageLoadEvent.ON_LOAD);
|
||||
} finally {
|
||||
dataSource.close();
|
||||
}
|
||||
@ -158,8 +164,8 @@ import com.facebook.infer.annotation.Assertions;
|
||||
|
||||
@Override
|
||||
public void onFailure(DataSource<CloseableReference<CloseableImage>> dataSource) {
|
||||
if (mDataSource != dataSource) {
|
||||
// Should always be the case, but let's be safe.
|
||||
if (mDataSource == dataSource) {
|
||||
Assertions.assumeNotNull(mBitmapUpdateListener).onImageLoadEvent(ImageLoadEvent.ON_LOAD_END);
|
||||
mDataSource = null;
|
||||
}
|
||||
|
||||
@ -168,6 +174,11 @@ import com.facebook.infer.annotation.Assertions;
|
||||
|
||||
@Override
|
||||
public void onCancellation(DataSource<CloseableReference<CloseableImage>> dataSource) {
|
||||
if (mDataSource == dataSource) {
|
||||
mDataSource = null;
|
||||
}
|
||||
|
||||
dataSource.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -80,6 +80,11 @@ import com.facebook.react.views.image.ImageResizeMode;
|
||||
}
|
||||
}
|
||||
|
||||
@ReactProp(name = "shouldNotifyLoadEvents")
|
||||
public void setShouldNotifyLoadEvents(boolean shouldNotifyLoadEvents) {
|
||||
getMutableDrawImage().setReactTag(shouldNotifyLoadEvents ? getReactTag() : 0);
|
||||
}
|
||||
|
||||
@ReactProp(name = "src")
|
||||
public void setSource(@Nullable String source) {
|
||||
getMutableDrawImage().setImageRequest(
|
||||
|
Loading…
x
Reference in New Issue
Block a user