1.背景
本文使用的RN(使用RN表示React Native)的版本为0.44版本。在应用的开发过程,可能会遇到这么一种场景,就是在图片的拉伸过程中,需要保持部分区域不被拉伸,而部分区域需要进行拉伸。比如IM中聊天的背景气泡等。那么这个时候我们就可能需要使用到点9图片。那么在RN中,该如何使用点9图片呢?
2.RN上显示点9图片的思路
首先既然是图片,那么在RN中肯定是需要在组件Image中进行显示,那么RN的Image可以同时支持Android和ios平台的点9图片的制作和显示吗?我们去官方的Api文档上找找看。在RN的文档上我们看到了这样的介绍
ios
capInsets {top: number, left: number, bottom: number, right: number}
当图片被缩放的时候,capInsets指定的角上的尺寸会被固定而不进行缩放,而中间和边上其他的部分则会被拉伸。这在制作一些可变大小的圆角按钮、阴影、以及其它资源的时候非常有用(译注:这就是常说的九宫格或者.9图。了解更多信息,可以参见[苹果官方文档]
可以看到RN的Image组件是可以直接支持capInsets属性,对我们需要的图片进行对应的拉伸操作,这与ios原生的使用是一样的,那么在Android平台上该如何使用呢?很遗憾,在RN上并没有这方面的介绍。
做过Android原生开发的可能知道,在Android平台上是可以通过工具制作点9图片,然后作为背景图片直接使用,那么按照这个思路,我们可以在Android封装对应的组件,然后在Android平台上要使用的时候就直接使用制作好的点9图片,而在ios平台上我们使用capInsets属性。
3.React Native 9patch image
在这里,我们找到了一个封装好的开源组件,Github地址:https://github.com/rusfearuth/react-native-9patch-image 我们来看下它在Android平台下的封装思路
public class RCTImageCapInsetManager extends SimpleViewManager<RCTImageCapInsetView> {
@Override
public String getName() {
return "RCTImageCapInset";
}
@Override
protected RCTImageCapInsetView createViewInstance(ThemedReactContext reactContext) {
return new RCTImageCapInsetView(reactContext);
}
@ReactProp(name = "source")
public void setSource(final RCTImageCapInsetView view, ReadableMap source) {
String uri = source.getString("uri");
view.setSource(uri);
}
}
首先从source中获取uri的地址,然后将其赋值给这里的RCTImageCapInsetView,而对于RCTImageCapInsetView
public class RCTImageCapInsetView extends ImageView {
private String mUri;
public RCTImageCapInsetView(Context context) {
super(context);
}
public void setSource(String uri) {
mUri = uri;
reload();
}
public void reload() {
Integer resId = null;
if (getImageCache().has(mUri)) {
resId = getImageCache().get(mUri);
if (resId == null) {
getImageCache().remove(mUri);
}
}
if (resId == null) {
resId = getResourceDrawableId(mUri);
getImageCache().put(mUri, resId);
}
setBackgroundResource(resId);
}
private @NonNull Integer getResourceDrawableId(@NonNull final String aName) {
if (aName == null || aName.isEmpty()) {
return 0;
}
final String name = aName.toLowerCase().replace("-", "_");
return getResources().getIdentifier(
name,
"drawable",
getContext().getPackageName()
);
}
private RCTImageCache getImageCache()
{
return RCTImageCache.getInstance();
}
}
RCTImageCapInsetView的本质是一个ImageView,获取到uri的名称,然后在drawable之中查找到对应的id名称,最后得到图片资源作为ImageView背景,跟我们在Android原生上使用点9图片的方式是一样的。
4.制作点9图片
4.1 Android平台下制作
在这里我们用到的是Android上默认的logo图片
将其赋值到res/drawable目录下,并将其改名为image.9.png,在android studio中双击打开它,选择9-patch模式
这个时候我们就可以直接在android studio直接进行点9图片的制作,当然我们也可以打开android sdk中提供的点9图片制作工具进行制作,工具路径为:/Users/hzl/Library/Android/sdk/tools/draw9patch 至于如何点9图片的上下左右边界代表的意思,这里不作过多的阐述,可以通过百度,Google等去搜索相关的介绍。这样Android平台上的点9图片就制作完成了。
4.2 ios平台下制作
在上面我们制作了Android平台下的点9图片,那么在ios平台上,对应的capInsets属性是多少呢?我们把鼠标悬停在边界上
可以看到Horizontal Patch:29-66px,那么对应的capInsets属性中的left和right就是29和29(95-66=29,其中95是原始图片的宽),同理根据Vertical Patch:40-86px,可以知道capInsets属性中的top和bottom就是40和9
5.RN上显示点9图片
在上面中我们制作好了对应的点9图片,那么我们分别在Android和ios平台上看下效果如果。
import React, {Component} from 'react';
import {View, Platform} from 'react-native';
import NinePatchView from 'react-native-9patch-image';
export default class Main extends Component {
render() {
return (
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<NinePatchView
style={{width: 200, height: 200}}
source={Platform.OS === 'android' ? {uri: 'image'} : require('./image.png')}
capInsets={{top: 40, left: 29, bottom: 9, right: 29}}/>
</View>)
}
}
这里要特别注意的是Android平台要使用Release版本的apk才可以看到效果,至于如何打包Android Release版本apk,可以去看下RN官方文档上的介绍,http://reactnative.cn/docs/0.43/signed-apk-android.html#content
可以看到,两个平台上的显示效果是一致的。
6.最后
文章中使用的例子已经上传了Github:https://github.com/hzl123456/NinePatchView