寫在前面
在Android應用開發中,由于客戶或者個人的需要(
誰叫Android默認的字體那么丑),所以需要配置不同的字體,而 Android 只能在 xml 中配置系統默認提供的四種字體,需要自定義的字體都需要在 Java 代碼中配置。
總結一下以前自定義字體的方法
1 .通過findViewById找到view,然后一個個的去設置字體
Typeface customFont = Typeface.createFromAsset(this.getAssets(), "fonts/customFont.ttf");
TextView view = (TextView) findViewById(R.id.text);
view.setTypeface(customFont);
···
? 一個看著還好,可是應用中可是有很多的文本或者按鈕的,不可能逐個去設置。于是大多數都選擇了第二種方法。
2 .創建一個子類,繼承自TextView
或者Button
等等
public class CustomTextView extends TextView {
public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public CustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomTextView(Context context) {
super(context);
}
public void setTypeface(Typeface tf, int style) {
if (style == Typeface.BOLD) {
super.setTypeface(Typeface.createFromAsset(getContext().getAssets(), "fonts/CustomFont_Bold.ttf"));
} else {
super.setTypeface(Typeface.createFromAsset(getContext().getAssets(), "fonts/CustomFont.ttf"));
}
}
}
然后在xml文件中每次都使用自定義的View,相比上一個方案,這一個要稍微好點。但相信都達不到各位的要求,只不過是換一個字體,需要這么麻煩嗎?
3 . Calligraphy
這是一個開源庫,地址是https://github.com/chrisjenx/Calligraphy ,在github上5000+star,感覺還是不錯的,也從側面說出自定義字體的需求量有多大。
那么接下來就講重點了
如何使用DataBinding來進行字體的自定義呢?
TOO EASY,不用每次都去手寫,也不需要自定義View
首先,打開DataBinding
android {
compileSdkVersion 25
buildToolsVersion "25.0.0"
defaultConfig {
···
}
buildTypes {
···
}
dataBinding {
enabled = true
}
}
再看結構
在項目中的assets/fonts文件夾下加入了5種字體,然后在strings.xml
中定義了字體的路徑
<resources>
···
<string name="notoSans_regular">fonts/NotoSans-Regular.ttf</string>
<string name="notoSansui_boldItalic">fonts/NotoSansUI-BoldItalic.ttf</string>
<string name="icomoon">fonts/icomoon.ttf</string>
<string name="nutso2">fonts/Nutso2.otf</string>
<string name="ruthie">fonts/Ruthie.ttf</string>
···
</resources>
而在layout的xml中只需要這么使用,那么便已經完成了8成了
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center">
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:text="Hello world"
android:textSize="18sp"
android:typeface="@{@string/nutso2}"/>
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:textSize="18sp"
android:text="Hello world"
android:typeface="@{@string/notoSans_regular}"/>
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:textSize="18sp"
android:text="Hello world"
android:typeface="@{@string/notoSansui_boldItalic}"/>
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:text="Hello world"
android:textSize="18sp"
android:typeface="@{@string/icomoon}"/>
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:text="Hello world"
android:textSize="18sp"
android:typeface="@{@string/ruthie}"/>
</LinearLayout>
</layout>
而剩下的兩成,一成在FontBinding
文件
public class FontBinding {
@BindingConversion
public static Typeface convertStringToFace(String s){
try {
return Typeface.createFromAsset(FontApp.getInstance().getAssets(),s);
}catch (Exception e){
throw e;
}
}
}
這里定義了一個轉換器,將xml文件中獲取到的字符資源,轉換成了一個Typeface
最后一成,只需要使用就好了
public class MainActivity extends AppCompatActivity {
ActivityMainBinding mMainBinding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
}
}
看一下截圖,一起哈啤
沒了解過DataBinding的人可能不知道ActivityMainBinding
是怎么來的,這是編譯時生成的,在如下圖所示的位置可以找到
打開
ActivityMainBinding
可以看到這樣的代碼
this.mboundView1.setTypeface(com.ditclear.sample.FontBinding.convertStringToFace(mboundView1.getResources().getString(R.string.nutso2)));
this.mboundView2.setTypeface(com.ditclear.sample.FontBinding.convertStringToFace(mboundView2.getResources().getString(R.string.notoSans_regular)));
this.mboundView3.setTypeface(com.ditclear.sample.FontBinding.convertStringToFace(mboundView3.getResources().getString(R.string.notoSansui_boldItalic)));
this.mboundView4.setTypeface(com.ditclear.sample.FontBinding.convertStringToFace(mboundView4.getResources().getString(R.string.icomoon)));
this.mboundView5.setTypeface(com.ditclear.sample.FontBinding.convertStringToFace(mboundView5.getResources().getString(R.string.ruthie)));
這些mboundViewX
就是xml中的TextView,由于沒寫id,所以都是自動生成的名稱,可以看到給每一個使用了綁定的TextView都設置了字體,相當于系統幫我們做了第一個方法中重復性的工作。
當然我們還可以優化一下,由于每次都要操作assests文件夾,也會帶來一定的開銷,所以也有必要提供一個字體緩存FontCache
,代碼來自 britzl on stackoverflow
public class FontCache {
private static ArrayMap<String, Typeface> fontCache = new ArrayMap<String, Typeface>();
public static Typeface getTypeface(String fontName, Context context) {
Typeface tf = fontCache.get(fontName);
if(tf == null) {
try {
tf = Typeface.createFromAsset(context.getAssets(), fontName);
}
catch (Exception e) {
return null;
}
fontCache.put(fontName, tf);
}
return tf;
}
}
那么FontBinding
就變成了這樣
public class FontBinding {
@BindingConversion
public static Typeface convertStringToFace(String fontName){
try {
return FontCache.getTypeface(fontName,FontApp.getInstance());
}catch (Exception e){
throw e;
}
}
}
好了,大功告成!這也算是一種新思路吧。
附上github地址:https://github.com/ditclear/FontDataBinding
補充:
如果不想每次都在xml中設置字體,可以在綁定一個常用的屬性時設置一個默認的字體。比如字體是需要作用在text
上的,那么我們只需要在setText
的時候綁定一個默認的字體就??了,看代碼
public class FontBinding {
···
@BindingAdapter("android:text")
public static void setText(TextView v, String s){
v.setTypeface(convertStringToFace(FontApp.getInstance().getString(R.string.ruthie)));
v.setText(s);
}
}
這樣在綁定文本的時候就會綁定一個默認的字體,不用每次都寫
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center">
<!--綁定默認字體-->
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:text="@{@string/hello_world}"
android:textSize="18sp"/>
<!--綁定默認字體,然后自定義字體-->
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:textSize="18sp"
android:text="@{@string/hello_world}"
android:typeface="@{@string/notoSans_regular}"/>
···
</LinearLayout>
</layout>
最后,效果圖:
總結
這只是DataBinding的一個小例子,它能做的遠不止如此,而且DataBinding是一個support庫,最低支持到Android 2.1(API Level 7+)。不需要引入第三方庫,只需要在app.build文件中開啟就好了,而且學習成本極低。
再說明一個可能被大家誤解的地方,DataBinding并不是要一定和MVVM結合使用,應該說是MVVM離不開DataBinding,但DataBinding是可以在其它任何框架下使用的,包括MVC、MVP等等,至少它可以取代ButterKnife
,不用生成那么一長串@BindView的代碼。
想要了解DataBinding的可以看看慕課網上的視頻或者看看完全掌握Android Data Binding