forked from alwx/react-native-photo-view
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
iOS version, more methods for Android PhotoView from default ImageView
- Loading branch information
Showing
11 changed files
with
575 additions
and
110 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
84 changes: 84 additions & 0 deletions
84
android/src/main/java/com/reactnative/photoview/ImageEvent.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
/** | ||
* Copyright (c) 2015-present, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the BSD-style license found in the | ||
* LICENSE file in the root directory of this source tree. An additional grant | ||
* of patent rights can be found in the PATENTS file in the same directory. | ||
*/ | ||
|
||
package com.reactnative.photoview; | ||
|
||
import android.support.annotation.IntDef; | ||
import com.facebook.react.bridge.WritableMap; | ||
import com.facebook.react.uimanager.events.Event; | ||
import com.facebook.react.uimanager.events.RCTEventEmitter; | ||
|
||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
|
||
public class ImageEvent extends Event<ImageEvent> { | ||
@IntDef({ON_ERROR, ON_LOAD, ON_LOAD_END, ON_LOAD_START, ON_TAP, ON_VIEW_TAP, ON_SCALE}) | ||
@Retention(RetentionPolicy.SOURCE) | ||
@interface ImageEventType {} | ||
|
||
public static final int ON_ERROR = 1; | ||
public static final int ON_LOAD = 2; | ||
public static final int ON_LOAD_END = 3; | ||
public static final int ON_LOAD_START = 4; | ||
public static final int ON_TAP = 5; | ||
public static final int ON_VIEW_TAP = 6; | ||
public static final int ON_SCALE = 7; | ||
|
||
private final int mEventType; | ||
private WritableMap mMap; | ||
|
||
public ImageEvent(int viewId, long timestampMs, @ImageEventType int eventType) { | ||
super(viewId, timestampMs); | ||
mEventType = eventType; | ||
mMap = null; | ||
} | ||
|
||
public static String eventNameForType(@ImageEventType int eventType) { | ||
switch(eventType) { | ||
case ON_ERROR: | ||
return "topError"; | ||
case ON_LOAD: | ||
return "topLoad"; | ||
case ON_LOAD_END: | ||
return "topLoadEnd"; | ||
case ON_LOAD_START: | ||
return "topLoadStart"; | ||
case ON_TAP: | ||
return "topTap"; | ||
case ON_VIEW_TAP: | ||
return "topViewTap"; | ||
case ON_SCALE: | ||
return "topScale"; | ||
default: | ||
throw new IllegalStateException("Invalid image event: " + Integer.toString(eventType)); | ||
} | ||
} | ||
|
||
@Override | ||
public String getEventName() { | ||
return ImageEvent.eventNameForType(mEventType); | ||
} | ||
|
||
@Override | ||
public short getCoalescingKey() { | ||
// Intentionally casting mEventType because it is guaranteed to be small | ||
// enough to fit into short. | ||
return (short) mEventType; | ||
} | ||
|
||
@Override | ||
public void dispatch(RCTEventEmitter rctEventEmitter) { | ||
rctEventEmitter.receiveEvent(getViewTag(), getEventName(), mMap); | ||
} | ||
|
||
public ImageEvent setExtras(WritableMap map){ | ||
this.mMap = map; | ||
return this; | ||
} | ||
} |
220 changes: 220 additions & 0 deletions
220
android/src/main/java/com/reactnative/photoview/PhotoView.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,220 @@ | ||
package com.reactnative.photoview; | ||
|
||
import android.content.Context; | ||
import android.graphics.drawable.Animatable; | ||
import android.graphics.drawable.Drawable; | ||
import android.net.Uri; | ||
import android.support.annotation.NonNull; | ||
import android.util.AttributeSet; | ||
import android.view.View; | ||
import com.facebook.drawee.backends.pipeline.PipelineDraweeControllerBuilder; | ||
import com.facebook.drawee.controller.BaseControllerListener; | ||
import com.facebook.drawee.controller.ControllerListener; | ||
import com.facebook.drawee.drawable.AutoRotateDrawable; | ||
import com.facebook.drawee.drawable.ScalingUtils; | ||
import com.facebook.drawee.generic.GenericDraweeHierarchy; | ||
import com.facebook.imagepipeline.image.ImageInfo; | ||
import com.facebook.react.bridge.Arguments; | ||
import com.facebook.react.bridge.ReactContext; | ||
import com.facebook.react.bridge.WritableMap; | ||
import com.facebook.react.common.SystemClock; | ||
import com.facebook.react.uimanager.UIManagerModule; | ||
import com.facebook.react.uimanager.events.EventDispatcher; | ||
import me.relex.photodraweeview.OnPhotoTapListener; | ||
import me.relex.photodraweeview.OnScaleChangeListener; | ||
import me.relex.photodraweeview.OnViewTapListener; | ||
import me.relex.photodraweeview.PhotoDraweeView; | ||
|
||
import javax.annotation.Nullable; | ||
|
||
import static com.facebook.react.views.image.ReactImageView.REMOTE_IMAGE_FADE_DURATION_MS; | ||
|
||
/** | ||
* @author alwx (https://github.com/alwx) | ||
* @version 1.0 | ||
*/ | ||
public class PhotoView extends PhotoDraweeView { | ||
private Uri mUri; | ||
private boolean mIsDirty; | ||
private boolean mIsLocalImage; | ||
private Drawable mLoadingImageDrawable; | ||
private PipelineDraweeControllerBuilder mDraweeControllerBuilder; | ||
private int mFadeDurationMs = -1; | ||
private ControllerListener mControllerListener; | ||
|
||
public PhotoView(Context context, GenericDraweeHierarchy hierarchy) { | ||
super(context, hierarchy); | ||
} | ||
|
||
public PhotoView(Context context) { | ||
super(context); | ||
} | ||
|
||
public PhotoView(Context context, AttributeSet attrs) { | ||
super(context, attrs); | ||
} | ||
|
||
public PhotoView(Context context, AttributeSet attrs, int defStyle) { | ||
super(context, attrs, defStyle); | ||
} | ||
|
||
public void setSource(@Nullable String source, | ||
@NonNull PipelineDraweeControllerBuilder builder, | ||
@NonNull ResourceDrawableIdHelper resourceDrawableIdHelper) { | ||
mDraweeControllerBuilder = builder; | ||
mUri = null; | ||
if (source != null) { | ||
try { | ||
mUri = Uri.parse(source); | ||
// Verify scheme is set, so that relative uri (used by static resources) are not handled. | ||
if (mUri.getScheme() == null) { | ||
mUri = null; | ||
} | ||
} catch (Exception e) { | ||
// ignore malformed uri, then attempt to extract resource ID. | ||
} | ||
if (mUri == null) { | ||
mUri = resourceDrawableIdHelper.getResourceDrawableUri(getContext(), source); | ||
mIsLocalImage = true; | ||
} else { | ||
mIsLocalImage = false; | ||
} | ||
} | ||
mIsDirty = true; | ||
} | ||
|
||
public void setLoadingIndicatorSource(@Nullable String name, | ||
ResourceDrawableIdHelper resourceDrawableIdHelper) { | ||
Drawable drawable = resourceDrawableIdHelper.getResourceDrawable(getContext(), name); | ||
mLoadingImageDrawable = | ||
drawable != null ? (Drawable) new AutoRotateDrawable(drawable, 1000) : null; | ||
mIsDirty = true; | ||
} | ||
|
||
public void setFadeDuration(int durationMs) { | ||
mFadeDurationMs = durationMs; | ||
// no worth marking as dirty if it already rendered.. | ||
} | ||
|
||
public void setShouldNotifyLoadEvents(boolean shouldNotify) { | ||
if (!shouldNotify) { | ||
mControllerListener = null; | ||
} else { | ||
final EventDispatcher eventDispatcher = ((ReactContext) getContext()) | ||
.getNativeModule(UIManagerModule.class).getEventDispatcher(); | ||
mControllerListener = new BaseControllerListener<ImageInfo>() { | ||
@Override | ||
public void onSubmit(String id, Object callerContext) { | ||
eventDispatcher.dispatchEvent( | ||
new ImageEvent(getId(), SystemClock.nanoTime(), ImageEvent.ON_LOAD_START) | ||
); | ||
} | ||
|
||
@Override | ||
public void onFinalImageSet( | ||
String id, | ||
@Nullable final ImageInfo imageInfo, | ||
@Nullable Animatable animatable) { | ||
if (imageInfo != null) { | ||
eventDispatcher.dispatchEvent( | ||
new ImageEvent(getId(), SystemClock.nanoTime(), ImageEvent.ON_LOAD) | ||
); | ||
eventDispatcher.dispatchEvent( | ||
new ImageEvent(getId(), SystemClock.nanoTime(), ImageEvent.ON_LOAD_END) | ||
); | ||
} | ||
} | ||
|
||
@Override | ||
public void onFailure(String id, Throwable throwable) { | ||
eventDispatcher.dispatchEvent( | ||
new ImageEvent(getId(), SystemClock.nanoTime(), ImageEvent.ON_ERROR) | ||
); | ||
eventDispatcher.dispatchEvent( | ||
new ImageEvent(getId(), SystemClock.nanoTime(), ImageEvent.ON_LOAD_END) | ||
); | ||
} | ||
}; | ||
} | ||
mIsDirty = true; | ||
} | ||
|
||
public void maybeUpdateView() { | ||
if (!mIsDirty) { | ||
return; | ||
} | ||
|
||
GenericDraweeHierarchy hierarchy = getHierarchy(); | ||
if (mLoadingImageDrawable != null) { | ||
hierarchy.setPlaceholderImage(mLoadingImageDrawable, ScalingUtils.ScaleType.CENTER); | ||
} | ||
hierarchy.setFadeDuration( | ||
mFadeDurationMs >= 0 | ||
? mFadeDurationMs | ||
: mIsLocalImage ? 0 : REMOTE_IMAGE_FADE_DURATION_MS); | ||
|
||
mDraweeControllerBuilder.setUri(mUri); | ||
mDraweeControllerBuilder.setOldController(getController()); | ||
mDraweeControllerBuilder.setControllerListener(new BaseControllerListener<ImageInfo>() { | ||
@Override | ||
public void onFinalImageSet(String id, ImageInfo imageInfo, Animatable animatable) { | ||
super.onFinalImageSet(id, imageInfo, animatable); | ||
if (imageInfo == null) { | ||
return; | ||
} | ||
update(imageInfo.getWidth(), imageInfo.getHeight()); | ||
} | ||
}); | ||
|
||
if (mControllerListener != null) { | ||
mDraweeControllerBuilder.setControllerListener(mControllerListener); | ||
} | ||
|
||
setController(mDraweeControllerBuilder.build()); | ||
setViewCallbacks(); | ||
|
||
mIsDirty = false; | ||
} | ||
|
||
private void setViewCallbacks() { | ||
final EventDispatcher eventDispatcher = ((ReactContext) getContext()) | ||
.getNativeModule(UIManagerModule.class).getEventDispatcher(); | ||
|
||
setOnPhotoTapListener(new OnPhotoTapListener() { | ||
@Override | ||
public void onPhotoTap(View view, float x, float y) { | ||
WritableMap scaleChange = Arguments.createMap(); | ||
scaleChange.putDouble("x", x); | ||
scaleChange.putDouble("y", y); | ||
eventDispatcher.dispatchEvent( | ||
new ImageEvent(getId(), SystemClock.nanoTime(), ImageEvent.ON_TAP).setExtras(scaleChange) | ||
); | ||
} | ||
}); | ||
|
||
setOnScaleChangeListener(new OnScaleChangeListener() { | ||
@Override | ||
public void onScaleChange(float scaleFactor, float focusX, float focusY) { | ||
WritableMap scaleChange = Arguments.createMap(); | ||
scaleChange.putDouble("scaleFactor", scaleFactor); | ||
scaleChange.putDouble("focusX", focusX); | ||
scaleChange.putDouble("focusY", focusY); | ||
eventDispatcher.dispatchEvent( | ||
new ImageEvent(getId(), SystemClock.nanoTime(), ImageEvent.ON_SCALE).setExtras(scaleChange) | ||
); | ||
} | ||
}); | ||
|
||
setOnViewTapListener(new OnViewTapListener() { | ||
@Override | ||
public void onViewTap(View view, float x, float y) { | ||
WritableMap scaleChange = Arguments.createMap(); | ||
scaleChange.putDouble("x", x); | ||
scaleChange.putDouble("y", y); | ||
eventDispatcher.dispatchEvent( | ||
new ImageEvent(getId(), SystemClock.nanoTime(), ImageEvent.ON_TAP).setExtras(scaleChange) | ||
); | ||
} | ||
}); | ||
} | ||
} |
Oops, something went wrong.