本文的目的是介绍如何设计一个好用的ReactImage组件?的详细情况,特别关注react组件设计原则的相关信息。我们将通过专业的研究、有关数据的分析等多种方式,为您呈现一个全面的了解如何设计一个好用
本文的目的是介绍如何设计一个好用的 React Image 组件?的详细情况,特别关注react组件设计原则的相关信息。我们将通过专业的研究、有关数据的分析等多种方式,为您呈现一个全面的了解如何设计一个好用的 React Image 组件?的机会,同时也不会遗漏关于Android 设计一个菱形形状的Imageview组件.、com.facebook.imagepipeline.image.CloseableAnimatedImage的实例源码、com.facebook.react.views.image.ImageResizeMode的实例源码、com.facebook.react.views.image.ReactImageManager的实例源码的知识。
本文目录一览:- 如何设计一个好用的 React Image 组件?(react组件设计原则)
- Android 设计一个菱形形状的Imageview组件.
- com.facebook.imagepipeline.image.CloseableAnimatedImage的实例源码
- com.facebook.react.views.image.ImageResizeMode的实例源码
- com.facebook.react.views.image.ReactImageManager的实例源码
如何设计一个好用的 React Image 组件?(react组件设计原则)
前言
本文为笔者阅读 react-image[1] 源码过程中的总结,若有所错漏烦请指出。✨ 仓库传送门[2]
https://github.com/worldzhao/blog/issues/1
<img />
可以说是开发过程中极其常用的标签了。但是很多同学都是<img src="xxx.png" />
一把梭,直到 UI 小姐姐来找你谈谈人生理想:
-
图片加载太慢,需要展示 loading
占位符; -
图片加载失败,加载备选图片或展示 error
占位符。
作为开发者的我们,可能会经历以下几个阶段:
-
第一阶段: img
标签上使用onLoad
以及onError
进行处理; -
第二阶段:写一个较为通用的组件; -
第三阶段:抽离 hooks
,使用方自定义视图组件(当然也要提供基本组件);
现在让我们直接从第三阶段开始,看看如何使用少量代码打造一个易用性、封装性以及扩展性俱佳的image
组件。
useImage
首先分析可复用的逻辑,可以发现使用者需要关注三个状态:loading
、error
以及src
,毕竟加载图片也是异步请求嘛。
对 react-use[3] 熟悉的同学会很容易联想到
useAsync
。
自定义一个 hooks,接收图片链接作为参数,返回调用方需要的三个状态。
基础实现
import * as React from "react";
// 将图片加载转为promise调用形式
function imgPromise(src: string) {
return new Promise((resolve, reject) => {
const i = new Image();
i.onload = () => resolve();
i.onerror = reject;
i.src = src;
});
}
function useImage({ src }: { src: string }): {
src: string | undefined,
isLoading: boolean,
error: any,
} {
const [loading, setLoading] = React.useState(true);
const [error, setError] = React.useState(null);
const [value, setValue] = (React.useState < string) | (undefined > undefined);
React.useEffect(() => {
imgPromise(src)
.then(() => {
// 加载成功
setLoading(false);
setValue(src);
})
.catch((error) => {
// 加载失败
setLoading(false);
setError(error);
});
}, [src]);
return { isLoading: loading, src: value, error: error };
}
我们已经完成了最基础的实现,现在来慢慢优化。
性能优化
对于同一张图片来讲,在组件 A 加载过的图片,组件 B 不用再走一遍new Image()
的流程,直接返回上一次结果即可。
+ const cache: {
+ [key: string]: Promise<void>;
+ } = {};
function useImage({
src,
}: {
src: string;
}): { src: string | undefined; isLoading: boolean; error: any } {
const [loading, setLoading] = React.useState(true);
const [error, setError] = React.useState(null);
const [value, setValue] = React.useState<string | undefined>(undefined);
React.useEffect(() => {
+ if (!cache[src]) {
+ cache[src] = imgPromise(src);
+ }
- imgPromise(src)
+ cache[src]
.then(() => {
setLoading(false);
setValue(src);
})
.catch(error => {
setLoading(false);
setError(error);
});
}, [src]);
return { isLoading: loading, src: value, error: error };
}
优化了一丢丢性能。
支持 srcList
上文提到过一点:图片加载失败,加载备选图片或展示error
占位符。
展示error
占位符我们可以通过error
状态去控制,但是加载备选图片的功能还没有完成。
主要思路如下:
-
将入参 src
改为srcList
,值为图片url
或图片(含备选图片)的url
数组; -
从第一张开始加载,若失败则加载第二张,直到某一张成功或全部失败,流程结束。类似于 tapable [4] 的 AsyncSeriesBailHook
。
对入参进行处理:
const removeBlankArrayElements = (a: string[]) => a.filter((x) => x);
const stringToArray = (x: string | string[]) => (Array.isArray(x) ? x : [x]);
function useImage({ srcList }: { srcList: string | string[] }): {
src: string | undefined,
loading: boolean,
error: any,
} {
// 获取url数组
const sourceList = removeBlankArrayElements(stringToArray(srcList));
// 获取用于缓存的键名
const sourceKey = sourceList.join("");
}
接下来就是重要的加载流程啦,定义promiseFind
方法,用于完成以上加载图片的逻辑。
/**
* 注意 此处将imgPromise作为参数传入,而没有直接使用imgPromise
* 主要是为了扩展性
* 后面会将imgPromise方法作为一个参数由使用者传入,使得使用者加载图片的操作空间更大
* 当然若使用者不传该参数,就是用默认的imgPromise方法
*/
function promiseFind(
sourceList: string[],
imgPromise: (src: string) => Promise<void>
): Promise<string> {
let done = false;
// 重新使用Promise包一层
return new Promise((resolve, reject) => {
const queueNext = (src: string) => {
return imgPromise(src).then(() => {
done = true;
// 加载成功 resolve
resolve(src);
});
};
const firstPromise = queueNext(sourceList.shift() || "");
// 生成一条promise链[队列],每一个promise都跟着catch方法处理当前promise的失败
// 从而继续下一个promise的处理
sourceList
.reduce((p, src) => {
// 如果加载失败 继续加载
return p.catch(() => {
if (!done) return queueNext(src);
return;
});
}, firstPromise)
// 全都挂了 reject
.catch(reject);
});
}
再来改动useImage
。
const cache: {
- [key: string]: Promise<void>;
+ [key: string]: Promise<string>;
} = {};
function useImage({
- src,
+ srcList,
}: {
- src: string;
+ srcList: string | string[];
}): { src: string | undefined; loading: boolean; error: any } {
const [loading, setLoading] = React.useState(true);
const [error, setError] = React.useState(null);
const [value, setValue] = React.useState<string | undefined>(undefined);
// 图片链接数组
+ const sourceList = removeBlankArrayElements(stringToArray(srcList));
// cache唯一键名
+ const sourceKey = sourceList.join('''');
React.useEffect(() => {
- if (!cache[src]) {
- cache[src] = imgPromise(src);
- }
+ if (!cache[sourceKey]) {
+ cache[sourceKey] = promiseFind(sourceList, imgPromise);
+ }
- cache[src]
- .then(() => {
+ cache[sourceKey]
+ .then((src) => {
setLoading(false);
setValue(src);
})
.catch(error => {
setLoading(false);
setError(error);
});
}, [src]);
return { isLoading: loading, src: value, error: error };
}
需要注意的一点:现在传入的图片链接可能不是单个src
,最终设置的value
为promiseFind
找到的src
,所以 cache
类型定义也有变化。
自定义 imgPromise
前面提到过,加载图片过程中,使用方可能会插入自己的逻辑,所以将 imgPromise
方法作为可选参数loadImg
传入,若使用者想自定义加载方法,可传入该参数。
function useImage({
+ loadImg = imgPromise,
srcList,
}: {
+ loadImg?: (src: string) => Promise<void>;
srcList: string | string[];
}): { src: string | undefined; loading: boolean; error: any } {
const [loading, setLoading] = React.useState(true);
const [error, setError] = React.useState(null);
const [value, setValue] = React.useState<string | undefined>(undefined);
const sourceList = removeBlankArrayElements(stringToArray(srcList));
const sourceKey = sourceList.join('''');
React.useEffect(() => {
if (!cache[sourceKey]) {
- cache[sourceKey] = promiseFind(sourceList, imgPromise);
+ cache[sourceKey] = promiseFind(sourceList, loadImg);
}
cache[sourceKey]
.then(src => {
setLoading(false);
setValue(src);
})
.catch(error => {
setLoading(false);
setError(error);
});
}, [sourceKey]);
return { loading: loading, src: value, error: error };
}
实现 Img 组件
完成useImage
后,我们就可以基于其实现 Img
组件了。
预先定义好相关 API:
属性 说明 类型 默认值 src 图片链接 string / string[] - loader 可选,加载过程占位元素 ReactNode null unloader 可选,加载失败占位元素 ReactNode null loadImg 可选,图片加载方法,返回一个 Promise (src:string)=>Promise imgPromise 当然,除了以上 API,还有<img />
标签原生属性。编写类型声明文件如下:
export type ImgProps = Omit<
React.DetailedHTMLProps<
React.ImgHTMLAttributes<HTMLImageElement>,
HTMLImageElement
>,
"src"
> &
Omit<useImageParams, "srcList"> & {
src: useImageParams["srcList"];
loader?: JSX.Element | null;
unloader?: JSX.Element | null;
};
实现如下:
export default ({
src: srcList,
loadImg,
loader = null,
unloader = null,
...imgProps
}: ImgProps) => {
const { src, loading, error } = useImage({
srcList,
loadImg,
});
if (src) return <img src={src} {...imgProps} />;
if (loading) return loader;
if (error) return unloader;
return null;
};
测试效果如下:
结语
值得注意的是,本文遵循 react-image
大体思路,但部分内容暂未实现(所以代码可读性要好一点)。其它特性,如:
-
支持 Suspense 形式调用; -
默认在渲染图片前会进行 decode,避免页面卡顿或者闪烁。
有兴趣的同学可以看看下面这些文章:
-
用于数据获取的 Suspense(试验阶段) [5] -
错误边界(Error Boundaries) [6] -
React:Suspense 的实现与探讨 [7] -
HTMLImageElement.decode() [8] -
Chrome 图片解码与 Image.decode API [9]
参考资料
react-image: https://github.com/mbrevda/react-image
[2]✨ 仓库传送门: https://github.com/worldzhao/build-your-own-react-image
[3]react-use: https://github.com/streamich/react-use
[4]tapable: https://github.com/webpack/tapable
[5]用于数据获取的 Suspense(试验阶段): https://zh-hans.reactjs.org/docs/concurrent-mode-suspense.html
[6]错误边界(Error Boundaries): https://zh-hans.reactjs.org/docs/error-boundaries.html#introducing-error-boundaries
[7]React:Suspense 的实现与探讨: https://zhuanlan.zhihu.com/p/34210780
[8]HTMLImageElement.decode(): https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLImageElement/decode
[9]Chrome 图片解码与 Image.decode API: https://zhuanlan.zhihu.com/p/43991630
本文分享自微信公众号 - 前端从进阶到入院(code_with_love)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。
Android 设计一个菱形形状的Imageview组件.
网上没有资料,特来请教下大神
Android 设计一个菱形形状的Imageview组件. >> android
这个答案描述的挺清楚的:
http://www.goodpm.net/postreply/android/1010000007107851/Android设计一个菱形形状的Imageview组件.html
com.facebook.imagepipeline.image.CloseableAnimatedImage的实例源码
private Drawable createDrawableFromFetchedResult(Context context,CloseableImage image) { if (image instanceof CloseableStaticBitmap) { CloseableStaticBitmap closeableStaticBitmap = (CloseableStaticBitmap) image; BitmapDrawable bitmapDrawable = createBitmapDrawable(context,closeableStaticBitmap.getUnderlyingBitmap()); return (closeableStaticBitmap.getRotationAngle() != 0 && closeableStaticBitmap.getRotationAngle() != -1 ? new OrientedDrawable(bitmapDrawable,closeableStaticBitmap.getRotationAngle()) : bitmapDrawable); } else if (image instanceof CloseableAnimatedImage) { AnimatedDrawableFactory animatedDrawableFactory = Fresco.getimagePipelineFactory().getAnimatedFactory().getAnimatedDrawableFactory(context); if (animatedDrawableFactory != null) { AnimatedDrawable animatedDrawable = (AnimatedDrawable) animatedDrawableFactory.create(image); if (animatedDrawable != null) { return animatedDrawable; } } } throw new UnsupportedOperationException("Unrecognized image class: " + image); }
@Test public void testNonStaticBitmapIsPassedOn() { SingleUsePostprocessorConsumer postprocessorConsumer = produceResults(); CloseableAnimatedImage sourceCloseableAnimatedImage = mock(CloseableAnimatedImage.class); CloseableReference<CloseableImage> sourceCloseableImageRef = CloseableReference.<CloseableImage>of(sourceCloseableAnimatedImage); postprocessorConsumer.onNewResult(sourceCloseableImageRef,Consumer.IS_LAST); sourceCloseableImageRef.close(); mTestExecutorService.runUntilIdle(); mInorder.verify(mConsumer).onNewResult(any(CloseableReference.class),eq(Consumer.IS_LAST)); mInorder.verifyNoMoreInteractions(); assertEquals(1,mResults.size()); CloseableReference<CloseableImage> res0 = mResults.get(0); assertTrue(CloseableReference.isValid(res0)); assertSame(sourceCloseableAnimatedImage,res0.get()); res0.close(); verify(sourceCloseableAnimatedImage).close(); }
@Test public void testNonStaticBitmapIsPassedOn() { RepeatedPostprocessorConsumer postprocessorConsumer = produceResults(); RepeatedPostprocessorRunner repeatedPostprocessorRunner = getRunner(); CloseableAnimatedImage sourceCloseableAnimatedImage = mock(CloseableAnimatedImage.class); CloseableReference<CloseableImage> sourceCloseableImageRef = CloseableReference.<CloseableImage>of(sourceCloseableAnimatedImage); postprocessorConsumer.onNewResult(sourceCloseableImageRef,eq(Consumer.NO_FLAGS)); mInorder.verifyNoMoreInteractions(); assertEquals(1,res0.get()); res0.close(); performCancelAndVerifyOnCancellation(); verify(sourceCloseableAnimatedImage).close(); }
private Drawable createDrawableFromFetchedResult(Context context,closeableStaticBitmap.getRotationAngle()) : bitmapDrawable); } else if (image instanceof CloseableAnimatedImage) { AnimatedDrawableFactory animatedDrawableFactory = Fresco.getimagePipelineFactory().getAnimatedFactory().getAnimatedDrawableFactory(context); if (animatedDrawableFactory != null) { AnimatedDrawable animatedDrawable = (AnimatedDrawable) animatedDrawableFactory.create(image); if (animatedDrawable != null) { return animatedDrawable; } } } throw new UnsupportedOperationException("Unrecognized image class: " + image); }
@Test public void testNonStaticBitmapIsPassedOn() { SingleUsePostprocessorConsumer postprocessorConsumer = produceResults(); CloseableAnimatedImage sourceCloseableAnimatedImage = mock(CloseableAnimatedImage.class); CloseableReference<CloseableImage> sourceCloseableImageRef = CloseableReference.<CloseableImage>of(sourceCloseableAnimatedImage); postprocessorConsumer.onNewResult(sourceCloseableImageRef,res0.get()); res0.close(); verify(sourceCloseableAnimatedImage).close(); }
@Test public void testNonStaticBitmapIsPassedOn() { RepeatedPostprocessorConsumer postprocessorConsumer = produceResults(); RepeatedPostprocessorRunner repeatedPostprocessorRunner = getRunner(); CloseableAnimatedImage sourceCloseableAnimatedImage = mock(CloseableAnimatedImage.class); CloseableReference<CloseableImage> sourceCloseableImageRef = CloseableReference.<CloseableImage>of(sourceCloseableAnimatedImage); postprocessorConsumer.onNewResult(sourceCloseableImageRef,res0.get()); res0.close(); performCancelAndVerifyOnCancellation(); verify(sourceCloseableAnimatedImage).close(); }
private CloseableImage getCloseableImage( ImageDecodeOptions options,AnimatedImage image,Bitmap.Config bitmapConfig) { List<CloseableReference<Bitmap>> decodedFrames = null; CloseableReference<Bitmap> previewBitmap = null; try { final int frameForPreview = options.useLastFrameForPreview ? image.getFrameCount() - 1 : 0; if (options.forceStaticImage) { return new CloseableStaticBitmap( createPreviewBitmap(image,bitmapConfig,frameForPreview),ImmutableQualityInfo.FULL_QUALITY,0); } if (options.decodeAllFrames) { decodedFrames = decodeAllFrames(image,bitmapConfig); previewBitmap = CloseableReference.cloneOrNull(decodedFrames.get(frameForPreview)); } if (options.decodePreviewFrame && previewBitmap == null) { previewBitmap = createPreviewBitmap(image,frameForPreview); } AnimatedImageResult animatedImageResult = AnimatedImageResult.newBuilder(image) .setPreviewBitmap(previewBitmap) .setFrameForPreview(frameForPreview) .setDecodedFrames(decodedFrames) .build(); return new CloseableAnimatedImage(animatedImageResult); } finally { CloseableReference.closeSafely(previewBitmap); CloseableReference.closeSafely(decodedFrames); } }
@Test public void testCreateDefaults() { WebPImage mockWebPImage = mock(WebPImage.class); // Expect a call to WebPImage.create TrivialPooledByteBuffer byteBuffer = createByteBuffer(); when(mWebPImageMock.decode(byteBuffer.getNativePtr(),byteBuffer.size())) .thenReturn(mockWebPImage); EncodedImage encodedImage = new EncodedImage( CloseableReference.of(byteBuffer,FAKE_RESOURCE_RELEASER)); encodedImage.setimageFormat(ImageFormat.UNKNowN); CloseableAnimatedImage closeableImage = (CloseableAnimatedImage) mAnimatedImageFactory.decodeWebP( encodedImage,ImageDecodeOptions.defaults(),DEFAULT_BITMAP_CONfig); // Verify we got the right result AnimatedImageResult imageResult = closeableImage.getimageResult(); assertSame(mockWebPImage,imageResult.getimage()); assertNull(imageResult.getPreviewBitmap()); assertFalse(imageResult.hasDecodedFrame(0)); // Should not have interacted with these. verifyZeroInteractions(mMockAnimatedDrawableBackendProvider); verifyZeroInteractions(mMockBitmapFactory); }
@Test public void testCreateDefaults() { GifImage mockGifImage = mock(GifImage.class); // Expect a call to GifImage.create TrivialPooledByteBuffer byteBuffer = createByteBuffer(); when(mGifImageMock.decode(byteBuffer.getNativePtr(),byteBuffer.size())) .thenReturn(mockGifImage); EncodedImage encodedImage = new EncodedImage( CloseableReference.of(byteBuffer,FAKE_RESOURCE_RELEASER)); encodedImage.setimageFormat(ImageFormat.UNKNowN); CloseableAnimatedImage closeableImage = (CloseableAnimatedImage) mAnimatedImageFactory.decodeGif( encodedImage,DEFAULT_BITMAP_CONfig); // Verify we got the right result AnimatedImageResult imageResult = closeableImage.getimageResult(); assertSame(mockGifImage,imageResult.getimage()); assertNull(imageResult.getPreviewBitmap()); assertFalse(imageResult.hasDecodedFrame(0)); // Should not have interacted with these. verifyZeroInteractions(mMockAnimatedDrawableBackendProvider); verifyZeroInteractions(mMockBitmapFactory); }
private CloseableImage getCloseableImage( ImageDecodeOptions options,frameForPreview); } AnimatedImageResult animatedImageResult = AnimatedImageResult.newBuilder(image) .setPreviewBitmap(previewBitmap) .setFrameForPreview(frameForPreview) .setDecodedFrames(decodedFrames) .build(); return new CloseableAnimatedImage(animatedImageResult); } finally { CloseableReference.closeSafely(previewBitmap); CloseableReference.closeSafely(decodedFrames); } }
@Test public void testCreateDefaults() { WebPImage mockWebPImage = mock(WebPImage.class); // Expect a call to WebPImage.create TrivialPooledByteBuffer byteBuffer = createByteBuffer(); when(mWebPImageMock.decode(byteBuffer.getNativePtr(),imageResult.getimage()); assertNull(imageResult.getPreviewBitmap()); assertFalse(imageResult.hasDecodedFrame(0)); // Should not have interacted with these. verifyZeroInteractions(mMockAnimatedDrawableBackendProvider); verifyZeroInteractions(mMockBitmapFactory); }
@Test public void testCreateDefaults() { GifImage mockGifImage = mock(GifImage.class); // Expect a call to GifImage.create TrivialPooledByteBuffer byteBuffer = createByteBuffer(); when(mGifImageMock.decode(byteBuffer.getNativePtr(),imageResult.getimage()); assertNull(imageResult.getPreviewBitmap()); assertFalse(imageResult.hasDecodedFrame(0)); // Should not have interacted with these. verifyZeroInteractions(mMockAnimatedDrawableBackendProvider); verifyZeroInteractions(mMockBitmapFactory); }
@Override public boolean supportsImageType(CloseableImage image) { return image instanceof CloseableAnimatedImage; }
@Override public AnimatedDrawable2 createDrawable(CloseableImage image) { return new AnimatedDrawable2( createAnimationBackend( ((CloseableAnimatedImage) image).getimageResult())); }
@Test public void testCreateWithPreviewBitmap() throws Exception { WebPImage mockWebPImage = mock(WebPImage.class); Bitmap mockBitmap = MockBitmapFactory.create(50,50,DEFAULT_BITMAP_CONfig); // Expect a call to WebPImage.create TrivialPooledByteBuffer byteBuffer = createByteBuffer(); when(mWebPImageMock.decode(byteBuffer.getNativePtr(),byteBuffer.size())) .thenReturn(mockWebPImage); when(mockWebPImage.getWidth()).thenReturn(50); when(mockWebPImage.getHeight()).thenReturn(50); // For decoding preview frame,expect some calls. final AnimatedDrawableBackend mockAnimatedDrawableBackend = createAnimatedDrawableBackendMock(1); when(mMockAnimatedDrawableBackendProvider.get( any(AnimatedImageResult.class),isNull(Rect.class))) .thenReturn(mockAnimatedDrawableBackend); when(mMockBitmapFactory.createBitmapInternal(50,DEFAULT_BITMAP_CONfig)) .thenReturn(CloseableReference.of(mockBitmap,FAKE_BITMAP_RESOURCE_RELEASER)); AnimatedImageCompositor mockCompositor = mock(AnimatedImageCompositor.class); powermockito.whenNew(AnimatedImageCompositor.class) .withAnyArguments() .thenReturn(mockCompositor); ImageDecodeOptions imageDecodeOptions = ImageDecodeOptions.newBuilder() .setDecodePreviewFrame(true) .build(); EncodedImage encodedImage = new EncodedImage( CloseableReference.of(byteBuffer,FAKE_RESOURCE_RELEASER)); encodedImage.setimageFormat(ImageFormat.UNKNowN); CloseableAnimatedImage closeableImage = (CloseableAnimatedImage) mAnimatedImageFactory.decodeWebP( encodedImage,imageDecodeOptions,imageResult.getimage()); assertNotNull(imageResult.getPreviewBitmap()); assertFalse(imageResult.hasDecodedFrame(0)); // Should not have interacted with these. verify(mMockAnimatedDrawableBackendProvider).get( any(AnimatedImageResult.class),isNull(Rect.class)); verifyNoMoreInteractions(mMockAnimatedDrawableBackendProvider); verify(mMockBitmapFactory).createBitmapInternal(50,DEFAULT_BITMAP_CONfig); verifyNoMoreInteractions(mMockBitmapFactory); verify(mockCompositor).renderFrame(0,mockBitmap); }
@Test public void testCreateWithDecodeAlFrames() throws Exception { WebPImage mockWebPImage = mock(WebPImage.class); Bitmap mockBitmap1 = MockBitmapFactory.create(50,DEFAULT_BITMAP_CONfig); Bitmap mockBitmap2 = MockBitmapFactory.create(50,expect some calls. final AnimatedDrawableBackend mockAnimatedDrawableBackend = createAnimatedDrawableBackendMock(2); when( mMockAnimatedDrawableBackendProvider.get( any(AnimatedImageResult.class),isNull(Rect.class))) .thenReturn(mockAnimatedDrawableBackend); when(mMockBitmapFactory.createBitmapInternal(50,DEFAULT_BITMAP_CONfig)) .thenReturn(CloseableReference.of(mockBitmap1,FAKE_BITMAP_RESOURCE_RELEASER)) .thenReturn(CloseableReference.of(mockBitmap2,FAKE_BITMAP_RESOURCE_RELEASER)); AnimatedImageCompositor mockCompositor = mock(AnimatedImageCompositor.class); powermockito.whenNew(AnimatedImageCompositor.class) .withAnyArguments() .thenReturn(mockCompositor); ImageDecodeOptions imageDecodeOptions = ImageDecodeOptions.newBuilder() .setDecodePreviewFrame(true) .setDecodeAllFrames(true) .build(); EncodedImage encodedImage = new EncodedImage( CloseableReference.of(byteBuffer,imageResult.getimage()); assertNotNull(imageResult.getDecodedFrame(0)); assertNotNull(imageResult.getDecodedFrame(1)); assertNotNull(imageResult.getPreviewBitmap()); // Should not have interacted with these. verify(mMockAnimatedDrawableBackendProvider).get( any(AnimatedImageResult.class),isNull(Rect.class)); verifyNoMoreInteractions(mMockAnimatedDrawableBackendProvider); verify(mMockBitmapFactory,times(2)).createBitmapInternal(50,mockBitmap1); verify(mockCompositor).renderFrame(1,mockBitmap2); }
@Test public void testCreateWithPreviewBitmap() throws Exception { GifImage mockGifImage = mock(GifImage.class); Bitmap mockBitmap = MockBitmapFactory.create(50,DEFAULT_BITMAP_CONfig); // Expect a call to WebPImage.create TrivialPooledByteBuffer byteBuffer = createByteBuffer(); when(mGifImageMock.decode(byteBuffer.getNativePtr(),byteBuffer.size())) .thenReturn(mockGifImage); when(mockGifImage.getWidth()).thenReturn(50); when(mockGifImage.getHeight()).thenReturn(50); // For decoding preview frame,expect some calls. final AnimatedDrawableBackend mockAnimatedDrawableBackend = createAnimatedDrawableBackendMock(1); when(mMockAnimatedDrawableBackendProvider.get( any(AnimatedImageResult.class),FAKE_RESOURCE_RELEASER)); encodedImage.setimageFormat(ImageFormat.UNKNowN); CloseableAnimatedImage closeableImage = (CloseableAnimatedImage) mAnimatedImageFactory.decodeGif( encodedImage,mockBitmap); }
@Test public void testCreateWithDecodeAlFrames() throws Exception { GifImage mockGifImage = mock(GifImage.class); Bitmap mockBitmap1 = MockBitmapFactory.create(50,DEFAULT_BITMAP_CONfig); // Expect a call to GifImage.create TrivialPooledByteBuffer byteBuffer = createByteBuffer(); when(mGifImageMock.decode(byteBuffer.getNativePtr(),expect some calls. final AnimatedDrawableBackend mockAnimatedDrawableBackend = createAnimatedDrawableBackendMock(2); when( mMockAnimatedDrawableBackendProvider.get( any(AnimatedImageResult.class),mockBitmap2); }
@Override public boolean supportsImageType(CloseableImage image) { return image instanceof CloseableAnimatedImage; }
@Override public AnimatedDrawable2 createDrawable(CloseableImage image) { return new AnimatedDrawable2( createAnimationBackend( ((CloseableAnimatedImage) image).getimageResult())); }
@Test public void testCreateWithPreviewBitmap() throws Exception { WebPImage mockWebPImage = mock(WebPImage.class); Bitmap mockBitmap = MockBitmapFactory.create(50,mockBitmap); }
@Test public void testCreateWithDecodeAlFrames() throws Exception { WebPImage mockWebPImage = mock(WebPImage.class); Bitmap mockBitmap1 = MockBitmapFactory.create(50,mockBitmap2); }
@Test public void testCreateWithPreviewBitmap() throws Exception { GifImage mockGifImage = mock(GifImage.class); Bitmap mockBitmap = MockBitmapFactory.create(50,mockBitmap); }
@Test public void testCreateWithDecodeAlFrames() throws Exception { GifImage mockGifImage = mock(GifImage.class); Bitmap mockBitmap1 = MockBitmapFactory.create(50,mockBitmap2); }
private void handleAnimateBitmap(CloseableAnimatedImage animatedImage,int position) { AnimatedDrawableFactory animatedDrawableFactory = Fresco.getimagePipelineFactory().getAnimatedDrawableFactory(); AnimatedDrawable drawable = animatedDrawableFactory.create(animatedImage.getimageResult()); Bitmap bitmap = drawable2Bitmap(drawable); map.put(position,bitmap); }
com.facebook.react.views.image.ImageResizeMode的实例源码
@ReactProp(name = ViewProps.RESIZE_MODE) public void setResizeMode(@Nullable String resizeMode) { ScaleType scaleType = ImageResizeMode.toScaleType(resizeMode); if (mDrawImage.getScaleType() != scaleType) { getMutableDrawImage().setScaleType(scaleType); } }
com.facebook.react.views.image.ReactImageManager的实例源码
@Override public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { return Arrays.<ViewManager>asList( new ReactDrawerLayoutManager(),new ReacthorizontalscrollviewManager(),new ReactimageManager(),new ReactProgressBarViewManager(),new ReactRawTextManager(),new ReactScrollViewManager(),new ReactSwitchManager(),new ReactTextInputManager(),new ReactTextViewManager(),new ReactToolbarManager(),new ReactViewManager(),new ReactViewPagerManager(),new ReactTextInlineImageViewManager(),new ReactVirtualTextViewManager(),new SwipeRefreshLayoutManager(),new ReactWebViewManager()); }
@Override public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { return Arrays.<ViewManager>asList( ARTRenderableViewManager.createARTGroupViewManager(),ARTRenderableViewManager.createARTShapeViewManager(),ARTRenderableViewManager.createARTTextViewManager(),new ARTSurfaceViewManager(),new ReactDialogPickerManager(),new ReactDrawerLayoutManager(),new ReactDropdownPickerManager(),new FrescoBasedReactTextInlineImageViewManager(),new ReactWebViewManager(),new RecyclerViewBackedScrollViewManager(),new SwipeRefreshLayoutManager()); }
@Override public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { return Arrays.<ViewManager>asList( ARTRenderableViewManager.createARTGroupViewManager(),new SwipeRefreshLayoutManager()); }
@Override public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { return Arrays.<ViewManager>asList( ARTRenderableViewManager.createARTGroupViewManager(),new ReactModalHostManager(),new ReactSliderManager(),new SwipeRefreshLayoutManager()); }
@Override public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { return Arrays.<ViewManager>asList( ARTRenderableViewManager.createARTGroupViewManager(),new SwipeRefreshLayoutManager()); }
@Override public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { List<ViewManager> viewManagers = new ArrayList<>(); viewManagers.add(ARTRenderableViewManager.createARTGroupViewManager()); viewManagers.add(ARTRenderableViewManager.createARTShapeViewManager()); viewManagers.add(ARTRenderableViewManager.createARTTextViewManager()); viewManagers.add(new ARTSurfaceViewManager()); viewManagers.add(new ReactDialogPickerManager()); viewManagers.add(new ReactDrawerLayoutManager()); viewManagers.add(new ReactDropdownPickerManager()); viewManagers.add(new ReacthorizontalscrollviewManager()); viewManagers.add(new ReactimageManager()); viewManagers.add(new ReactModalHostManager()); viewManagers.add(new ReactProgressBarViewManager()); viewManagers.add(new ReactRawTextManager()); viewManagers.add(new ReactScrollViewManager()); viewManagers.add(new ReactSliderManager()); viewManagers.add(new ReactSwitchManager()); viewManagers.add(new FrescoBasedReactTextInlineImageViewManager()); viewManagers.add(new ReactTextInputManager()); viewManagers.add(new ReactTextViewManager()); viewManagers.add(new ReactToolbarManager()); viewManagers.add(new ReactViewManager()); viewManagers.add(new ReactViewPagerManager()); viewManagers.add(new ReactVirtualTextViewManager()); viewManagers.add(new ReactWebViewManager()); viewManagers.add(new SwipeRefreshLayoutManager()); SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(reactContext); if (preferences.getBoolean("flat_uiimplementation",false)) { viewManagers.addAll(Arrays.asList( new RCTViewManager(),new RCTTextManager(),new RCTRawTextManager(),new RCTVirtualTextManager(),new RCTTextInlineImageManager(),new RCtimageViewManager(),new RCTTextInputManager(),new RCTViewPagerManager(),new FlatARTSurfaceViewManager(),new RCTModalHostManager())); } return viewManagers; }
今天关于如何设计一个好用的 React Image 组件?和react组件设计原则的讲解已经结束,谢谢您的阅读,如果想了解更多关于Android 设计一个菱形形状的Imageview组件.、com.facebook.imagepipeline.image.CloseableAnimatedImage的实例源码、com.facebook.react.views.image.ImageResizeMode的实例源码、com.facebook.react.views.image.ReactImageManager的实例源码的相关知识,请在本站搜索。
本文标签: