以前在做项目的时候遇到一个问题:如何将rn的图片传给原生使用?
以前总是百度,但百度遍也没有找到一篇博客给出答案,又去各种技术交流群问,也没有人理我,于是GG。(百度查不到等于我不知道,不知道多少人和我一样。。。)
近日,不知脑子开了什么光突然想到一个问题,rn的image是如何实现的。我是不是可以借鉴一下?于是便有了这篇笔记。(ios不太懂,只写了android)
打开项目找到node-modules目录下的react-native,再找到image目录。可以看到image目录下有个image.android.js文件。点进入:
进入到image.android.js后发现:原来rn的image也是封装的原生组件。(有兴趣自己点进去看,我就直接截图重点了。)这两行如果看不懂,附送rn中文网地址https://reactnative.cn/docs/0.51/native-component-android.html#content(怎么感觉江青青技术专栏和中文网的文档有点像啊。。。)
现在就要找rn的android代码了,再去翻node-modules。发现了ReactAndroid这个目录,用ide的全局查找搜索RCTImageView。然后发现,果然是在这里。(webStorm关于java代码不能Ctrl进去,我就将整个ReactAndroid抠出来放在Android studio中,方便阅读。)
找重点,我们发现rn其实是将src传入ReactImageView中,那就再看看他的ReactImageView是怎么写的。
这里我们发现他其实是将rn传过来的src传到ImageSource中处理了一下,再添加到mSources集合中。
这里段代码的功能就是将rn传过来的图片显示在界面上。
看了image的源码后我们大概了解了rn是如何将js端的图片路径传给android的逻辑。
现在我们取关键部分的代码贴出来。
@ReactProp(name = "setSource")
public void setSource(FrescoView view,ReadableArray sources){
List mSources = new LinkedList<>();
ReadableMap source = sources.getMap(0);
String uri = source.getString("uri");
ImageSource imageSource = new ImageSource(mReactContext, uri);
ResizeOptions resizeOptions = new ResizeOptions(100, 100);
ImageRequestBuilder imageRequestBuilder = ImageRequestBuilder.newBuilderWithSource(imageSource.getUri())
.setPostprocessor(new RoundedCornerPostprocessor())
.setResizeOptions(resizeOptions)
.setAutoRotateEnabled(true)
.setProgressiveRenderingEnabled(true);
ImageRequest imageRequest = ReactNetworkImageRequest.fromBuilderWithHeaders(imageRequestBuilder,null );
AbstractDraweeControllerBuilder mDraweeControllerBuilder = Fresco.newDraweeControllerBuilder();
mDraweeControllerBuilder
.setAutoPlayAnimations(true)
.setCallerContext(mCallerContext)
// .setOldController(getController())
.setImageRequest(imageRequest)
.build();
mDraweeControllerBuilder.reset();
}
RoundedCornerPostprocessor类。
private class RoundedCornerPostprocessor extends BasePostprocessor {
void getRadii(Bitmap source, float[] computedCornerRadii, float[] mappedRadii) {
mScaleType.getTransform(
sMatrix,
new Rect(0, 0, source.getWidth(), source.getHeight()),
source.getWidth(),
source.getHeight(),
0.0f,
0.0f);
sMatrix.invert(sInverse);
mappedRadii[0] = sInverse.mapRadius(computedCornerRadii[0]);
mappedRadii[1] = mappedRadii[0];
mappedRadii[2] = sInverse.mapRadius(computedCornerRadii[1]);
mappedRadii[3] = mappedRadii[2];
mappedRadii[4] = sInverse.mapRadius(computedCornerRadii[2]);
mappedRadii[5] = mappedRadii[4];
mappedRadii[6] = sInverse.mapRadius(computedCornerRadii[3]);
mappedRadii[7] = mappedRadii[6];
}
@Override
public void process(Bitmap output, Bitmap source) {
//cornerRadii(sComputedCornerRadii);
output.setHasAlpha(true);
if (FloatUtil.floatsEqual(sComputedCornerRadii[0], 0f) &&
FloatUtil.floatsEqual(sComputedCornerRadii[1], 0f) &&
FloatUtil.floatsEqual(sComputedCornerRadii[2], 0f) &&
FloatUtil.floatsEqual(sComputedCornerRadii[3], 0f)) {
super.process(output, source);
return;
}
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setShader(new BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
Canvas canvas = new Canvas(output);
float[] radii = new float[8];
getRadii(source, sComputedCornerRadii, radii);
Path pathForBorderRadius = new Path();
pathForBorderRadius.addRoundRect(
new RectF(0, 0, source.getWidth(), source.getHeight()),
radii,
Path.Direction.CW);
canvas.drawPath(pathForBorderRadius, paint);
}
}
ImageSource类
/**
* Class describing an image source (network URI or resource) and size.
*/
public class ImageSource {
private @Nullable Uri mUri;
private String mSource;
private double mSize;
private boolean isResource;
public ImageSource(Context context, String source, double width, double height) {
mSource = source;
mSize = width * height;
// Important: we compute the URI here so that we don't need to hold a reference to the context,
// potentially causing leaks.
mUri = computeUri(context);
}
public ImageSource(Context context, String source) {
this(context, source, 0.0d, 0.0d);
}
/**
* Get the source of this image, as it was passed to the constructor.
*/
public String getSource() {
return mSource;
}
/**
* Get the URI for this image - can be either a parsed network URI or a resource URI.
*/
public Uri getUri() {
return Assertions.assertNotNull(mUri);
}
/**
* Get the area of this image.
*/
public double getSize() {
return mSize;
}
/**
* Get whether this image source represents an Android resource or a network URI.
*/
public boolean isResource() {
return isResource;
}
private Uri computeUri(Context context) {
try {
Uri uri = Uri.parse(mSource);
// Verify scheme is set, so that relative uri (used by static resources) are not handled.
return uri.getScheme() == null ? computeLocalUri(context) : uri;
} catch (Exception e) {
return computeLocalUri(context);
}
}
private Uri computeLocalUri(Context context) {
isResource = true;
return ResourceDrawableIdHelper.getInstance().getResourceDrawableUri(context, mSource);
}
}