Skip to content

Commit c47f9fb

Browse files
committed
feat(core): Typography improvements
1 parent e5caa2c commit c47f9fb

File tree

7 files changed

+80
-68
lines changed

7 files changed

+80
-68
lines changed

packages/core/platforms/ios/src/UIView+NativeScript.m

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ - (void)nativeScriptSetTextDecorationAndTransform:(NSString*)text textDecoration
1515
}
1616
BOOL isTextType = [self isKindOfClass:[UITextField class]] || [self isKindOfClass:[UITextView class]] | [self isKindOfClass:[UILabel class]] | [self isKindOfClass:[UIButton class]];
1717

18-
if (letterSpacing != 0 && isTextType && ((UITextView*)self).font != nil) {
19-
NSNumber *kern = [NSNumber numberWithDouble:letterSpacing * ((UITextView*)self).font.pointSize];
18+
if (letterSpacing != 0 && isTextType) {
19+
NSNumber *kern = [NSNumber numberWithDouble:letterSpacing];
2020
attrDict[NSKernAttributeName] = kern;
2121
if ([self isKindOfClass:[UITextField class]]) {
2222
[((UITextField*)self).defaultTextAttributes setValue:kern forKey:NSKernAttributeName];
@@ -26,13 +26,19 @@ - (void)nativeScriptSetTextDecorationAndTransform:(NSString*)text textDecoration
2626
BOOL isTextView = [self isKindOfClass:[UITextView class]];
2727
if (lineHeight > 0) {
2828
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
29-
// Note: Avoid using lineSpacing as it will append the height as extra space
30-
paragraphStyle.minimumLineHeight = lineHeight;
3129
// make sure a possible previously set text alignment setting is not lost when line height is specified
3230
if ([self isKindOfClass:[UIButton class]]) {
3331
paragraphStyle.alignment = ((UIButton*)self).titleLabel.textAlignment;
32+
33+
if (((UIButton*)self).titleLabel.font) {
34+
paragraphStyle.lineSpacing = lineHeight - ((UIButton*)self).titleLabel.font.lineHeight;
35+
}
3436
} else {
3537
paragraphStyle.alignment = ((UILabel*)self).textAlignment;
38+
39+
if (((UILabel*)self).font) {
40+
paragraphStyle.lineSpacing = lineHeight - ((UILabel*)self).font.lineHeight;
41+
}
3642
}
3743

3844
if ([self isKindOfClass:[UILabel class]]) {
@@ -79,7 +85,7 @@ - (void)nativeScriptSetTextDecorationAndTransform:(NSString*)text textDecoration
7985
-(void)nativeScriptSetFormattedTextDecorationAndTransform:(NSDictionary*)details letterSpacing:(CGFloat)letterSpacing lineHeight:(CGFloat)lineHeight {
8086
NSMutableAttributedString *attrText = [NativeScriptUtils createMutableStringWithDetails:details];
8187
if (letterSpacing != 0) {
82-
NSNumber *kern = [NSNumber numberWithDouble:letterSpacing * ((UITextView*)self).font.pointSize];
88+
NSNumber *kern = [NSNumber numberWithDouble:letterSpacing];
8389
[attrText addAttribute:NSKernAttributeName value:kern range:(NSRange){
8490
0,
8591
attrText.length
@@ -89,14 +95,20 @@ -(void)nativeScriptSetFormattedTextDecorationAndTransform:(NSDictionary*)details
8995
BOOL isLabel = [self isKindOfClass:[UILabel class]];
9096
if (lineHeight > 0) {
9197
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
92-
// Note: Avoid using lineSpacing as it will append the height as extra space
93-
paragraphStyle.minimumLineHeight = lineHeight;
9498
// make sure a possible previously set text alignment setting is not lost when line height is specified
9599
if ([self isKindOfClass:[UIButton class]]) {
96100
paragraphStyle.alignment = ((UIButton*)self).titleLabel.textAlignment;
101+
102+
if (((UIButton*)self).titleLabel.font) {
103+
paragraphStyle.lineSpacing = lineHeight - ((UIButton*)self).titleLabel.font.lineHeight;
104+
}
97105
} else {
98106
// Paragraph alignment is also important for tappable spans as NSTextContainer takes it into account
99107
paragraphStyle.alignment = ((UILabel*)self).textAlignment;
108+
109+
if (((UILabel*)self).font) {
110+
paragraphStyle.lineSpacing = lineHeight - ((UILabel*)self).font.lineHeight;
111+
}
100112
}
101113

102114
if (isLabel) {

packages/core/ui/html-view/index.android.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Color } from '../../color';
2+
import { layout } from '../../utils';
23
import { SDK_VERSION } from '../../utils/constants';
34
import { Font } from '../styling/font';
45
import { colorProperty, fontSizeProperty, fontInternalProperty } from '../styling/style-properties';
@@ -86,14 +87,10 @@ export class HtmlView extends HtmlViewBase {
8687
this.nativeViewProtected.setTypeface(font);
8788
}
8889

89-
[fontSizeProperty.getDefault](): { nativeSize: number } {
90-
return { nativeSize: this.nativeViewProtected.getTextSize() };
90+
[fontSizeProperty.getDefault](): number {
91+
return this.nativeViewProtected.getTextSize() / layout.getDisplayDensity();
9192
}
92-
[fontSizeProperty.setNative](value: number | { nativeSize: number }) {
93-
if (typeof value === 'number') {
94-
this.nativeViewProtected.setTextSize(value);
95-
} else {
96-
this.nativeViewProtected.setTextSize(android.util.TypedValue.COMPLEX_UNIT_PX, value.nativeSize);
97-
}
93+
[fontSizeProperty.setNative](value: number) {
94+
this.nativeViewProtected.setTextSize(value);
9895
}
9996
}

packages/core/ui/search-bar/index.android.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Font } from '../styling/font';
22
import { SearchBarBase, textProperty, hintProperty, textFieldHintColorProperty, textFieldBackgroundColorProperty } from './search-bar-common';
33
import { isUserInteractionEnabledProperty, isEnabledProperty } from '../core/view';
4-
import { ad } from '../../utils';
4+
import { ad, layout } from '../../utils';
55
import { Color } from '../../color';
66
import { colorProperty, backgroundColorProperty, backgroundInternalProperty, fontInternalProperty, fontSizeProperty } from '../styling/style-properties';
77

@@ -199,15 +199,11 @@ export class SearchBar extends SearchBarBase {
199199
textView.setTextColor(color);
200200
}
201201

202-
[fontSizeProperty.getDefault](): { nativeSize: number } {
203-
return { nativeSize: this._getTextView().getTextSize() };
202+
[fontSizeProperty.getDefault](): number {
203+
return this._getTextView().getTextSize() / layout.getDisplayDensity();
204204
}
205-
[fontSizeProperty.setNative](value: number | { nativeSize: number }) {
206-
if (typeof value === 'number') {
207-
this._getTextView().setTextSize(value);
208-
} else {
209-
this._getTextView().setTextSize(android.util.TypedValue.COMPLEX_UNIT_PX, value.nativeSize);
210-
}
205+
[fontSizeProperty.setNative](value: number) {
206+
this._getTextView().setTextSize(value);
211207
}
212208

213209
[fontInternalProperty.getDefault](): android.graphics.Typeface {

packages/core/ui/segmented-bar/index.android.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -140,15 +140,11 @@ export class SegmentedBarItem extends SegmentedBarItemBase {
140140
this.nativeViewProtected.setTextColor(color);
141141
}
142142

143-
[fontSizeProperty.getDefault](): { nativeSize: number } {
144-
return { nativeSize: this.nativeViewProtected.getTextSize() };
143+
[fontSizeProperty.getDefault](): number {
144+
return this.nativeViewProtected.getTextSize() / layout.getDisplayDensity();
145145
}
146-
[fontSizeProperty.setNative](value: number | { nativeSize: number }) {
147-
if (typeof value === 'number') {
148-
this.nativeViewProtected.setTextSize(value);
149-
} else {
150-
this.nativeViewProtected.setTextSize(android.util.TypedValue.COMPLEX_UNIT_PX, value.nativeSize);
151-
}
146+
[fontSizeProperty.setNative](value: number) {
147+
this.nativeViewProtected.setTextSize(value);
152148
}
153149

154150
[fontInternalProperty.getDefault](): android.graphics.Typeface {

packages/core/ui/tab-view/index.android.ts

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -392,15 +392,11 @@ export class TabViewItem extends TabViewItemBase {
392392
return tabFragment.getChildFragmentManager();
393393
}
394394

395-
[fontSizeProperty.getDefault](): { nativeSize: number } {
396-
return { nativeSize: this.nativeViewProtected.getTextSize() };
395+
[fontSizeProperty.getDefault](): number {
396+
return this.nativeViewProtected.getTextSize() / layout.getDisplayDensity();
397397
}
398-
[fontSizeProperty.setNative](value: number | { nativeSize: number }) {
399-
if (typeof value === 'number') {
400-
this.nativeViewProtected.setTextSize(value);
401-
} else {
402-
this.nativeViewProtected.setTextSize(android.util.TypedValue.COMPLEX_UNIT_PX, value.nativeSize);
403-
}
398+
[fontSizeProperty.setNative](value: number) {
399+
this.nativeViewProtected.setTextSize(value);
404400
}
405401

406402
[fontInternalProperty.getDefault](): android.graphics.Typeface {
@@ -494,7 +490,7 @@ export class TabView extends TabViewBase {
494490
JSON.stringify([
495491
{ value: 1, type: 0 /* org.nativescript.widgets.GridUnitType.auto */ },
496492
{ value: 1, type: 2 /* org.nativescript.widgets.GridUnitType.star */ },
497-
])
493+
]),
498494
);
499495
viewPager.setLayoutParams(lp);
500496

@@ -506,7 +502,7 @@ export class TabView extends TabViewBase {
506502
JSON.stringify([
507503
{ value: 1, type: 2 /* org.nativescript.widgets.GridUnitType.star */ },
508504
{ value: 1, type: 0 /* org.nativescript.widgets.GridUnitType.auto */ },
509-
])
505+
]),
510506
);
511507
tabLayout.setLayoutParams(lp);
512508
viewPager.setSwipePageEnabled(false);
@@ -771,12 +767,8 @@ export class TabView extends TabViewBase {
771767
[tabTextFontSizeProperty.getDefault](): number {
772768
return this._tabLayout.getTabTextFontSize();
773769
}
774-
[tabTextFontSizeProperty.setNative](value: number | { nativeSize: number }) {
775-
if (typeof value === 'number') {
776-
this._tabLayout.setTabTextFontSize(value);
777-
} else {
778-
this._tabLayout.setTabTextFontSize(value.nativeSize);
779-
}
770+
[tabTextFontSizeProperty.setNative](value: number) {
771+
this._tabLayout.setTabTextFontSize(value);
780772
}
781773

782774
[tabTextColorProperty.getDefault](): number {

packages/core/ui/tab-view/index.ios.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,7 @@ export class TabView extends TabViewBase {
580580
[tabTextFontSizeProperty.getDefault](): number {
581581
return null;
582582
}
583-
[tabTextFontSizeProperty.setNative](value: number | { nativeSize: number }) {
583+
[tabTextFontSizeProperty.setNative](value: number) {
584584
this._updateIOSTabBarColorsAndFonts();
585585
}
586586

packages/core/ui/text-base/index.android.ts

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -360,15 +360,24 @@ export class TextBase extends TextBaseCommon {
360360
}
361361
}
362362

363-
[fontSizeProperty.getDefault](): { nativeSize: number } {
364-
return { nativeSize: this.nativeTextViewProtected.getTextSize() };
365-
}
366-
[fontSizeProperty.setNative](value: number | { nativeSize: number }) {
367-
if (!this.formattedText || typeof value !== 'number') {
368-
if (typeof value === 'number') {
369-
this.nativeTextViewProtected.setTextSize(value);
370-
} else {
371-
this.nativeTextViewProtected.setTextSize(android.util.TypedValue.COMPLEX_UNIT_PX, value.nativeSize);
363+
[fontSizeProperty.getDefault](): number {
364+
return this.nativeTextViewProtected.getTextSize() / layout.getDisplayDensity();
365+
}
366+
[fontSizeProperty.setNative](value: number) {
367+
if (!this.formattedText) {
368+
this.nativeTextViewProtected.setTextSize(value);
369+
370+
// Re-calculate line-height
371+
if (this.lineHeight != 0) {
372+
// It's done automatically for API 28+
373+
if (SDK_VERSION < 28) {
374+
this._setLineHeightLegacy(this.lineHeight);
375+
}
376+
}
377+
378+
// Re-calculate letter-spacing
379+
if (this.letterSpacing != 0) {
380+
this._updateLetterSpacing(this.letterSpacing);
372381
}
373382
}
374383
}
@@ -377,16 +386,12 @@ export class TextBase extends TextBaseCommon {
377386
return this.nativeTextViewProtected.getLineHeight() / layout.getDisplayDensity();
378387
}
379388
[lineHeightProperty.setNative](value: number) {
380-
const dpValue = value * layout.getDisplayDensity();
381-
389+
// Note: android throws exception in the case of negative line height
390+
// so make sure that minimum is zero
382391
if (SDK_VERSION >= 28) {
383-
this.nativeTextViewProtected.setLineHeight(dpValue);
392+
this.nativeTextViewProtected.setLineHeight(Math.max(value * layout.getDisplayDensity(), 0));
384393
} else {
385-
const fontHeight = this.nativeTextViewProtected.getPaint().getFontMetricsInt(null);
386-
// Actual line spacing is the diff of line height and font height
387-
const lineSpacing = Math.max(dpValue - fontHeight, 0);
388-
389-
this.nativeTextViewProtected.setLineSpacing(lineSpacing, 1);
394+
this._setLineHeightLegacy(value);
390395
}
391396
}
392397

@@ -443,10 +448,10 @@ export class TextBase extends TextBaseCommon {
443448
}
444449

445450
[letterSpacingProperty.getDefault](): number {
446-
return org.nativescript.widgets.ViewHelper.getLetterspacing(this.nativeTextViewProtected);
451+
return org.nativescript.widgets.ViewHelper.getLetterspacing(this.nativeTextViewProtected) * this.fontSize;
447452
}
448453
[letterSpacingProperty.setNative](value: number) {
449-
org.nativescript.widgets.ViewHelper.setLetterspacing(this.nativeTextViewProtected, value);
454+
this._updateLetterSpacing(value);
450455
}
451456

452457
[paddingTopProperty.getDefault](): CoreTypes.LengthType {
@@ -495,6 +500,20 @@ export class TextBase extends TextBaseCommon {
495500
}
496501
}
497502

503+
_setLineHeightLegacy(value: number): void {
504+
const dpValue = value * layout.getDisplayDensity();
505+
const fontHeight = this.nativeTextViewProtected.getPaint().getFontMetricsInt(null);
506+
// Actual line spacing is the diff of line height and font height
507+
const lineSpacing = Math.max(dpValue - fontHeight, 0);
508+
509+
this.nativeTextViewProtected.setLineSpacing(lineSpacing, 1);
510+
}
511+
512+
_updateLetterSpacing(value: number): void {
513+
const emValue = value / this.fontSize;
514+
org.nativescript.widgets.ViewHelper.setLetterspacing(this.nativeTextViewProtected, emValue);
515+
}
516+
498517
_setNativeText(reset = false): void {
499518
if (reset) {
500519
this.nativeTextViewProtected.setText(null);

0 commit comments

Comments
 (0)