鸿蒙原生开发使用iconfont封装Icon组件

669 阅读3分钟

自从传出鸿蒙Next版本不再是安卓套壳的消息之后,就觉得可能安卓和IOS两分天下的局势起码在国内要被打破了,正好由于工作原因得到了一个接触鸿蒙开发的机会,觉得自己还挺感兴趣的,所以就浅浅研究了一下,这里记录一下,在鸿蒙原生stage模型开发的工程中,如何使用iconfont,并且封装一个Iconfont组件,像在web端使用Iconfont一样简单使用

准备Iconfont

相信这一步,做过前端开发的大佬们都门儿清,就不再多说了,总之就是从iconfont网站上获取那个zip压缩包

如何在鸿蒙原生项目中使用iconfont

鸿蒙原生项目中通过文档,了解到提供了注册自定义字体的能力,所以第一步先注册自定义字体

注册自定义字体

在原生SDK中有一个叫@ohos.font的包提供了一个名为registerFont的方法,咱们在入口文件src/main/ets/EntryAbility.ets文件的windowStage.loadContent回调函数中去注册自定义字体, 在这之前需要先把上一步获取到的zip压缩包解压,在src/main/resource/rawfile目录下新建一个icon文件夹放进去。

  • 导入模块
import font from '@ohos.font'
  • 注册自定义字体
// 注册字体
font.registerFont({
  familyName:$r('app.string.icon_font'),//字体名称,在之后的使用中用得到所以放在资源文件string里面,便于引用
  familySrc:$rawfile('font/iconfont.ttf')//字体ttf文件路径,直接使用资源获取内置方法获取
})

这里的$r$rowfile分别是鸿蒙开发中获取资源的两种内置方法,在此不做赘述。

  • 使用自定义字体
const unicode = String.formCharCode(fontHexValue)//这里的fontHexValue是字体图标的十六进制值
 Text(unicode)
.align(Alignment.Center)
.fontSize(20)
.fontFamily('iconFont')

发现这个字体的16进制值信息在zip压缩包中解压出来的iconfont.json文件中,而我们平时的习惯是通过className使用iconfont,所以这里萌生了封装一个Icon组件的想法,实现在鸿蒙开发中,也能像web中通过className使用iconfont。

封装Icon组件

想要通过使用className使用iconfont,那么就要通过字体图标的className获取到对应图标的十六进制值,思路大概就是这样,具体实现如下

iconfont.json文件内容实例:

{
  "id": "3625586",
  "name": "喵喵狗狗",
  "font_family": "iconfont",
  "css_prefix_text": "icon-",
  "description": "",
  "glyphs": [
    {
      "icon_id": "5387520",
      "name": "二维码",
      "font_class": "erweima",
      "unicode": "eaf1",
      "unicode_decimal": 60145
    }
  ]
}

咱们能用到的就是glyphs这个key下的这个对象数组,其中font_class对应的就是icon的className,而unicode_decimal对应的就是icon的十六进制值,思路就是通过className获取到相应图标的十六进制值,带入使用icon的方法中。

  • 创建Icon组件 多的不说直接上Icon.ets代码:
import { common } from '@kit.AbilityKit';
import { buffer } from '@kit.ArkTS';
import { BusinessError } from '@kit.BasicServicesKit';

const storage = LocalStorage.getShared();
@Entry(storage) // 为组件注入本地存储,我觉得可以理解为dva中的connect吧
@Component
export struct Icon{
  @Prop name:string|number// className,就是从iconfont网站中复制到的那个className
  @Prop iconSize:number = 16 // 字体大小
  @Prop iconColor:string|Color//字体颜色,不过有些icon不支持自定义颜色
  @State @Watch('onIconFontData') iconfontData:IconfontInfo|null = null; //监听字体数据变化
  @State unicode:string = ''
  aboutToAppear(): void {
   this.getIconfontData(); // 加载字体json文件数据
  }
  onIconFontData(){
    if(this.iconfontData){ // 当字体文件加载成功之后重新获取unicode
      const unicode = this.getCharCode(this.iconfontData);
      this.unicode = unicode;
    }
  }
  getIconfontData(){
    let context = getContext(this) as common.UIAbilityContext
    try{
      let value = context.resourceManager.getRawFileContentSync("font/iconfont.json");
      let str = buffer.from(value.buffer).toString()
      this.iconfontData = JSON.parse(str) as IconfontInfo;
    } catch(error) {
      let code = (error as BusinessError).code;
      let message = (error as BusinessError).message;
      console.error(`getRawFileContentSync failed, error code: ${code}, message: ${message}.`);
    }
  }
  build() {
    Text(this.unicode)
      .fontFamily($r('app.string.icon_font'))// 注册的自定义字体的name就是registerFont方法中的familyName
      .fontSize(this.iconSize)
      .fontColor(this.iconColor)
  }

  getCharCode(iconfontInfo:IconfontInfo){
    let unicode_decimal:number =0;
    if(this.iconfontData){
      const iconfontInfoList:IconfontItem[] = iconfontInfo.glyphs; //获取到icon的信息
      const currentItem:IconfontItem|undefined = iconfontInfoList.find((value:IconfontItem)=>{
        return 'icon-'+value.font_class===this.name;
      })//通过className获取到相应图标的信息
     if(currentItem){
       unicode_decimal = currentItem.unicode_decimal; //十六进制值
     }
    }
    const result:string =  String.fromCharCode(unicode_decimal)//赋值给result
    return result
  }
}


interface IconfontInfo{
  glyphs:IconfontItem[]
}
export interface IconfontItem{
  icon_id:string,
  name:string,
  font_class:string,
  unicode:string,
  unicode_decimal:number
}

最后

本人就是个前端小菜鸟,也没有研究过安卓原生开发,属于摸着石头过河,如果有说的不对的地方,恳请各位大佬轻点喷