Toolbar的title使用自定义字体

2018-02-28  本文已影响108人  风雪守候

ToolBar并没有提供类似于TextView的setTypeface()方法来修改字体。但是如果我们需要对ToolBar的title设置自定义的字体怎么办呢?
1.不使用ToolBar控件,自己去实现一个titleBar。
2.在ToolBar中放置一个TextView,使用该TextView来显示title
3.使用SpannableString来设置title,在SpannableString中对title设置自定义的字体,下面详细介绍一下这种实现方式。
通过了解发现SpannableString设置字体的方式如下:

SpannableString string = new SpannableString("test");
string.setSpan(new TypefaceSpan("monospace"),0,4,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

但是这种方法只支持系统的几种字体(如:monospace,serif等),如果需要设置自己想要的字体就需要自定义类了,首先对TypefaceSpan进行研究。

/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.text.style;

import android.graphics.Paint;
import android.graphics.Typeface;
import android.os.Parcel;
import android.text.ParcelableSpan;
import android.text.TextPaint;
import android.text.TextUtils;

/**
 * Changes the typeface family of the text to which the span is attached.
 */
public class TypefaceSpan extends MetricAffectingSpan implements ParcelableSpan {
    private final String mFamily;

    /**
     * @param family The font family for this typeface.  Examples include
     * "monospace", "serif", and "sans-serif".
     */
    public TypefaceSpan(String family) {
        mFamily = family;
    }

    public TypefaceSpan(Parcel src) {
        mFamily = src.readString();
    }
    
    public int getSpanTypeId() {
        return getSpanTypeIdInternal();
    }

    /** @hide */
    public int getSpanTypeIdInternal() {
        return TextUtils.TYPEFACE_SPAN;
    }
    
    public int describeContents() {
        return 0;
    }

    public void writeToParcel(Parcel dest, int flags) {
        writeToParcelInternal(dest, flags);
    }

    /** @hide */
    public void writeToParcelInternal(Parcel dest, int flags) {
        dest.writeString(mFamily);
    }

    /**
     * Returns the font family name.
     */
    public String getFamily() {
        return mFamily;
    }

    @Override
    public void updateDrawState(TextPaint ds) {
        apply(ds, mFamily);
    }

    @Override
    public void updateMeasureState(TextPaint paint) {
        apply(paint, mFamily);
    }
    //设置字体的关键方法
    private static void apply(Paint paint, String family) {
        int oldStyle;

        Typeface old = paint.getTypeface();
        if (old == null) {
            oldStyle = 0;
        } else {
            oldStyle = old.getStyle();
        }

        Typeface tf = Typeface.create(family, oldStyle);
        int fake = oldStyle & ~tf.getStyle();

        if ((fake & Typeface.BOLD) != 0) {
            paint.setFakeBoldText(true);
        }

        if ((fake & Typeface.ITALIC) != 0) {
            paint.setTextSkewX(-0.25f);
        }
        //设置字体的关键语句
        paint.setTypeface(tf);
    }
}

通过源码发现TypefaceSpan是继承了MetricAffectingSpan类,然后在updateMeasureState和updateDrawState方法中调用了apply方法。
在apply方法发现以下语句

Typeface tf = Typeface.create(family, oldStyle);

       .....

paint.setTypeface(tf);

所以我们只要在apply方法中使用paint.setTypeface();即可。而且我们自定义的类中可以直接传入一个Typeface作为参数。
实现代码如下:

package com.cxample.test;

import android.graphics.Paint;
import android.graphics.Typeface;
import android.text.TextPaint;
import android.text.style.MetricAffectingSpan;

public class TestTypefaceSpan extends MetricAffectingSpan {

    private final Typeface typeface;

    public TestTypefaceSpan(final Typeface typeface) {
        this.typeface = typeface;
    }

    @Override
    public void updateDrawState(final TextPaint drawState) {
        apply(drawState);
    }

    @Override
    public void updateMeasureState(final TextPaint paint) {
        apply(paint);
    }

    private void apply(final Paint paint) {
        final Typeface oldTypeface = paint.getTypeface();
        final int oldStyle = oldTypeface != null ? oldTypeface.getStyle() : 0;
        final int fakeStyle = oldStyle & ~typeface.getStyle();
        if ((fakeStyle & Typeface.BOLD) != 0) {
            paint.setFakeBoldText(true);
        }
        if ((fakeStyle & Typeface.ITALIC) != 0) {
            paint.setTextSkewX(-0.25f);
        }
        paint.setTypeface(typeface);
    }

}

然后和普通的TypefaceSpan使用相同,如:

mToolbar.setTitle(getTitleSpannable(mTitleText));

private SpannableString getTitleSpannable(String title) {
        SpannableString titleSpannable = new SpannableString(title);
        titleSpannable.setSpan(new TestTypefaceSpan(mTypeface), 0, title.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        return titleSpannable;
}

其中mTypeface是自己创建的字体类型,如:

mTypeface = Typeface.createFromAsset(context.getAssets(), "BebasNeue.ttf");

参考来源:https://www.cnblogs.com/dongweiq/p/4648085.html

上一篇下一篇

猜你喜欢

热点阅读