feat:add PlcaeHolder and Error setting for Image

This commit is contained in:
pengfei.zhou 2020-03-05 11:01:10 +08:00 committed by osborn
parent 9394e8927e
commit 5053262dd5
13 changed files with 393 additions and 28 deletions

View File

@ -15,6 +15,7 @@
*/ */
package pub.doric; package pub.doric;
import android.graphics.drawable.Drawable;
import android.text.TextUtils; import android.text.TextUtils;
import java.util.HashMap; import java.util.HashMap;
@ -70,6 +71,10 @@ public class DoricRegistry {
private Set<IDoricMonitor> monitors = new HashSet<>(); private Set<IDoricMonitor> monitors = new HashSet<>();
private Drawable defaultPlaceHolderDrawable = null;
private Drawable defaultErrorDrawable = null;
private static void initRegistry(DoricRegistry doricRegistry) { private static void initRegistry(DoricRegistry doricRegistry) {
for (DoricLibrary library : doricLibraries) { for (DoricLibrary library : doricLibraries) {
library.load(doricRegistry); library.load(doricRegistry);
@ -168,4 +173,26 @@ public class DoricRegistry {
monitor.onLog(type, message); monitor.onLog(type, message);
} }
} }
public Drawable getDefaultPlaceHolderDrawable() {
return defaultPlaceHolderDrawable;
}
/**
* @param defaultPlaceHolderDrawable Default display when image is loading and not set by JS API
*/
public void setDefaultPlaceHolderDrawable(Drawable defaultPlaceHolderDrawable) {
this.defaultPlaceHolderDrawable = defaultPlaceHolderDrawable;
}
public Drawable getDefaultErrorDrawable() {
return defaultErrorDrawable;
}
/**
* @param defaultErrorDrawable Default display when image load error and not set by JS API
*/
public void setDefaultErrorDrawable(Drawable defaultErrorDrawable) {
this.defaultErrorDrawable = defaultErrorDrawable;
}
} }

View File

@ -17,6 +17,8 @@ package pub.doric.shader;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Base64; import android.util.Base64;
@ -41,6 +43,7 @@ import androidx.annotation.Nullable;
import jp.wasabeef.glide.transformations.BlurTransformation; import jp.wasabeef.glide.transformations.BlurTransformation;
import pub.doric.DoricContext; import pub.doric.DoricContext;
import pub.doric.extension.bridge.DoricPlugin; import pub.doric.extension.bridge.DoricPlugin;
import pub.doric.utils.DoricLog;
import pub.doric.utils.DoricUtils; import pub.doric.utils.DoricUtils;
/** /**
@ -52,6 +55,10 @@ import pub.doric.utils.DoricUtils;
public class ImageNode extends ViewNode<ImageView> { public class ImageNode extends ViewNode<ImageView> {
private String loadCallbackId = ""; private String loadCallbackId = "";
private boolean isBlur; private boolean isBlur;
private String placeHolderImage;
private String errorImage;
private int placeHolderColor = Color.TRANSPARENT;
private int errorColor = Color.TRANSPARENT;
public ImageNode(DoricContext doricContext) { public ImageNode(DoricContext doricContext) {
super(doricContext); super(doricContext);
@ -69,21 +76,86 @@ public class ImageNode extends ViewNode<ImageView> {
if (jsValue.isBoolean()) { if (jsValue.isBoolean()) {
isBlur = jsValue.asBoolean().value(); isBlur = jsValue.asBoolean().value();
} }
JSValue placeHolder = jsObject.getProperty("placeHolderImage");
if (placeHolder.isString()) {
this.placeHolderImage = placeHolder.asString().value();
}
JSValue error = jsObject.getProperty("errorImage");
if (error.isString()) {
this.errorImage = error.asString().value();
}
JSValue placeHolderColor = jsObject.getProperty("placeHolderColor");
if (placeHolderColor.isNumber()) {
this.placeHolderColor = placeHolderColor.asNumber().toInt();
}
JSValue errorColor = jsObject.getProperty("errorColor");
if (errorColor.isNumber()) {
this.errorColor = errorColor.asNumber().toInt();
}
} }
super.blend(jsObject); super.blend(jsObject);
} }
private Drawable getPlaceHolderDrawable() {
if (!TextUtils.isEmpty(placeHolderImage)) {
int resId = getDoricContext().getContext().getResources().getIdentifier(
placeHolderImage.toLowerCase(),
"drawable",
getDoricContext().getContext().getPackageName());
if (resId > 0) {
return getDoricContext().getContext().getResources().getDrawable(resId);
} else {
DoricLog.e("Cannot find PlaceHolder Drawable for " + placeHolderImage);
return new ColorDrawable(Color.GRAY);
}
} else if (placeHolderColor != Color.TRANSPARENT) {
return new ColorDrawable(placeHolderColor);
} else {
return getDoricContext().getDriver().getRegistry().getDefaultPlaceHolderDrawable();
}
}
private Drawable getErrorDrawable() {
if (!TextUtils.isEmpty(errorImage)) {
int resId = getDoricContext().getContext().getResources().getIdentifier(
errorImage.toLowerCase(),
"drawable",
getDoricContext().getContext().getPackageName());
if (resId > 0) {
return getDoricContext().getContext().getResources().getDrawable(resId);
} else {
DoricLog.e("Cannot find Error Drawable for " + errorImage);
return new ColorDrawable(Color.GRAY);
}
} else if (errorColor != Color.TRANSPARENT) {
return new ColorDrawable(errorColor);
} else {
return getDoricContext().getDriver().getRegistry().getDefaultErrorDrawable();
}
}
@Override @Override
protected void blend(ImageView view, String name, JSValue prop) { protected void blend(ImageView view, String name, JSValue prop) {
switch (name) { switch (name) {
case "imageUrl": case "imageUrl":
RequestBuilder<Drawable> requestBuilder = Glide.with(getContext())
RequestBuilder<Drawable> requestBuilder = Glide.with(getContext()).load(prop.asString().value()); .load(prop.asString().value());
if (isBlur) { if (isBlur) {
requestBuilder = requestBuilder requestBuilder = requestBuilder
.apply(RequestOptions .apply(RequestOptions
.bitmapTransform(new BlurTransformation(25, 3))); .bitmapTransform(new BlurTransformation(25, 3)));
} }
Drawable placeHolderDrawable = getPlaceHolderDrawable();
if (placeHolderDrawable != null) {
requestBuilder = requestBuilder.apply(new RequestOptions().placeholder(placeHolderDrawable));
}
Drawable errorDrawable = getErrorDrawable();
if (errorDrawable != null) {
requestBuilder = requestBuilder.apply(new RequestOptions().error(errorDrawable));
}
requestBuilder requestBuilder
.listener(new RequestListener<Drawable>() { .listener(new RequestListener<Drawable>() {
@Override @Override

View File

@ -22,11 +22,14 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "DoricMonitorProtocol.h" #import "DoricMonitorProtocol.h"
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@class DoricLibrary; @class DoricLibrary;
@interface DoricRegistry : NSObject <DoricMonitorProtocol> @interface DoricRegistry : NSObject <DoricMonitorProtocol>
@property(nonatomic, strong) UIImage *defaultPlaceHolderImage;
@property(nonatomic, strong) UIImage *defaultErrorImage;
- (NSString *)acquireJSBundle:(NSString *)name; - (NSString *)acquireJSBundle:(NSString *)name;

View File

@ -27,6 +27,11 @@
@interface DoricImageNode () @interface DoricImageNode ()
@property(nonatomic, copy) NSString *loadCallbackId; @property(nonatomic, copy) NSString *loadCallbackId;
@property(nonatomic, assign) BOOL isBlur; @property(nonatomic, assign) BOOL isBlur;
@property(nonatomic, assign) UIViewContentMode contentMode;
@property(nonatomic, strong) NSNumber *placeHolderColor;
@property(nonatomic, strong) NSString *placeHolderImage;
@property(nonatomic, strong) NSNumber *errorColor;
@property(nonatomic, strong) NSString *errorImage;
@end @end
@implementation DoricImageNode @implementation DoricImageNode
@ -39,19 +44,78 @@ - (UIImageView *)build {
- (void)blend:(NSDictionary *)props { - (void)blend:(NSDictionary *)props {
NSInteger value = [props[@"isBlur"] intValue]; NSInteger value = [props[@"isBlur"] intValue];
if(value == 1) { if (value == 1) {
self.isBlur = YES; self.isBlur = YES;
} }
[props[@"placeHolderColor"] also:^(id it) {
self.placeHolderColor = it;
}];
[props[@"placeHolderImage"] also:^(id it) {
self.placeHolderImage = it;
}];
[props[@"errorColor"] also:^(id it) {
self.errorColor = it;
}];
[props[@"errorImage"] also:^(id it) {
self.errorImage = it;
}];
[super blend:props]; [super blend:props];
} }
- (UIImage *)currentPlaceHolderImage {
if (self.placeHolderImage) {
return [UIImage imageNamed:self.placeHolderImage];
}
if (self.placeHolderColor) {
UIColor *color = DoricColor(self.placeHolderColor);
CGRect rect = CGRectMake(0, 0, 1, 1);
self.view.contentMode = UIViewContentModeScaleToFill;
UIGraphicsBeginImageContextWithOptions(rect.size, NO, [UIScreen mainScreen].scale);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, color.CGColor);
CGContextFillRect(context, rect);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
return self.doricContext.driver.registry.defaultPlaceHolderImage;
}
- (UIImage *)currentErrorImage {
if (self.errorImage) {
return [UIImage imageNamed:self.errorImage];
}
if (self.errorColor) {
UIColor *color = DoricColor(self.errorColor);
CGRect rect = CGRectMake(0, 0, 1, 1);
self.view.contentMode = UIViewContentModeScaleToFill;
UIGraphicsBeginImageContextWithOptions(rect.size, NO, [UIScreen mainScreen].scale);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, color.CGColor);
CGContextFillRect(context, rect);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
return self.doricContext.driver.registry.defaultErrorImage;
}
- (void)blendView:(UIImageView *)view forPropName:(NSString *)name propValue:(id)prop { - (void)blendView:(UIImageView *)view forPropName:(NSString *)name propValue:(id)prop {
if ([@"imageUrl" isEqualToString:name]) { if ([@"imageUrl" isEqualToString:name]) {
__weak typeof(self) _self = self; __weak typeof(self) _self = self;
[view yy_setImageWithURL:[NSURL URLWithString:prop] placeholder:nil options:0 completion:^(UIImage *image, NSURL *url, YYWebImageFromType from, YYWebImageStage stage, NSError *error) { [view yy_setImageWithURL:[NSURL URLWithString:prop] placeholder:[self currentPlaceHolderImage] options:0 completion:^(UIImage *image, NSURL *url, YYWebImageFromType from, YYWebImageStage stage, NSError *error) {
__strong typeof(_self) self = _self; __strong typeof(_self) self = _self;
if (self.placeHolderColor || self.errorColor) {
self.view.contentMode = self.contentMode;
}
if (error) { if (error) {
[[self currentErrorImage] also:^(UIImage *it) {
view.image = it;
}];
if (self.loadCallbackId.length > 0) { if (self.loadCallbackId.length > 0) {
[self callJSResponse:self.loadCallbackId, nil]; [self callJSResponse:self.loadCallbackId, nil];
} }
@ -64,9 +128,9 @@ - (void)blendView:(UIImageView *)view forPropName:(NSString *)name propValue:(id
[self requestLayout]; [self requestLayout];
} }
if(self.isBlur) { if (self.isBlur) {
UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]; UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
UIVisualEffectView *effectView = [[UIVisualEffectView alloc]initWithEffect:blurEffect]; UIVisualEffectView *effectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
effectView.frame = CGRectMake(0, 0, image.size.width, image.size.height); effectView.frame = CGRectMake(0, 0, image.size.width, image.size.height);
[view addSubview:effectView]; [view addSubview:effectView];
} }
@ -86,6 +150,7 @@ - (void)blendView:(UIImageView *)view forPropName:(NSString *)name propValue:(id
break; break;
} }
} }
self.contentMode = self.view.contentMode;
} else if ([@"loadCallback" isEqualToString:name]) { } else if ([@"loadCallback" isEqualToString:name]) {
self.loadCallbackId = prop; self.loadCallbackId = prop;
} else if ([@"imageBase64" isEqualToString:name]) { } else if ([@"imageBase64" isEqualToString:name]) {

View File

@ -1662,6 +1662,27 @@ var Image = /** @class */ (function (_super) {
Property, Property,
__metadata$4("design:type", Boolean) __metadata$4("design:type", Boolean)
], Image.prototype, "isBlur", void 0); ], Image.prototype, "isBlur", void 0);
__decorate$4([
Property,
__metadata$4("design:type", String)
], Image.prototype, "placeHolderImage", void 0);
__decorate$4([
Property,
__metadata$4("design:type", Color
/**
* Display while image is failed to load
* It can be file name in local path
*/
)
], Image.prototype, "placeHolderColor", void 0);
__decorate$4([
Property,
__metadata$4("design:type", String)
], Image.prototype, "errorImage", void 0);
__decorate$4([
Property,
__metadata$4("design:type", Color)
], Image.prototype, "errorColor", void 0);
__decorate$4([ __decorate$4([
Property, Property,
__metadata$4("design:type", Function) __metadata$4("design:type", Function)

View File

@ -1228,6 +1228,27 @@ __decorate$4([
Property, Property,
__metadata$4("design:type", Boolean) __metadata$4("design:type", Boolean)
], Image.prototype, "isBlur", void 0); ], Image.prototype, "isBlur", void 0);
__decorate$4([
Property,
__metadata$4("design:type", String)
], Image.prototype, "placeHolderImage", void 0);
__decorate$4([
Property,
__metadata$4("design:type", Color
/**
* Display while image is failed to load
* It can be file name in local path
*/
)
], Image.prototype, "placeHolderColor", void 0);
__decorate$4([
Property,
__metadata$4("design:type", String)
], Image.prototype, "errorImage", void 0);
__decorate$4([
Property,
__metadata$4("design:type", Color)
], Image.prototype, "errorColor", void 0);
__decorate$4([ __decorate$4([
Property, Property,
__metadata$4("design:type", Function) __metadata$4("design:type", Function)

View File

@ -2687,6 +2687,27 @@ __decorate$4([
Property, Property,
__metadata$4("design:type", Boolean) __metadata$4("design:type", Boolean)
], Image.prototype, "isBlur", void 0); ], Image.prototype, "isBlur", void 0);
__decorate$4([
Property,
__metadata$4("design:type", String)
], Image.prototype, "placeHolderImage", void 0);
__decorate$4([
Property,
__metadata$4("design:type", Color
/**
* Display while image is failed to load
* It can be file name in local path
*/
)
], Image.prototype, "placeHolderColor", void 0);
__decorate$4([
Property,
__metadata$4("design:type", String)
], Image.prototype, "errorImage", void 0);
__decorate$4([
Property,
__metadata$4("design:type", Color)
], Image.prototype, "errorColor", void 0);
__decorate$4([ __decorate$4([
Property, Property,
__metadata$4("design:type", Function) __metadata$4("design:type", Function)

27
doric-js/index.d.ts vendored
View File

@ -473,6 +473,7 @@ declare module 'doric/lib/src/widget/text' {
declare module 'doric/lib/src/widget/image' { declare module 'doric/lib/src/widget/image' {
import { IView, View } from "doric/lib/src/ui/view"; import { IView, View } from "doric/lib/src/ui/view";
import { Color } from "doric/lib/src/util/color";
export enum ScaleType { export enum ScaleType {
ScaleToFill = 0, ScaleToFill = 0,
ScaleAspectFit = 1, ScaleAspectFit = 1,
@ -483,6 +484,10 @@ declare module 'doric/lib/src/widget/image' {
imageBase64?: string; imageBase64?: string;
scaleType?: ScaleType; scaleType?: ScaleType;
isBlur?: boolean; isBlur?: boolean;
placeHolderImage?: string;
placeHolderColor?: Color;
errorImage?: string;
errorColor?: Color;
loadCallback?: (image: { loadCallback?: (image: {
width: number; width: number;
height: number; height: number;
@ -493,6 +498,28 @@ declare module 'doric/lib/src/widget/image' {
imageBase64?: string; imageBase64?: string;
scaleType?: ScaleType; scaleType?: ScaleType;
isBlur?: boolean; isBlur?: boolean;
/**
* Display while image is loading
* Local file name
*/
placeHolderImage?: string;
/**
* Display while image is loading
* Color
* This priority is lower than placeHolderImage
*/
placeHolderColor?: Color;
/**
* Display while image is failed to load
* It can be file name in local path
*/
errorImage?: string;
/**
* Display while image is failed to load
* Color
* This priority is lower than errorImage
*/
errorColor?: Color;
loadCallback?: (image: { loadCallback?: (image: {
width: number; width: number;
height: number; height: number;

View File

@ -1,4 +1,5 @@
import { IView, View } from "../ui/view"; import { IView, View } from "../ui/view";
import { Color } from "../util/color";
export declare enum ScaleType { export declare enum ScaleType {
ScaleToFill = 0, ScaleToFill = 0,
ScaleAspectFit = 1, ScaleAspectFit = 1,
@ -9,6 +10,10 @@ export interface IImage extends IView {
imageBase64?: string; imageBase64?: string;
scaleType?: ScaleType; scaleType?: ScaleType;
isBlur?: boolean; isBlur?: boolean;
placeHolderImage?: string;
placeHolderColor?: Color;
errorImage?: string;
errorColor?: Color;
loadCallback?: (image: { loadCallback?: (image: {
width: number; width: number;
height: number; height: number;
@ -19,6 +24,28 @@ export declare class Image extends View implements IImage {
imageBase64?: string; imageBase64?: string;
scaleType?: ScaleType; scaleType?: ScaleType;
isBlur?: boolean; isBlur?: boolean;
/**
* Display while image is loading
* Local file name
*/
placeHolderImage?: string;
/**
* Display while image is loading
* Color
* This priority is lower than placeHolderImage
*/
placeHolderColor?: Color;
/**
* Display while image is failed to load
* It can be file name in local path
*/
errorImage?: string;
/**
* Display while image is failed to load
* Color
* This priority is lower than errorImage
*/
errorColor?: Color;
loadCallback?: (image: { loadCallback?: (image: {
width: number; width: number;
height: number; height: number;

View File

@ -24,6 +24,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
*/ */
import { View, Property } from "../ui/view"; import { View, Property } from "../ui/view";
import { layoutConfig } from "../util/layoutconfig"; import { layoutConfig } from "../util/layoutconfig";
import { Color } from "../util/color";
export var ScaleType; export var ScaleType;
(function (ScaleType) { (function (ScaleType) {
ScaleType[ScaleType["ScaleToFill"] = 0] = "ScaleToFill"; ScaleType[ScaleType["ScaleToFill"] = 0] = "ScaleToFill";
@ -48,6 +49,27 @@ __decorate([
Property, Property,
__metadata("design:type", Boolean) __metadata("design:type", Boolean)
], Image.prototype, "isBlur", void 0); ], Image.prototype, "isBlur", void 0);
__decorate([
Property,
__metadata("design:type", String)
], Image.prototype, "placeHolderImage", void 0);
__decorate([
Property,
__metadata("design:type", Color
/**
* Display while image is failed to load
* It can be file name in local path
*/
)
], Image.prototype, "placeHolderColor", void 0);
__decorate([
Property,
__metadata("design:type", String)
], Image.prototype, "errorImage", void 0);
__decorate([
Property,
__metadata("design:type", Color)
], Image.prototype, "errorColor", void 0);
__decorate([ __decorate([
Property, Property,
__metadata("design:type", Function) __metadata("design:type", Function)

View File

@ -15,6 +15,7 @@
*/ */
import { IView, View, Property } from "../ui/view" import { IView, View, Property } from "../ui/view"
import { layoutConfig } from "../util/layoutconfig" import { layoutConfig } from "../util/layoutconfig"
import { Color } from "../util/color"
export enum ScaleType { export enum ScaleType {
ScaleToFill = 0, ScaleToFill = 0,
@ -27,19 +28,56 @@ export interface IImage extends IView {
imageBase64?: string imageBase64?: string
scaleType?: ScaleType scaleType?: ScaleType
isBlur?: boolean isBlur?: boolean
placeHolderImage?: string
placeHolderColor?: Color
errorImage?: string
errorColor?: Color
loadCallback?: (image: { width: number; height: number } | undefined) => void loadCallback?: (image: { width: number; height: number } | undefined) => void
} }
export class Image extends View implements IImage { export class Image extends View implements IImage {
@Property @Property
imageUrl?: string imageUrl?: string
@Property @Property
imageBase64?: string imageBase64?: string
@Property @Property
scaleType?: ScaleType scaleType?: ScaleType
@Property @Property
isBlur?: boolean isBlur?: boolean
/**
* Display while image is loading
* Local file name
*/
@Property
placeHolderImage?: string
/**
* Display while image is loading
* Color
* This priority is lower than placeHolderImage
*/
@Property
placeHolderColor?: Color
/**
* Display while image is failed to load
* It can be file name in local path
*/
@Property
errorImage?: string
/**
* Display while image is failed to load
* Color
* This priority is lower than errorImage
*/
@Property
errorColor?: Color
@Property @Property
loadCallback?: (image: { width: number; height: number } | undefined) => void loadCallback?: (image: { width: number; height: number } | undefined) => void
} }

View File

@ -2745,6 +2745,27 @@ __decorate$4([
Property, Property,
__metadata$4("design:type", Boolean) __metadata$4("design:type", Boolean)
], Image.prototype, "isBlur", void 0); ], Image.prototype, "isBlur", void 0);
__decorate$4([
Property,
__metadata$4("design:type", String)
], Image.prototype, "placeHolderImage", void 0);
__decorate$4([
Property,
__metadata$4("design:type", Color
/**
* Display while image is failed to load
* It can be file name in local path
*/
)
], Image.prototype, "placeHolderColor", void 0);
__decorate$4([
Property,
__metadata$4("design:type", String)
], Image.prototype, "errorImage", void 0);
__decorate$4([
Property,
__metadata$4("design:type", Color)
], Image.prototype, "errorColor", void 0);
__decorate$4([ __decorate$4([
Property, Property,
__metadata$4("design:type", Function) __metadata$4("design:type", Function)

File diff suppressed because one or more lines are too long