1
1
import {
2
+ LightFormattedString ,
2
3
VerticalTextAlignment ,
3
4
computeBaseLineOffset ,
4
5
createNativeAttributedString ,
@@ -60,8 +61,8 @@ declare module '@nativescript/core/ui/text-base' {
60
61
interface TextBase {
61
62
_requestLayoutOnTextChanged ( ) ;
62
63
_setNativeText ( ) ;
63
- createMutableStringForSpan ?( span , text ) : NSMutableAttributedString ;
64
- createNSMutableAttributedString ?( formattedString : FormattedString ) : NSMutableAttributedString ;
64
+ // createMutableStringForSpan?(span, text): NSMutableAttributedString;
65
+ // createNSMutableAttributedString?(formattedString: FormattedString): NSMutableAttributedString;
65
66
// createNSMutableAttributedString(formattedString: FormattedString);
66
67
}
67
68
}
@@ -164,13 +165,13 @@ export class Label extends LabelBase {
164
165
attributedString : NSMutableAttributedString ;
165
166
private _delegate : LabelUITextViewDelegateImpl ;
166
167
static DTCORETEXT_INIT = false ;
167
- constructor ( ) {
168
- super ( ) ;
169
- // if (iOSUseDTCoreText && !Label.DTCORETEXT_INIT) {
170
- // Label.DTCORETEXT_INIT = true;
171
- // DTCoreTextFontDescriptor.asyncPreloadFontLookupTable();
172
- // }
173
- }
168
+ // constructor() {
169
+ // super();
170
+ // if (iOSUseDTCoreText && !Label.DTCORETEXT_INIT) {
171
+ // Label.DTCORETEXT_INIT = true;
172
+ // DTCoreTextFontDescriptor.asyncPreloadFontLookupTable();
173
+ // }
174
+ // }
174
175
public createNativeView ( ) {
175
176
const view = UITextView . new ( ) ;
176
177
if ( ! view . font ) {
@@ -183,13 +184,10 @@ export class Label extends LabelBase {
183
184
view . backgroundColor = UIColor . clearColor ;
184
185
view . userInteractionEnabled = true ;
185
186
view . dataDetectorTypes = UIDataDetectorTypes . All ;
186
- view . textContainerInset = {
187
- top : 0 ,
188
- left : 0 ,
189
- bottom : 0 ,
190
- right : 0
191
- } ;
192
- view . textContainer . lineFragmentPadding = 0 ; // to remove left padding
187
+ view . textContainerInset = UIEdgeInsetsZero ;
188
+ view . textContainer . lineFragmentPadding = 0 ;
189
+ // ignore font leading just like UILabel does
190
+ view . layoutManager . usesFontLeading = false ;
193
191
// view.textContainer.lineBreakMode = NSLineBreakMode.ByCharWrapping;
194
192
return view ;
195
193
}
@@ -206,12 +204,6 @@ export class Label extends LabelBase {
206
204
null
207
205
) ;
208
206
this . nativeViewProtected . attributedText = this . attributedString ;
209
- // this.htmlText = null;
210
- // this.needsHTMLUpdate = false;
211
- // this.updatingHTML = false;
212
- // if (this.htmlText && this.needsHTMLUpdate) {
213
- // this.updateHTMLString();
214
- // }
215
207
}
216
208
public disposeNativeView ( ) {
217
209
this . _delegate = null ;
@@ -236,21 +228,33 @@ export class Label extends LabelBase {
236
228
}
237
229
computeTextHeight ( size : CGSize ) {
238
230
const tv = this . nativeTextViewProtected ;
231
+ const oldtextContainerInset = tv . textContainerInset ;
232
+ tv . textContainerInset = UIEdgeInsetsZero ;
233
+ // if (tv.attributedText) {
234
+ // const result = tv.attributedText.boundingRectWithSizeOptionsContext(
235
+ // size,
236
+ // NSStringDrawingOptions.UsesLineFragmentOrigin | NSStringDrawingOptions.UsesFontLeading,
237
+ // null
238
+ // );
239
+ // return Math.round(CGRectGetHeight(result));
240
+ // }
239
241
const result = tv . sizeThatFits ( size ) ;
242
+ tv . textContainerInset = oldtextContainerInset ;
240
243
return result . height ;
241
244
}
242
245
243
246
updateTextContainerInset ( applyVerticalTextAlignment = true ) {
244
- // if (!this.text) {
245
- // return;
246
- // }
247
247
const tv = this . nativeTextViewProtected ;
248
248
const top = layout . toDeviceIndependentPixels ( this . effectivePaddingTop + this . effectiveBorderTopWidth ) ;
249
249
const right = layout . toDeviceIndependentPixels ( this . effectivePaddingRight + this . effectiveBorderRightWidth ) ;
250
250
const bottom = layout . toDeviceIndependentPixels ( this . effectivePaddingBottom + this . effectiveBorderBottomWidth ) ;
251
251
const left = layout . toDeviceIndependentPixels ( this . effectivePaddingLeft + this . effectiveBorderLeftWidth ) ;
252
- if ( ! applyVerticalTextAlignment || ! this . verticalTextAlignment ) {
253
- this . nativeViewProtected . textContainerInset = {
252
+ if (
253
+ ! applyVerticalTextAlignment ||
254
+ ! this . verticalTextAlignment ||
255
+ ( tv . text ?. length === 0 && tv . attributedText ?. length === 0 )
256
+ ) {
257
+ tv . textContainerInset = {
254
258
top,
255
259
left,
256
260
bottom,
@@ -261,7 +265,7 @@ export class Label extends LabelBase {
261
265
switch ( this . verticalTextAlignment ) {
262
266
case 'initial' : // not supported
263
267
case 'top' :
264
- this . nativeViewProtected . textContainerInset = {
268
+ tv . textContainerInset = {
265
269
top,
266
270
left,
267
271
bottom,
@@ -274,7 +278,7 @@ export class Label extends LabelBase {
274
278
const height = this . computeTextHeight ( CGSizeMake ( tv . bounds . size . width , 10000 ) ) ;
275
279
let topCorrect = ( tv . bounds . size . height - top - bottom - height * tv . zoomScale ) / 2.0 ;
276
280
topCorrect = topCorrect < 0.0 ? 0.0 : topCorrect ;
277
- this . nativeViewProtected . textContainerInset = {
281
+ tv . textContainerInset = {
278
282
top : top + topCorrect ,
279
283
left,
280
284
bottom,
@@ -285,9 +289,9 @@ export class Label extends LabelBase {
285
289
286
290
case 'bottom' : {
287
291
const height = this . computeTextHeight ( CGSizeMake ( tv . bounds . size . width , 10000 ) ) ;
288
- let bottomCorrect = tv . bounds . size . height - bottom - height * tv . zoomScale ;
292
+ let bottomCorrect = tv . bounds . size . height - top - bottom - height * tv . zoomScale ;
289
293
bottomCorrect = bottomCorrect < 0.0 ? 0.0 : bottomCorrect ;
290
- this . nativeViewProtected . textContainerInset = {
294
+ tv . textContainerInset = {
291
295
top : top + bottomCorrect ,
292
296
left,
293
297
bottom,
@@ -304,86 +308,6 @@ export class Label extends LabelBase {
304
308
}
305
309
private _fixedSize : FixedSize ;
306
310
307
- // setTextDecorationAndTransform() {
308
- // const style = this.style;
309
- // const dict = new Map<string, any>();
310
- // switch (style.textDecoration) {
311
- // case 'none':
312
- // break;
313
- // case 'underline':
314
- // // TODO: Replace deprecated `StyleSingle` with `Single` after the next typings update
315
- // dict.set(NSUnderlineStyleAttributeName, NSUnderlineStyle.Single);
316
- // break;
317
- // case 'line-through':
318
- // // TODO: Replace deprecated `StyleSingle` with `Single` after the next typings update
319
- // dict.set(NSStrikethroughStyleAttributeName, NSUnderlineStyle.Single);
320
- // break;
321
- // case 'underline line-through':
322
- // // TODO: Replace deprecated `StyleSingle` with `Single` after the next typings update
323
- // dict.set(NSUnderlineStyleAttributeName, NSUnderlineStyle.Single);
324
- // dict.set(NSStrikethroughStyleAttributeName, NSUnderlineStyle.Single);
325
- // break;
326
- // default:
327
- // throw new Error(`Invalid text decoration value: ${style.textDecoration}. Valid values are: 'none', 'underline', 'line-through', 'underline line-through'.`);
328
- // }
329
-
330
- // if (style.letterSpacing !== 0) {
331
- // dict.set(NSKernAttributeName, style.letterSpacing * this.nativeTextViewProtected.font.pointSize);
332
- // }
333
-
334
- // if (style.lineHeight || style.whiteSpace === 'nowrap' || (style['lineBreak'] && style['lineBreak'] !== 'none')) {
335
- // const paragraphStyle = NSMutableParagraphStyle.alloc().init();
336
- // paragraphStyle.minimumLineHeight = style.lineHeight;
337
- // // make sure a possible previously set text alignment setting is not lost when line height is specified
338
- // paragraphStyle.alignment = (this.nativeTextViewProtected as UITextField | UITextView | UILabel).textAlignment;
339
-
340
- // // make sure a possible previously set line break mode is not lost when line height is specified
341
-
342
- // if (style['lineBreak']) {
343
- // paragraphStyle.lineBreakMode = lineBreakToLineBreakMode(style['lineBreak']);
344
- // } else if (style.whiteSpace) {
345
- // paragraphStyle.lineBreakMode = whiteSpaceToLineBreakMode(style.whiteSpace);
346
- // }
347
- // dict.set(NSParagraphStyleAttributeName, paragraphStyle);
348
- // } else if (isTextView && this.style.textAlignment !== 'initial') {
349
- // const paragraphStyle = NSMutableParagraphStyle.alloc().init();
350
- // paragraphStyle.alignment = this.nativeTextViewProtected.textAlignment;
351
- // dict.set(NSParagraphStyleAttributeName, paragraphStyle);
352
- // }
353
-
354
- // if (style.color && dict.size > 0) {
355
- // // dict.set(NSForegroundColorAttributeName, style.color.ios);
356
- // }
357
-
358
- // const text = this.text;
359
- // const str = text === undefined || text === null ? '' : text.toString();
360
- // const source = getTransformedText(str, this.textTransform);
361
- // if (dict.size > 0) {
362
- // if (isTextView) {
363
- // // UITextView's font seems to change inside.
364
- // dict.set(NSFontAttributeName, this.nativeTextViewProtected.font);
365
- // }
366
-
367
- // const result = NSMutableAttributedString.alloc().initWithString(source);
368
- // result.setAttributesRange(dict as any, { location: 0, length: source.length });
369
- // if (this.nativeTextViewProtected instanceof UIButton) {
370
- // this.nativeTextViewProtected.setAttributedTitleForState(result, UIControlState.Normal);
371
- // } else {
372
- // this.nativeTextViewProtected.attributedText = result;
373
- // }
374
- // } else {
375
- // if (this.nativeTextViewProtected instanceof UIButton) {
376
- // // Clear attributedText or title won't be affected.
377
- // this.nativeTextViewProtected.setAttributedTitleForState(null, UIControlState.Normal);
378
- // this.nativeTextViewProtected.setTitleForState(source, UIControlState.Normal);
379
- // } else {
380
- // // Clear attributedText or text won't be affected.
381
- // this.nativeTextViewProtected.attributedText = undefined;
382
- // this.nativeTextViewProtected.text = source;
383
- // }
384
- // }
385
- // }
386
-
387
311
_requestLayoutOnTextChanged ( ) : void {
388
312
if ( this . _fixedSize === FixedSize . BOTH ) {
389
313
return ;
@@ -498,13 +422,13 @@ export class Label extends LabelBase {
498
422
// when in collectionView or pager
499
423
// if this is done sync (without DTCoreText) while init the cell
500
424
// it breaks the UICollectionView :s
501
- if ( usingIOSDTCoreText ( ) ) {
502
- this . _updateHTMLString ( ) ;
503
- } else {
504
- // setTimeout(() => {
505
- this . _updateHTMLString ( ) ;
506
- // }, 0);
507
- }
425
+ // if (usingIOSDTCoreText()) {
426
+ // this._updateHTMLString();
427
+ // } else {
428
+ // setTimeout(() => {
429
+ this . _updateHTMLString ( ) ;
430
+ // }, 0);
431
+ // }
508
432
}
509
433
_setColor ( color ) {
510
434
if ( this . nativeTextViewProtected instanceof UIButton ) {
@@ -629,6 +553,7 @@ export class Label extends LabelBase {
629
553
} else {
630
554
super . _setNativeText ( ) ;
631
555
}
556
+ this . updateTextContainerInset ( ) ;
632
557
this . _requestLayoutOnTextChanged ( ) ;
633
558
}
634
559
setTextDecorationAndTransform ( ) {
@@ -655,24 +580,18 @@ export class Label extends LabelBase {
655
580
if ( style . letterSpacing !== 0 && this . nativeTextViewProtected . font ) {
656
581
const kern = style . letterSpacing * this . nativeTextViewProtected . font . pointSize ;
657
582
dict . set ( NSKernAttributeName , kern ) ;
658
- if ( this . nativeTextViewProtected instanceof UITextField ) {
659
- this . nativeTextViewProtected . defaultTextAttributes . setValueForKey ( kern , NSKernAttributeName ) ;
660
- }
661
583
}
662
584
const isTextView = false ;
663
- if ( style . lineHeight ) {
585
+ if ( style . lineHeight !== undefined ) {
586
+ let lineHeight = style . lineHeight ;
587
+ if ( lineHeight === 0 ) {
588
+ lineHeight = 0.00001 ;
589
+ }
664
590
const paragraphStyle = NSMutableParagraphStyle . alloc ( ) . init ( ) ;
665
- paragraphStyle . lineSpacing = style . lineHeight ;
591
+ paragraphStyle . minimumLineHeight = lineHeight ;
592
+ paragraphStyle . maximumLineHeight = lineHeight ;
666
593
// make sure a possible previously set text alignment setting is not lost when line height is specified
667
- if ( this . nativeTextViewProtected instanceof UIButton ) {
668
- paragraphStyle . alignment = this . nativeTextViewProtected . titleLabel . textAlignment ;
669
- } else {
670
- paragraphStyle . alignment = this . nativeTextViewProtected . textAlignment ;
671
- }
672
- if ( this . nativeTextViewProtected instanceof UILabel ) {
673
- // make sure a possible previously set line break mode is not lost when line height is specified
674
- paragraphStyle . lineBreakMode = this . nativeTextViewProtected . lineBreakMode ;
675
- }
594
+ paragraphStyle . alignment = this . nativeTextViewProtected . textAlignment ;
676
595
dict . set ( NSParagraphStyleAttributeName , paragraphStyle ) ;
677
596
} else if ( isTextView ) {
678
597
const paragraphStyle = NSMutableParagraphStyle . alloc ( ) . init ( ) ;
@@ -695,96 +614,29 @@ export class Label extends LabelBase {
695
614
location : 0 ,
696
615
length : source . length
697
616
} ) ;
698
- if ( this . nativeTextViewProtected instanceof UIButton ) {
699
- this . nativeTextViewProtected . setAttributedTitleForState ( result , 0 /* Normal */ ) ;
700
- } else {
701
- this . nativeTextViewProtected . attributedText = result ;
702
- }
617
+ this . nativeTextViewProtected . attributedText = result ;
703
618
} else {
704
- if ( this . nativeTextViewProtected instanceof UIButton ) {
705
- // Clear attributedText or title won't be affected.
706
- this . nativeTextViewProtected . setAttributedTitleForState ( null , 0 /* Normal */ ) ;
707
- this . nativeTextViewProtected . setTitleForState ( source , 0 /* Normal */ ) ;
708
- } else {
709
- // Clear attributedText or text won't be affected.
710
- this . nativeTextViewProtected . attributedText = undefined ;
711
- this . nativeTextViewProtected . text = source ;
712
- }
619
+ // Clear attributedText or text won't be affected.
620
+ this . nativeTextViewProtected . attributedText = undefined ;
621
+ this . nativeTextViewProtected . text = source ;
713
622
}
714
623
if ( ! style . color && majorVersion >= 13 && UIColor . labelColor ) {
715
624
( this as any ) . _setColor ( UIColor . labelColor ) ;
716
625
}
717
626
}
718
- currentMaxFontSize = 0 ;
719
-
720
- createNSMutableAttributedString ( formattedString : FormattedString ) : NSMutableAttributedString {
721
- // we need to store the max Font size to pass it to createMutableStringForSpan
722
- const length = formattedString . spans . length ;
723
- let maxFontSize = formattedString . style ?. fontSize || this ?. style . fontSize || 0 ;
724
- for ( let i = 0 ; i < length ; i ++ ) {
725
- const s = formattedString . spans . getItem ( i ) ;
726
- if ( s . style . fontSize ) {
727
- maxFontSize = Math . max ( maxFontSize , s . style . fontSize ) ;
728
- }
729
- }
730
- this . currentMaxFontSize = maxFontSize ;
731
- return super . createNSMutableAttributedString ( formattedString ) ;
627
+ createFormattedTextNative ( value : FormattedString ) {
628
+ return createNativeAttributedString ( value , this , this . autoFontSize , this . fontSizeRatio ) ;
732
629
}
733
- createMutableStringForSpan ( span : Span , text : string ) : NSMutableAttributedString {
734
- const viewFont = this . nativeTextViewProtected . font ;
735
- const attrDict : { key : string ; value : any } = { } as any ;
736
- const style = span . style ;
737
-
738
- let align = style . verticalAlignment || ( span . parent as FormattedString ) . style . verticalAlignment ;
739
- if ( ! align || align === 'stretch' ) {
740
- align = this . verticalTextAlignment as any ;
630
+ setFormattedTextDecorationAndTransform ( ) {
631
+ const attrText = this . createFormattedTextNative ( this . formattedText ) ;
632
+ // we override parent class behavior because we apply letterSpacing and lineHeight on a per Span basis
633
+ if ( majorVersion >= 13 && UIColor . labelColor ) {
634
+ this . nativeTextViewProtected . textColor = UIColor . labelColor ;
741
635
}
742
- const font = new Font ( style . fontFamily , style . fontSize , style . fontStyle , style . fontWeight ) ;
743
- const iosFont = font . getUIFont ( viewFont ) ;
744
-
745
- attrDict [ NSFontAttributeName ] = iosFont ;
746
- if ( span . color ) {
747
- const color = span . color instanceof Color ? span . color : new Color ( span . color as any ) ;
748
- attrDict [ NSForegroundColorAttributeName ] = color . ios ;
749
- }
750
-
751
- // We don't use isSet function here because defaultValue for backgroundColor is null.
752
- const backgroundColor : Color = style . backgroundColor || ( span . parent as FormattedString ) . backgroundColor ;
753
- if ( backgroundColor ) {
754
- const color = backgroundColor instanceof Color ? backgroundColor : new Color ( backgroundColor ) ;
755
- attrDict [ NSBackgroundColorAttributeName ] = color . ios ;
756
- }
757
-
758
- const textDecoration : CoreTypes . TextDecorationType = getClosestPropertyValue ( textDecorationProperty , span ) ;
759
636
760
- if ( textDecoration ) {
761
- const underline = textDecoration . indexOf ( 'underline' ) !== - 1 ;
762
- if ( underline ) {
763
- attrDict [ NSUnderlineStyleAttributeName ] = underline ;
764
- }
765
-
766
- const strikethrough = textDecoration . indexOf ( 'line-through' ) !== - 1 ;
767
- if ( strikethrough ) {
768
- attrDict [ NSStrikethroughStyleAttributeName ] = strikethrough ;
769
- }
770
- }
771
-
772
- if ( align && align !== 'stretch' ) {
773
- if ( iosFont ) {
774
- attrDict [ NSBaselineOffsetAttributeName ] = - computeBaseLineOffset (
775
- align ,
776
- - iosFont . ascender ,
777
- - iosFont . descender ,
778
- - iosFont . ascender ,
779
- - iosFont . descender ,
780
- iosFont . pointSize ,
781
- this . currentMaxFontSize
782
- ) ;
783
- }
784
- }
785
-
786
- return NSMutableAttributedString . alloc ( ) . initWithStringAttributes ( text , attrDict as any ) ;
637
+ this . nativeTextViewProtected . attributedText = attrText ;
787
638
}
639
+
788
640
[ paddingTopProperty . getDefault ] ( ) : CoreTypes . LengthType {
789
641
return {
790
642
value : 0 ,
0 commit comments