zoukankan      html  css  js  c++  java
  • Android项目实战(二十三):仿QQ设置App全局字体大小

    一、项目需求:

    因为产品对象用于中老年人,所以产品设计添加了APP全局字体调整大小功能。

    这里仿做QQ设置字体大小的功能。

      

    QQ实现的效果是,滚动下面的seekbar,当只有seekbar到达某一个刻度的时候,这时候上部分的效果展示部分会改变文字大小,

    但是在拖动过程中字体不会改变。关闭此界面,就可以看到改变文字后app整体的实际文字大小效果了。

    -----------------------------------------------------------------------------------------------------------------------------

    二、理清一下实现思路:

    1、先将一个APP内所有的文本设置级别,大概3--5个级别(具体看项目需求),比如标题栏的TextView我们给他设置级别1(默认24sp)  ,类似设置 级别2(默认22sp)等等。

      这样做的目的可以方便的我们设置,如果每个Textview大小都乱乱的,那这个文字大小改变的功能也没什么意义了。

    2、创建一个类Constant,类中创建一个静态变量,这个变量用于记录当我们拖动seekbar的时候 对应改变。取值范围就是我们seekbar的界点。

    Demo我们限制文字大小有四个界点:小、标准、大、特大。

    那么静态变量 TEXT_SIZE 取值就有0,1,2,3

     public static int TEXT_SIZE = 0;

    3、滑动seekbar,当达到界点的时候,改变静态变量TEXT_SIZE的值,并且刷新列表适配器(这个列表是展示文字大小效果的,所以数据是我们自己写死的,

    要求达到某个界点才会刷新适配器,绝不可能seekbar有滑动操作我们就执行刷新适配器的)

    4、在退出设置字体界面的时候,用sharedPreferences保存,每次进入app的时候读取。

    这样在每个Activity或者Fragment 创建View的过程中在 TextView创建的时候给控件动态设置文字的大小   

    textview.setTextSize(级别默认文字大小+seekbar级别*3);

    思路就是这么简单,看懂的可以自己去实现了,有点懵的看下面的例子来深入了解下。

    整体思路就是:  一个标记变量,记录要显示文字大小的级别,sharedpreference保存。然后在每个要打开的新的界面创建View的过程中 给TextView动态设置文字大小

    注意:不是我修改文字大小之后,整个APP所有界面的TextView都立马改变。

    -----------------------------------------------------------------------------------------------------------------------------

     三、代码实现

    1、首先就是这个SeekBar控件,上面需要有刻度,需要有文字,显然我们用android提供的自带的SeekBar控件已经不满足我们的需求了。

         但是,这里我找到了一个很好的自定义控件可以完美的实现这个问题:

         资料来源:   Android 自定义带刻度的seekbar   

      这里我加了一些注释

      1 public class CustomSeekbar extends View {
      2     private final String TAG = "CustomSeekbar";
      3     private int width;
      4     private int height;
      5     private int downX = 0;
      6     private int downY = 0;
      7     private int upX = 0;
      8     private int upY = 0;
      9     private int moveX = 0;
     10     private int moveY = 0;
     11     private float scale = 0;
     12     private int perWidth = 0;
     13     private Paint mPaint;
     14     private Paint mTextPaint;
     15     private Paint buttonPaint;
     16     private Canvas canvas;
     17     private Bitmap bitmap;
     18     private Bitmap thumb;
     19     private Bitmap spot;
     20     private Bitmap spot_on;
     21     private int hotarea = 100;//点击的热区
     22     private int cur_sections = 2;
     23     private ResponseOnTouch responseOnTouch;
     24     private int bitMapHeight = 38;//第一个点的起始位置起始,图片的长宽是76,所以取一半的距离
     25     private int textMove = 60;//字与下方点的距离,因为字体字体是40px,再加上10的间隔
     26     private int[] colors = new int[]{0xffdf5600,0x33000000};//进度条的橙色,进度条的灰色,字体的灰色
     27     private int textSize;
     28     private int circleRadius;
     29     private ArrayList<String> section_title;
     30     public CustomSeekbar(Context context) {
     31         super(context);
     32     }
     33     public CustomSeekbar(Context context, AttributeSet attrs) {
     34         this(context, attrs, 0);
     35     }
     36     public CustomSeekbar(Context context, AttributeSet attrs, int defStyleAttr) {
     37         super(context, attrs, defStyleAttr);
     38         cur_sections = 0;
     39         bitmap = Bitmap.createBitmap(900, 1100, Bitmap.Config.ARGB_8888);
     40         canvas = new Canvas();
     41         canvas.setBitmap(bitmap);
     42         thumb = BitmapFactory.decodeResource(getResources(), R.mipmap.img_setting_seekbar_thumbe_large);   //这个是滑动图标
     43         spot = BitmapFactory.decodeResource(getResources(),R.mipmap.img_setting_seekbar_thumbe);            //这个是未滑动到的界点的图标
     44         spot_on = BitmapFactory.decodeResource(getResources(),R.mipmap.img_setting_seekbar_thumbe);         //这个是已经滑动过的界点的图标
     45         bitMapHeight = thumb.getHeight()/2;   //这里影响点中的图标的位置  这个正好 不用改
     46         textMove = bitMapHeight+ 5;   //xqx  这里参数大小要改,不是固定的,具体看项目效果
     47         textSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20, getResources().getDisplayMetrics());   //文字大小,第二个参数个人设置
     48         circleRadius = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 3, getResources().getDisplayMetrics());
     49         mPaint = new Paint(Paint.DITHER_FLAG);
     50         mPaint.setAntiAlias(true);//锯齿不显示
     51         mPaint.setStrokeWidth(3);
     52         mTextPaint = new Paint(Paint.DITHER_FLAG);
     53         mTextPaint.setAntiAlias(true);
     54         mTextPaint.setTextSize(textSize);
     55         mTextPaint.setColor(0xffb5b5b4);
     56         buttonPaint = new Paint(Paint.DITHER_FLAG);
     57         buttonPaint.setAntiAlias(true);
     58 
     59     }
     60     /**
     61      * 实例化后调用,设置bar的段数和文字
     62      */
     63     public void initData(ArrayList<String> section){
     64         if(section != null){
     65             section_title = section;
     66         }else {
     67             //如果没有传入正确的分类级别数据,则默认使用“低”“中”“高”
     68             String[] str = new String[]{"", "", ""};
     69             section_title = new ArrayList<String>();
     70             for (int i = 0; i < str.length; i++) {
     71                 section_title.add(str[i]);
     72             }
     73         }
     74     }
     75 
     76     @Override
     77     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
     78         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
     79 
     80         int widthMode = MeasureSpec.getMode(widthMeasureSpec);
     81         int widthSize = MeasureSpec.getSize(widthMeasureSpec);
     82         int heightMode = MeasureSpec.getMode(heightMeasureSpec);
     83         int heightSize = MeasureSpec.getSize(heightMeasureSpec);
     84 
     85         width = widthSize;
     86         float scaleX = widthSize / 1080;
     87         float scaleY = heightSize / 1920;
     88         scale = Math.max(scaleX,scaleY);
     89         //控件的高度
     90         //height = 185;
     91         height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 62, getResources().getDisplayMetrics());
     92         setMeasuredDimension(width, height);
     93         width = width-bitMapHeight/2;
     94         perWidth = (width - section_title.size()*spot.getWidth() - thumb.getWidth()/2) / (section_title.size()-1);
     95         hotarea = perWidth/2;
     96     }
     97 
     98     @Override
     99     protected void onDraw(Canvas canvas) {
    100         super.onDraw(canvas);
    101         mPaint.setColor(Color.WHITE);
    102         mPaint.setStyle(Paint.Style.FILL);
    103         mPaint.setAlpha(0);
    104         canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);
    105         canvas.drawBitmap(bitmap, 0, 0, null);
    106         mPaint.setAlpha(255);
    107         mPaint.setColor(colors[1]);
    108         canvas.drawLine(bitMapHeight, height * 2 / 3, width - bitMapHeight - spot_on.getWidth() / 2, height * 2 / 3, mPaint);
    109         int section = 0;
    110         while(section < section_title.size()){
    111             if(section < cur_sections) {
    112                 mPaint.setColor(colors[0]);
    113                 canvas.drawLine(thumb.getWidth()/2 + section * perWidth + (section+1) * spot_on.getWidth(),height * 2 / 3,
    114                         thumb.getWidth()/2 + section * perWidth + (section+1) * spot_on.getWidth() + perWidth,height * 2 / 3,mPaint);
    115                 canvas.drawBitmap(spot_on, thumb.getWidth()/2 + section * perWidth + section * spot_on.getWidth(),height * 2 / 3 - spot_on.getHeight()/2,mPaint);
    116             }else{
    117                 mPaint.setAlpha(255);
    118                 if(section == section_title.size()-1){
    119                     canvas.drawBitmap(spot,  width - spot_on.getWidth() - bitMapHeight/2, height * 2 / 3 - spot.getHeight() / 2, mPaint);
    120                 }else {
    121                     canvas.drawBitmap(spot, thumb.getWidth()/2 + section * perWidth + section * spot_on.getWidth(), height * 2 / 3 - spot.getHeight() / 2, mPaint);
    122                 }
    123             }
    124 
    125             if(section == section_title.size()-1) {
    126                 canvas.drawText(section_title.get(section), width - spot_on.getWidth()- bitMapHeight/4 - textSize / 2, height * 2 / 3 - textMove, mTextPaint);
    127             }else{
    128                 canvas.drawText(section_title.get(section), thumb.getWidth()/2 + section * perWidth + section * spot_on.getWidth(), height * 2 / 3 - textMove, mTextPaint);
    129             }
    130             section++;
    131         }
    132         if(cur_sections == section_title.size()-1){
    133             canvas.drawBitmap(thumb, width - spot_on.getWidth() - bitMapHeight/2 - thumb.getWidth() / 2,
    134                     height * 2 / 3 - bitMapHeight, buttonPaint);
    135         }else {
    136             canvas.drawBitmap(thumb, thumb.getWidth()/2 + cur_sections * perWidth + cur_sections * spot_on.getWidth() - thumb.getWidth()/4 ,
    137                     height * 2 / 3 - bitMapHeight, buttonPaint);
    138         }
    139     }
    140 
    141     @Override
    142     public boolean onTouchEvent(MotionEvent event) {
    143         super.onTouchEvent(event);
    144         switch (event.getAction()) {
    145             case MotionEvent.ACTION_DOWN:
    146                 thumb = BitmapFactory.decodeResource(getResources(), R.mipmap.img_setting_seekbar_thumbe_large);
    147                 downX = (int) event.getX();
    148                 downY = (int) event.getY();
    149                 responseTouch(downX, downY);
    150                 break;
    151             case MotionEvent.ACTION_MOVE:
    152                 thumb = BitmapFactory.decodeResource(getResources(), R.mipmap.img_setting_seekbar_thumbe_large);
    153                 moveX = (int) event.getX();
    154                 moveY = (int) event.getY();
    155                 responseTouch(moveX, moveY);
    156                 break;
    157             case MotionEvent.ACTION_UP:
    158                 thumb = BitmapFactory.decodeResource(getResources(), R.mipmap.img_setting_seekbar_thumbe_large);
    159                 upX = (int) event.getX();
    160                 upY = (int) event.getY();
    161                 responseTouch(upX, upY);
    162                 responseOnTouch.onTouchResponse(cur_sections);
    163                 break;
    164         }
    165         return true;
    166     }
    167     private void responseTouch(int x, int y){
    168         if(x <= width-bitMapHeight/2) {
    169             cur_sections = (x + perWidth / 3) / perWidth;
    170         }else{
    171             cur_sections = section_title.size()-1;
    172         }
    173         invalidate();
    174     }
    175 
    176     //设置监听
    177     public void setResponseOnTouch(ResponseOnTouch response){
    178         //注意 ,这里是接口,实现你到达界点的监听事件,因为这个自定义控件继承的View而不是SeekBar,所以只能使用接口实现监听
    179         responseOnTouch = response;
    180     }
    181 
    182 
    183     //设置进度
    184     public void setProgress(int progress){
    185         cur_sections = progress;
    186         invalidate();
    187     }
    188 }
    CustomSeekbar.class

    2、根据这个自定义CustomSeekbar控件,我们首先要建一个接口

    public interface ResponseOnTouch {
        public void onTouchResponse(int volume);
    }

    3、创建一个类。设置一个静态属性 

    public class Constant {
    public static int TEXT_SIZE = 0;
    }

    4、接下来写字体设置后的效果界面:qq的效果界面有两个,一个是聊天的界面,一个是列表的界面。

    这里我们只展示列表的界面

    列表代码就不展示了

    直接看如何使用CustomSeekbar

     1         private CustomSeekbar seekBar;
     2         seekBar = (CustomSeekbar) findViewById(R.id.progressBar);
     3      //这个集合用于给自定义SeekBar设置界点级别,集合里有几个数据,就有几个界点
     4         ArrayList<String> volume_sections = new ArrayList<String>();      
     5         volume_sections.add("");
     6         volume_sections.add("标准");
     7         volume_sections.add("");
     8         volume_sections.add("特大");
     9         seekBar.initData(volume_sections);
    10         seekBar.setProgress(0); //设置默认级别
    11 
    12 
    13         seekBar.setResponseOnTouch(this);//activity实现了下面的接口ResponseOnTouch,每次touch会回调onTouchResponse

    实现接口:

    @Override
        public void onTouchResponse(int volume) {
            Toast.makeText(this,"volume-->"+volume,Toast.LENGTH_SHORT).show();
            //参数volume就是级别,如果我们集合有4个数据 那么volume的取值就为0、1、2、3
         Constant.TEXT_SIZE
    = volume;
         //这里写sharedpreferences保存该静态变量
         //刷新列表 ,查看文字改变后的效果   adapter.notifyDataSetChanged(); }

    列表适配器中对textview设置大小的代码:

     holder.community_doctor_name.setTextSize(该TextView控件级别默认文字大小+ Constant.TEXT_SIZE*5);

    效果图:

    后续补上。

    个人思路,实现的局限性是有的,大家有修改意见欢迎提出。

  • 相关阅读:
    如何处理iOS中照片的方向
    Builder Pattern 在 Objective-C 中的使用
    多线程(三)-- 线程安全问题
    多线程(二)--NSThread基本使用
    多线程 (一)
    报错:Request failed: unacceptable content-type: text/html
    Cocoapods简单安装和使用
    Objective
    Objective
    Python学习笔记(一)--注释
  • 原文地址:https://www.cnblogs.com/xqxacm/p/5779762.html
Copyright © 2011-2022 走看看