美文网首页Android技术知识
Android 实现更改字体大小

Android 实现更改字体大小

作者: 夜远曦白 | 来源:发表于2020-04-28 14:49 被阅读0次
    • 调节字体大小的自定义 Seekbar(CustomSeekbar .java)
    package com.fcsc.fcscuilib.customview;
    
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.Point;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.view.View;
    
    import com.fcsc.fcscuilib.R;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 调节字体大小的自定义Seekbar
     */
    public class CustomSeekbar extends View {
    
        private static final String A = "A";
        private static final String strStandard = "标准";
    
        private static final int DEFAULT_LINE_COLOR = Color.BLACK;
        private static final int DEFAULT_COUNT = 5;
        private static final int DEFAULT_CIRCLE_COLOR = Color.WHITE;
        private static final int DEFAULT_POSITION = 1;
        private static final int DEFAULT_LINE_HEIGHT = 16;
    
        private static int DEFAULT_LINE_WIDTH;
        private static int DEFAULT_CIRCLE_RADIUS;
    
        // 一共有多少格
        private int mMax = 5;
        // 线条颜色
        private int mLineColor;
        // 线条粗细
        private int mLineWidth;
        // 突出部分的线条高度
        private int mLineHeight;
        // 指标的圆半径
        private int mCircleRadius;
        // 指标的颜色
        private int mCircleColor;
        // 一段的宽度,根据总宽度和总格数计算得来
        private int mItemWidth;
        // 控件的宽高
        private int mHeight;
        private int mWidth;
        // 当前所在位置
        private int mCurrentPosition = DEFAULT_POSITION;
        // 画笔
        private Paint mLinePaint;
        private Paint mCirclePaint;
        // 滑动过程中x坐标
        private float mCurrentX = 0;
        // 有效数据点
        private List<Point> mPoints = new ArrayList<>();
    
        private float mCircleX;
        private float mCircleY;
    
        public CustomSeekbar(Context context) {
            this(context, null);
        }
    
        public CustomSeekbar(Context context, AttributeSet attrs) {
            super(context, attrs);
            init(context, attrs);
        }
    
        private void init(Context context, AttributeSet attrs) {
            // initDefault
            DEFAULT_LINE_WIDTH = dp2px(context, 2);
            DEFAULT_CIRCLE_RADIUS = dp2px(context, 32);
    
            mLineColor = Color.rgb(33, 33, 33);
            mLineWidth = dp2px(context, 0);
            mCircleColor = Color.WHITE;
    
            // initCustomAttrs
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomSeekbar);
            final int N = typedArray.getIndexCount();
            for (int i = 0; i < N; i++) {
                initCustomAttr(typedArray.getIndex(i), typedArray);
            }
            typedArray.recycle();
    
            // 初始化画笔
            mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mLinePaint.setColor(mLineColor);
            mLinePaint.setStyle(Paint.Style.FILL_AND_STROKE);
            mLinePaint.setStrokeWidth(mLineWidth);
    
            mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mCirclePaint.setColor(mCircleColor);
            mCirclePaint.setStyle(Paint.Style.FILL);
            // 设置阴影效果
            setLayerType(LAYER_TYPE_SOFTWARE, null);
            mCirclePaint.setShadowLayer(2, 0, 0, Color.GRAY);
        }
    
        private void initCustomAttr(int attr, TypedArray typedArray) {
            if (attr == R.styleable.CustomSeekbar_customLineColor) {
                mLineColor = typedArray.getColor(attr, DEFAULT_LINE_COLOR);
            } else if (attr == R.styleable.CustomSeekbar_circleColor) {
                mCircleColor = typedArray.getColor(attr, DEFAULT_CIRCLE_COLOR);
            } else if (attr == R.styleable.CustomSeekbar_customLineWidth) {
                mLineWidth = typedArray.getDimensionPixelSize(attr, DEFAULT_LINE_WIDTH);
            } else if (attr == R.styleable.CustomSeekbar_circleRadius) {
                mCircleRadius = typedArray.getDimensionPixelSize(attr, DEFAULT_CIRCLE_RADIUS);
            } else if (attr == R.styleable.CustomSeekbar_totalCount) {
                mMax = typedArray.getInteger(attr, DEFAULT_COUNT);
            }
        }
    
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            mHeight = h;
            mWidth = w;
            mCircleY = mHeight / 2;
            mLineHeight = DEFAULT_LINE_HEIGHT;
            // 横线宽度是总宽度-2个圆的半径
            mItemWidth = (w - 2 * mCircleRadius) / mMax;
            // 把可点击点保存起来
            for (int i = 0; i <= mMax; i++) {
                mPoints.add(new Point(mCircleRadius + i * mItemWidth, mHeight / 2));
            }
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            // 先画中间的横线
            canvas.drawLine(mPoints.get(0).x, mHeight / 2, mPoints.get(mPoints.size() - 1).x, mHeight / 2, mLinePaint);
            // 绘制刻度
            for (Point point : mPoints) {
                canvas.drawLine(point.x, mHeight / 2 - mLineHeight, point.x, mHeight / 2 + mLineHeight, mLinePaint);
            }
            mLinePaint.setTextSize(40);
            canvas.drawText(A, mPoints.get(0).x - mLinePaint.measureText(A)/2, mPoints.get(0).y - ((Math.max(mLineHeight, mCircleRadius) + 16)), mLinePaint);
            mLinePaint.setTextSize(56);
            canvas.drawText(strStandard, mPoints.get(2).x - mLinePaint.measureText(strStandard)/2, mPoints.get(2).y - ((Math.max(mLineHeight, mCircleRadius) + 16)), mLinePaint);
            mLinePaint.setTextSize(86);
            canvas.drawText(A, mPoints.get(5).x - mLinePaint.measureText(A)/2, mPoints.get(5).y - ((Math.max(mLineHeight, mCircleRadius) + 16)), mLinePaint);
            // 画圆
            if (canMove) {
                // 随手指滑动过程
                if (mCurrentX < mCircleRadius) {
                    mCurrentX = mCircleRadius;
                }
                if (mCurrentX > mWidth - mCircleRadius) {
                    mCurrentX = mWidth - mCircleRadius;
                }
                mCircleX = mCurrentX;
            } else {
                // 最终
                mCircleX = mPoints.get(mCurrentPosition).x;
            }
            // 实体圆
            canvas.drawCircle(mCircleX, mCircleY, mCircleRadius, mCirclePaint);
        }
    
        float downX = 0;
        private boolean canMove = false;
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            // 过滤掉不合法的坐标
    //        if (event.getX() < mCircleRadius || event.getX() > mWidth - mCircleRadius) {
    //            return false;
    //        }
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    // 判断是否是数据点
                    downX = event.getX();
                    canMove = isDownOnCircle(downX);
                    break;
                case MotionEvent.ACTION_MOVE:
                    if (canMove) {
                        mCurrentX = event.getX();
                        invalidate();
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    // 手指抬起之后就圆就不能在非有效点
                    mCurrentX = 0;
                    float upX = event.getX();
                    if (canMove) {
                        // 是滑动过来的,要判断距离哪个有效点最近,就滑动到哪个点
                        Point targetPoint = getNearestPoint(upX);
                        if (targetPoint != null) {
                            invalidate();
                        }
                    } else {
                        if (Math.abs(downX - upX) < 30) {
                            Point point = isValidPoint(upX);
                            if (point != null) {
                                invalidate();
                            }
                        }
                    }
                    if (onPointResultListener != null) {
                        onPointResultListener.onPointResult(mCurrentPosition);
                    }
                    downX = 0;
                    canMove = false;
                    break;
            }
            return true;
        }
    
        /**
         * 滑动抬起之后,要滑动到最近的一个点那里
         *
         * @param x
         * @return
         */
        private Point getNearestPoint(float x) {
            for (int i = 0; i < mPoints.size(); i++) {
                Point point = mPoints.get(i);
                if (Math.abs(point.x - x) < mItemWidth / 2) {
                    mCurrentPosition = i;
                    return point;
                }
            }
            return null;
        }
    
        /**
         * 判断是否点击到圆上
         *
         * @param x
         * @return
         */
        private boolean isDownOnCircle(float x) {
            return Math.abs(mPoints.get(mCurrentPosition).x - x) < mCircleRadius;
        }
    
        /**
         * 判断是否是有效的点击点
         *
         * @param x
         */
        private Point isValidPoint(float x) {
            for (int i = 0; i < mPoints.size(); i++) {
                Point point = mPoints.get(i);
                if (Math.abs(point.x - x) < 30) {
                    mCurrentPosition = i;
                    return point;
                }
            }
            return null;
        }
    
        /**
         * 设置当前的位置
         *
         * @param position
         */
        public void setCurrntPosition(int position) {
            mCurrentPosition = position;
        }
    
        public void setOnPointResultListener(OnPointResultListener onPointResultListener) {
            this.onPointResultListener = onPointResultListener;
        }
    
        private OnPointResultListener onPointResultListener;
    
        public interface OnPointResultListener {
            void onPointResult(int position);
        }
    
        public static int dp2px(Context context, float dipValue) {
            final float scale = context.getResources().getDisplayMetrics().density;
            return (int) (dipValue * scale + 0.5f);
        }
    }
    
    • FontChangeActivity.java
    package com.fcsc.commine.activity;
    
    import android.app.Activity;
    import android.content.Intent;
    import android.content.res.Configuration;
    import android.content.res.Resources;
    import android.util.DisplayMetrics;
    import android.widget.ImageView;
    import android.widget.TextView;
    
    import com.alibaba.android.arouter.facade.annotation.Route;
    import com.fcsc.commine.R;
    import com.fcsc.commine.R2;
    import com.fcsc.common.FcscKey;
    import com.fcsc.fcscbaseframwork.base.BaseActivity;
    import com.fcsc.fcscbaseframwork.base.IPresenter;
    import com.fcsc.fcscbaseframwork.base.PageManager;
    import com.fcsc.fcscbaseframwork.util.MMKVHelper;
    import com.fcsc.fcscuilib.customview.CustomSeekbar;
    
    import java.util.Stack;
    
    import androidx.annotation.NonNull;
    import androidx.annotation.Nullable;
    import butterknife.BindView;
    
    /**
     * 改变字体大小的activity
     * @author pengyanni
     */
    @Route(path = "/commine/fontchangeactivity")
    public class FontChangeActivity extends BaseActivity {
    
        private float[] mFontSize = {0.84f, 0.92f, 1.0f, 1.04f, 1.08f, 1.12f};
    
        @BindView(R2.id.custom_seekbar_fontsize)
        CustomSeekbar customSeekbar;
        @BindView(R2.id.tv_commom_title)
        TextView tvTitle;
        @BindView(R2.id.img_commom_back)
        ImageView imgBack;
    
        /**
         * 默认标准
         */
        private float newFontScale;
    
        @Override
        protected void initViewAndEvent() {
    
            tvTitle.setText("字体大小");
            imgBack.setOnClickListener(v -> finish());
            mImmersionBar.statusBarColor(R.color.colorPrimary).init();
    
            float oldFontScale = MMKVHelper.getInstance().getFloat(FcscKey.KEY_FONT_SCALE, 1.0f);
            for (int index = 0; index < mFontSize.length; index++) {
                if (mFontSize[index] == oldFontScale) {
                    customSeekbar.setCurrntPosition(index);
                }
            }
    
            newFontScale = oldFontScale;
    
            customSeekbar.setOnPointResultListener(position -> {
                newFontScale = mFontSize[position];
                if (newFontScale != oldFontScale) {
                    updateAppFontSize(newFontScale);
                    startActivity(new Intent(this, FontChangeActivity.class));
                    overridePendingTransition(R.anim.anim_in, R.anim.anim_out);
                    finish();
                }
            });
    
        }
    
        @Override
        protected void initDatas() {
    
        }
    
        @Nullable
        @Override
        protected IPresenter createPresenter() {
            return null;
        }
    
        @NonNull
        @Override
        protected int getLayoutId() {
            return R.layout.activity_font_change;
        }
    
        /**
         * 更新app的字体缩放
         *
         * @param newFontScale 缩放比例
         */
        private void updateAppFontSize(float newFontScale) {
    
            Stack<Activity> activityStack = PageManager.getInstance().getAllActivities();
            if (activityStack != null) {
                for (Activity activity : activityStack) {
                    if (activity instanceof FontChangeActivity) {
                        continue;
                    }
                    Resources resources = activity.getResources();
                    if (resources != null) {
                        Configuration configuration = activity.getResources().getConfiguration();
                        configuration.fontScale = newFontScale;
                        DisplayMetrics metrics = new DisplayMetrics();
                        activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
                        metrics.scaledDensity = configuration.fontScale * metrics.density;
                        resources.updateConfiguration(configuration, metrics);
                        activity.recreate();
                    }
                }
                MMKVHelper.getInstance().saveFloat(FcscKey.KEY_FONT_SCALE, newFontScale);
            }
        }
    }
    
    
    • activity_font_change.xml
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  xmlns:app="http://schemas.android.com/apk/res-auto"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent"
                  android:background="@color/windowBackground"
                  android:fitsSystemWindows="true"
                  android:orientation="vertical">
    
        <include layout="@layout/commom_title_bar"/>
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:lineSpacingExtra="10dp"
            android:layout_marginTop="50dp"
            android:paddingLeft="@dimen/aroundMargins"
            android:paddingRight="@dimen/aroundMargins"
            android:singleLine="false"
            android:text="@string/change_fontsize_description"
            android:textAppearance="?android:textAppearanceMedium"
            android:layout_weight="1"
            android:textColor="@color/textMainColor"/>
    
        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="150dp"
            android:layout_gravity="bottom"
            android:background="@color/viewBackground"
            android:padding="16dp">
    
            <com.fcsc.fcscuilib.customview.CustomSeekbar
                android:id="@+id/custom_seekbar_fontsize"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                app:circleRadius="12dp"
                app:customLineColor="@color/textMainColor"
                app:totalCount="5"/>
    
        </FrameLayout>
    
    </LinearLayout>
    
    • 效果
    截图

    相关文章

      网友评论

        本文标题:Android 实现更改字体大小

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