web-dev-qa-db-ja.com

表示のシミュレーション:インラインin React Native

React NativeはCSS displayプロパティをサポートしておらず、デフォルトですべての要素がdisplay: flexの動作を使用します(inline-flexもなし)。ほとんどの非フレックスレイアウトは、フレックスプロパティを使用してシミュレートできますが、インラインテキストに悩まされています。

私のアプリには、テキストにいくつかの単語が含まれているコンテナがあり、その中には書式設定が必要なものもあります。つまり、書式設定を行うにはスパンを使用する必要があります。スパンの折り返しを実現するために、flex-wrap: wrapを使用するようにコンテナを設定できますが、これはWordブレークでの折り返しの従来のインライン動作ではなく、スパンの最後でのみ折り返しを許可します。

視覚化された問題(黄色のスパン):

enter image description here

(経由で http://codepen.io/anon/pen/GoWmdm?editors=11

Flexプロパティを使用して適切なラッピングと真のインラインシミュレーションを取得する方法はありますか?

38
Brent Traut

この効果を得るには、divまたは別の要素でスパンをラップする方法で、テキスト要素を他のテキスト要素にラップします。

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

この効果は、親のflexDirection: 'row'プロパティとflexWrap: 'wrap'を宣言することでも取得できます。子はインラインで表示されます:

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

this の例をご覧ください。

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

79
Nader Dabit

テキストブロックを他のコンテンツとインライン化する適切な方法が見つかりませんでした。現在の「ハッキング」の回避策は、テキスト文字列内のすべてのWordを独自のブロックに分割して、flexWrapが各Wordに対して適切にラップするようにすることです。

4
Kristfal

目的の効果を得るためにflexを使用せずにテキストノードのみをネストできます。このように: 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

次のユースケースがありました。

さまざまなサイズで折り返すことができるテキストが必要でしたが、そのテキスト全体で(クリック可能であることを示すために)いくつかの単語に下線を引きたいと思いました。

下線を何らかの方法で制御できない場合(それがどれだけ近いか、どの色かなど)の場合は非常に単純です-これにより、ウサギの穴を通り抜け、最終的に分割の解決策を思い付きましたすべてのWordを個別のテキストコンポーネントでラップし、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>
    );
  }

これが最終結果です。

example

2