mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-15 19:26:42 +08:00
feat(text-base): Add Span vertical-align support (#8257)
This commit is contained in:

committed by
GitHub

parent
e2a9af2bc7
commit
faa0181b9c
@ -358,13 +358,18 @@ export namespace HorizontalAlignment {
|
|||||||
export const horizontalAlignmentProperty = new CssProperty<Style, HorizontalAlignment>({ name: "horizontalAlignment", cssName: "horizontal-align", defaultValue: HorizontalAlignment.STRETCH, affectsLayout: isIOS, valueConverter: HorizontalAlignment.parse });
|
export const horizontalAlignmentProperty = new CssProperty<Style, HorizontalAlignment>({ name: "horizontalAlignment", cssName: "horizontal-align", defaultValue: HorizontalAlignment.STRETCH, affectsLayout: isIOS, valueConverter: HorizontalAlignment.parse });
|
||||||
horizontalAlignmentProperty.register(Style);
|
horizontalAlignmentProperty.register(Style);
|
||||||
|
|
||||||
export type VerticalAlignment = "top" | "middle" | "bottom" | "stretch";
|
export type VerticalAlignment = "top" | "middle" | "bottom" | "stretch" | "text-top" | "text-bottom" | "super" | "sub" | "baseline";
|
||||||
export namespace VerticalAlignment {
|
export namespace VerticalAlignment {
|
||||||
export const TOP: "top" = "top";
|
export const TOP: "top" = "top";
|
||||||
export const MIDDLE: "middle" = "middle";
|
export const MIDDLE: "middle" = "middle";
|
||||||
export const BOTTOM: "bottom" = "bottom";
|
export const BOTTOM: "bottom" = "bottom";
|
||||||
export const STRETCH: "stretch" = "stretch";
|
export const STRETCH: "stretch" = "stretch";
|
||||||
export const isValid = makeValidator<VerticalAlignment>(TOP, MIDDLE, BOTTOM, STRETCH);
|
export const TEXTTOP: "text-top" = "text-top";
|
||||||
|
export const TEXTBOTTOM: "text-bottom" = "text-bottom";
|
||||||
|
export const SUPER: "super" = "super";
|
||||||
|
export const SUB: "sub" = "sub";
|
||||||
|
export const BASELINE: "baseline" = "baseline";
|
||||||
|
export const isValid = makeValidator<VerticalAlignment>(TOP, MIDDLE, BOTTOM, STRETCH, TEXTTOP, TEXTBOTTOM, SUPER, SUB, BASELINE);
|
||||||
export const parse = (value: string) => value.toLowerCase() === "center" ? MIDDLE : parseStrict(value);
|
export const parse = (value: string) => value.toLowerCase() === "center" ? MIDDLE : parseStrict(value);
|
||||||
const parseStrict = makeParser<VerticalAlignment>(isValid);
|
const parseStrict = makeParser<VerticalAlignment>(isValid);
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ export class Span extends ViewBase implements SpanDefinition {
|
|||||||
}
|
}
|
||||||
set text(value: string) {
|
set text(value: string) {
|
||||||
if (this._text !== value) {
|
if (this._text !== value) {
|
||||||
this._text = value;
|
this._text = value && value.replace("\\n", "\n").replace("\\t", "\t");
|
||||||
this.notifyPropertyChange("text", value);
|
this.notifyPropertyChange("text", value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -201,6 +201,18 @@ function onFormattedTextPropertyChanged(textBase: TextBaseCommon, oldValue: Form
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getClosestPropertyValue<T>(property: CssProperty<any, T>, span: Span): T {
|
||||||
|
if (property.isSet(span.style)) {
|
||||||
|
return span.style[property.name];
|
||||||
|
} else if (property.isSet(span.parent.style)) {
|
||||||
|
// parent is FormattedString
|
||||||
|
return span.parent.style[property.name];
|
||||||
|
} else if (property.isSet(span.parent.parent.style)) {
|
||||||
|
// parent.parent is TextBase
|
||||||
|
return span.parent.parent.style[property.name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const textAlignmentConverter = makeParser<TextAlignment>(makeValidator<TextAlignment>("initial", "left", "center", "right"));
|
const textAlignmentConverter = makeParser<TextAlignment>(makeValidator<TextAlignment>("initial", "left", "center", "right"));
|
||||||
export const textAlignmentProperty = new InheritedCssProperty<Style, TextAlignment>({ name: "textAlignment", cssName: "text-align", defaultValue: "initial", valueConverter: textAlignmentConverter });
|
export const textAlignmentProperty = new InheritedCssProperty<Style, TextAlignment>({ name: "textAlignment", cssName: "text-align", defaultValue: "initial", valueConverter: textAlignmentConverter });
|
||||||
textAlignmentProperty.register(Style);
|
textAlignmentProperty.register(Style);
|
||||||
@ -217,10 +229,10 @@ const textDecorationConverter = makeParser<TextDecoration>(makeValidator<TextDec
|
|||||||
export const textDecorationProperty = new CssProperty<Style, TextDecoration>({ name: "textDecoration", cssName: "text-decoration", defaultValue: "none", valueConverter: textDecorationConverter });
|
export const textDecorationProperty = new CssProperty<Style, TextDecoration>({ name: "textDecoration", cssName: "text-decoration", defaultValue: "none", valueConverter: textDecorationConverter });
|
||||||
textDecorationProperty.register(Style);
|
textDecorationProperty.register(Style);
|
||||||
|
|
||||||
export const letterSpacingProperty = new CssProperty<Style, number>({ name: "letterSpacing", cssName: "letter-spacing", defaultValue: 0, affectsLayout: isIOS, valueConverter: v => parseFloat(v) });
|
export const letterSpacingProperty = new InheritedCssProperty<Style, number>({ name: "letterSpacing", cssName: "letter-spacing", defaultValue: 0, affectsLayout: isIOS, valueConverter: v => parseFloat(v) });
|
||||||
letterSpacingProperty.register(Style);
|
letterSpacingProperty.register(Style);
|
||||||
|
|
||||||
export const lineHeightProperty = new CssProperty<Style, number>({ name: "lineHeight", cssName: "line-height", affectsLayout: isIOS, valueConverter: v => parseFloat(v) });
|
export const lineHeightProperty = new InheritedCssProperty<Style, number>({ name: "lineHeight", cssName: "line-height", affectsLayout: isIOS, valueConverter: v => parseFloat(v) });
|
||||||
lineHeightProperty.register(Style);
|
lineHeightProperty.register(Style);
|
||||||
|
|
||||||
export const resetSymbol = Symbol("textPropertyDefault");
|
export const resetSymbol = Symbol("textPropertyDefault");
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Types
|
// Types
|
||||||
import { TextTransformation, TextDecoration, TextAlignment, TextTransform, WhiteSpace } from "./text-base-common";
|
import { TextTransformation, TextDecoration, TextAlignment, TextTransform, WhiteSpace, getClosestPropertyValue } from "./text-base-common";
|
||||||
|
|
||||||
// Requires
|
// Requires
|
||||||
import { Font } from "../styling/font";
|
import { Font } from "../styling/font";
|
||||||
@ -33,7 +33,7 @@ function initializeTextTransformation(): void {
|
|||||||
// NOTE: Do we need to transform the new text here?
|
// NOTE: Do we need to transform the new text here?
|
||||||
const formattedText = this.textBase.formattedText;
|
const formattedText = this.textBase.formattedText;
|
||||||
if (formattedText) {
|
if (formattedText) {
|
||||||
return createSpannableStringBuilder(formattedText);
|
return createSpannableStringBuilder(formattedText, (<android.widget.TextView>view).getTextSize());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const text = this.textBase.text;
|
const text = this.textBase.text;
|
||||||
@ -170,7 +170,7 @@ export class TextBase extends TextBaseCommon {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const spannableStringBuilder = createSpannableStringBuilder(value);
|
const spannableStringBuilder = createSpannableStringBuilder(value, this.style.fontSize);
|
||||||
nativeView.setText(<any>spannableStringBuilder);
|
nativeView.setText(<any>spannableStringBuilder);
|
||||||
this._setTappableState(isStringTappable(value));
|
this._setTappableState(isStringTappable(value));
|
||||||
|
|
||||||
@ -265,10 +265,11 @@ export class TextBase extends TextBaseCommon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[lineHeightProperty.getDefault](): number {
|
[lineHeightProperty.getDefault](): number {
|
||||||
return this.nativeTextViewProtected.getLineSpacingExtra() / layout.getDisplayDensity();
|
return this.nativeTextViewProtected.getLineHeight() / layout.getDisplayDensity();
|
||||||
}
|
}
|
||||||
[lineHeightProperty.setNative](value: number) {
|
[lineHeightProperty.setNative](value: number) {
|
||||||
this.nativeTextViewProtected.setLineSpacing(value * layout.getDisplayDensity(), 1);
|
const fontHeight = this.nativeTextViewProtected.getPaint().getFontMetricsInt(null);
|
||||||
|
this.nativeTextViewProtected.setLineSpacing(Math.max(value - fontHeight, 0) * layout.getDisplayDensity(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
[fontInternalProperty.getDefault](): android.graphics.Typeface {
|
[fontInternalProperty.getDefault](): android.graphics.Typeface {
|
||||||
@ -348,7 +349,7 @@ export class TextBase extends TextBaseCommon {
|
|||||||
|
|
||||||
let transformedText: any;
|
let transformedText: any;
|
||||||
if (this.formattedText) {
|
if (this.formattedText) {
|
||||||
transformedText = createSpannableStringBuilder(this.formattedText);
|
transformedText = createSpannableStringBuilder(this.formattedText, this.style.fontSize);
|
||||||
} else {
|
} else {
|
||||||
const text = this.text;
|
const text = this.text;
|
||||||
const stringValue = (text === null || text === undefined) ? "" : text.toString();
|
const stringValue = (text === null || text === undefined) ? "" : text.toString();
|
||||||
@ -415,7 +416,7 @@ function isStringTappable(formattedString: FormattedString) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createSpannableStringBuilder(formattedString: FormattedString): android.text.SpannableStringBuilder {
|
function createSpannableStringBuilder(formattedString: FormattedString, defaultFontSize: number): android.text.SpannableStringBuilder {
|
||||||
if (!formattedString || !formattedString.parent) {
|
if (!formattedString || !formattedString.parent) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -433,7 +434,7 @@ function createSpannableStringBuilder(formattedString: FormattedString): android
|
|||||||
spanLength = spanText.length;
|
spanLength = spanText.length;
|
||||||
if (spanLength > 0) {
|
if (spanLength > 0) {
|
||||||
ssb.insert(spanStart, spanText);
|
ssb.insert(spanStart, spanText);
|
||||||
setSpanModifiers(ssb, span, spanStart, spanStart + spanLength);
|
setSpanModifiers(ssb, span, spanStart, spanStart + spanLength, defaultFontSize);
|
||||||
spanStart += spanLength;
|
spanStart += spanLength;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -441,10 +442,67 @@ function createSpannableStringBuilder(formattedString: FormattedString): android
|
|||||||
return ssb;
|
return ssb;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setSpanModifiers(ssb: android.text.SpannableStringBuilder, span: Span, start: number, end: number): void {
|
class BaselineAdjustedSpan extends android.text.style.MetricAffectingSpan {
|
||||||
|
fontSize: number;
|
||||||
|
align: string | number = "baseline";
|
||||||
|
|
||||||
|
constructor(fontSize: number, align?: string | number) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.align = align;
|
||||||
|
this.fontSize = fontSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDrawState(paint: android.text.TextPaint) {
|
||||||
|
this.updateState(paint);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateMeasureState(paint: android.text.TextPaint) {
|
||||||
|
this.updateState(paint);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateState(paint: android.text.TextPaint) {
|
||||||
|
const metrics = paint.getFontMetrics();
|
||||||
|
|
||||||
|
if (!this.align || this.align === "baseline") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.align === "top") {
|
||||||
|
return paint.baselineShift = -this.fontSize - metrics.bottom - metrics.top;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.align === "bottom") {
|
||||||
|
return paint.baselineShift = metrics.bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.align === "text-top") {
|
||||||
|
return paint.baselineShift = -this.fontSize - metrics.descent - metrics.ascent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.align === "text-bottom") {
|
||||||
|
return paint.baselineShift = metrics.bottom - metrics.descent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.align === "middle") {
|
||||||
|
return paint.baselineShift = (metrics.descent - metrics.ascent) / 2 - metrics.descent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.align === "super") {
|
||||||
|
return paint.baselineShift = -this.fontSize * .4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.align === "sub") {
|
||||||
|
return paint.baselineShift = (metrics.descent - metrics.ascent) * .4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setSpanModifiers(ssb: android.text.SpannableStringBuilder, span: Span, start: number, end: number, defaultFontSize: number): void {
|
||||||
const spanStyle = span.style;
|
const spanStyle = span.style;
|
||||||
const bold = isBold(spanStyle.fontWeight);
|
const bold = isBold(spanStyle.fontWeight);
|
||||||
const italic = spanStyle.fontStyle === "italic";
|
const italic = spanStyle.fontStyle === "italic";
|
||||||
|
const align = spanStyle.verticalAlignment;
|
||||||
|
|
||||||
if (bold && italic) {
|
if (bold && italic) {
|
||||||
ssb.setSpan(new android.text.style.StyleSpan(android.graphics.Typeface.BOLD_ITALIC), start, end, android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
ssb.setSpan(new android.text.style.StyleSpan(android.graphics.Typeface.BOLD_ITALIC), start, end, android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
@ -474,45 +532,30 @@ function setSpanModifiers(ssb: android.text.SpannableStringBuilder, span: Span,
|
|||||||
ssb.setSpan(new android.text.style.ForegroundColorSpan(color.android), start, end, android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
ssb.setSpan(new android.text.style.ForegroundColorSpan(color.android), start, end, android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
let backgroundColor: Color;
|
const backgroundColor: Color = getClosestPropertyValue(backgroundColorProperty, span);
|
||||||
if (backgroundColorProperty.isSet(spanStyle)) {
|
|
||||||
backgroundColor = spanStyle.backgroundColor;
|
|
||||||
} else if (backgroundColorProperty.isSet(span.parent.style)) {
|
|
||||||
// parent is FormattedString
|
|
||||||
backgroundColor = span.parent.style.backgroundColor;
|
|
||||||
} else if (backgroundColorProperty.isSet(span.parent.parent.style)) {
|
|
||||||
// parent.parent is TextBase
|
|
||||||
backgroundColor = span.parent.parent.style.backgroundColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (backgroundColor) {
|
if (backgroundColor) {
|
||||||
ssb.setSpan(new android.text.style.BackgroundColorSpan(backgroundColor.android), start, end, android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
ssb.setSpan(new android.text.style.BackgroundColorSpan(backgroundColor.android), start, end, android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
let valueSource: typeof spanStyle;
|
const textDecoration: TextDecoration = getClosestPropertyValue(textDecorationProperty, span);
|
||||||
if (textDecorationProperty.isSet(spanStyle)) {
|
|
||||||
valueSource = spanStyle;
|
|
||||||
} else if (textDecorationProperty.isSet(span.parent.style)) {
|
|
||||||
// span.parent is FormattedString
|
|
||||||
valueSource = span.parent.style;
|
|
||||||
} else if (textDecorationProperty.isSet(span.parent.parent.style)) {
|
|
||||||
// span.parent.parent is TextBase
|
|
||||||
valueSource = span.parent.parent.style;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (valueSource) {
|
if (textDecoration) {
|
||||||
const textDecorations = valueSource.textDecoration;
|
const underline = textDecoration.indexOf("underline") !== -1;
|
||||||
const underline = textDecorations.indexOf("underline") !== -1;
|
|
||||||
if (underline) {
|
if (underline) {
|
||||||
ssb.setSpan(new android.text.style.UnderlineSpan(), start, end, android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
ssb.setSpan(new android.text.style.UnderlineSpan(), start, end, android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
const strikethrough = textDecorations.indexOf("line-through") !== -1;
|
const strikethrough = textDecoration.indexOf("line-through") !== -1;
|
||||||
if (strikethrough) {
|
if (strikethrough) {
|
||||||
ssb.setSpan(new android.text.style.StrikethroughSpan(), start, end, android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
ssb.setSpan(new android.text.style.StrikethroughSpan(), start, end, android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (align) {
|
||||||
|
ssb.setSpan(new BaselineAdjustedSpan(defaultFontSize * layout.getDisplayDensity(), align), start, end, android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
}
|
||||||
|
|
||||||
const tappable = span.tappable;
|
const tappable = span.tappable;
|
||||||
if (tappable) {
|
if (tappable) {
|
||||||
initializeClickableSpan();
|
initializeClickableSpan();
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
// Types
|
// Types
|
||||||
import { TextDecoration, TextAlignment, TextTransform } from "./text-base-common";
|
import { TextDecoration, TextAlignment, TextTransform, layout, getClosestPropertyValue } from "./text-base-common";
|
||||||
|
|
||||||
// Requires
|
// Requires
|
||||||
import { Font } from "../styling/font";
|
import { Font } from "../styling/font";
|
||||||
import {
|
import {
|
||||||
TextBaseCommon, textProperty, formattedTextProperty, textAlignmentProperty, textDecorationProperty,
|
TextBaseCommon, textProperty, formattedTextProperty, textAlignmentProperty, textDecorationProperty,
|
||||||
textTransformProperty, letterSpacingProperty, colorProperty, fontInternalProperty, lineHeightProperty,
|
textTransformProperty, letterSpacingProperty, colorProperty, fontInternalProperty, lineHeightProperty,
|
||||||
FormattedString, Span, Color, isBold, resetSymbol
|
FormattedString, Span, Color, resetSymbol
|
||||||
} from "./text-base-common";
|
} from "./text-base-common";
|
||||||
import { isString } from "../../utils/types";
|
import { isString } from "../../utils/types";
|
||||||
import { ios } from "../../utils/utils";
|
import { ios } from "../../utils/utils";
|
||||||
|
import { Property } from "../core/properties/properties";
|
||||||
|
|
||||||
export * from "./text-base-common";
|
export * from "./text-base-common";
|
||||||
|
|
||||||
@ -229,7 +230,7 @@ export class TextBase extends TextBaseCommon {
|
|||||||
|
|
||||||
if (this.style.lineHeight) {
|
if (this.style.lineHeight) {
|
||||||
const paragraphStyle = NSMutableParagraphStyle.alloc().init();
|
const paragraphStyle = NSMutableParagraphStyle.alloc().init();
|
||||||
paragraphStyle.lineSpacing = this.lineHeight;
|
paragraphStyle.minimumLineHeight = this.lineHeight;
|
||||||
// make sure a possible previously set text alignment setting is not lost when line height is specified
|
// make sure a possible previously set text alignment setting is not lost when line height is specified
|
||||||
if (this.nativeTextViewProtected instanceof UIButton) {
|
if (this.nativeTextViewProtected instanceof UIButton) {
|
||||||
paragraphStyle.alignment = (<UIButton>this.nativeTextViewProtected).titleLabel.textAlignment;
|
paragraphStyle.alignment = (<UIButton>this.nativeTextViewProtected).titleLabel.textAlignment;
|
||||||
@ -280,12 +281,15 @@ export class TextBase extends TextBaseCommon {
|
|||||||
throw new Error(`Invalid text decoration value: ${style.textDecoration}. Valid values are: 'none', 'underline', 'line-through', 'underline line-through'.`);
|
throw new Error(`Invalid text decoration value: ${style.textDecoration}. Valid values are: 'none', 'underline', 'line-through', 'underline line-through'.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (style.letterSpacing !== 0) {
|
if (style.letterSpacing !== 0 && this.nativeTextViewProtected.font) {
|
||||||
const kern = style.letterSpacing * this.nativeTextViewProtected.font.pointSize
|
const kern = style.letterSpacing * this.nativeTextViewProtected.font.pointSize
|
||||||
dict.set(NSKernAttributeName, kern);
|
dict.set(NSKernAttributeName, kern);
|
||||||
if (this.nativeTextViewProtected instanceof UITextField) {
|
}
|
||||||
this.nativeTextViewProtected.defaultTextAttributes.setObjectForKey(kern, NSKernAttributeName);
|
|
||||||
}
|
if (style.color) {
|
||||||
|
dict.set(NSForegroundColorAttributeName, style.color.ios);
|
||||||
|
} else if (majorVersion >= 13 && UIColor.labelColor) {
|
||||||
|
dict.set(NSForegroundColorAttributeName, UIColor.labelColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
const isTextView = this.nativeTextViewProtected instanceof UITextView;
|
const isTextView = this.nativeTextViewProtected instanceof UITextView;
|
||||||
@ -310,19 +314,9 @@ export class TextBase extends TextBaseCommon {
|
|||||||
dict.set(NSParagraphStyleAttributeName, paragraphStyle);
|
dict.set(NSParagraphStyleAttributeName, paragraphStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const source = getTransformedText(this.text ? this.text.toString() : "", this.textTransform);
|
||||||
if (dict.size > 0 || isTextView) {
|
if (dict.size > 0 || isTextView) {
|
||||||
if (style.color) {
|
if (isTextView && this.nativeTextViewProtected.font) {
|
||||||
dict.set(NSForegroundColorAttributeName, style.color.ios);
|
|
||||||
} else if (majorVersion >= 13 && UIColor.labelColor) {
|
|
||||||
dict.set(NSForegroundColorAttributeName, UIColor.labelColor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const text = this.text;
|
|
||||||
const string = (text === undefined || text === null) ? "" : text.toString();
|
|
||||||
const source = getTransformedText(string, this.textTransform);
|
|
||||||
if (dict.size > 0 || isTextView) {
|
|
||||||
if (isTextView) {
|
|
||||||
// UITextView's font seems to change inside.
|
// UITextView's font seems to change inside.
|
||||||
dict.set(NSFontAttributeName, this.nativeTextViewProtected.font);
|
dict.set(NSFontAttributeName, this.nativeTextViewProtected.font);
|
||||||
}
|
}
|
||||||
@ -370,59 +364,81 @@ export class TextBase extends TextBaseCommon {
|
|||||||
return mas;
|
return mas;
|
||||||
}
|
}
|
||||||
|
|
||||||
createMutableStringForSpan(span: Span, text: string): NSMutableAttributedString {
|
getBaselineOffset(font: UIFont, align?: string | number): number {
|
||||||
const viewFont = this.nativeTextViewProtected.font;
|
if (!align || align === "baseline") {
|
||||||
let attrDict = <{ key: string, value: any }>{};
|
return 0;
|
||||||
const style = span.style;
|
|
||||||
const bold = isBold(style.fontWeight);
|
|
||||||
const italic = style.fontStyle === "italic";
|
|
||||||
|
|
||||||
let fontFamily = span.fontFamily;
|
|
||||||
let fontSize = span.fontSize;
|
|
||||||
|
|
||||||
if (bold || italic || fontFamily || fontSize) {
|
|
||||||
let font = new Font(style.fontFamily, style.fontSize, style.fontStyle, style.fontWeight);
|
|
||||||
let iosFont = font.getUIFont(viewFont);
|
|
||||||
attrDict[NSFontAttributeName] = iosFont;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const color = span.color;
|
if (align === "top") {
|
||||||
if (color) {
|
return -this.fontSize - font.descender - font.ascender - font.leading / 2;
|
||||||
attrDict[NSForegroundColorAttributeName] = color.ios;
|
}
|
||||||
|
|
||||||
|
if (align === "bottom") {
|
||||||
|
return font.descender + font.leading / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (align === "text-top") {
|
||||||
|
return -this.fontSize - font.descender - font.ascender;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (align === "text-bottom") {
|
||||||
|
return font.descender;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (align === "middle") {
|
||||||
|
return (font.descender - font.ascender) / 2 - font.descender;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (align === "super") {
|
||||||
|
return -this.fontSize * .4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (align === "sub") {
|
||||||
|
return (font.descender - font.ascender) * .4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createMutableStringForSpan(span: Span, text: string): NSMutableAttributedString {
|
||||||
|
const viewFont = this.nativeTextViewProtected.font;
|
||||||
|
const attrDict = <{ key: string, value: any }>{};
|
||||||
|
const style = span.style;
|
||||||
|
const align = style.verticalAlignment;
|
||||||
|
|
||||||
|
const font = new Font(style.fontFamily, style.fontSize, style.fontStyle, style.fontWeight);
|
||||||
|
const iosFont = font.getUIFont(viewFont);
|
||||||
|
|
||||||
|
attrDict[NSFontAttributeName] = iosFont;
|
||||||
|
|
||||||
|
if (span.color) {
|
||||||
|
attrDict[NSForegroundColorAttributeName] = span.color.ios;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't use isSet function here because defaultValue for backgroundColor is null.
|
// We don't use isSet function here because defaultValue for backgroundColor is null.
|
||||||
const backgroundColor = <Color>(style.backgroundColor
|
const backgroundColor = <Color>(style.backgroundColor
|
||||||
|| (<FormattedString>span.parent).backgroundColor
|
|| (<FormattedString>span.parent).backgroundColor
|
||||||
|| (<TextBase>(<FormattedString>span.parent).parent).backgroundColor);
|
|| (<TextBase>span.parent.parent).backgroundColor);
|
||||||
if (backgroundColor) {
|
if (backgroundColor) {
|
||||||
attrDict[NSBackgroundColorAttributeName] = backgroundColor.ios;
|
attrDict[NSBackgroundColorAttributeName] = backgroundColor.ios;
|
||||||
}
|
}
|
||||||
|
|
||||||
let valueSource: typeof style;
|
const textDecoration: TextDecoration = getClosestPropertyValue(textDecorationProperty, span);
|
||||||
if (textDecorationProperty.isSet(style)) {
|
|
||||||
valueSource = style;
|
|
||||||
} else if (textDecorationProperty.isSet(span.parent.style)) {
|
|
||||||
// span.parent is FormattedString
|
|
||||||
valueSource = span.parent.style;
|
|
||||||
} else if (textDecorationProperty.isSet(span.parent.parent.style)) {
|
|
||||||
// span.parent.parent is TextBase
|
|
||||||
valueSource = span.parent.parent.style;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (valueSource) {
|
if (textDecoration) {
|
||||||
const textDecorations = valueSource.textDecoration;
|
const underline = textDecoration.indexOf("underline") !== -1;
|
||||||
const underline = textDecorations.indexOf("underline") !== -1;
|
|
||||||
if (underline) {
|
if (underline) {
|
||||||
attrDict[NSUnderlineStyleAttributeName] = underline;
|
attrDict[NSUnderlineStyleAttributeName] = underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
const strikethrough = textDecorations.indexOf("line-through") !== -1;
|
const strikethrough = textDecoration.indexOf("line-through") !== -1;
|
||||||
if (strikethrough) {
|
if (strikethrough) {
|
||||||
attrDict[NSStrikethroughStyleAttributeName] = strikethrough;
|
attrDict[NSStrikethroughStyleAttributeName] = strikethrough;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (align) {
|
||||||
|
attrDict[NSBaselineOffsetAttributeName] = this.getBaselineOffset(iosFont, align);
|
||||||
|
}
|
||||||
|
|
||||||
return NSMutableAttributedString.alloc().initWithStringAttributes(text, <any>attrDict);
|
return NSMutableAttributedString.alloc().initWithStringAttributes(text, <any>attrDict);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user