最近團隊裡面在做程序界面統一的工作,因此希望統一字體,接到一個研究怎麼自定義字體的任務。因為我們的開發模式,所以需要研究在界面內的字體自定義,以及webview的顯示中的字體自定義。
android系統內置字體android 系統本身內置了一些字體,可以在程序中使用,並且支持在xml配置textView的時候進行修改字體的樣式。支持欄位為android:textStyle ,android:typeface, android:fontFamily,系統內置了normal|bold|italic三種style, 內置了normal,sans,serif,monospace,幾種字體(實測這幾種字體僅英文有效),typace和fontFamily功能一樣。
使用自定義的字體以上的方式可以改變字體的樣式,還不是真正的自定義。
android系統支持TypeFace,即ttf的字體文件。
我們可以在程序中放入ttf字體文件,在程序中使用Typeface設置字
體。
第一步,在assets目錄下新建fonts目錄,把ttf字體文件放到這。
第二步,程序中調用:
1
2
3
AssetManager mgr=getAssets();
Typeface tf=Typeface.createFromAsset(mgr, "fonts/ttf.ttf");
tv.setTypeface(tf);
注意ttf文件命名不能使用中文,否則可能無法加載。
對於需要使用比較多的地方,可以寫一個TextView的子類來統一處理。
在webview中使用自定義地體對於本地的網頁,在asset目錄放字體文件,並在css中添加以下內容,自定義一個字體face,並且在需要的地方使用這個字體face即可。
1
2
3
4
5
6
@font-face {
font-family: "MyFont";
src: url('file:///android_asset/fonts/ttf.ttf');
}
h3 { font-family:"MyFont"}
對於在線的網頁,則需要把字體文件放到伺服器,使用同樣的方式定義字體face,應用到每個地方。
為了減少網頁或者說伺服器端的工作,可以使用本地注入的方式注入font-face的css,並對整個網頁進行樣式替換。
給webview自定義webViewClient,重寫onPageFinish,在其中添加如下內容:
1
2
3
4
5
view.loadUrl("javascript:!function(){" +
"s=document.createElement('style');s.innerHTML="
+ "\"@font-face{font-family:myhyqh;src:url('**injection**/hyqh.ttf');}*{font-family:myhyqh !important;}\";"
+ "document.getElementsByTagName('head')[0].appendChild(s);" +
"document.getElementsByTagName('body')[0].style.fontFamily = \"myhyqh\";}()");
由於網頁上是沒有權限訪問本地的asset文件夾的,因此我們需要攔截請求來加載本地的文件,我這裡替換了file:///android_assets/為 **injection**/了,我們還需要重寫
shouldInterceptRequest
在請求為我們這個字體文件的時候,加載本地文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
WebResourceResponse response = super.shouldInterceptRequest(view, url);
CLog.i("load intercept request:" + url);
if (url != null && url.contains("**injection**/")) {
String assertPath = url.substring(url.indexOf("**injection**/") + "**injection**/".length(), url.length());
try {
response = new WebResourceResponse("application/x-font-ttf",
"UTF8", getAssets().open(assertPath)
);
} catch (IOException e) {
e.printStackTrace();
}
}
return response;
}
問題使用字體統一界面,但是也遇到了一些問題,如下:
運行速度變慢(毫秒級,用戶覺查不到),由於需要讀取自定義的字體文件,以及需要渲染,比使用系統字體要慢。
emoji在5.0以下的系統會有問題。
在網頁,如果採用伺服器文件的方法,會消耗用戶的流量
在網頁,採用本地注入方式,因為是在onpagefinish後才開始加載字體,因此頁面會重新渲染,影響效果。這樣還會造成網頁可能會出現樣式錯誤。
因為我們的程序中大量使用到emoji,以及考慮到性能的問題,決定還是使用系統自帶的字體了。
如果你在這方面有更好的方案,歡迎交流!