web-dev-qa-db-fra.com

Simuler l’affichage: inline in React Native

React Native ne prend pas en charge la propriété CSS display et, par défaut, tous les éléments utilisent le comportement de display: flex (non inline-flex non plus). La plupart des mises en page non flexibles peuvent être simulées avec des propriétés flex, mais je suis perturbé par le texte en ligne.

Mon application contient un conteneur contenant plusieurs mots dans le texte, dont certains doivent être formatés. Cela signifie que je dois utiliser des plages pour effectuer le formatage. Afin de réaliser l'emballage des étendues, je peux configurer le conteneur pour utiliser flex-wrap: wrap, mais cela n'autorisera que le wrapping à la fin d'une étendue plutôt que le comportement en ligne traditionnel du wrapping lors des ruptures dans Word.

Le problème visualisé (étend en jaune):

enter image description here

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

Existe-t-il un moyen d'obtenir un habillage correct et une véritable simulation en ligne à l'aide des propriétés flex?

38
Brent Traut

Vous pouvez obtenir cet effet en encapsulant des éléments de texte dans d'autres éléments de texte comme vous le feriez pour encapsuler une étendue dans un div ou un autre élément:

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

Vous pouvez également obtenir cet effet en déclarant une propriété flexDirection: 'row' sur le parent, ainsi qu'un flexWrap: 'wrap'. Les enfants afficheront alors inline:

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

Découvrez this exemple.

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

79
Nader Dabit

Je n'ai pas trouvé de moyen approprié pour insérer des blocs de texte avec d'autres contenus. Notre solution de contournement "hack" actuelle consiste à scinder chaque mot d'une chaîne de texte en son propre bloc afin que flexWrap soit correctement enveloppé pour chaque mot.

4
Kristfal

Vous pouvez uniquement imbriquer des nœuds de texte sans utiliser flex pour obtenir l'effet souhaité. Comme ceci: https://facebook.github.io/react-native/docs/text

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

J'ai eu le cas d'utilisation suivant:

J'avais besoin d'un texte pouvant contenir différentes tailles, et tout au long de ce texte, je voulais souligner certains mots (pour indiquer qu'ils sont cliquables).

C'est assez simple: dans le cas où vous ne pouvez pas contrôler le soulignement de quelque manière que ce soit (quelle est sa proximité, sa couleur, etc.), cela m'a conduit à travers le terrier du lapin et a finalement abouti à la solution du fractionnement. chaque mot, et en le enveloppant dans un composant texte séparé, enveloppé avec View.

Je vais coller le code ici:



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>
    );
  }
}

et utilisation:

  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>
    );
  }

c'est le résultat final:

example

2
Erti-Chris Eelmaa