React Native Text Inline Image

原文地址(需科学上网):React Native Text Inline Image

RN 版本:0.49

图文混排(在文字中插入图片,并保持正确换行)是客户端普遍的需求,但在 RN 中它有一点问题,具体表现在 Android 平台下图片显得异常的小,并且相同系统不同设备之间的表现也不尽一样,而 ios 则表现正常。

就像这样:

import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Image,
} from 'react-native';

const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 50,
backgroundColor: '#f6f7f8',
},
image: {
width: 80,
height: 80,
},
text: {
backgroundColor: '#dcdcde',
},
});

class App extends Component {

render() {
return (
<View style={styles.container}>
<Text style={styles.text}>
Hello people!
<Image
style={styles.image}
source={{uri: 'http://s3.hilariousgifs.com/displeased-cat.jpg'}}
/>
</Text>
</View>
);
}
}

AppRegistry.registerComponent('App', () => App);

它在 ios 下看起来是这样的:

ios-before

而在 Android 下看起来是这样的:

android-before

可以看到,在 Android 下面这张图异常地小!

实际上这与设备的像素比(pixel ratio)有关,是现版本 React Native 在渲染文字内联图片时的一个 Bug,为了解决这个问题,我们可以给图片设定一个基于设备像素比的宽高。

就像这样:

import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Image,
Platform,
PixelRatio,
} from 'react-native';

const width = 80 * (Platform.OS === 'ios' ? 1 : PixelRatio.get());
const height = 80 * (Platform.OS === 'ios' ? 1 : PixelRatio.get());

const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 50,
backgroundColor: '#f6f7f8',
},
image: {
width: width,
height: height,
},
text: {
backgroundColor: '#dcdcde',
},
});

class App extends Component {

render() {
return (
<View style={styles.container}>
<Text style={styles.text}>
Hello people!
<Image
style={styles.image}
source={{uri: 'http://s3.hilariousgifs.com/displeased-cat.jpg'}}
/>
</Text>
</View>
);
}
}

AppRegistry.registerComponent('App', () => App);

结果:

android-after

如此一来,内联图片在 Android 下就能以正常缩放比显示了。

方便起见,可以将这段逻辑封装到组件中去。

import React from 'react';
import {
StyleSheet,
Image,
Platform,
PixelRatio,
} from 'react-native';

// This component fixes a bug in React Native with <Image> component inside of
// <Text> components.
const InlineImage = (props) => {
let style = props.style;
if (style && Platform.OS !== 'ios') {
// Multiply width and height by pixel ratio to fix React Native bug
style = Object.assign({}, StyleSheet.flatten(props.style));
['width', 'height'].forEach((propName) => {
if (style[propName]) {
style[propName] *= PixelRatio.get();
}
});
}

return (
<Image
{...props}
style={style}
/>
);
};

// "Inherit" prop types from Image
InlineImage.propTypes = Image.propTypes;

export default InlineImage;