我有以下用例:
我需要一个可以用不同大小换行的文本,并且在整个文本中,我想对一些单词加下划线(以表明它们是可点击的)。
对于您无法以任何方式控制下划线(它有多近,它是什么颜色等)的情况,这是非常简单的期望 - 这使我通过了兔子洞,并最终想出了拆分的解决方案每个单词,并将其包装在单独的 Text 组件中,用 View 包装。
我将在这里粘贴代码:
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>
    );
  }
}
和用法:
  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>
    );
  }
这是最终结果:
