mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-26 11:17:04 +08:00
fix(android): Span should accept all font weight types
This commit is contained in:

committed by
Nathan Walker

parent
e545f5869c
commit
a21d4f94ac
@ -3,6 +3,8 @@ import { ParsedFont, FontStyleType, FontWeightType, FontVariationSettingsType }
|
||||
import { makeValidator, makeParser } from '../core/properties';
|
||||
import { Trace } from '../../trace';
|
||||
|
||||
export const FONTS_BASE_PATH = '/fonts/';
|
||||
|
||||
export abstract class Font implements FontDefinition {
|
||||
public static default = undefined;
|
||||
public readonly fontStyle: FontStyleType;
|
||||
@ -14,7 +16,7 @@ export abstract class Font implements FontDefinition {
|
||||
}
|
||||
|
||||
get isBold(): boolean {
|
||||
return this.fontWeight === FontWeight.SEMI_BOLD || this.fontWeight === FontWeight.BOLD || this.fontWeight === '700' || this.fontWeight === FontWeight.EXTRA_BOLD || this.fontWeight === FontWeight.BLACK;
|
||||
return isFontWeightBold(this.fontWeight);
|
||||
}
|
||||
|
||||
protected constructor(
|
||||
@ -137,6 +139,10 @@ export function parseFontFamily(value: string): Array<string> {
|
||||
.filter((v) => !!v);
|
||||
}
|
||||
|
||||
export function isFontWeightBold(fontWeight: FontWeightType): boolean {
|
||||
return fontWeight === FontWeight.SEMI_BOLD || fontWeight === FontWeight.BOLD || fontWeight === '700' || fontWeight === FontWeight.EXTRA_BOLD || fontWeight === FontWeight.BLACK;
|
||||
}
|
||||
|
||||
export namespace genericFontFamilies {
|
||||
export const serif = 'serif';
|
||||
export const sansSerif = 'sans-serif';
|
||||
@ -144,8 +150,7 @@ export namespace genericFontFamilies {
|
||||
export const system = 'system';
|
||||
}
|
||||
|
||||
const styles = new Set();
|
||||
[FontStyle.NORMAL, FontStyle.ITALIC].forEach((val, i, a) => styles.add(val));
|
||||
const styles = new Set<string>([FontStyle.NORMAL, FontStyle.ITALIC]);
|
||||
|
||||
// http://www.w3schools.com/cssref/pr_font_weight.asp
|
||||
//- normal(same as 400)
|
||||
@ -159,8 +164,7 @@ const styles = new Set();
|
||||
//- 700(Bold) (API16 -bold)
|
||||
//- 800(Extra Bold / Ultra Bold) (API16 -bold)
|
||||
//- 900(Black / Heavy) (API21 -black)
|
||||
const weights = new Set();
|
||||
[FontWeight.THIN, FontWeight.EXTRA_LIGHT, FontWeight.LIGHT, FontWeight.NORMAL, '400', FontWeight.MEDIUM, FontWeight.SEMI_BOLD, FontWeight.BOLD, '700', FontWeight.EXTRA_BOLD, FontWeight.BLACK].forEach((val, i, a) => weights.add(val));
|
||||
const weights = new Set<string>([FontWeight.THIN, FontWeight.EXTRA_LIGHT, FontWeight.LIGHT, FontWeight.NORMAL, '400', FontWeight.MEDIUM, FontWeight.SEMI_BOLD, FontWeight.BOLD, '700', FontWeight.EXTRA_BOLD, FontWeight.BLACK]);
|
||||
|
||||
export function parseFont(fontValue: string): ParsedFont {
|
||||
const result: ParsedFont = {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Font as FontBase, parseFontFamily, genericFontFamilies, FontWeight, FontVariationSettings } from './font-common';
|
||||
import { Font as FontBase, parseFontFamily, genericFontFamilies, FontWeight, FontVariationSettings, FONTS_BASE_PATH } from './font-common';
|
||||
import { FontStyleType, FontWeightType, FontVariationSettingsType } from './font-interfaces';
|
||||
import { Trace } from '../../trace';
|
||||
import { SDK_VERSION } from '../../utils/constants';
|
||||
@ -7,7 +7,6 @@ import { ad } from '../../utils';
|
||||
|
||||
export * from './font-common';
|
||||
|
||||
const FONTS_BASE_PATH = '/fonts/';
|
||||
const typefaceCache = new Map<string, android.graphics.Typeface>();
|
||||
let appAssets: android.content.res.AssetManager;
|
||||
|
||||
@ -66,24 +65,28 @@ function loadFontFromFile(fontFamily: string, font: Font): android.graphics.Type
|
||||
return null;
|
||||
}
|
||||
|
||||
let result = typefaceCache.get(cacheKey);
|
||||
// Check for undefined explicitly as null mean we tried to load the font, but failed.
|
||||
if (result === undefined) {
|
||||
result = null;
|
||||
let result: android.graphics.Typeface;
|
||||
|
||||
if (typefaceCache.has(cacheKey)) {
|
||||
result = typefaceCache.get(cacheKey);
|
||||
} else {
|
||||
const basePath = fs.path.join(fs.knownFolders.currentApp().path, FONTS_BASE_PATH, fontFamily);
|
||||
|
||||
let fontAssetPath: string;
|
||||
const basePath = fs.path.join(fs.knownFolders.currentApp().path, 'fonts', fontFamily);
|
||||
|
||||
if (fs.File.exists(basePath + '.ttf')) {
|
||||
fontAssetPath = FONTS_BASE_PATH + fontFamily + '.ttf';
|
||||
fontAssetPath = basePath + '.ttf';
|
||||
} else if (fs.File.exists(basePath + '.otf')) {
|
||||
fontAssetPath = FONTS_BASE_PATH + fontFamily + '.otf';
|
||||
fontAssetPath = basePath + '.otf';
|
||||
} else if (Trace.isEnabled()) {
|
||||
fontAssetPath = null;
|
||||
Trace.write('Could not find font file for ' + fontFamily, Trace.categories.Error, Trace.messageType.error);
|
||||
}
|
||||
|
||||
result = null; // Default
|
||||
|
||||
if (fontAssetPath) {
|
||||
try {
|
||||
fontAssetPath = fs.path.join(fs.knownFolders.currentApp().path, fontAssetPath);
|
||||
if (SDK_VERSION >= 26) {
|
||||
const builder = new android.graphics.Typeface.Builder(fontAssetPath);
|
||||
if (builder) {
|
||||
@ -104,6 +107,8 @@ function loadFontFromFile(fontFamily: string, font: Font): android.graphics.Type
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The value might be null if there has already been an attempt to load the font but failed
|
||||
typefaceCache.set(cacheKey, result);
|
||||
}
|
||||
|
||||
@ -111,7 +116,18 @@ function loadFontFromFile(fontFamily: string, font: Font): android.graphics.Type
|
||||
}
|
||||
|
||||
function createTypeface(font: Font): android.graphics.Typeface {
|
||||
let fontStyle = 0;
|
||||
const fontFamilies = parseFontFamily(font.fontFamily);
|
||||
const fontWeight = font.fontWeight;
|
||||
const supportsFontWeight = SDK_VERSION > 27;
|
||||
|
||||
let result: android.graphics.Typeface;
|
||||
let fontStyle: number = 0;
|
||||
// https://stackoverflow.com/questions/19691530/valid-values-for-androidfontfamily-and-what-they-map-to
|
||||
let fontSuffix: string;
|
||||
|
||||
if (supportsFontWeight) {
|
||||
fontSuffix = '';
|
||||
} else {
|
||||
if (font.isBold) {
|
||||
fontStyle |= android.graphics.Typeface.BOLD;
|
||||
}
|
||||
@ -119,20 +135,20 @@ function createTypeface(font: Font): android.graphics.Typeface {
|
||||
fontStyle |= android.graphics.Typeface.ITALIC;
|
||||
}
|
||||
|
||||
//http://stackoverflow.com/questions/19691530/valid-values-for-androidfontfamily-and-what-they-map-to
|
||||
const fontFamilies = parseFontFamily(font.fontFamily);
|
||||
let result: android.graphics.Typeface = null;
|
||||
fontSuffix = getFontWeightSuffix(fontWeight);
|
||||
}
|
||||
|
||||
for (const fontFamily of fontFamilies) {
|
||||
switch (fontFamily.toLowerCase()) {
|
||||
case genericFontFamilies.serif:
|
||||
result = android.graphics.Typeface.create('serif' + getFontWeightSuffix(font.fontWeight), fontStyle);
|
||||
result = android.graphics.Typeface.create('serif' + fontSuffix, fontStyle);
|
||||
break;
|
||||
case genericFontFamilies.sansSerif:
|
||||
case genericFontFamilies.system:
|
||||
result = android.graphics.Typeface.create('sans-serif' + getFontWeightSuffix(font.fontWeight), fontStyle);
|
||||
result = android.graphics.Typeface.create('sans-serif' + fontSuffix, fontStyle);
|
||||
break;
|
||||
case genericFontFamilies.monospace:
|
||||
result = android.graphics.Typeface.create('monospace' + getFontWeightSuffix(font.fontWeight), fontStyle);
|
||||
result = android.graphics.Typeface.create('monospace' + fontSuffix, fontStyle);
|
||||
break;
|
||||
default: {
|
||||
result = loadFontFromFile(fontFamily, font);
|
||||
@ -143,14 +159,19 @@ function createTypeface(font: Font): android.graphics.Typeface {
|
||||
}
|
||||
}
|
||||
|
||||
if (result) {
|
||||
// Found the font!
|
||||
if (result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
result = android.graphics.Typeface.create('sans-serif' + getFontWeightSuffix(font.fontWeight), fontStyle);
|
||||
result = android.graphics.Typeface.create('sans-serif' + fontSuffix, fontStyle);
|
||||
}
|
||||
|
||||
// Newer versions can accept a specific font weight number
|
||||
if (supportsFontWeight) {
|
||||
result = android.graphics.Typeface.create(result, getFontWeightNumber(fontWeight), font.isItalic);
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -184,3 +205,27 @@ function getFontWeightSuffix(fontWeight: FontWeightType): string {
|
||||
throw new Error(`Invalid font weight: "${fontWeight}"`);
|
||||
}
|
||||
}
|
||||
|
||||
function getFontWeightNumber(fontWeight: FontWeightType): number {
|
||||
let value: number;
|
||||
|
||||
if (typeof fontWeight === 'number') {
|
||||
value = fontWeight;
|
||||
} else {
|
||||
switch (fontWeight) {
|
||||
case FontWeight.NORMAL:
|
||||
case undefined:
|
||||
case null:
|
||||
value = 400;
|
||||
break;
|
||||
case FontWeight.BOLD:
|
||||
value = 700;
|
||||
break;
|
||||
default:
|
||||
value = parseInt(fontWeight);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
3
packages/core/ui/styling/font.d.ts
vendored
3
packages/core/ui/styling/font.d.ts
vendored
@ -1,6 +1,8 @@
|
||||
import { Font as FontBase } from './font-common';
|
||||
export type { FontStyleType, FontWeightType, ParsedFont, FontVariationSettingsType } from './font-interfaces';
|
||||
|
||||
export const FONTS_BASE_PATH = '/fonts/';
|
||||
|
||||
export declare class Font extends FontBase {
|
||||
public static default: Font;
|
||||
|
||||
@ -56,6 +58,7 @@ export namespace FontVariationSettings {
|
||||
}
|
||||
|
||||
export function parseFont(fontValue: string): ParsedFont;
|
||||
export function isFontWeightBold(fontWeight: FontWeightType): boolean;
|
||||
|
||||
export namespace ios {
|
||||
export function registerFont(fontFile: string);
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Font as FontBase, parseFontFamily, FontWeight, FontVariationSettings, fuzzySearch } from './font-common';
|
||||
import { Font as FontBase, parseFontFamily, FontWeight, FontVariationSettings, fuzzySearch, FONTS_BASE_PATH } from './font-common';
|
||||
import { FontStyleType, FontWeightType, FontVariationSettingsType } from './font-interfaces';
|
||||
import { Trace } from '../../trace';
|
||||
import * as fs from '../../file-system';
|
||||
@ -115,10 +115,9 @@ export class Font extends FontBase {
|
||||
}
|
||||
|
||||
function getNativeFontWeight(fontWeight: FontWeightType): number {
|
||||
if (typeof fontWeight === 'number') {
|
||||
fontWeight = (fontWeight + '') as any;
|
||||
}
|
||||
switch (fontWeight) {
|
||||
const value = typeof fontWeight === 'number' ? fontWeight + '' : fontWeight;
|
||||
|
||||
switch (value) {
|
||||
case FontWeight.THIN:
|
||||
return UIFontWeightUltraLight;
|
||||
case FontWeight.EXTRA_LIGHT:
|
||||
@ -148,7 +147,7 @@ function getNativeFontWeight(fontWeight: FontWeightType): number {
|
||||
|
||||
export namespace ios {
|
||||
export function registerFont(fontFile: string) {
|
||||
let filePath = fs.path.join(fs.knownFolders.currentApp().path, 'fonts', fontFile);
|
||||
let filePath = fs.path.join(fs.knownFolders.currentApp().path, FONTS_BASE_PATH, fontFile);
|
||||
if (!fs.File.exists(filePath)) {
|
||||
filePath = fs.path.join(fs.knownFolders.currentApp().path, fontFile);
|
||||
}
|
||||
@ -179,7 +178,8 @@ function registerFontsInFolder(fontsFolderPath) {
|
||||
if (fs.Folder.exists(fs.path.join(fontsFolderPath, fileEntity.name))) {
|
||||
return true;
|
||||
}
|
||||
if (fileEntity instanceof fs.File && ((<fs.File>fileEntity).extension === '.ttf' || (<fs.File>fileEntity).extension === '.otf')) {
|
||||
|
||||
if (fileEntity instanceof fs.File && (fileEntity.extension === '.ttf' || fileEntity.extension === '.otf')) {
|
||||
ios.registerFont(fileEntity.name);
|
||||
}
|
||||
|
||||
@ -189,7 +189,7 @@ function registerFontsInFolder(fontsFolderPath) {
|
||||
|
||||
function registerCustomFonts() {
|
||||
const appDir = fs.knownFolders.currentApp().path;
|
||||
const fontsDir = fs.path.join(appDir, 'fonts');
|
||||
const fontsDir = fs.path.join(appDir, FONTS_BASE_PATH);
|
||||
if (fs.Folder.exists(fontsDir)) {
|
||||
registerFontsInFolder(fontsDir);
|
||||
}
|
||||
|
@ -3,9 +3,9 @@ import { getClosestPropertyValue, maxLinesProperty, textOverflowProperty } from
|
||||
import { ShadowCSSValues } from '../styling/css-shadow';
|
||||
|
||||
// Requires
|
||||
import { Font } from '../styling/font';
|
||||
import { Font, isFontWeightBold } from '../styling/font';
|
||||
import { backgroundColorProperty } from '../styling/style-properties';
|
||||
import { TextBaseCommon, formattedTextProperty, textAlignmentProperty, textDecorationProperty, textProperty, textTransformProperty, textShadowProperty, textStrokeProperty, letterSpacingProperty, whiteSpaceProperty, lineHeightProperty, isBold, resetSymbol } from './text-base-common';
|
||||
import { TextBaseCommon, formattedTextProperty, textAlignmentProperty, textDecorationProperty, textProperty, textTransformProperty, textShadowProperty, textStrokeProperty, letterSpacingProperty, whiteSpaceProperty, lineHeightProperty, resetSymbol } from './text-base-common';
|
||||
import { Color } from '../../color';
|
||||
import { colorProperty, fontSizeProperty, fontInternalProperty, paddingLeftProperty, paddingTopProperty, paddingRightProperty, paddingBottomProperty, Length } from '../styling/style-properties';
|
||||
import { StrokeCSSValues } from '../styling/css-stroke';
|
||||
@ -593,10 +593,11 @@ function createSpannableStringBuilder(formattedString: FormattedString, defaultF
|
||||
|
||||
function setSpanModifiers(ssb: android.text.SpannableStringBuilder, span: Span, start: number, end: number, defaultFontSize: number): void {
|
||||
const spanStyle = span.style;
|
||||
const bold = isBold(spanStyle.fontWeight);
|
||||
const bold = isFontWeightBold(spanStyle.fontWeight);
|
||||
const italic = spanStyle.fontStyle === 'italic';
|
||||
const align = spanStyle.verticalAlignment;
|
||||
|
||||
// We set font style using StyleSpan in case the font doesn't support font styles
|
||||
if (bold && italic) {
|
||||
ssb.setSpan(new android.text.style.StyleSpan(android.graphics.Typeface.BOLD_ITALIC), start, end, android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
} else if (bold) {
|
||||
@ -607,7 +608,7 @@ function setSpanModifiers(ssb: android.text.SpannableStringBuilder, span: Span,
|
||||
|
||||
const fontFamily = span.fontFamily;
|
||||
if (fontFamily) {
|
||||
const font = new Font(fontFamily, 0, italic ? 'italic' : 'normal', bold ? 'bold' : 'normal', spanStyle.fontScaleInternal, spanStyle.fontVariationSettings);
|
||||
const font = new Font(fontFamily, 0, spanStyle.fontStyle, spanStyle.fontWeight, spanStyle.fontScaleInternal, spanStyle.fontVariationSettings);
|
||||
const typeface = font.getAndroidTypeface() || android.graphics.Typeface.create(fontFamily, 0);
|
||||
const typefaceSpan: android.text.style.TypefaceSpan = new org.nativescript.widgets.CustomTypefaceSpan(fontFamily, typeface);
|
||||
ssb.setSpan(typefaceSpan, start, end, android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
|
@ -224,10 +224,6 @@ export abstract class TextBaseCommon extends View implements TextBaseDefinition
|
||||
|
||||
TextBaseCommon.prototype._isSingleLine = false;
|
||||
|
||||
export function isBold(fontWeight: FontWeightType): boolean {
|
||||
return fontWeight === 'bold' || fontWeight === '700' || fontWeight === '800' || fontWeight === '900';
|
||||
}
|
||||
|
||||
export const textProperty = new Property<TextBaseCommon, string>({
|
||||
name: 'text',
|
||||
defaultValue: '',
|
||||
|
Reference in New Issue
Block a user