本文共 3840 字,大约阅读时间需要 12 分钟。
尊重版权,未经授权不得转载
本项目来自 文章来自江清清的技术专栏()
原文地址(需要翻墙):
我最近正在开发一个React Native项目,同时想要给大家分享一个方法库,可以在图片显示的时候更加的平滑,以此来提升用户体验。该使用的库就是 项目实现的效果如下:
React Native交流10群:157867561,欢迎各位大牛,React Native技术爱好者加入交流!同时博客右侧欢迎微信扫描关注订阅号,移动技术干货,精彩文章技术推送!
以上的动态效果中,会有头像,列表上面的图片等多种图片类型,在本项目中采用
针对用户自定义生成的图片(例如:app的用户上传的图片),我们有两种缓存策略:immmutable和mutable。immutable缓存策略用于图片地址不变的情况,反正mutable用于图片地址经常变化的情况。但是我们为什么同时需要这两种策略呢?让我们来看下面的用户配置项。
如上界面效果:当我们现实用于资料头像的时候,该图片通过后台服务器提供。然后当我们需要显示列表中的图像信息的时候,只需要显示用户头像的缩略图即可,并不需要发送额外的请求到服务器。
不可变的图片需要依靠后台服务器提供的最新图片的URL地址,在上面个人头像的案例中,后台可能会返回如下的信息:
1 2 3 4 5 6 7 8 9 | { profile: { pictures: { large: "" , medium: "" , small: "" } } } |
缓存这些头像图片是非常简单便捷的,通过图片URL地址的哈希串号,我们可以检测本地缓存文件中是否存在该图片,然后进行相关处理。下面就是采用库下载图片,然后进行缓存处理的实例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import RNFetchBlob from "react-native-fetch-blob" ; const SHA1 = require( "crypto-js/sha1" ); export default class ImageCache { static function get(uri: string): Promise<string> { const path = RNFetchBlob.fs.dirs.CacheDir + "_immutable_images/" + SHA1(uri) + ".jpg" ; return RNFetchBlob.fs.exists(path).then(exists => { if (exists) { return path; } else { return RNFetchBlob.config({ path }) .fetch( "GET" , uri, {}) .then(() => path); } }); } } |
针对可变的图片,我们需要实现一个observable接口。针对APP应用中的每一个URL,该监听着会观察到在本地缓存中的图片当前的路径。如果图片被下载,那么该观察者就会收到图片的本地当前路径。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | type ImageCacheObserver = (path: string) => void; interface IImageCacheObservable { on(uri: string, observer: ImageCacheObserver); dispose(observer: ImageCacheObserver); } interface IImageCache extends IImageCacheObservable { /* * When busting an URI, the new local path of the image will * be provided to all its observers */ bust(uri: string); } |
下面的代码片段显示了如何在React Native组件实现IIMageCache的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | interface CachedImageProps { uri: string; style?: React.ImageStyle; } @observer export class CachedImage extends Component<CachedImageProps, void> { @observable private _path; private handler = path => this .path = path; @computed get path() { return this ._path; } set path(path: string) { return this ._path = path; } observe(uri: string) { // We start observing the cache ImageCache.on(uri, handler): } componentWillMount() { observe( this .props.uri); } componentWillReceiveProps(nextProps: CachedImageProps) { observe(nextProps.uri); } componentWillUnmount() { // We stop observing the cache ImageCache.dispose(handler); } render() { const {style} = this .props; return <Image style={style} source={ { uri: this .store.path }}>{ this .props.children}</Image>; } } |
实现IImageCache接口类,可以实现同时不下载相同的图片。同时在接口方法中添加一个额外的immutable的参数来进行设置缓存策略。
1 2 3 4 5 | interface IImageCacheObservable { // The immutable parameter indicates which caching strategy to use on(uri: string, observer: ImageCacheObserver, immutable: boolean); dispose(observer: ImageCacheObserver); } |
针对具体的ImageCache的实现效果代码可以在库中找到
针对静态图片资源,同时这边也提供一个小小的库用来扫描应用的图片文件夹,然后生成包含应用中所有的静态图片资源的类。可以看如下一个实例:
1 2 3 4 5 6 7 8 | /* * Generated by */ export default class Images { static readonly resetPassword = require( "../public/images/ResetPassword.jpg" ); static readonly signIn = require( "../public/images/SignIn.jpg" ); static readonly signUp = require( "../public/images/SignUp.jpg" ); } |
但是如果用户使用的是旧版本的应用,后台可能会引用到部分静态资源,但是这些图片没有在已安装的应用中。如果是这种情况,那我们就必须下载远程图片了,具体做法如下:
1 2 3 4 5 6 7 8 9 10 11 12 | export default class { static getImage(id: string): any { // We check if the image is present within the app bundle const entry: any = _.get(Images, _.camelCase(id)); if (entry !== undefined) { return entry; } else { // If not, we return a remote link for that image return { uri: `${StaticDomain}/${id}` }; } } } |
React Native交流10群:157867561,欢迎各位大牛,React Native技术爱好者加入交流!同时博客右侧欢迎微信扫描关注订阅号,移动技术干货,精彩文章技术推送!
尊重原创,转载请注明:From Sky丶清() 侵权必究!