match RN attachment images Feed experience with Native with spinner/fade in

Reviewed By: astreet

Differential Revision: D2722917

fb-gh-sync-id: a09b9a1a4b9a19b94471d8e93ec5bde53af7da06
This commit is contained in:
Olivier Notteghem 2015-12-06 15:44:47 -08:00 committed by facebook-github-bot-7
parent f1a575eb30
commit a38ce5c570
3 changed files with 51 additions and 7 deletions

View File

@ -53,6 +53,7 @@ var resolveAssetSource = require('resolveAssetSource');
var ImageViewAttributes = merge(ReactNativeViewAttributes.UIView, {
src: true,
loadingIndicatorSrc: true,
resizeMode: true,
progressiveRenderingEnabled: true,
fadeDuration: true,
@ -74,6 +75,18 @@ var Image = React.createClass({
// Opaque type returned by require('./image.jpg')
PropTypes.number,
]).isRequired,
/**
* similarly to `source`, this property represents the resource used to render
* the loading indicator for the image, displayed until image is ready to be
* displayed, typically after when it got downloaded from network.
*/
loadingIndicatorSource: PropTypes.oneOfType([
PropTypes.shape({
uri: PropTypes.string,
}),
// Opaque type returned by require('./image.jpg')
PropTypes.number,
]),
progressiveRenderingEnabled: PropTypes.bool,
fadeDuration: PropTypes.number,
/**
@ -138,6 +151,7 @@ var Image = React.createClass({
render: function() {
var source = resolveAssetSource(this.props.source);
var loadingIndicatorSource = resolveAssetSource(this.props.loadingIndicatorSource);
// As opposed to the ios version, here it render `null`
// when no source or source.uri... so let's not break that.
@ -155,6 +169,7 @@ var Image = React.createClass({
style,
shouldNotifyLoadEvents: !!(onLoadStart || onLoad || onLoadEnd),
src: source.uri,
loadingIndicatorSrc: loadingIndicatorSource ? loadingIndicatorSource.uri : null,
});
if (nativeProps.children) {
@ -197,6 +212,7 @@ var styles = StyleSheet.create({
var cfg = {
nativeOnly: {
src: true,
loadingIndicatorSrc: true,
defaultImageSrc: true,
imageTag: true,
progressHandlerRegistered: true,

View File

@ -73,6 +73,12 @@ public class ReactImageManager extends SimpleViewManager<ReactImageView> {
view.setSource(source);
}
// In JS this is Image.props.loadingIndicatorSource.uri
@ReactProp(name = "loadingIndicatorSrc")
public void setLoadingIndicatorSource(ReactImageView view, @Nullable String source) {
view.setLoadingIndicatorSource(source);
}
@ReactProp(name = "borderColor", customType = "Color")
public void setBorderColor(ReactImageView view, @Nullable Integer borderColor) {
if (borderColor == null) {

View File

@ -15,6 +15,7 @@ import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
@ -26,6 +27,7 @@ import android.os.SystemClock;
import com.facebook.common.util.UriUtil;
import com.facebook.drawee.controller.AbstractDraweeControllerBuilder;
import com.facebook.drawee.drawable.AutoRotateDrawable;
import com.facebook.drawee.controller.BaseControllerListener;
import com.facebook.drawee.controller.ControllerListener;
import com.facebook.drawee.controller.ForwardingControllerListener;
@ -104,6 +106,7 @@ public class ReactImageView extends GenericDraweeView {
}
private @Nullable Uri mUri;
private @Nullable Drawable mLoadingImageDrawable;
private int mBorderColor;
private float mBorderWidth;
private float mBorderRadius;
@ -220,6 +223,13 @@ public class ReactImageView extends GenericDraweeView {
mIsDirty = true;
}
public void setLoadingIndicatorSource(@Nullable String name) {
Drawable drawable = getResourceDrawable(getContext(), name);
mLoadingImageDrawable =
drawable != null ? (Drawable) new AutoRotateDrawable(drawable, 1000) : null;
mIsDirty = true;
}
public void setProgressiveRenderingEnabled(boolean enabled) {
mProgressiveRenderingEnabled = enabled;
// no worth marking as dirty if it already rendered..
@ -244,6 +254,10 @@ public class ReactImageView extends GenericDraweeView {
GenericDraweeHierarchy hierarchy = getHierarchy();
hierarchy.setActualImageScaleType(mScaleType);
if (mLoadingImageDrawable != null) {
hierarchy.setPlaceholderImage(mLoadingImageDrawable, ScalingUtils.ScaleType.CENTER);
}
boolean usePostprocessorScaling =
mScaleType != ScalingUtils.ScaleType.CENTER_CROP &&
mScaleType != ScalingUtils.ScaleType.FOCUS_CROP;
@ -322,18 +336,26 @@ public class ReactImageView extends GenericDraweeView {
return uri != null && (UriUtil.isLocalContentUri(uri) || UriUtil.isLocalFileUri(uri));
}
private static @Nullable Uri getResourceDrawableUri(Context context, @Nullable String name) {
private static int getResourceDrawableId(Context context, @Nullable String name) {
if (name == null || name.isEmpty()) {
return null;
return 0;
}
name = name.toLowerCase().replace("-", "_");
int resId = context.getResources().getIdentifier(
name,
return context.getResources().getIdentifier(
name.toLowerCase().replace("-", "_"),
"drawable",
context.getPackageName());
return new Uri.Builder()
}
private static @Nullable Drawable getResourceDrawable(Context context, @Nullable String name) {
int resId = getResourceDrawableId(context, name);
return resId > 0 ? context.getResources().getDrawable(resId) : null;
}
private static @Nullable Uri getResourceDrawableUri(Context context, @Nullable String name) {
int resId = getResourceDrawableId(context, name);
return resId > 0 ? new Uri.Builder()
.scheme(UriUtil.LOCAL_RESOURCE_SCHEME)
.path(String.valueOf(resId))
.build();
.build() : null;
}
}