ArKTS: font
/** # encoding: utf-8 # 版权所有 2025 ©涂聚文有限公司™ ® # 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎 # 描述: # Author : geovindu,Geovin Du 涂聚文. # IDE : DevEco Studio 5.1.1 HarmonyOS ArKTS # os : windows 10 # database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j # Datetime : 2025/8/9 5:22 # User : geovindu # Product : DevEco Studio # Project : sqliteAppHelper # File : DuNodeController.ets **/ import { NodeController, FrameNode, RenderNode, DrawContext } from '@kit.ArkUI' import { UIContext } from '@kit.ArkUI' import { text } from '@kit.ArkGraphics2D' /** * 自定义节点控制器类 */ export class DuNodeController extends NodeController { private rootNode: FrameNode | null = null; makeNode(uiContext: UIContext): FrameNode { this.rootNode = new FrameNode(uiContext) if (this.rootNode == null) { return this.rootNode } const renderNode = this.rootNode.getRenderNode() if (renderNode != null) { renderNode.frame = { x: 0, y: 0, width: 300, height: 50 } renderNode.pivot = { x: 0, y: 0 } } return this.rootNode } addNode(node: RenderNode): void { if (this.rootNode == null) { return } const renderNode = this.rootNode.getRenderNode() if (renderNode != null) { renderNode.appendChild(node) console.log('节点已添加到控制器'); } } clearNodes(): void { if (this.rootNode == null) { return } const renderNode = this.rootNode.getRenderNode() if (renderNode != null) { renderNode.clearChildren() } } } /** # encoding: utf-8 # 版权所有 2025 ©涂聚文有限公司™ ® # 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎 # 描述: # Author : geovindu,Geovin Du 涂聚文. # IDE : DevEco Studio 5.1.1 HarmonyOS ArKTS # os : windows 10 # database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j # Datetime : 2025/8/9 5:19 # User : geovindu ArkGraphics2D # Product : DevEco Studio # Project : sqliteAppHelper # File : DuRenderNode.ets **/ import { NodeController, FrameNode, RenderNode, DrawContext } from '@kit.ArkUI' import { UIContext } from '@kit.ArkUI' import { text } from '@kit.ArkGraphics2D' /** * 创建一个自定义的渲染节点类,用于绘制文本 */ export class DuRenderNode extends RenderNode { async draw(context: DrawContext) { // 创建画布canvas对象 const canvas = context.canvas // 获取全局字体集实例 let fontCollection = text.FontCollection.getGlobalInstance() //获取Arkui全局FC // 注册自定义字体 fontCollection.loadFontSync('myFamilyName', 'file:///system/fonts/NotoSansMalayalamUI-SemiBold.ttf') // 方式二:确保已经将自定义字体myFontFile.ttf文件放在本应用工程的entry/src/main/resources/rawfile目录 fontCollection.loadFontSync('mao',$rawfile('mao.ttf')) // 使用自定义字体 let myFontFamily: Array<string> = ["mao"] // 如果已经注册自定义字体,填入自定义字体的字体家族名 // 设置文本样式 let myTextStyle: text.TextStyle = { color: { alpha: 255, red: 255, green: 0, blue: 0 }, fontSize: 80, // 在文本样式中加入可使用的自定义字体 fontFamilies: myFontFamily }; // 创建一个段落样式对象,以设置排版风格 let myParagraphStyle: text.ParagraphStyle = { textStyle: myTextStyle, align: 3, wordBreak:text.WordBreak.NORMAL }; // 创建一个段落生成器 let ParagraphGraphBuilder = new text.ParagraphBuilder(myParagraphStyle, fontCollection) // 在段落生成器中设置文本样式 ParagraphGraphBuilder.pushStyle(myTextStyle); // 在段落生成器中设置文本内容 ParagraphGraphBuilder.addText("《沁园春·雪》\n" + "\n" + "作者:毛\n北国风光,千里冰封,万里雪飘。\n" + "\n" + "望长城内外,惟余莽莽;大河上下,顿失滔滔。\n" + "\n" + "山舞银蛇,原驰蜡象,欲与天公试比高。\n" + "\n" + "须晴日,看红装素裹,分外妖娆。\n" + "\n" + "江山如此多娇,引无数英雄竞折腰。\n" + "\n" + "惜秦皇汉武,略输文采;唐宗宋祖,稍逊风骚。\n" + "\n" + "一代天骄,成吉思汗,只识弯弓射大雕。\n" + "\n" + "俱往矣,数风流人物,还看今朝。"); // 通过段落生成器生成段落 let paragraph = ParagraphGraphBuilder.build(); // 设置段落宽度为1000px paragraph.layoutSync(1000); paragraph.paint(canvas, 0, 400); } }
/** # encoding: utf-8 # 版权所有 2025 ©涂聚文有限公司™ ® # 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎 # 描述: 自定义字体页面 # Author : geovindu,Geovin Du 涂聚文. # IDE : DevEco Studio 5.1.1 HarmonyOS ArKTS # os : windows 10 # database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j # Datetime : 2025/8/9 5:19 # User : geovindu # Product : DevEco Studio # Project : sqliteAppHelper # File : CustomFontPage.ets **/ import { NodeController, FrameNode, RenderNode, DrawContext } from '@kit.ArkUI' import { UIContext } from '@kit.ArkUI' import { text } from '@kit.ArkGraphics2D' import { DuNodeController } from "../utils/DuNodeController" import { DuRenderNode } from "../utils/DuRenderNode" // 创建并初始化渲染节点实例 const newNode = new DuRenderNode(); // 设置渲染节点的位置和尺寸 newNode.frame = { x: 0, y: 0, width: 400, height: 600 }; @Entry @Component struct MaoFontntPage { @State message: string = 'Hello Geovin Dui'; private Controller: DuNodeController = new DuNodeController() build() { Scroll() { Column() { Row() { NodeContainer(this.Controller) .height('100%') } .height('99%') .backgroundColor(Color.White) Row(){ Button("写字") .fontSize('16fp') .fontWeight(500) .margin({ bottom: 24, right: 12 }) .onClick(() => { this.Controller.clearNodes() this.Controller.addNode(newNode) }) .width('50%') .height(40) .shadow(ShadowStyle.OUTER_DEFAULT_LG) } .width('100%') .justifyContent(FlexAlign.Center) // 设置当前Row容器内子元素在主轴上居中对齐 .shadow(ShadowStyle.OUTER_DEFAULT_SM) // 设置Row容器外阴影效果 .alignItems(VerticalAlign.Bottom) // 设置当前Row容器内子元素在交叉轴(垂直方向)上的对齐方式为底部对齐 .layoutWeight(1) // 设置当前Row在父容器Column中的布局权重为1 } } } }
/** # encoding: utf-8 # 版权所有 2025 ©涂聚文有限公司™ ® # 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎 # 描述: 自定义字体页面 # Author : geovindu,Geovin Du 涂聚文. # IDE : DevEco Studio 5.1.1 HarmonyOS ArKTS # os : windows 10 # database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j # Datetime : 2025/8/9 5:19 # User : geovindu # Product : DevEco Studio # Project : sqliteAppHelper # File : CustomFontPage.ets **/ import { NodeController, FrameNode, RenderNode, DrawContext } from '@kit.ArkUI' import { UIContext } from '@kit.ArkUI' import { text } from '@kit.ArkGraphics2D' import { DuNodeController } from "../utils/DuNodeController" import { DuRenderNode } from "../utils/DuRenderNode" import font from '@ohos.font'; // 创建并初始化渲染节点实例 const newNode = new DuRenderNode(); // 设置渲染节点的位置和尺寸 newNode.frame = { x: 0, y: 0, width: 400, height: 600 }; @Entry @Component struct MaoFontntPage { @State message: string = 'Hello Geovin Dui'; aboutToAppear() { // familyName和familySrc都支持string font.registerFont({ familyName: 'maozedong', familySrc: 'font/maozedong.ttf',// font文件与pages目录同级 }) } private Controller: DuNodeController = new DuNodeController() build() { Scroll() { Column() { Row() { NodeContainer(this.Controller) .height('100%') } .height('99%') .backgroundColor(Color.White) Row(){ Button("写字") .fontSize('16fp') .fontWeight(500) .fontFamily('maozedong') .margin({ bottom: 24, right: 12 }) .onClick(() => { this.Controller.clearNodes() this.Controller.addNode(newNode) }) .width('50%') .height(40) .shadow(ShadowStyle.OUTER_DEFAULT_LG) } .width('100%') .justifyContent(FlexAlign.Center) // 设置当前Row容器内子元素在主轴上居中对齐 .shadow(ShadowStyle.OUTER_DEFAULT_SM) // 设置Row容器外阴影效果 .alignItems(VerticalAlign.Bottom) // 设置当前Row容器内子元素在交叉轴(垂直方向)上的对齐方式为底部对齐 .layoutWeight(1) // 设置当前Row在父容器Column中的布局权重为1 } } } }
项目结构:
/** # encoding: utf-8 # 版权所有 2025 ©涂聚文有限公司™ ® # 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎 # 描述: 自定义字体页面 https://developer.huawei.com/consumer/en/doc/harmonyos-references-V14/ts-canvasrenderingcontext2d-V14#font # Author : geovindu,Geovin Du 涂聚文. # IDE : DevEco Studio 5.1.1 HarmonyOS ArKTS # os : windows 10 # database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j # Datetime : 2025/8/9 5:19 # User : geovindu # Product : DevEco Studio # Project : sqliteAppHelper # File : CustomFontPage.ets **/ import promptAction from '@ohos.promptAction' import common from '@ohos.app.ability.common'; import { BusinessError } from '@ohos.base'; import { text } from '@kit.ArkGraphics2D'; import { AddFormMenuItem } from '@kit.ArkUI'; import { formBindingData } from '@kit.FormKit'; import { hilog } from '@kit.PerformanceAnalysisKit'; import font from '@ohos.font'; class TextTyper { private fullText: string = "《沁园春·雪》\n\n作者:毛\n北国风光,千里冰封,万里雪飘。\n\n望长城内外,惟余莽莽;大河上下,顿失滔滔。\n\n山舞银蛇,原驰蜡象,欲与天公试比高。\n\n须晴日,看红装素裹,分外妖娆。\n\n江山如此多娇,引无数英雄竞折腰。\n\n惜秦皇汉武,略输文采;唐宗宋祖,稍逊风骚。\n\n一代天骄,成吉思汗,只识弯弓射大雕。\n\n俱往矣,数风流人物,还看今朝。"; currentText: string = ""; currentIndex: number = 0; typingSpeed: number = 100; timerId: number | null = null; fontCollection: text.FontCollection; fontLoaded: boolean = false; fontName: string = 'maozedong'; fontPath: string = 'maozedong.ttf'; // 新增:字体文件信息校验 fontFileSize: number = 0; // 用于验证文件是否有效 constructor() { this.fontCollection = text.FontCollection.getGlobalInstance(); this.checkFontFileExists(); // 先检查文件是否可访问 this.loadCustomFont(); } // 关键:检查字体文件是否真的可访问 private async checkFontFileExists() { try { const context = getContext(this) as common.UIAbilityContext; // 尝试读取文件元数据判断是否存在 const fileInfo = context.resourceManager.getRawFile(this.fontPath); console.log(`[文件检查] 存在: ${this.fontPath}, 大小: ${this.fontFileSize}字节`); if (this.fontFileSize < 1024) { // 小于1KB的字体文件几乎肯定无效 promptAction.showToast({ message: `警告:字体文件过小,可能损坏` }); } } catch (error) { const err = error as BusinessError; console.error(`[文件检查] 不存在或无法访问: ${this.fontPath}, 错误: ${err.code}`); promptAction.showToast({ message: `文件访问失败: ${err.code}` }); } } // 优化的字体加载逻辑,增加格式兼容性处理 private async loadCustomFont() { // 先确保文件存在且有效 if (this.fontFileSize === 0) { console.log(`[字体加载] 跳过加载,文件无效`); return; } try { console.log(`[字体加载] 开始加载有效文件 (${this.fontFileSize}字节)`); // 尝试不同的字体加载方式 const loadResult = await this.fontCollection.loadFont( this.fontName, $rawfile(this.fontPath), ).then( () => { console.log(`[字体加载] 加载成功`); return true; }, (error:BusinessError) => { console.error(`[字体加载] 加载失败: ${error}`); return false; } ); this.fontLoaded = loadResult; console.log(`[字体加载] 加载结果: ${this.fontLoaded}`); // 加载成功但可能未生效的额外提示 if (this.fontLoaded) { promptAction.showToast({ message: `字体加载成功,若显示异常请尝试更换TTF文件` }); } else { promptAction.showToast({ message: `字体格式不兼容,请使用标准TTF` }); } } catch (error) { this.fontLoaded = false; const err = error as BusinessError; console.error(`[字体加载] 异常: ${err.code}-${err.message}`); // 常见错误码提示 const errorTips: Record<number, string> = { 13900002: "文件格式错误(非TTF)", 13900003: "文件损坏或加密", 13900004: "不支持的字体格式" }; const tip = errorTips[err.code] || `错误码: ${err.code}`; promptAction.showToast({ message: `加载失败: ${tip}` }); } } startTyping(invalidate: () => void) { this.currentText = ""; this.currentIndex = 0; if (this.timerId) clearInterval(this.timerId); this.timerId = setInterval(() => { if (this.currentIndex < this.fullText.length) { this.currentText += this.fullText[this.currentIndex]; this.currentIndex++; invalidate(); } else { clearInterval(this.timerId!); this.timerId = null; } }, this.typingSpeed); } resetTyping() { if (this.timerId) clearInterval(this.timerId); this.currentText = ""; this.currentIndex = 0; } } @Entry @Component struct CustomFontPage { private settings = new RenderingContextSettings(true); private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings); @State needRedraw: boolean = false; private typer = new TextTyper(); private canvasWidth: number = 600; private canvasHeight: number = 800; private fontColor: string = '#8B0000'; private fontSize: number = 46; private lineHeight: number = 20; // 测试文本,用于直观对比字体效果 private testText: string = "测试文本:毛字体"; private draw() { if (!this.context) return; // 清空画布 this.context.fillStyle = '#ffffff'; this.context.fillRect(0, 0, this.canvasWidth, this.canvasHeight); // 构建字体样式SimHei const targetFont = this.typer.fontLoaded ? `${this.typer.fontName}` : `${this.typer.fontName}`; const fontStyle = `${this.fontSize}px ${this.typer.fontName}`; //, Microsoft YaHei, sans-serif this.context.font = fontStyle; // 字体生效检测 this.context.fillStyle = '#666666'; this.context.fillText(`当前字体配置: ${targetFont}`, 10, 40); // 显示测试文本对比 this.context.fillStyle = '#0000ff'; this.context.fillText(this.testText, 10, 80); this.context.font = `${this.fontSize}px ${this.typer.fontName}`; // 系统字体对比 this.context.fillStyle = '#008000'; this.context.fillText(`系统字体对比: ${this.testText}`, 10, 120); // 恢复设置绘制主文本 this.context.font = fontStyle; this.context.fillStyle = this.fontColor; this.drawCenteredText(this.typer.currentText); } // 显示字体文件状态信息 private showFontFileInfo() { return "" } private calculateTextHeight(text: string): number { const lines = text.split('\n'); return lines.length * this.lineHeight; } private drawCenteredText(text: string) { const lines = text.split('\n'); const totalHeight = this.calculateTextHeight(text); let lineY = (this.canvasHeight - totalHeight) / 2 + this.fontSize; lines.forEach(line => { if (line) { const textWidth = this.context.measureText(line).width; const x = (this.canvasWidth - textWidth) / 2; this.context.fillText(line, x, lineY); this.context.font = `${this.fontSize}px ${this.typer.fontName}`; // this.context.font= `${this.fontSize}vp maozedong` } lineY += this.lineHeight; }); } aboutToAppear() { // familyName和familySrc都支持string font.registerFont({ familyName: 'maozedong', familySrc: 'font/maozedong.ttf' // font文件与pages目录同级 }) } build() { Column({space: 10}) { // 显示字体文件信息,帮助调试 Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { Canvas(this.context) .width(this.canvasWidth) .height(this.canvasHeight) .backgroundColor(Color.White) .onReady(() => this.draw()) Row() { Button("开始写字") .fontFamily('maozedong') .fontSize('16fp') .margin({ right: 12 }) .onClick(() => { this.typer.startTyping(() => { this.needRedraw = !this.needRedraw; this.draw(); }); }) .width('45%') .height(40) Button("重置") .fontSize('16fp') .fontFamily('maozedong') .margin({ left: 12 }) .onClick(() => { this.typer.resetTyping(); this.needRedraw = !this.needRedraw; this.draw(); }) .width('45%') .height(40) } .margin(12) } .width('99%') .height('100%') } .width('100%') .height('100%') .backgroundColor(Color.White) .padding(5) } }
卡片:
https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-container-formlink-V5
ohpm install @mcui/mccharts
https://gitee.com/openharmony-sig/ohos_axios
https://developer.huawei.com/consumer/cn/doc/harmonyos-references/canvas-drawing
https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/custom-font-arkts 自定义字体的注册和使用
https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkui-js-full-comp 兼容JS的类Web开发范式(ArkUI.Full)
https://developer.huawei.com/consumer/cn/doc/harmonyos-faqs/faqs-arkui-21 如何加载和使用自定义字体 方舟UI框架(ArkUI)
https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/ui-js-dev
https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V2/1_3arkts_u8bed_u8a00_u57fa_u7840_u7c7b_u5e93-0000001632530086-V2 ArkTS语言基础类库
https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/system-font-arkts
系统字体的信息获取和使用(ArkTS)