React Native: определение количества строк текстового компонента

Как говорится в заголовке, я пытался найти способ определить количество строк текстового компонента ПОСЛЕ того, как ему был предоставлен текст. Посмотрите на мой пример ниже.

<Text>
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi semper ut ipsum in ultrices. Vivamus fringilla lacinia odio in accumsan. Proin sit amet pellentesque tortor. Nam mollis sit amet ligula id convallis. Etiam in semper diam. Cras id elit consectetur, interdum ante id, tincidunt nisi. Integer non elit placerat, dignissim nibh at, faucibus sem. Curabitur nec posuere turpis. Vivamus rhoncus nulla vitae mi imperdiet, elementum eleifend mi laoreet. Vestibulum molestie turpis non nibh elementum, sed ornare magna tristique. Aliquam erat volutpat. Phasellus volutpat mi vel tempor finibus.
</Text>

Во время выполнения, как определить количество строк, которые этот компонент Text визуализировал. Это число будет варьироваться в зависимости от устройства (например, iPhone 5 нужно будет отображать больше строк против iPhone 6+, так как он имеет меньший размер экрана). Я проверил исходный код для компонента Text, но, похоже, ничего не ищу.

Я использую React Native 0.24.

Любые идеи?

Приветствия.

Ответ 1

Похоже, что React Native 0.24 реализует функцию onLayout
http://facebook.github.io/react-native/docs/text.html#onlayout

onLayout function
Вызывается при изменении монтирования и макета с помощью {nativeEvent: {layout: {x, y, width, height}}}

Итак, похоже, что вы можете передать функцию обратного вызова onLayout, получить высоту компонента Text и затем выполнить некоторые вычисления с использованием высоты строки, чтобы получить число строк

Ответ 2

Вы можете использовать эту формулу:

CPL = Ширина /(font-size/font-constant)

font-constant = константа, указанная для каждого шрифта. CPL = количество символов в строке

Здесь некоторые шрифты с их константой:

 - Serif Fonts:
 American Typewriter — 2.14
 Baskerville — 2.14
 Georgia — 1.91
 Times New Roman — 2.21

 - Sans-serif Fonts:
 Arial — 1.91
 Calibri — 2.1
 Helvetica Neue — 1.9
 Lucida Grande — 1.91
 Tahoma — 1.91
 Trebuchet MS — 2.11
 Verdana — 1.73

 - Monospace Font:
 Courier New — 1.64

например:

function getNumberOfLines(text, fontSize, fontConstant, containerWidth){

    let cpl = Math.floor(containerWidth / (fontSize / fontConstant) );
    const words = text.split(' ');
    const elements = [];
    let line = '';

    while(words.length > 0){
        if(line.length + words[0].length + 1 <= cpl || line.length === 0 && words[0].length + 1 >= cpl){
            let word = words.splice(0,1);
            if(line.length === 0){
                line = word;
            }else {
                line = line + " " + word;
            }
            if(words.length === 0){
                elements.push(line);
            }
        }
        else {
            elements.push(line);
            line = "";
        }
    }
    return elements.length;
}

Ответ 3

Решение, предложенное Гарретом Маккалоу, похоже, работает для меня, и я просто хочу добавить пример кода:

import React from 'react';
import { StyleSheet, Text, View, TouchableHighlight } from 'react-native';

const styles = StyleSheet.create({
    text: {
      fontSize: 24,
      lineHeight: 30,
    }
});

export default class App extends React.Component {

    onLayout = e => {
        const { height } = e.nativeEvent.layout;
        this.count = Math.floor(height / styles.text.lineHeight)
    }

    render() {
        return (
            <View style={styles.page}>
              <Text onLayout={this.onLayout} style={styles.text}>
                Random text. Random text. Random text. Random text. Random text. Random text. Random text.
                Random text. Random text. Random text. Random text. Random text. Random text. Random text.
                Random text. Random text. Random text. Random text. Random text. Random text. Random text.
                Random text. Random text. Random text. Random text. Random text. Random text.
              </Text>

              <TouchableHighlight onPress={() => alert('text lines count is ${this.count}')}>
                <Text style={{ fontSize: 50 }}>touch me!</Text>
              </TouchableHighlight>
            </View>
        );
    }
}

https://snack.expo.io/@devastr1/text-lines-count-example