@nativescript/core
Version:
A JavaScript library providing an easy to use api for interacting with iOS and Android platform APIs.
220 lines • 10 kB
JavaScript
import { Background } from '../styling/background';
import { borderTopWidthProperty, borderRightWidthProperty, borderBottomWidthProperty, borderLeftWidthProperty, paddingTopProperty, paddingRightProperty, paddingBottomProperty, paddingLeftProperty } from '../styling/style-properties';
import { booleanConverter } from '../core/view-base';
import { View, CSSType } from '../core/view';
import { TextBase, whiteSpaceProperty, textOverflowProperty } from '../text-base';
import { layout } from '../../utils';
import { ios } from '../styling/background';
var FixedSize;
(function (FixedSize) {
FixedSize[FixedSize["NONE"] = 0] = "NONE";
FixedSize[FixedSize["WIDTH"] = 1] = "WIDTH";
FixedSize[FixedSize["HEIGHT"] = 2] = "HEIGHT";
FixedSize[FixedSize["BOTH"] = 3] = "BOTH";
})(FixedSize || (FixedSize = {}));
let Label = class Label extends TextBase {
createNativeView() {
const view = TNSLabel.new();
view.userInteractionEnabled = true;
return view;
}
// @ts-ignore
get ios() {
return this.nativeTextViewProtected;
}
get textWrap() {
return this.style.whiteSpace === 'normal';
}
set textWrap(value) {
if (typeof value === 'string') {
value = booleanConverter(value);
}
this.style.whiteSpace = value ? 'normal' : 'nowrap';
}
_requestLayoutOnTextChanged() {
if (this._fixedSize === FixedSize.BOTH) {
return;
}
if (this._fixedSize === FixedSize.WIDTH && !this.textWrap && this.getMeasuredHeight() > 0) {
// Single line label with fixed width will skip request layout on text change.
return;
}
super._requestLayoutOnTextChanged();
}
onMeasure(widthMeasureSpec, heightMeasureSpec) {
const nativeView = this.nativeTextViewProtected;
if (nativeView) {
const width = layout.getMeasureSpecSize(widthMeasureSpec);
const widthMode = layout.getMeasureSpecMode(widthMeasureSpec);
const height = layout.getMeasureSpecSize(heightMeasureSpec);
const heightMode = layout.getMeasureSpecMode(heightMeasureSpec);
this._fixedSize = (widthMode === layout.EXACTLY ? FixedSize.WIDTH : FixedSize.NONE) | (heightMode === layout.EXACTLY ? FixedSize.HEIGHT : FixedSize.NONE);
let nativeSize;
if (this.textWrap) {
// https://github.com/NativeScript/NativeScript/issues/4834
// NOTE: utils.measureNativeView(...) relies on UIView.sizeThatFits(...) that
// seems to have various issues when laying out UILabel instances.
// We use custom measure logic here that relies on overriden
// UILabel.textRectForBounds:limitedToNumberOfLines: in TNSLabel widget.
nativeSize = this._measureNativeView(width, widthMode, height, heightMode);
}
else {
// https://github.com/NativeScript/NativeScript/issues/6059
// NOTE: _measureNativeView override breaks a scenario with StackLayout that arranges
// labels horizontally (with textWrap=false) e.g. we are measuring label #2 within 356px,
// label #2 needs more, and decides to show ellipsis(...) but because of this its native size
// returned from UILabel.textRectForBounds:limitedToNumberOfLines: logic becomes 344px, so
// StackLayout tries to measure label #3 within the remaining 12px which is wrong;
// label #2 with ellipsis should take the whole 356px and label #3 should not be visible at all.
nativeSize = layout.measureNativeView(nativeView, width, widthMode, height, heightMode);
}
let labelWidth = nativeSize.width;
if (this.textWrap && widthMode === layout.AT_MOST) {
labelWidth = Math.min(labelWidth, width);
}
const measureWidth = Math.max(labelWidth, this.effectiveMinWidth);
const measureHeight = Math.max(nativeSize.height, this.effectiveMinHeight);
const widthAndState = View.resolveSizeAndState(measureWidth, width, widthMode, 0);
const heightAndState = View.resolveSizeAndState(measureHeight, height, heightMode, 0);
this.setMeasuredDimension(widthAndState, heightAndState);
}
}
_measureNativeView(width, widthMode, height, heightMode) {
const view = this.nativeTextViewProtected;
const nativeSize = view.textRectForBoundsLimitedToNumberOfLines(CGRectMake(0, 0, widthMode === 0 /* layout.UNSPECIFIED */ ? Number.POSITIVE_INFINITY : layout.toDeviceIndependentPixels(width), heightMode === 0 /* layout.UNSPECIFIED */ ? Number.POSITIVE_INFINITY : layout.toDeviceIndependentPixels(height)), view.numberOfLines).size;
nativeSize.width = layout.round(layout.toDevicePixels(nativeSize.width));
nativeSize.height = layout.round(layout.toDevicePixels(nativeSize.height));
return nativeSize;
}
[whiteSpaceProperty.setNative](value) {
this.adjustLineBreak();
}
[textOverflowProperty.setNative](value) {
this.adjustLineBreak();
}
adjustLineBreak() {
const whiteSpace = this.whiteSpace;
const textOverflow = this.textOverflow;
const nativeView = this.nativeViewProtected;
switch (whiteSpace) {
case 'normal':
nativeView.lineBreakMode = 0 /* NSLineBreakMode.ByWordWrapping */;
nativeView.numberOfLines = this.maxLines;
break;
case 'initial':
nativeView.lineBreakMode = 4 /* NSLineBreakMode.ByTruncatingTail */;
nativeView.numberOfLines = 1;
break;
case 'nowrap':
switch (textOverflow) {
case 'clip':
nativeView.lineBreakMode = 2 /* NSLineBreakMode.ByClipping */;
nativeView.numberOfLines = this.maxLines;
break;
default:
nativeView.lineBreakMode = 4 /* NSLineBreakMode.ByTruncatingTail */;
nativeView.numberOfLines = 1;
break;
}
break;
}
}
_redrawNativeBackground(value) {
if (value instanceof Background) {
const nativeView = this.nativeTextViewProtected;
if (nativeView) {
ios.createBackgroundUIColor(this, (color) => {
const cgColor = color ? color.CGColor : null;
nativeView.layer.backgroundColor = cgColor;
}, true);
}
}
this._setNativeClipToBounds();
}
[borderTopWidthProperty.setNative](value) {
const nativeView = this.nativeTextViewProtected;
const border = nativeView.borderThickness;
nativeView.borderThickness = {
top: layout.toDeviceIndependentPixels(this.effectiveBorderTopWidth),
right: border.right,
bottom: border.bottom,
left: border.left,
};
}
[borderRightWidthProperty.setNative](value) {
const nativeView = this.nativeTextViewProtected;
const border = nativeView.borderThickness;
nativeView.borderThickness = {
top: border.top,
right: layout.toDeviceIndependentPixels(this.effectiveBorderRightWidth),
bottom: border.bottom,
left: border.left,
};
}
[borderBottomWidthProperty.setNative](value) {
const nativeView = this.nativeTextViewProtected;
const border = nativeView.borderThickness;
nativeView.borderThickness = {
top: border.top,
right: border.right,
bottom: layout.toDeviceIndependentPixels(this.effectiveBorderBottomWidth),
left: border.left,
};
}
[borderLeftWidthProperty.setNative](value) {
const nativeView = this.nativeTextViewProtected;
const border = nativeView.borderThickness;
nativeView.borderThickness = {
top: border.top,
right: border.right,
bottom: border.bottom,
left: layout.toDeviceIndependentPixels(this.effectiveBorderLeftWidth),
};
}
[paddingTopProperty.setNative](value) {
const nativeView = this.nativeTextViewProtected;
const padding = nativeView.padding;
nativeView.padding = {
top: layout.toDeviceIndependentPixels(this.effectivePaddingTop),
right: padding.right,
bottom: padding.bottom,
left: padding.left,
};
}
[paddingRightProperty.setNative](value) {
const nativeView = this.nativeTextViewProtected;
const padding = nativeView.padding;
nativeView.padding = {
top: padding.top,
right: layout.toDeviceIndependentPixels(this.effectivePaddingRight),
bottom: padding.bottom,
left: padding.left,
};
}
[paddingBottomProperty.setNative](value) {
const nativeView = this.nativeTextViewProtected;
const padding = nativeView.padding;
nativeView.padding = {
top: padding.top,
right: padding.right,
bottom: layout.toDeviceIndependentPixels(this.effectivePaddingBottom),
left: padding.left,
};
}
[paddingLeftProperty.setNative](value) {
const nativeView = this.nativeTextViewProtected;
const padding = nativeView.padding;
nativeView.padding = {
top: padding.top,
right: padding.right,
bottom: padding.bottom,
left: layout.toDeviceIndependentPixels(this.effectivePaddingLeft),
};
}
};
Label = __decorate([
CSSType('Label')
], Label);
export { Label };
Label.prototype.recycleNativeView = 'auto';
//# sourceMappingURL=index.ios.js.map