Skip to content

Commit b1d46a5

Browse files
committed
Closes #5 and give flatHeights better performance
1 parent 7f532e4 commit b1d46a5

File tree

7 files changed

+61
-38
lines changed

7 files changed

+61
-38
lines changed

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22

33
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
44

5-
## [Unreleased]
5+
## [2.0.2] - 2018-08-31
6+
### Changed
7+
- iOS: Give `flatHeights` better performace by avoiding multiple creation of NSTextStorage.
68

79
### Fixed
10+
- Closes #5: Inconsistency in flatHeights between Android and iOS.
811
- Some error in the README and include note about unlink the previous version.
912

1013
## [2.0.1] - 2018-08-22

README.md

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,14 @@ Both, width and height, are practically the same as those received from the `onL
3131

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

34-
rnTextSize is WIP, but if it has helped you, please support my work with a star :star2: or [buy me a coffee](https://www.buymeacoffee.com/aMarCruz).
34+
rnTextSize is WIP, but if it has helped you, please support my work with a star :star2: or [buy me a coffee][bmc-url].
3535

3636
---
3737
**IMPORTANT:**
3838

3939
**rnTextSize (react-native-text-size) v2.0 is a complete refactoring, before using it, please unlink the previous version.**
4040

41-
**If `react-native unlink` fails, please reverse the changes described in [Manual Installation](https://github.com/aMarCruz/react-native-text-size/wiki/Manual-Installation).**
41+
**If `react-native unlink` fails, please reverse the changes described in [Manual Installation][2].**
4242

4343
---
4444

@@ -47,7 +47,7 @@ rnTextSize is WIP, but if it has helped you, please support my work with a star
4747
- React Native v0.52.0 or later
4848
- Targets Android API 16 and iOS 9.0
4949

50-
The [sample App](https://github.com/aMarCruz/rn-text-size-sample-app) uses RN v0.52.0, the minimum supported version but, to take advantage of features such as `letterSpacing` and better support for the most modern devices, use RN v0.55 or above.
50+
The [sample App][1] uses RN v0.52.0, the minimum supported version but, to take advantage of features such as `letterSpacing` and better support for the most modern devices, use RN v0.55 or above.
5151

5252
## Installation
5353

@@ -58,7 +58,7 @@ $ react-native link react-native-text-size
5858

5959
If you are using Gradle 4 or later, don't forget to change the `compile` directive to `implementation` in the dependencies block of the android/app/build.gradle file.
6060

61-
See [Manual Installation](https://github.com/aMarCruz/react-native-text-size/wiki/Manual-Installation) on the Wiki as an alternative if you have problems with automatic installation.
61+
See [Manual Installation][2] on the Wiki as an alternative if you have problems with automatic installation.
6262

6363
## API
6464

@@ -80,7 +80,7 @@ See [Manual Installation](https://github.com/aMarCruz/react-native-text-size/wik
8080
measure(options: TSMeasureParams): Promise<TSMeasureResult>
8181
```
8282

83-
This function measures the text as RN does and its result is consistent\* with that of `Text`'s onLayout event. It take a subset of the properties used by [`<Text>`](https://facebook.github.io/react-native/docs/text#props) to describe the font and other options to use.
83+
This function measures the text as RN does and its result is consistent\* with that of `Text`'s onLayout event. It take a subset of the properties used by [`<Text>`][3] to describe the font and other options to use.
8484

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

@@ -98,7 +98,7 @@ Property | Type | Default | Notes
9898
---------- | ------ | -------- | ------
9999
text | string | (none) | This is the only required parameter and may include _emojis_ or be empty, but it can not be `null`. If this is an empty string the resulting `width` will be zero.
100100
width | number | Infinity | Restrict the width. The resulting height will vary depending on the automatic flow of the text.
101-
usePreciseWidth | boolean | false | If `true`, request an exact `width` and the value of `lastLineWidth` (iOS always returns the exact width).<br>You can see the effect of this flag in the [sample App](https://github.com/aMarCruz/rn-text-size-sample-app).
101+
usePreciseWidth | boolean | false | If `true`, request an exact `width` and the value of `lastLineWidth` (iOS always returns the exact width).<br>You can see the effect of this flag in the [sample App][1].
102102
fontFamily | string | OS dependent | The default is the same applied by React Native: Roboto in Android, San Francisco in iOS.<br>**Note:** Device manufacturer or custom ROM can change the default font.
103103
fontWeight | string | 'normal' | On android, numeric ranges has no granularity and '500' to '900' becomes 'bold', but you can use fonts of specific weights, like "sans-serif-medium".
104104
fontSize | number | 14 | The default value comes from RN.
@@ -109,15 +109,15 @@ letterSpacing | number | (none) | Additional spacing between characters (
109109
includeFontPadding | boolean | true | Include additional top and bottom padding, to avoid clipping certain characters.<br>_Android only_
110110
textBreakStrategy | string | 'highQuality' | One of 'simple', 'balanced', or 'highQuality'.<br>_Android only, with API 23+_
111111

112-
The [sample App](https://github.com/aMarCruz/rn-text-size-sample-app) shows interactively the effect of these parameters on the screen.
112+
The [sample App][1] shows interactively the effect of these parameters on the screen.
113113

114114
**TSMeasureResult**
115115

116116
`measure` returns a Promise that resolves to a plain JS object with this properties:
117117

118118
Property | Type | Notes
119119
--------- | ------ | ------
120-
width | number | Total used width. It may be less or equal to the given width. On Android this value may vary depending on the `usePreciseWidth` flag.
120+
width | number | Total used width. It may be less or equal to the given width.<br>On Android this value may vary depending on the `usePreciseWidth` flag.
121121
height | number | Total height, including top and bottom padding if `includingFontPadding` was set (the default).
122122
lastLineWidth | number | Width of the last line, without trailing blanks.<br>__Note:__ If `usePreciseWidth` is `false` (the default), this field is undefined.
123123
lineCount | number | Number of lines, taking into account hard and automatic line breaks.
@@ -221,7 +221,7 @@ letterSpacing | number | (none)
221221
includeFontPadding | boolean | true
222222
textBreakStrategy | string | 'highQuality'
223223

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

226226
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).
227227

@@ -234,7 +234,7 @@ specsForTextStyles(): Promise<{ [key: string]: TSFontForStyle }>
234234

235235
Get system font information for the running OS.
236236

237-
This is a wrapper for the iOS [`UIFont.preferredFontForTextStyle`](https://developer.apple.com/documentation/uikit/uifont/1619030-preferredfontfortextstyle) method and the current Android [Material Design Type Scale](https://material.io/design/typography/#type-scale) styles.
237+
This is a wrapper for the iOS [`UIFont.preferredFontForTextStyle`][4] method and the current Android [Material Design Type Scale][5] styles.
238238

239239
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:
240240

@@ -249,7 +249,7 @@ fontWeight | TSFontWeight | Only if 'bold', undefined if the weight is 'norma
249249
fontVariant | TSFontVariant[] or null | _iOS only_. Currently, no style includes this property.
250250
letterSpacing | number | Omitted if running on Android with RN lower than 0.55
251251

252-
To know the key names, please see [Keys from specsForTextStyles](https://github.com/aMarCruz/react-native-text-size/wiki/Keys-from-specsForTextStyles) the Wiki.
252+
To know the key names, please see [Keys from specsForTextStyles][6] the Wiki.
253253

254254
I have not tried to normalize these keys since, with the exception of 2 or 3, they have a different interpretation in each OS. You will know how to use them to create custom styles according to your needs.
255255

@@ -264,7 +264,7 @@ Returns the characteristics of the font obtained from the given specifications.
264264

265265
**TSFontSpecs**
266266

267-
This parameter is a subset of [`TSMeasureParams`](#tsmeasureparams), so the details are omitted here.
267+
This parameter is a subset of [`TSMeasureParams`](#incorrent-height-ios), so the details are omitted here.
268268

269269
Property | Type | Default
270270
---------- | ------ | -------
@@ -279,7 +279,7 @@ letterSpacing | number | 0
279279

280280
<a name="tsfontinfo"></a> **TSFontInfo**
281281

282-
The result is a Promise that resolves to a JS object with info for the given font and size, units in [_SP_](https://developer.android.com/guide/topics/resources/more-resources#Dimension) in Android or points in iOS, using floating point numbers where applicable\*.
282+
The result is a Promise that resolves to a JS object with info for the given font and size, units in [_SP_][7] in Android or points in iOS, using floating point numbers where applicable\*.
283283

284284
Property | Type | Details
285285
----------- | ------ | --------
@@ -303,9 +303,9 @@ _hash | number | Hash code, maybe useful for debugging.
303303

304304
See more in:
305305

306-
[Understanding typography](https://material.io/design/typography/understanding-typography.html#type-properties) at the Google Material Design site.
306+
[Understanding typography][8] at the Google Material Design site.
307307

308-
[About Text Handling in iOS](https://developer.apple.com/library/archive/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/Introduction/Introduction.html#//apple_ref/doc/uid/TP40009542.) for iOS.
308+
[About Text Handling in iOS][9] for iOS.
309309

310310
**Tip**
311311

@@ -322,11 +322,11 @@ fontFamilyNames(): Promise<string[]>
322322

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

325-
On iOS, this uses the [`UIFont.familyNames`](https://developer.apple.com/documentation/uikit/uifont/1619040-familynames?language=objc) method of the UIKit.
325+
On iOS, this uses the [`UIFont.familyNames`][10] method of the UIKit.
326326

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

329-
See [About Android Fonts](https://github.com/aMarCruz/react-native-text-size/wiki/About-Android-Fonts) and [Custom Fonts](https://github.com/aMarCruz/react-native-text-size/wiki/Custom-Fonts) in the Wiki to know more about this list.
329+
See [About Android Fonts][11] and [Custom Fonts][12] in the Wiki to know more about this list.
330330

331331

332332
## fontNamesForFamilyName
@@ -350,7 +350,7 @@ On iOS, RN takes into account the absolute position on the screen to calculate t
350350

351351
#### letterSpacing not scaling (iOS)
352352

353-
RN does not support the [Dynamic Type Sizes](https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/typography#dynamic-type-sizes), but does an excellent job imitating this feature through `allowFontScaling` ...except for `letterSpacing` that is not scaled.
353+
RN does not support the [Dynamic Type Sizes][13], but does an excellent job imitating this feature through `allowFontScaling` ...except for `letterSpacing` that is not scaled.
354354

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

@@ -373,7 +373,6 @@ Nested `<Text>` components (or with images inside) can be rasterized with dimens
373373
- [ ] And a lot of more things.
374374
- [ ] Ahh a... lot of money, of course. I need a Mac 😆 so...
375375

376-
377376
## Support my Work
378377

379378
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...
@@ -387,7 +386,7 @@ Thanks for your support!
387386

388387
## License
389388

390-
The [BSD 2-Clause](LICENCE) "Simplified" License.
389+
The [BSD 2-Clause](LICENSE) "Simplified" License.
391390

392391
Copyright (c) 2018, Alberto Martínez. All rights reserved.
393392

@@ -397,3 +396,17 @@ Copyright (c) 2018, Alberto Martínez. All rights reserved.
397396
[license-url]: https://github.com/aMarCruz/react-native-text-size/blob/master/LICENSE
398397
[bmc-image]: https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png
399398
[bmc-url]: https://www.buymeacoffee.com/aMarCruz
399+
400+
[1]: https://github.com/aMarCruz/rn-text-size-sample-app
401+
[2]: https://github.com/aMarCruz/react-native-text-size/wiki/Manual-Installation
402+
[3]: https://facebook.github.io/react-native/docs/text#props
403+
[4]: https://developer.apple.com/documentation/uikit/uifont/1619030-preferredfontfortextstyle
404+
[5]: https://material.io/design/typography/#type-scale
405+
[6]: https://github.com/aMarCruz/react-native-text-size/wiki/Keys-from-specsForTextStyles
406+
[7]: https://developer.android.com/guide/topics/resources/more-resources#Dimension
407+
[8]: https://material.io/design/typography/understanding-typography.html#type-properties
408+
[9]: https://developer.apple.com/library/archive/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/Introduction/Introduction.html#//apple_ref/doc/uid/TP40009542.
409+
[10]: https://developer.apple.com/documentation/uikit/uifont/1619040-familynames?language=objc
410+
[11]: https://github.com/aMarCruz/react-native-text-size/wiki/About-Android-Fonts
411+
[12]: https://github.com/aMarCruz/react-native-text-size/wiki/Custom-Fonts
412+
[13]: https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/typography#dynamic-type-sizes

android/src/main/java/com/github/amarcruz/rntextsize/RNTextSizeModule.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,17 +198,21 @@ public void flatHeights(@Nullable final ReadableMap specs, final Promise promise
198198

199199
for (int ix = 0; ix < texts.size(); ix++) {
200200

201+
// If this element is `null` or another type, return zero
201202
if (texts.getType(ix) != ReadableType.String) {
202203
result.pushInt(0);
203204
continue;
204205
}
205206

206207
final String text = texts.getString(ix);
208+
209+
// If empty, return the minimum height of <Text> components
207210
if (text.isEmpty()) {
208211
result.pushDouble(minimalHeight(density, includeFontPadding));
209212
continue;
210213
}
211214

215+
// Reset the SB text, the attrs will expand to its full length
212216
sb.replace(0, sb.length(), text);
213217

214218
if (Build.VERSION.SDK_INT >= 23) {

index.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ declare module "react-native-text-size" {
7575
}
7676

7777
export type TSFontForStyle = {
78-
fontFamily: string | void,
78+
fontFamily: string,
7979
/** Unscaled font size, untits are SP in Android, points in iOS */
8080
fontSize: number,
8181
/** fontStyle is omitted if it is "normal" */
@@ -90,7 +90,7 @@ declare module "react-native-text-size" {
9090

9191
export interface TSHeightsParams extends TSFontSpecs {
9292
/** The required text to measure. */
93-
text: string[];
93+
text: Array<string | null>;
9494
/** Maximum width of the area to display the text. @default MAX_INT */
9595
width?: number;
9696
/** @default true */

index.js.flow

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export type TSFontInfo = {
6060
}
6161

6262
export type TSFontSpecs = {
63-
fontFamily?: string | void,
63+
fontFamily?: string,
6464
fontSize?: number,
6565
fontStyle?: TSFontStyle,
6666
fontWeight?: TSFontWeight,
@@ -75,7 +75,7 @@ export type TSFontSpecs = {
7575
}
7676

7777
export type TSFontForStyle = {
78-
fontFamily: string | void,
78+
fontFamily: string,
7979
fontSize: number,
8080
/** fontStyle is omitted if it is "normal" */
8181
fontStyle?: TSFontStyle,
@@ -89,7 +89,7 @@ export type TSFontForStyle = {
8989

9090
export type TSHeightsParams = TSFontSpecs & {
9191
/** The required text to measure. */
92-
text: string[],
92+
text: (string | null)[],
9393
/** Maximum width of the area to display the text. @default MAX_INT */
9494
width?: number,
9595
/** @default true */

ios/RNTextSize.m

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,10 @@
33
#if __has_include(<React/RCTConvert.h>)
44
#import <React/RCTConvert.h>
55
#import <React/RCTFont.h>
6-
#import <React/RCTLog.h>
76
#import <React/RCTUtils.h>
87
#else
98
#import "React/RCTConvert.h" // Required when used as a Pod in a Swift project
109
#import "React/RCTFont.h"
11-
#import "React/RCTLog.h"
1210
#import "React/RCTUtils.h"
1311
#endif
1412

@@ -75,7 +73,7 @@ - (dispatch_queue_t)methodQueue {
7573
}
7674

7775
// Allow empty text without generating error
78-
// TODO: Return the same height as RN.
76+
// ~~TODO~~: Return the same height as RN. @completed(v2.0.1)
7977
if (!text.length) {
8078
resolve(@{
8179
@"width": @0,
@@ -185,26 +183,31 @@ - (dispatch_queue_t)methodQueue {
185183
NSLayoutManager *layoutManager = [NSLayoutManager new];
186184
[layoutManager addTextContainer:textContainer];
187185

186+
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithString:@" " attributes:attributes];
187+
[textStorage addLayoutManager:layoutManager];
188+
188189
NSMutableArray<NSNumber *> *result = [[NSMutableArray alloc] initWithCapacity:texts.count];
189190
const CGFloat epsilon = 0.001;
190191

191192
for (int ix = 0; ix < texts.count; ix++) {
192193
NSString *text = texts[ix];
193-
if (!text) {
194+
195+
// If this element is `null` or another type, return zero
196+
if (![text isKindOfClass:[NSString class]]) {
194197
result[ix] = @0;
195198
continue;
196199
}
197-
if (text == (id) kCFNull) {
200+
201+
// If empty, return the minimum height of <Text> components
202+
if (!text.length) {
198203
result[ix] = @14;
199204
continue;
200205
}
201206

202-
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithString:text attributes:attributes];
203-
[textStorage addLayoutManager:layoutManager];
204-
205-
[layoutManager ensureLayoutForTextContainer:textContainer];
207+
// Reset the textStorage, the attrs will expand to its new length
208+
NSRange range = NSMakeRange(0, textStorage.length);
209+
[textStorage replaceCharactersInRange:range withString:text];
206210
CGSize size = [layoutManager usedRectForTextContainer:textContainer].size;
207-
[textStorage removeLayoutManager:layoutManager];
208211

209212
const CGFloat height = MIN(RCTCeilPixelValue(size.height + epsilon), maxSize.height);
210213
result[ix] = @(height);

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-native-text-size",
3-
"version": "2.0.1",
3+
"version": "2.0.2",
44
"description": "Measure text accurately before laying it out and get font information from your App",
55
"main": "index.js",
66
"keywords": [

0 commit comments

Comments
 (0)