Android APP自定义字体大小修改

简单记录下今天做的自定义字体大小修改的功能

需求:添加具体字体自定义大小功能、不需要跟随系统字体大小改变而改变
1.首先看一下用到的调节字体大小的控件:
字体大小调节页

控件继承自系统的SeekBar,添加了刻度、文字
代码如下:

/**
 * Des:
 * Created by kele on 2020/9/30.
 * E-mail:984127585@qq.com
 */
public class RaeSeekBar extends AppCompatSeekBar {

    //  刻度说明文本,数组数量跟刻度数量一致,跟mTextSize的长度要一致
    private String[] mTickMarkTitles = new String[]{
            "A",
            "标准",
            "",
            "A"
    };
    // 刻度代表的字体大小
    private float[] mTextSize = new float[]{
            0.8f,
            1.0f,
            1.15f,
            1.3f
    };

    // 刻度画笔
    private final Paint mTickMarkTitlePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
    //文本画笔
    private final Paint mTitlePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
    //  刻度文本字体大小
    private float mTickMarkTitleTextSize = 18;
    // 刻度文本跟刻度之间的间隔
    private float mOffsetY = 40;
    // 刻度线的高度
    private int mLineHeight = 10;
    // 保存位置大小信息
    private final Rect mRect = new Rect();
    private int mThumbHeight;
    private int mThumbWidth;

    public RaeSeekBar(Context context) {
        this(context, null);
    }

    public RaeSeekBar(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RaeSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    protected void init() {
        mTickMarkTitleTextSize = getSize(mTickMarkTitleTextSize);
        mOffsetY = getSize(mOffsetY);
        mLineHeight = getSize(mLineHeight);
        mTickMarkTitlePaint.setTextAlign(Paint.Align.CENTER);
        mTickMarkTitlePaint.setColor(ContextCompat.getColor(getContext(), R.color.color_66989FC3));
        mTitlePaint.setTextAlign(Paint.Align.CENTER);
        mTitlePaint.setColor(ContextCompat.getColor(getContext(), R.color.color_303132));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int max = getMax();
        int width = canvas.getWidth();
        int height = canvas.getHeight();
        int h2 = height / 2;

        // 画刻度背景
        mRect.left = getPaddingLeft();
        mRect.right = width - getPaddingRight();
        mRect.top = h2 - getSize(1);
        mRect.bottom = mRect.top + getSize(1.0f);
        canvas.drawRect(mRect, mTickMarkTitlePaint);
        int cw = mRect.right - mRect.left; // 总画线的长度 = 右边坐标 - 左边坐标
        for (int i = 0; i <= max; i++) {
            // 每个间隔的大小
            int thumbPos = getPaddingLeft() + (cw * i / max);
            // 画分割线
            mRect.top = h2 - mLineHeight / 2;
            mRect.bottom = h2 + mLineHeight / 2;
            mRect.left = thumbPos;
            mRect.right = thumbPos + getSize(1.0f);
            canvas.drawRect(mRect, mTickMarkTitlePaint);

            // 画刻度文本
            String title = mTickMarkTitles[i % mTickMarkTitles.length];
            mTitlePaint.getTextBounds(title, 0, title.length(), mRect);
            mTitlePaint.setTextSize(mTextSize[i] * mTickMarkTitleTextSize);
            canvas.drawText(title, thumbPos, mTextSize[mTextSize.length - 1] * mTickMarkTitleTextSize, mTitlePaint);
        }
    }

    @Override
    protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mThumbWidth = getThumb().getIntrinsicWidth();
        mThumbHeight = getThumb().getIntrinsicHeight();
        // 加上字体大小
        int wm = MeasureSpec.getMode(widthMeasureSpec);
        int hm = MeasureSpec.getMode(heightMeasureSpec);
        int w = getMeasuredWidth();
        int h = getMeasuredHeight();
        h += mTextSize[mTextSize.length - 1] * mTickMarkTitleTextSize; // 最大的字体
        h += mOffsetY;
        // 保存
        setMeasuredDimension(MeasureSpec.makeMeasureSpec(w, wm), MeasureSpec.makeMeasureSpec(h, hm));

    }

    protected int getSize(float size) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, size, getResources().getDisplayMetrics());
    }

    public float getRawTextSize(int progress) {
        return mTextSize[progress % mTextSize.length];
    }

    public void setTextSize(float size) {
        for (int i = 0; i < mTextSize.length; i++) {
            float textSize = mTextSize[i];
            if (textSize == size) {
                setProgress(i);
                break;
            }
        }
    }
}
2.RaeSeekBar控件的具体使用

代码如下:

        RaeSeekBar raeSeekBar = findViewById(R.id.rae_seek_bar);

        scalaSize = SPUtils.getInstance().getFloat(SPConfig.FONT_SIZE_SCALE, 1.0f);
        setTvSize(scalaSize);
        raeSeekBar.setTextSize(scalaSize);
        raeSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                scalaSize = raeSeekBar.getRawTextSize(progress);
                setTvSize(scalaSize);
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        });
3.实现部分界面的字体大小的修改

先看看修改字体大小代码,如下:

    /**
     * 修改字体大小
     *
     * @param spKey
     */
    protected void changeFontSize(String spKey) {
        float scale = 1.0f;
        Configuration c = getResources().getConfiguration();
        if (!TextUtils.isEmpty(spKey)) {
            scale = SPUtils.getInstance().getFloat(spKey, 1.0f);
        }
        c.fontScale = scale;
//        DisplayMetrics metrics = new DisplayMetrics();
//        getWindowManager().getDefaultDisplay().getMetrics(metrics);
//        metrics.scaledDensity = c.fontScale * metrics.density;
        getResources().updateConfiguration(c, getResources().getDisplayMetrics());
    }

修改字体大小的代码放在BaseActivity中
在onCreate中调用changeFontSize(null);,即:

 /**
     * 是否需要重置字体大小
     * 只有在需要调节字体大小的界面不需要重置,其他的均需要重置
     */
    protected boolean isNeedResetFontSize = true;

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        BarUtils.setStatusBarColor(this, getResources().getColor(R.color.color_translation));
        BarUtil.getInstance().setStatusBarFontIconDark(this, false);
        if (isNeedResetFontSize) {
            changeFontSize(null);
        }
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_base);
    }

在需要字体大小改变的页面onCreate中调用changeFontSize("你保存的修改后的字体的倍数对应的SP中的Key");,例如:

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        isNeedResetFontSize = false;
        changeFontSize(SPConfig.FONT_SIZE_SCALE);
        super.onCreate(savedInstanceState);
    }

到这里修改字体的工作基本上算是完了
但是
修改系统字体大小后会发现自己修改的字体的大小是累加在修改后的系统字体大小之上的

4.禁止APP的字体大小跟随系统字体大小改变而改变

1.Application中重写getResources方法:

    /**
     * 重写 getResource 方法,防止系统字体影响
     */
    @Override
    public Resources getResources() {//禁止app字体大小跟随系统字体大小调节
        Resources resources = super.getResources();
        if (resources != null && resources.getConfiguration().fontScale != 1.0f) {
            android.content.res.Configuration configuration = resources.getConfiguration();
            configuration.fontScale = 1.0f;
            resources.updateConfiguration(configuration, resources.getDisplayMetrics());
        }
        return resources;
    }

2.BaseActivity中重写getResources方法:

    /**
     * 重写 getResource 方法,防止系统字体影响
     */
    @Override
    public Resources getResources() {//禁止app字体大小跟随系统字体大小调节
        Resources resources = super.getResources();
        if (isNeedResetFontSize) {
            if (resources != null && resources.getConfiguration().fontScale != 1.0f) {
                android.content.res.Configuration configuration = resources.getConfiguration();
                configuration.fontScale = 1.0f;
                resources.updateConfiguration(configuration, resources.getDisplayMetrics());
            }
        }
        return resources;
    }

参考链接

https://blog.csdn.net/weixin_34377919/article/details/91412289
https://blog.csdn.net/weitao_666/article/details/79745806

补充(201009)

  • 上面的代码在红米3开发版手机上的效果不理想,如下图:


    红米3开发版手机效果

    图中SeekBar设置的thumb图片跑到了刻度上方

看了下源码(AbsSeekBar.java:732行):

    /**
     * Draw the thumb.
     */
    void drawThumb(Canvas canvas) {
        if (mThumb != null) {
            final int saveCount = canvas.save();
            // Translate the padding. For the x, we need to allow the thumb to
            // draw in its extra space
            canvas.translate(mPaddingLeft - mThumbOffset, mPaddingTop);
            mThumb.draw(canvas);
            canvas.restoreToCount(saveCount);
        }
    }

源码中画thumb是通过padding值来确定位置的,所以,通过设置padding来适配红米3,代码修改如下:

    @Override
    protected void onDraw(Canvas canvas) {
        Drawable thumb = getThumb();
        int max = getMax();
        int width = canvas.getWidth();
        int height = canvas.getHeight();
        int h2 = height / 2;
        boolean xiaomi = RomUtils.isXiaomi();
        if (xiaomi) {
            setPadding(getPaddingLeft(), (height - thumb.getIntrinsicHeight()) / 2, getPaddingRight(), getPaddingBottom());
        }
        super.onDraw(canvas);

        // 画刻度背景
        mRect.left = getPaddingLeft();
        mRect.right = width - getPaddingRight();
        mRect.top = h2 - getSize(1);
        mRect.bottom = mRect.top + getSize(1.0f);
        canvas.drawRect(mRect, mTickMarkTitlePaint);
        int cw = mRect.right - mRect.left; // 总画线的长度 = 右边坐标 - 左边坐标
        for (int i = 0; i <= max; i++) {
            // 每个间隔的大小
            int thumbPos = getPaddingLeft() + (cw * i / max);
            // 画分割线
            mRect.top = h2 - mLineHeight / 2;
            mRect.bottom = h2 + mLineHeight / 2;
            mRect.left = thumbPos;
            mRect.right = thumbPos + getSize(1.0f);
            canvas.drawRect(mRect, mTickMarkTitlePaint);

            // 画刻度文本
            String title = mTickMarkTitles[i % mTickMarkTitles.length];
            mTitlePaint.getTextBounds(title, 0, title.length(), mRect);
            mTitlePaint.setTextSize(mTextSize[i] * mTickMarkTitleTextSize);
            canvas.drawText(title, thumbPos, mTextSize[mTextSize.length - 1] * mTickMarkTitleTextSize, mTitlePaint);
        }
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269