Android字体工作原理与应用

本文探讨了Android中fontFamily和typeface属性的工作原理。当fontFamily指定的字体缺少特定样式时,系统会使用其他样式字体。typeface属性结合style参数,即使字体文件不完整,也能确保文字显示与textStyle设置一致。同时,文章提到了fontFamily的有效值取决于系统字体配置文件,而typeface则提供预设的字体类型选项,是fontFamily的子集。
摘要由CSDN通过智能技术生成
       Android字体系统由android 2D图形引擎skia实现,字体系统的配置方法在各个版本中不完全相同,按照API level可以划分为三个阶段:4.0以下版本、4.0-4.4版本、5.0及以上版本。本文主要针对4.0及以上版本中字体系统的配置方法及字体相关应用进行分析。注意,浏览器及webView中的字体有单独的字体系统。     
     Android中将每个字体文件描述为字型(Typeface),包括字体族(FontFamily)和字体样式(textStyle)两个维度,字体族对应各种字体类型,样式则分为normal、bold、italic和bold-italic四种。
     

工作原理

   下面对字体工作原理的分析围绕系统字体配置文件解析与字体加载相关内容,不涉及skia的实现细节,为便于理解分为三个部分。

1. java层
     在这一层,android.graphics.Typeface类负责加载系统字体,并对上层提供创建字体功能调用。下面分析Typeface类的调用过程。
     在android启动过程中,ZygoteInit类的入口函数main()中调用preload()函数,preload()函数主要用于加载并初始化各种类、链接库、资源等。
static void preload() {
        Log.d(TAG, "begin preload");
        preloadClasses();
        preloadResources();
        preloadOpenGL();
        preloadSharedLibraries();
        // Ask the WebViewFactory to do any initialization that must run in the zygote process,
        // for memory sharing purposes.
        WebViewFactory.prepareWebViewInZygote();
        Log.d(TAG, "end preload");
}
     在preload()中调用了preloadClasses()函数用于加载并初始化一些系统常用类,这些类的列表位于frameworks/base/preloaded-classes文件中,其中包括了Typeface类。
/**
* Performs Zygote process initialization. Loads and initializes
* commonly used classes.
*
* Most classes only cause a few hundred bytes to be allocated, but
* a few will allocate a dozen Kbytes (in one case, 500+K).
*/
private static void preloadClasses() {
    ......
    InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream(PRELOADED_CLASSES);
     
    ......
 
    try {
                BufferedReader br = new BufferedReader(new InputStreamReader(is), 256);
 
                int count = 0;
                String line;
                while ((line = br.readLine()) != null) {
                    // Skip comments and blank lines.
                    line = line.trim();
                    if (line.startsWith("#") || line.equals("")) {
                        continue;
                    }
 
                    try {
                        if (false) {
                            Log.v(TAG, "Preloading " + line + "...");
                        }
                        Class.forName(line);
 
    ......
}
     preloadClasses()中调用Class.forName("android.graphics.Typeface")加载Typeface类,并调用Typeface类的static块。create()通过调用相应的native方法创建字体对象。
// 4.x
    static {
        DEFAULT         = create((String) null, 0);
        DEFAULT_BOLD    = create((String) null, Typeface.BOLD);
        SANS_SERIF      = create("sans-serif", 0);
        SERIF           = create("serif", 0);
        MONOSPACE       = create("monospace", 0);
  
        sDefaults = new Typeface[] {
            DEFAULT,
            DEFAULT_BOLD,
            create((String) null, Typeface.ITALIC),
            create((String) null, Typeface.BOLD_ITALIC),
        };
  
    private static native int  nativeCreate(String familyName, int style);
    private static native int  nativeCreateFromTypeface(int native_instance, int style);
    private static native void nativeUnref(int native_instance);
    private static native int  nativeGetStyle(int native_instance);
    private static native int  nativeCreateFromAsset(AssetManager mgr, String path);
    private static native int nativeCreateFromFile(String path);
 
 
// 5.x
    static {
        init();
        // Set up defaults and typefaces exposed in public API
        DEFAULT         = create((String) null, 0);
        DEFAULT_BOLD    = create((String) null, Typeface.BOLD);
        SANS_SERIF      = create("sans-serif", 0);
        SERIF           = create("serif", 0);
        MONOSPACE       = create("monospace", 0);
  
        sDefaults = new Typeface[] {
            DEFAULT,
            DEFAULT_BOLD,
            create((String) null, Typeface.ITALIC),
            create((String) null, Typeface.BOLD_ITALIC),
        };
 
    private static native long nativeCreateFromTypeface(long native_instance, int style);
    private static native long nativeCreateWeightAlias(long native_instance, int weight);
    private static native void nativeUnref(long native_instance);
    private static native int  nativeGetStyle(long native_instance);
    private static native long nativeCreateFromArray(long[] familyArray);
    private static native void nativeSetDefault(long native_instance);
     注意4.x版本与5.x版本提供的上层API调用是一致的,但是c++层的native函数却并不一致,这与5.x版本中static块增加了一个init()函数调用有关,init()方法主要实现了解析系统字体配置文件,并据此加载系统字体。对于4.x版本,解析并加载系统字体的功能在c++层的skia代码中实现,留到下面进行分析。
private static void init() {
        // Load font config and initialize Minikin state
        File systemFontConfigLocation = getSystemFontConfigLocation();
        File configFilename = new File(systemFontConfigLocation, F
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值