Code Monkey home page Code Monkey logo

react-native-text-size's Introduction

React Native Text Size

npm Version License

Measure text accurately before laying it out and get font information from your App (Android and iOS).

In my country (México), software developers are poorly paid, so I have had to look for another job to earn a living and I cannot dedicate more time to maintaining this and other repositories that over the years have never generated any money for me. If anyone is interested in maintaining this repository, I'd be happy to transfer it to them, along with the associated npm package.
En mi país (México), los desarrolladores de software somos pésimamente pagados, por lo que he tenido que buscar otro trabajo para ganarme la vida y no puedo dedicar más tiempo a mantener éste y otros repositorios que a través de los años nunca me generaron dinero. Si a alguien le interesa dar mantenimiento a este repositorio, con gusto se lo transferiré, así como el paquete de npm asociado.

There are two main functions: flatHeights to obtain the height of different blocks of text simultaneously, optimized for components such as <FlatList> or <RecyclerListView>.

The other one is measure, which gets detailed information about one block of text:

  • The width used by the text, with an option to calculate the real width of the largest line.
  • The height of the text, with or without paddings.
  • The number of lines.
  • The width of the last line.
  • Extended information of a given line.

The width and height are practically the same as those received from the onLayout event of a <Text> component with the same properties.

In both functions, the text to be measured is required, but the rest of the parameters are optional and work in the same way as with React Native:

  • fontFamily
  • fontSize
  • fontWeight
  • fontStyle
  • fontVariant (iOS)
  • includeFontPadding (Android)
  • textBreakStrategy (Android)
  • letterSpacing
  • allowFontScaling
  • width: Constraint for automatic line-break based on text-break strategy.

In addition, the library includes functions to obtain information about the fonts visible to the App.

If it has helped you, please support my work with a star ⭐️ or ko-fi.

Installation

Mostly automatic installation from npm

yarn add react-native-text-size
react-native link react-native-text-size

Change the compile directive to implementation in the dependencies block of the android/app/build.gradle file.

Requirements:

  • React Native v0.57 or later.
  • Android API 16 or iOS 9.0 and above.

For versions prior to 0.56 of React Native, please use react-native-text-size v2.1.1

See Manual Installation on the Wiki as an alternative if you have problems with automatic installation.

API

measure

measure(options: TSMeasureParams): Promise<TSMeasureResult>

This function measures the text as RN does and its result is consistent* with that of Text's onLayout event. It takes a subset of the properties used by <Text> to describe the font and other options to use.

If you provide width, the measurement will apply automatic wrapping in addition to the explicit line breaks.

* There may be some inconsistencies in iOS, see this Know Issue to know more.

Note:

Although this function is accurate and provides complete information, it can be heavy if the text is a lot, like the one that can be displayed in a FlatList. For these cases, it is better to use flatHeights, which is optimized for batch processing.

TSMeasureParams

Plain JS object with this properties (only text is required):

Property Type Default Notes
text string (none) This is the only required parameter and may include emojis or be empty, but it must not be null.
If this is an empty string the resulting width will be zero.
fontFamily string OS dependent The default is the same applied by React Native: Roboto in Android, San Francisco in iOS.
Note: Device manufacturer or custom ROM can change the default font.
fontWeight string 'normal' On android, numeric ranges has no granularity and '500' to '900' becomes 'bold', but you can use a fontFamily of specific weight ("sans-serif-thin", "sans-serif-medium", etc).
fontSize number 14 The default font size comes from RN.
fontStyle string 'normal' One of "normal" or "italic".
fontVariant array (none) iOS only
allowFontScaling boolean true To respect the user' setting of large fonts (i.e. use SP units).
letterSpacing number (none) Additional spacing between characters (aka tracking).
Note: In iOS a zero cancels automatic kerning.
All iOS, Android with API 21+
includeFontPadding boolean true Include additional top and bottom padding, to avoid clipping certain characters.
Android only
textBreakStrategy string 'highQuality' One of 'simple', 'balanced', or 'highQuality'.
Android only, with API 23+
width number MAX_INT Restrict the width. The resulting height will vary depending on the automatic flow of the text.
usePreciseWidth boolean false If true, the result will include an exact width and the lastLineWidth property.
You can see the effect of this flag in the sample App.
lineInfoForLine number (none) If >=0, the result will include a lineInfo property with information for the required line number.

The sample App shows interactively the effect of these parameters on the screen.

TSMeasureResult

measure returns a Promise that resolves to a JS object with this properties:

Property Type Notes
width number Total used width. It may be less or equal to the width option.
On Android, this value may vary depending on the usePreciseWidth flag.
height number Total height, including top and bottom padding if includingFontPadding was set (the default).
lastLineWidth number Width of the last line, without trailing blanks.
If usePreciseWidth is false (the default), this property is undefined.
lineCount number Number of lines, taking into account hard and automatic line breaks.
lineInfo object Line information.
If the lineInfoForLine option is not given, this property is undefined.

lineInfo

If the value of the lineInfoForLine is greater or equal than lineCount, this info is for the last line (i.e. lineCount - 1).

Property Type Notes
line number Line number of this info, base 0.
It can be less than the requested line number if lineInfoForLine is out of range.
start number Text offset of the beginning of this line.
end number Text offset after the last visible character (so whitespace is not counted) on this line.
bottom number The vertical position of the bottom of this line, including padding.
width number Horizontal extent of this line, including leading margin indent, but excluding trailing whitespace.
Use usePreciseWidth:true to get an accurate value for this property.

In case of error, the promise is rejected with an extended Error object with one of the following error codes, as a literal string:

Code Details
E_MISSING_PARAMETERS measure requires an object with the parameters, which was not provided.
E_MISSING_TEXT The text to measure is null or was not provided.
E_INVALID_FONT_SPEC The font specification is not valid. It is unlikely that this will happen on Android.
E_UNKNOWN_ERROR Well... who knows?

Example

//...
import rnTextSize, { TSFontSpecs } from 'react-native-text-size'

type Props = {}
type State = { width: number, height: number }

// On iOS 9+ will show 'San Francisco' and 'Roboto' on Android
const fontSpecs: TSFontSpecs = {
  fontFamily = undefined,
  fontSize = 24,
  fontStyle = 'italic',
  fontWeight = 'bold',
}
const text = 'I ❤️ rnTextSize'

class Test extends Component<Props, State> {
  state = {
    width: 0,
    height: 0,
  }

  async componentDidMount() {
    const width = Dimensions.get('window').width * 0.8
    const size = await rnTextSize.measure({
      text,             // text to measure, can include symbols
      width,            // max-width of the "virtual" container
      ...fontSpecs,     // RN font specification
    })
    this.setState({
      width: size.width,
      height: size.height
    })
  }

  // The result is reversible
  render() {
    const { width, height } = this.state
    return (
      <View style={{ padding: 12 }}>
        <Text style={{ width, height, ...fontSpecs }}>
          {text}
        </Text>
      </View>
    )
  }
}

flatHeights

flatHeights(options: TSHeightsParams): Promise<number[]>

Calculate the height of each of the strings in an array.

This is an alternative to measure designed for cases in which you have to calculate the height of numerous text blocks with common characteristics (width, font, etc), a typical use case with <FlatList> or <RecyclerListView> components.

The measurement uses the same algorithm as measure but it returns only the height of each block and, by avoiding multiple steps through the bridge, it is faster... much faster on Android!

I did tests on 5,000 random text blocks and these were the results (ms):

  measure flatHeights
Android 49,624 1,091
iOS 1,949 732

In the future I will prepare an example of its use with FlatList and multiple styles on the same card.

TSHeightsParams

This is an object similar to the one you pass to measure, but the text option is an array of strings and the usePreciseWidth and lineInfoForLine options are ignored.

Property Type Default
text string[] (none)
width number Infinity
fontFamily string OS dependent
fontWeight string 'normal'
fontSize number 14
fontStyle string 'normal'
fontVariant array (none)
allowFontScaling boolean true
letterSpacing number (none)
includeFontPadding boolean true
textBreakStrategy string 'highQuality'

The result is a Promise that resolves to an array with the height of each block (in SP), in the same order in which the blocks were received.

Unlike measure, null elements returns 0 without generating error, and empty strings returns the same height that RN assigns to empty <Text> components (the difference of the result between null and empty is intentional).

Example

//...
import rnTextSize, { TSFontSpecs } from 'react-native-text-size'

type Props = { texts: string[] }
type State = { heights: number[] }

// On iOS 9+ will show 'San Francisco' and 'Roboto' on Android
const fontSpecs: TSFontSpecs = {
  fontFamily = undefined,
  fontSize = 24,
  fontStyle = 'italic',
  fontWeight = 'bold',
}
const texts = ['I ❤️ rnTextSize', 'I ❤️ rnTextSize using flatHeights', 'Thx for flatHeights']

class Test extends Component<Props, State> {
  state = {
    heights: [],
  }

  async componentDidMount() {
    const { texts } = this.props
    const width = Dimensions.get('window').width * 0.8
    const heights = await rnTextSize.flatHeights({
      text: texts,      // array of texts to measure, can include symbols
      width,            // max-width of the "virtual" container
      ...fontSpecs,     // RN font specification
    })
    this.setState({
      heights
    })
  }

  render() {
    const { texts } = this.props
    const { heights } = this.state
    
    return (
      <View style={{ padding: 12 }}>
        {texts.map(
          (text, index) => (
            <Text style={{ height: heights[index], ...fontSpecs }}>
              {text}
            </Text>
          )
        )}
      </View>
    )
  }
}

specsForTextStyles

specsForTextStyles(): Promise<{ [key: string]: TSFontForStyle }>

Get system font information for the running OS.

This is a wrapper for the iOS UIFont.preferredFontForTextStyle method and the current Android Material Design Type Scale styles.

The result is a Promise that resolves to a JS object whose keys depend on the OS, but its values are in turn objects fully compatible with those used in the RN styles, so it can be used to stylize <Text> or <TextInput> components:

TSFontForStyle

Property Type Notes
fontFamily string System family name or font face.
fontSize number Font size in SP (unscaled).
fontStyle TSFontStyle Only if 'italic', undefined if the style is 'normal'.
fontWeight TSFontWeight Only if 'bold', undefined if the weight is 'normal'.
fontVariant TSFontVariant[] or null iOS only. Currently, no style includes this property.
letterSpacing number Omitted if running on Android with RN lower than 0.55

To know the key names, please see Keys from specsForTextStyles in the Wiki.

I have not tried to normalize the keys of the result because, with the exception of two or three, they have a different interpretation in each OS, but you can use them to create custom styles according to your needs.

fontFromSpecs

fontFromSpecs(specs: TSFontSpecs): Promise<TSFontInfo>

Returns the characteristics of the font obtained from the given specifications.

TSFontSpecs

This parameter is a subset of TSMeasureParams, so the details are omitted here.

Property Type Default
fontFamily string iOS: 'San Francisco', Android: 'Roboto'
fontWeight string 'normal'
fontSize number 14
fontStyle string 'normal'
fontVariant string[] (none)
letterSpacing number 0

fontFromSpecs uses an implicit allowsFontScaling:true and, since this is not a measuring function, includeFontPadding has no meaning.

TSFontInfo

The result is a Promise that resolves to a JS object with info for the given font and size, units in SP in Android or points in iOS, using floating point numbers where applicable*.

Property Type Details
fontFamily string In Android it is the same string passed as parameter.
fontName string iOS only, always undefined in Android.
fontSize number It may be different from the given parameter if the parameter includes decimals.
fontStyle string 'normal' or 'italic'.
fontWeight string 'normal' or 'bold', on iOS it can go from '100' to '900'.
fontVariant string[] iOS only, always undefined in Android.
ascender number The recommended distance above the baseline for singled spaced text.
descender number The recommended distance below the baseline for singled spaced text.
capHeight number iOS only Height of capital characters.
xHeight number iOS only Height of lowercase "x".
top number Android only. Maximum distance above the baseline for the tallest glyph in the font.
bottom number Android only. Maximum distance below the baseline for the lowest glyph in the font.
leading number The recommended additional space to add between lines of text.
lineHeight number The recommended line height. It should be greater if text contain Unicode symbols, such as emojis.
_hash number Hash code, may be useful for debugging.

* Using floats is more accurate than integers and allows you to use your preferred rounding method, but consider no more than 5 digits of precision in this values. Also, remember RN doesn't work with subpixels in Android and will truncate this values.

See more in:

Understanding typography at the Google Material Design site.

About Text Handling in iOS for iOS.

fontFamilyNames

fontFamilyNames(): Promise<string[]>

Returns a Promise for an array of font family names available on the system.

On iOS, this uses the UIFont.familyNames method of the UIKit.

On Android, the result is hard-coded for the system fonts and complemented dynamically with the fonts installed by your app, if any.

See About Android Fonts and Custom Fonts in the Wiki to know more about this list.

fontNamesForFamilyName

fontNamesForFamilyName(fontFamily: string): Promise<string[]>

Wrapper for the UIFont.fontNamesForFamilyName method of UIKit, returns an array of font names available in a particular font family.

You can use the rnTextSize's fontFamilyNames function to get an array of the available font family names on the system.

This is an iOS only function, on Android it always resolves to null.

Known Issues

Inconsistent width between platforms

In iOS, the resulting width of both, measure and flatHeights, includes leading whitespace while in Android these are discarded.

Incorrent height (iOS)

On iOS, RN takes into account the absolute position on the screen to calculate the dimensions. rnTextSize can't do that and both, width and height, can have a difference of up to 1 pixel (not point).

letterSpacing not scaling (iOS)

RN does not support the Dynamic Type Sizes, but does an excellent job imitating this feature through allowFontScaling ...except for letterSpacing that is not scaled.

I hope that a future version of RN solves this issue.

lineHeight Support

Although rnTextSize provides the resulting lineHeight in some functions, it does not support it as a parameter because RN uses a non-standard algorithm to set it. I recommend you do not use lineHeight unless it is strictly necessary, but if you use it, try to make it 30% or more than the font size, or use rnTextSize fontFromSpecs method if you want more precision.

Nested Text

Nested <Text> components (or with images inside) can be rasterized with dimensions different from those calculated, rnTextSize does not accept multiple sizes.

TODO

  • Normalized tracking or letter spacing in font info.
  • More testing, including Android and iOS TVs.
  • Learn the beautiful English, to make better docs.
  • Find something nice in the ugly Objective-C.

Support my Work

I'm a full-stack developer with more than 20 year of experience and I try to share most of my work for free and help others, but this takes a significant amount of time and effort so, if you like my work, please consider...

Of course, feedback, PRs, and stars are also welcome 🙃

Thanks for your support!

License

The BSD 2-Clause "Simplified" License.

© 2018-2019, Alberto Martínez. All rights reserved.

react-native-text-size's People

Contributors

abegehr avatar amarcruz avatar donni106 avatar jyrno42 avatar tuncaulubilge avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-native-text-size's Issues

Line end feature parity on iOS

Android has a lineEndForLineNo that measures how many characters would fit into a given number of lines, but this is not yet supported in iOS.

The issue was discussed in this pr:
#11

fontWeight support?

Great module, looking forward to the iOS support.

Currently the module looks like it support measuring the fontFamily and fontSize only. The fontWeight could also effect the measured width, it would be great to add support for it.

flatHeights is incorrect for unicode text

As below example, flatHeights and measure provide different measurement.

import TextSize from 'react-native-text-size';

const demoText = await TextSize.flatHeights({
  text: ['မြန်မာစာ'],
});

const demoSingle = await TextSize.measure({
  text: 'မြန်မာစာ',
});

// output: demoText: [17]
console.log(`demoText: ${JSON.stringify(demoText)}`);

// output: demoSingle: {"width":52.5,"lineCount":1,"height":31}
console.log(`demoSingle: ${JSON.stringify(demoSingle)}`);

The result should be 31 while flatHeights produce 17.

Chinese text is not incorrect

When I test both chinese text and english text for Multi font. the english text height is correct. but the chinese text height is incorrect.

Autolinking does not work with React Native 0.69.0

Issue

Due to change in react-native cli, react-native-community/cli#1537
Autolinking is no longer working with React Native 0.69

Expected Behavior

React Native autolinking to work with react-native-text-size

Repro Steps:

  • Create a new React Native Project version 0.69
  • install react-native-text-size
  • run pod install in ios directory

Notice that react-native-text-size is not included in the Podfile.lock

Repro repository
https://github.com/Naturalclar/react-native-notifications-repro

Not accurate with uppercase

When applying a textTransform uppercase to the Text style, the measures (width & lastLineWidth) are not accurate.

Can we implement auto-linking please? Here are the instructions:

It should be as easy as this:
Add a new file called react-native.config.js

in that file, add:

module.exports = {
  dependency: {
    platforms: {
      android: {
        packageImportPath:
          "import com.github.amarcruz.rntextsize.RNTextSizePackage;",
        packageInstance: "new RNTextSizePackage()",
      },
      ios: {
        podspecPath: "ios/RNTextSize.podspec",
      },
    },
  },
};

And I'm pretty sure that's it. I can create a PR if you give me access! Thanks!

Why isn't Line Height supported yet?

This library looks very promising to me, it has a lot of options and seems to be even quite fast!
However, I wonder why line-height is not supported yet as an option for the flatHeights function? 🤔
We use the line-height style prop every now and then and it's a common typography setting as well.

Error in measure: Missing required text

Hi,

I'm getting following error when try this library to calculate height of text in iOS:

'Error in measure:', { [Error: Missing required text.] framesToPop: 1, code: 'E_MISSING_TEXT', domain: 'RCTErrorDomain', userInfo: null}

My code snippet: for JS - HeightMeasurementFromText.js

import React, { Component } from 'react'; import { Platform } from 'react-native';

import RNTextSize, { TSFontSpecs } from 'react-native-text-size';

const fontSpecs: TSFontSpecs = { fontFamily: (Platform.OS === 'ios' ? 'Proxima Nova' : 'Proxima Nova Bold'), fontWeight: (Platform.OS === 'ios' ? 'bold' : null), fontSize: 18, }

export const nameTextHeight = async (nameText) => { const dimension = { width: 0, height: 0, };
await RNTextSize.measure({ nameText, width: 170, ...fontSpecs, }).then(result => { console.log('result - ' + JSON.stringify(result)); dimension.width = result.width; dimension.height = result.height; }).catch((err) => { console.log('Error in measure:', err); });
return dimension; };

I'm calling this in my some other JS file as:

import { nameTextHeight } from './library/helper/HeightMeasurementFromText';

let nameTextHgt = nameTextHeight(item.name.toUpperCase());

My Environment variables are:

"react": "16.8.3",
"react-native": "^0.59.9",
"react-native-text-size": "^4.0.0-rc.1",

What's the problem in my code and implementation of your library?

Kindly suggest. Please.

Thanks in advance.

RNTS produces different estimates for iOS than Android

We're attempting to use RNTS to estimate chat message text heights. We seem to have gotten estimates quite close on Android but on iOS they are over a screen height apart (see attachment). We're really not sure where we're going wrong or if there is a bug in estimating the height for ios.

Fontsize is pretty evenly set at 16. We are using recyclerlistview and not flatlist (which I know you've designed text height to work well with). Recyclerlistview is more performant than flatlist and ideally suited to couple with RNTS.

Here is the relevant code from our screen:

	constructor(props) {
		super(props);

		this.state = {
//get height and width for images in chat
			imageWidth: screen.width / 0.75,
			imageHeight: screen.height / 0.75,

			dataProvider: new DataProvider((message1, message2) => {
				return message1._id !== message2._id
			}).cloneWithRows(this.props.MainStore.messages),
			layoutProvider: new LayoutProvider(
				(index) => {
					return 'LIST';
				},
				async (type, dim, index) => {
					switch (type) {
						case 'LIST':
							dim.width = screen.width;
							dim.height = screen.height / 0.75;
							break;
						default:
							dim.width = 0;
							dim.heigh = 0;
					}
				}
			),
		};

	}

//FlatHeights code estimating starts here
	async initFlatHeights() {
		const flatHeights = await this.getFlatHeights();
		//console.debug("ChatRoomScreen flatHeights has been initialized");

		this.setState({
			layoutProvider: new LayoutProvider(
				(index) => {
					return 'LIST';
				},
				(type, dim, index) => {
					switch (type) {
						case 'LIST':
							dim.width = screen.width;
							dim.height = flatHeights[index];
							break;
						default:
							dim.width = 0;
							dim.heigh = 0;
					}
				}
			),
		});
	}

	async getFlatHeights() {
		const flatHeights = [];

		const imgHeight = screen.width - 133;
		const fontSpecs = {
			fontFamily: (Platform.OS === 'ios') ? 'System' : 'Roboto',
			fontSize: 16,
		}
		const margingBtm = 12;
		const spaceBetweenMessages = 18;

		//console.debug("chat messages count = " + this.props.MainStore.messages.length);

		for (let i = 0; i < this.props.MainStore.messages.length; i++) {
			const text = this.props.MainStore.messages[i].text;
			const imgCount = (this.props.MainStore.messages[i].images != null) ? this.props.MainStore.messages[i].images.length : 0;
			const width = imgHeight;
			//const lineHeight = 22;

			//console.debug("LayoutProvider: imgCount=" + imgCount + ", text=" + text);
			const size = await rnTextSize.measure({
				text,             // text to measure, can include symbols
				width,            // max-width of the "virtual" container
				lineHeight, 	  // It should be greater if text contain Unicode symbols, such as emojis.
				...fontSpecs,     // RN font specification
			})
			const messageOwnerName = 30;
			flatHeights[i] = 0;

			if (this.props.MainStore.messages[i].userId != this.props.MainStore.userId) {
				if (i != 0 &&
					i < this.props.MainStore.messages.length - 1 &&
					this.props.MainStore.messages[i].userId === this.props.MainStore.messages[i - 1].userId &&
					this.props.MainStore.messages[i].userId === this.props.MainStore.messages[i + 1].userId) {
					//middle
					//console.debug("middle" + i + ": " + this.props.MainStore.messages[i].text);
				} else {
					if (i != 0 && this.props.MainStore.messages[i].userId === this.props.MainStore.messages[i - 1].userId) {
						//first message
						flatHeights[i] += messageOwnerName;
						//console.debug("first" + i + ": " + this.props.MainStore.messages[i].text);
					} else {
						if (i < this.props.MainStore.messages.length - 1 && this.props.MainStore.messages[i].userId === this.props.MainStore.messages[i + 1].userId) {
							// last message
							//console.debug("last" + i + ": " + this.props.MainStore.messages[i].text);
						} else {
							// only a single message
							flatHeights[i] += messageOwnerName;
							//console.debug("single" + i + ": " + this.props.MainStore.messages[i].text);
						}
					}
				}
			}

			if (this.props.MainStore.messages[i].images.length > 0) {
				if (this.props.MainStore.messages[i].text != "") {
					flatHeights[i] += (imgHeight * imgCount) + size.height + margingBtm + spaceBetweenMessages;
				} else {
					flatHeights[i] += (imgHeight * imgCount) + spaceBetweenMessages;
				}
				//console.debug("getFlatHeights: flatHeights[" + i + "]=" + flatHeights[i] + ", text=" + text + ", this.props.MainStore.messages[i].images.length: " + this.props.MainStore.messages[i].images.length);
			} else {
				flatHeights[i] += size.height + margingBtm + spaceBetweenMessages;
				//console.debug("getFlatHeights: flatHeights[" + i + "]=" + flatHeights[i] + ", text=" + text + ", text.size.height: " + size.height);
			}
		}

		return flatHeights;
	}

	async componentDidMount() {
		await this.props.MainStore.joinRoom(this.props.roomId);
		this.setState({
			dataProvider: this.state.dataProvider.cloneWithRows(
				this.props.MainStore.messages
			),
		});

		this.initFlatHeights();
	}

	async _onEndReached() {
		console.log('loading more messages');
		if (!this.refreshing && !this.props.MainStore.endOfMessagesReached) {
			this.refreshing = true;
			await this.props.MainStore.getMessages(this.offset)
				.catch(error => console.log(error.message));

			this.refreshing = false;
			this.offset += 25;
			this.setState({
				dataProvider: this.state.dataProvider.cloneWithRows(
					this.props.MainStore.messages
				),
			});

			await this.initFlatHeights();
		}
	}

	rowRenderer = (type, message, index) => {
		return (
			<Animatable.View duration={250} useNativeDriver={true} animation="fadeIn">
				{index != 0 &&
					index < this.props.MainStore.messages.length - 1 &&
					message.userId === this.props.MainStore.messages[index - 1].userId &&
					message.userId === this.props.MainStore.messages[index + 1].userId ? (
						<ChatMessage message={message} position={"middle"} onImagePress={this._onPressImage(message)} onProfilePress={this._onPressProfile(message)} />
					) : (index != 0 &&
						message.userId === this.props.MainStore.messages[index - 1].userId) ? (
							<ChatMessage message={message} position={"first"} onImagePress={this._onPressImage(message)} onProfilePress={this._onPressProfile(message)} />
						) : (index < this.props.MainStore.messages.length - 1 &&
							message.userId === this.props.MainStore.messages[index + 1].userId) ? (
								<ChatMessage message={message} position={"last"} onImagePress={this._onPressImage(message)} onProfilePress={this._onPressProfile(message)} />
							) : (
								<ChatMessage message={message} position={"only"} onImagePress={this._onPressImage(message)} onProfilePress={this._onPressProfile(message)} />
							)}
			</Animatable.View>
		)
	}

	render() {
		return (
			<View
				style={styles.container}
			>
				{this.props.MainStore.users.length > 0
					? <RecyclerListView
						contentContainerStyle={{ marginTop: 5 }}
						onEndReached={this._onEndReached.bind(this)}
						dataProvider={this.state.dataProvider}
						layoutProvider={this.state.layoutProvider}
						rowRenderer={this.rowRenderer}
						renderFooter={this.renderFooter}
						onEndReachedThreshold={screen.height}
					/>
				: null}
			</View>
		);
	}

simulator screen shot - iphone xs - 2018-09-18 at 20 01 33

React Native Text Size version: 2.0.4
React Native version: 0.55.4
Recycler ListView version: 1.3.4
Platform(s) (iOS, Android, or both?): iOS 11.4-12
Device info (Simulator/Device? OS version? Debug/Release?): iPhones 5, 6 and 8, simulators for X/XR/XS

lineInfoForLine of TSMeasureParams has some problem

Dear author, you said "If the value of the lineInfoForLine is greater or equal than lineCount, this info is for the last line (i.e. lineCount - 1).", but I found that to be incorrect.

When the value of the lineInfoForLine is greater or equal than lineCount, I can't get the last line info.

Can you confirm that,thank you very much!

'compile' is obsolete, warning in Android studio

I'm using implementation as suggested in my own build file, however react-native-text-size is still using compile internally resulting in warnings when building.

.../node_modules/react-native-text-size/android/build.gradle:
Warning:Configuration 'compile' is obsolete and has been replaced with 'implementation' and 'api'.
It will be removed at the end of 2018. For more information see: http://d.android.com/r/tools/update-dependency-configurations.html

Is there anyway to make it work with TextInput?

Seems like the TextInput width is greater than the same text in Text. If I apply the calculated width to the Text, it displays it without a problem, but if I set the width to TextInput, it will get clipped.

Is there a good way to calculate TextInput width?

Why don't you use UITextView for flatHeights?

I fix flatHeights method (Your method is not correct to say the height of the text (unfortunately)):

RCT_EXPORT_METHOD(flatHeights:(NSDictionary * _Nullable)options
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)
{
  // Don't use NSStringArray, we are handling nulls
  NSArray *const _Nullable texts = [RCTConvert NSArray:options[@"text"]];
  if (isNull(texts)) {
    reject(E_MISSING_TEXT, @"Missing required text, must be an array.", nil);
    return;
  }

  UIFont *const _Nullable font = [self scaledUIFontFromUserSpecs:options];
  if (!font) {
    reject(E_INVALID_FONT_SPEC, @"Invalid font specification.", nil);
    return;
  }

  const CGFloat optWidth = CGFloatValueFrom(options[@"width"]);
  const CGFloat maxWidth = isnan(optWidth) || isinf(optWidth) ? CGFLOAT_MAX : optWidth;
  const CGSize maxSize = CGSizeMake(maxWidth, CGFLOAT_MAX);

  // Create attributes for the font and the optional letter spacing.
  const CGFloat letterSpacing = CGFloatValueFrom(options[@"letterSpacing"]);
  NSDictionary<NSAttributedStringKey,id> *const attributes = isnan(letterSpacing)
  ? @{NSFontAttributeName: font}
  : @{NSFontAttributeName: font, NSKernAttributeName: @(letterSpacing)};

  NSMutableArray<NSNumber *> *result = [[NSMutableArray alloc] initWithCapacity:texts.count];
  const CGFloat epsilon = 0.001;
    
  UITextView *view = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, maxWidth, 0)];
  view.textContainerInset = UIEdgeInsetsZero;
  view.typingAttributes = attributes;
  view.textContainer.lineFragmentPadding = 0.0;
  view.textContainer.lineBreakMode = NSLineBreakByClipping;

  for (int ix = 0; ix < texts.count; ix++) {
    NSString *text = texts[ix];

    // If this element is `null` or another type, return zero
    if (![text isKindOfClass:[NSString class]]) {
      result[ix] = @0;
      continue;
    }

    // If empty, return the minimum height of <Text> components
    if (!text.length) {
      result[ix] = @14;
      continue;
    }
    view.text = text;
    CGSize size = [view sizeThatFits: maxSize];
      
    const CGFloat height = MIN(RCTCeilPixelValue(size.height + epsilon), maxSize.height);
    result[ix] = @(height);
  }
  resolve(result);
}

Method to detect bold text within normal text string

We have a number of instances where we have bold text within a normal text string. Is there any method currently available to RNTS that can detect bolded text as such and measure it? If not, maybe we could add a simple regex for bold text.

For example, currently, we use a library known as React Native Auto-link which permits the styling of hash-tagged terms as such:

         <AutolinkComponent 
              style={styles.text}
              text={this.props.postText}
              hashtag="instagram"
              mention="twitter"
              linkStyle={{ fontWeight:'bold' }}
         />

Source files not included with autolinking on iOS

I just upgraded to react-native 0.60.0 and the react-native-text-size import became null in builds.

Checking the Xcode project, react-native did recognize the pod but didn't include the source files with it.

I don't know how it worked before but the source_files directive seems to be wrong:

s.source_files = 'RNTextSize/**/*.{h,m}'

After changing it to only *.{h,m} and re-running pod install, the source files were included in Xcode and the import works again.

Not working on iOS

Hi I'm trying to have this working on iOS, but at this point it is not even mounting as a NativeModule. I checked the code and it seems straightforward what it tries to achieve. You have a warning saying support for iOS is incomplete, do you have in mind already what needs be done to having it complete for iOS? I could help

Build error on react-native 0.69.5

When "./gradlew assembleRelease" I get this error:

> Task :react-native-text-size:compileReleaseJavaWithJavac
Note: C:\Users\MyUser\Documents\Git\my-app\node_modules\react-native-text-size\android\src\main\java\com\github\amarcruz\rntextsize\RNTextSizeModule.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.

Using it on React Native Web

I want to use this module on react-native-web, but the following code

const { width: partialTextWidth } = await reactNativeTextSize.measure({ text: text.slice(0, middle), fontSize: scaledFontSize, fontFamily, fontWeight, });

gives me this error: TypeError: Cannot read property 'measure' of undefined

import reactNativeTextSize from 'react-native-text-size';

When I console reactNativeTextSize, it shows undefined. I don't know what is causing the issue. Does anyone know how I can make this module work on react-native-web?

CUSTOM FONT SUPPORT - ANDROID

I'm using a custom font. It returns the text width for ios correctly. but in Android it always measures over the correct amount of width. anyway to incorporate custom fonts?

Cannot read property 'measure' of undefined

here is my code:

import rnTextSize, { TSFontSpecs } from 'react-native-text-size'
.
.
.
function renderedTextSize(text: string, size: number = 14, fontFamily: string = 'moein') {

  const dimension = {
    width: 0,
    height: 0,
  };
  const fontSpecs: TSFontSpecs = {
    fontFamily: fontFamily,
    fontSize: size,
  };

  rnTextSize.measure({
    text,             // text to measure, can include symbols
    ...fontSpecs,     // RN font specification
  }).then(result=> {
    dimension.width = result.width;
    dimension.height = result.height;
  });

  return dimension;
}

when I try to call the function, I get this error message, Cannot read property 'measure' of undefined.
why should rnTextSize be undefined when I import it from library?

Using `measure` function synchronous

Is there a way to use measure function synchronous?

I have a function that I can not use async keyword in its signature and also using this.setState function is not feasible too, because this function is a utility among many other components and classes.

this below code return Promise that is not what I want. I want only the inner result object contains width and height.

export function renderedTextSize(text: string, size: number = 14, fontFamily: string = 'someFontName') {

  const fontSpecs: TSFontSpecs = {
    fontFamily: fontFamily,
    fontSize: size,
  };

  return TextSize.measure({
    text,
    ...fontSpecs,
  }).then((result: TSMeasureResult) => {
    return {width: result.width, height: result.height};
  }).catch((err) => {
    console.log('Error in measure:', err);
  });
}

Trouble linking project on iOS

So i spent hours trying to figure out why do i get 'React/RCTBridgeModule.h' file not found when trying to build my project after linking react-native-text-size, i tried both manual install and using link. For some reason react-native-text-size can't find required header files, even though Search Header paths seem to point at the right direction $(SRCROOT)/../../react-native/React recursive. Also, Some people suggested unchecking Parallelize Build but i already have that disabled.

react-native Version: 0.59.8
react-native-text-size Version: 3.0.0

Any idea how can resolve this?

Get lineInfo for all lines

Would it be possible to have an option to get lineInfo for every line, instead of having to specify a line number? I'm trying to calculate the optimal font size for laying out headlines, and I'd like to be able to choose a size that has a low variance in line widths. I could imagine, for example, that setting a value of -1 for lineInfoForLine would then return an array of lineInfo objects.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.