美文网首页自定义View前端开发那些事儿
Android APP自定义字体大小修改

Android APP自定义字体大小修改

作者: 可乐_JS | 来源:发表于2020-09-30 18:07 被阅读0次

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

    需求:添加具体字体自定义大小功能、不需要跟随系统字体大小改变而改变
    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);
            }
        }
    

    相关文章

      网友评论

        本文标题:Android APP自定义字体大小修改

        本文链接:https://www.haomeiwen.com/subject/qbqpuktx.html