模拟显示: 在反应本机中内联

React National 不支持 CSS display属性,默认情况下所有元素都使用 display: flex的行为(也不支持 inline-flex)。大多数非 flex 布局都可以使用 flex 属性进行模拟,但是我对内联文本感到不安。

我的应用程序有一个容器,其中包含几个文本单词,其中一些需要格式化。这意味着我需要使用 span 来完成格式化。为了实现跨度的包装,我可以将容器设置为使用 flex-wrap: wrap,但是这只允许在跨度结束时进行包装,而不是传统的在断字时进行包装的内联行为。

可视化的问题(跨度为黄色) :

enter image description here

(via http://codepen.io/anon/pen/GoWmdm?editors=110)

有没有一种方法来获得正确的包装和真正的内联模拟使用伸缩性能?

114799 次浏览

You can get this effect by wrapping text elements in other text elements the way you would wrap a span in a div or another element:

<View>
<Text><Text>This writing should fill most of the container </Text><Text>This writing should fill most of the container</Text></Text>
</View>

You can also get this effect by declaring a flexDirection:'row' property on the parent along with a flexWrap: 'wrap'. The children will then display inline:

<View style=\{\{flexDirection:'row', flexWrap:'wrap'}}>
<Text>one</Text><Text>two</Text><Text>Three</Text><Text>Four</Text><Text>Five</Text>
</View>

Check out this example.

https://rnplay.org/apps/-rzWGg

I haven't found a proper way to inline text blocks with other content. Our current "hackish" workaround is to split every single word in a text string into its own block so flexWrap wraps properly for each word.

You can only nest text nodes without using flex to get the desired effect. Like this: https://facebook.github.io/react-native/docs/text

<Text style=\{\{fontWeight: 'bold'}}>
I am bold
<Text style=\{\{color: 'red'}}>
and red
</Text>
</Text>

I had the following use case:

I needed a text that can wrap with different sizes, and throughout that text, I wanted to underscore some of the words (to indicate that they are clickable).

It's quite simple expect for the case that you can't control the underline in any way (how close is it, what color is it, so on) - this led me through the rabbit hole, and eventually coming up with the solution of splitting every word, and wrapping it in separate Text component, wrapped with View.

I'll paste the code here:




import React from 'react';
import { StyleSheet, View, TouchableOpacity, Text } from 'react-native';
import Colors from '../../styles/Colors';
import Fonts from '../../styles/Fonts';


const styles = StyleSheet.create({
container: {
flex: 1,
},
});


export default class SaltText extends React.Component {


getTheme (type) {


if (type === 'robomonoregular10gray') {
return {
fontSize: Fonts.SIZES.TEN,
fontFamily: Fonts.ROBOTOMONO_REGULAR,
color: Colors.getColorOpacity(Colors.GRAY, 70),
lineHeight: Fonts.SIZES.TEN + 10
};
}


throw new Error('not supported');
}


splitText (text) {
const parts = [];
const maps = [];


let currentPart = '';
let matchIndex = 0;


for (const letter of text) {


const isOpening = letter === '[';
const isClosing = letter === ']';


if (!isOpening && !isClosing) {
currentPart += letter;
continue;
}


if (isOpening) {
parts.push(currentPart);
currentPart = '';
}


if (isClosing) {
parts.push(`[${matchIndex}]`);
maps.push(currentPart);
currentPart = '';
matchIndex++;
}
}


const partsModified = [];
for (const part of parts) {
const splitted = part
.split(' ')
.filter(f => f.length);


partsModified.push(...splitted);
}


return { parts: partsModified, maps };
}


render () {


const textProps = this.getTheme(this.props.type);
const children = this.props.children;


const getTextStyle = () => {
return {
...textProps,
};
};


const getTextUnderlineStyle = () => {
return {
...textProps,
borderBottomWidth: 1,
borderColor: textProps.color
};
};


const getViewStyle = () => {
return {
flexDirection: 'row',
flexWrap: 'wrap',
};
};


const { parts, maps } = this.splitText(children);


return (
<View style={getViewStyle()}>
{parts.map((part, index) => {


const key = `${part}_${index}`;
const isLast = parts.length === index + 1;


if (part[0] === '[') {
const mapIndex = part.substring(1, part.length - 1);
const val = maps[mapIndex];
const onPressHandler = () => {
this.props.onPress(parseInt(mapIndex, 10));
};
return (
<View key={key} style={getTextUnderlineStyle()}>
<Text style={getTextStyle()} onPress={() => onPressHandler()}>
{val}{isLast ? '' : ' '}
</Text>
</View>
);
}


return (
<Text key={key} style={getTextStyle()}>
{part}{isLast ? '' : ' '}
</Text>
);
})}
</View>
);
}
}

and usage:

  renderPrivacy () {


const openTermsOfService = () => {
Linking.openURL('https://reactnativecode.com');
};


const openPrivacyPolicy = () => {
Linking.openURL('https://reactnativecode.com');
};


const onUrlClick = (index) => {
if (index === 0) {
openTermsOfService();
}


if (index === 1) {
openPrivacyPolicy();
}
};


return (
<SaltText type="robomonoregular10gray" onPress={(index) => onUrlClick(index)}>
By tapping Create an account or Continue, I agree to SALT\'s [Terms of Service] and [Privacy Policy]
</SaltText>
);
}


this is the end result:

example

Try this, simple and clean.

<Text style=\{\{ fontFamily: 'CUSTOM_FONT', ... }}>
<Text>Lorem ipsum</Text>
<Text style=\{\{ color: "red" }}>&nbsp;dolor sit amet.</Text>
</Text>

Result:

Lorem ipsum dolor sit amet.