Android项目实战(二十三):仿QQ设置App全局字体大小

时间:2022-09-16 13:56:44

一、项目需求:

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

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

Android项目实战(二十三):仿QQ设置App全局字体大小

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 = ;

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

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

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

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

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

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

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

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

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

三、代码实现

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

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

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

  这里我加了一些注释

 public class CustomSeekbar extends View {
private final String TAG = "CustomSeekbar";
private int width;
private int height;
private int downX = ;
private int downY = ;
private int upX = ;
private int upY = ;
private int moveX = ;
private int moveY = ;
private float scale = ;
private int perWidth = ;
private Paint mPaint;
private Paint mTextPaint;
private Paint buttonPaint;
private Canvas canvas;
private Bitmap bitmap;
private Bitmap thumb;
private Bitmap spot;
private Bitmap spot_on;
private int hotarea = ;//点击的热区
private int cur_sections = ;
private ResponseOnTouch responseOnTouch;
private int bitMapHeight = ;//第一个点的起始位置起始,图片的长宽是76,所以取一半的距离
private int textMove = ;//字与下方点的距离,因为字体字体是40px,再加上10的间隔
private int[] colors = new int[]{0xffdf5600,0x33000000};//进度条的橙色,进度条的灰色,字体的灰色
private int textSize;
private int circleRadius;
private ArrayList<String> section_title;
public CustomSeekbar(Context context) {
super(context);
}
public CustomSeekbar(Context context, AttributeSet attrs) {
this(context, attrs, );
}
public CustomSeekbar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
cur_sections = ;
bitmap = Bitmap.createBitmap(, , Bitmap.Config.ARGB_8888);
canvas = new Canvas();
canvas.setBitmap(bitmap);
thumb = BitmapFactory.decodeResource(getResources(), R.mipmap.img_setting_seekbar_thumbe_large); //这个是滑动图标
spot = BitmapFactory.decodeResource(getResources(),R.mipmap.img_setting_seekbar_thumbe); //这个是未滑动到的界点的图标
spot_on = BitmapFactory.decodeResource(getResources(),R.mipmap.img_setting_seekbar_thumbe); //这个是已经滑动过的界点的图标
bitMapHeight = thumb.getHeight()/; //这里影响点中的图标的位置 这个正好 不用改
textMove = bitMapHeight+ ; //xqx 这里参数大小要改,不是固定的,具体看项目效果
textSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, , getResources().getDisplayMetrics()); //文字大小,第二个参数个人设置
circleRadius = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, , getResources().getDisplayMetrics());
mPaint = new Paint(Paint.DITHER_FLAG);
mPaint.setAntiAlias(true);//锯齿不显示
mPaint.setStrokeWidth();
mTextPaint = new Paint(Paint.DITHER_FLAG);
mTextPaint.setAntiAlias(true);
mTextPaint.setTextSize(textSize);
mTextPaint.setColor(0xffb5b5b4);
buttonPaint = new Paint(Paint.DITHER_FLAG);
buttonPaint.setAntiAlias(true); }
/**
* 实例化后调用,设置bar的段数和文字
*/
public void initData(ArrayList<String> section){
if(section != null){
section_title = section;
}else {
//如果没有传入正确的分类级别数据,则默认使用“低”“中”“高”
String[] str = new String[]{"低", "中", "高"};
section_title = new ArrayList<String>();
for (int i = ; i < str.length; i++) {
section_title.add(str[i]);
}
}
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec); width = widthSize;
float scaleX = widthSize / ;
float scaleY = heightSize / ;
scale = Math.max(scaleX,scaleY);
//控件的高度
//height = 185;
height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, , getResources().getDisplayMetrics());
setMeasuredDimension(width, height);
width = width-bitMapHeight/;
perWidth = (width - section_title.size()*spot.getWidth() - thumb.getWidth()/) / (section_title.size()-);
hotarea = perWidth/;
} @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(Color.WHITE);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setAlpha();
canvas.drawRect(, , getMeasuredWidth(), getMeasuredHeight(), mPaint);
canvas.drawBitmap(bitmap, , , null);
mPaint.setAlpha();
mPaint.setColor(colors[]);
canvas.drawLine(bitMapHeight, height * / , width - bitMapHeight - spot_on.getWidth() / , height * / , mPaint);
int section = ;
while(section < section_title.size()){
if(section < cur_sections) {
mPaint.setColor(colors[]);
canvas.drawLine(thumb.getWidth()/ + section * perWidth + (section+) * spot_on.getWidth(),height * / ,
thumb.getWidth()/ + section * perWidth + (section+) * spot_on.getWidth() + perWidth,height * / ,mPaint);
canvas.drawBitmap(spot_on, thumb.getWidth()/ + section * perWidth + section * spot_on.getWidth(),height * / - spot_on.getHeight()/,mPaint);
}else{
mPaint.setAlpha();
if(section == section_title.size()-){
canvas.drawBitmap(spot, width - spot_on.getWidth() - bitMapHeight/, height * / - spot.getHeight() / , mPaint);
}else {
canvas.drawBitmap(spot, thumb.getWidth()/ + section * perWidth + section * spot_on.getWidth(), height * / - spot.getHeight() / , mPaint);
}
} if(section == section_title.size()-) {
canvas.drawText(section_title.get(section), width - spot_on.getWidth()- bitMapHeight/ - textSize / , height * / - textMove, mTextPaint);
}else{
canvas.drawText(section_title.get(section), thumb.getWidth()/ + section * perWidth + section * spot_on.getWidth(), height * / - textMove, mTextPaint);
}
section++;
}
if(cur_sections == section_title.size()-){
canvas.drawBitmap(thumb, width - spot_on.getWidth() - bitMapHeight/ - thumb.getWidth() / ,
height * / - bitMapHeight, buttonPaint);
}else {
canvas.drawBitmap(thumb, thumb.getWidth()/ + cur_sections * perWidth + cur_sections * spot_on.getWidth() - thumb.getWidth()/ ,
height * / - bitMapHeight, buttonPaint);
}
} @Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
thumb = BitmapFactory.decodeResource(getResources(), R.mipmap.img_setting_seekbar_thumbe_large);
downX = (int) event.getX();
downY = (int) event.getY();
responseTouch(downX, downY);
break;
case MotionEvent.ACTION_MOVE:
thumb = BitmapFactory.decodeResource(getResources(), R.mipmap.img_setting_seekbar_thumbe_large);
moveX = (int) event.getX();
moveY = (int) event.getY();
responseTouch(moveX, moveY);
break;
case MotionEvent.ACTION_UP:
thumb = BitmapFactory.decodeResource(getResources(), R.mipmap.img_setting_seekbar_thumbe_large);
upX = (int) event.getX();
upY = (int) event.getY();
responseTouch(upX, upY);
responseOnTouch.onTouchResponse(cur_sections);
break;
}
return true;
}
private void responseTouch(int x, int y){
if(x <= width-bitMapHeight/) {
cur_sections = (x + perWidth / ) / perWidth;
}else{
cur_sections = section_title.size()-;
}
invalidate();
} //设置监听
public void setResponseOnTouch(ResponseOnTouch response){
//注意 ,这里是接口,实现你到达界点的监听事件,因为这个自定义控件继承的View而不是SeekBar,所以只能使用接口实现监听
responseOnTouch = response;
} //设置进度
public void setProgress(int progress){
cur_sections = progress;
invalidate();
}
}

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

         private CustomSeekbar seekBar;
seekBar = (CustomSeekbar) findViewById(R.id.progressBar);
     //这个集合用于给自定义SeekBar设置界点级别,集合里有几个数据,就有几个界点
ArrayList<String> volume_sections = new ArrayList<String>();
volume_sections.add("小");
volume_sections.add("标准");
volume_sections.add("大");
volume_sections.add("特大");
seekBar.initData(volume_sections);
seekBar.setProgress(); //设置默认级别 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);

效果图:

后续补上。

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

Android项目实战(二十三):仿QQ设置App全局字体大小的更多相关文章

  1. Android项目实战之高仿网易云音乐创建项目和配置

    这一节我们来讲解创建项目:说道大家可能就会说了,创建项目还有谁不会啊,还需要讲吗,别急听我慢慢到来,肯定有你不知道的. 使用项目Android Studio创建项目我们这里就不讲解了,主要是讲解如何配 ...

  2. Android项目实战之高仿网易云音乐项目介绍

    这一节我们来讲解这个项目所用到的一些技术,以及一些实现的效果图,让大家对该项目有一个整体的认识,推荐大家收藏该文章,因为我们发布文章后会在该文章里面加入链接,这样大家找着就很方便. 目录 第1章 前期 ...

  3. Android项目实战(十三):浅谈EventBus

    概述: EventBus是一款针对Android优化的发布/订阅事件总线. 主要功能是替代Intent,Handler,BroadCast在Fragment,Activity,Service. 线程之 ...

  4. Android项目实战(二十九):酒店预定日期选择

    先看需求效果图: 几个需求点: 1.显示当月以及下个月的日历 (可自行拓展更多月份) 2.首次点击选择"开始日期",再次点击选择"结束日期" (1).如果&qu ...

  5. (转载)Android项目实战(十七):QQ空间实现(二)—— 分享功能 &sol; 弹出PopupWindow

    Android项目实战(十七):QQ空间实现(二)—— 分享功能 / 弹出PopupWindow   这是一张QQ空间说说详情的截图. 分析: 1.点击右上角三个点的图标,在界面底部弹出一个区域,这个 ...

  6. (转载)Android项目实战(二十七):数据交互(信息编辑)填写总结

    Android项目实战(二十七):数据交互(信息编辑)填写总结   前言: 项目中必定用到的数据填写需求.比如修改用户名的文字编辑对话框,修改生日的日期选择对话框等等.现总结一下,方便以后使用. 注: ...

  7. (转载)Android项目实战(二十八):使用Zxing实现二维码及优化实例

    Android项目实战(二十八):使用Zxing实现二维码及优化实例 作者:听着music睡 字体:[增加 减小] 类型:转载 时间:2016-11-21我要评论 这篇文章主要介绍了Android项目 ...

  8. (转载)Android项目实战(三十二):圆角对话框Dialog

    Android项目实战(三十二):圆角对话框Dialog   前言: 项目中多处用到对话框,用系统对话框太难看,就自己写一个自定义对话框. 对话框包括:1.圆角 2.app图标 , 提示文本,关闭对话 ...

  9. (转载)Android项目实战(二十八):Zxing二维码实现及优化

    Android项目实战(二十八):Zxing二维码实现及优化   前言: 多年之前接触过zxing实现二维码,没想到今日项目中再此使用竟然使用的还是zxing,百度之,竟是如此牛的玩意. 当然,项目中 ...

随机推荐

  1. VALGRIND

    系统编程中一个重要的方面就是有效地处理与内存相关的问题.你的工作越接近系统,你就需要面对越多的内存问题.有时这些问题非常琐碎,而更多时候它会演变成一个调试内存问题的恶梦.所以,在实践中会用到很多工具来 ...

  2. Struts的前世今身

    1.Struts1的运行原理 a.初始化:struts框架的总控制器ActionServlet是一个Servlet,它在web.xml中配置成自动启动的Servlet,在启动时总控制器会读取配置文件( ...

  3. python实例编写(1)--浏览器操作,元素操作

    一.浏览器操作 1.  back()与 forward() #coding=gbk //编码不一定是utf-8 from selenium import webdriver //导入包,也叫”模组“ ...

  4. JAVA&lowbar;SE基础——69&period;Date类

    package cn.itcast.other; import java.text.ParseException; import java.text.SimpleDateFormat; import ...

  5. Winform外包团队 项目案例展示

    北京动点飞扬软件开发团队 C# WInform项目案例展示 长年承接WInForm C#项目开发,商业案例欢迎联系我们索取 有相关项目外包定制开发 欢迎联系我们 qq372900288 Tel 139 ...

  6. IO流----操作文件的9种方法代码实现

    IO流----操作文件的9种方法代码实现: 1:使用字节流读写数据: 四种方式: method1:          每次读写一个字节,边读边写: /* * 复制文本文件. * * 数据源:从哪里来 ...

  7. H5 C3

    为什么学习HTML5 a.因为语义化标签的出现网页结构更加清晰 b.因为多媒体的出现,让网页播放音频和视频没有了依赖 c.因为CSS3的出现,让页面变得更加炫酷和多彩 d.因为新的API的出现,使的开 ...

  8. html5 &plus; shiro

    偶然与巧合 舞动了蝶翼 谁的心头风起 前赴而后继 万千人追寻 荒漠唯一菩提 似擦肩相遇 或擦肩而去 命运犹如险棋 无数时间线 无数可能性 终于交织向你

  9. vbox中安装mac系统

    参考: https://www.cnblogs.com/liming2017/p/7566953.html

  10. Beta阶段第2周&sol;共2周 Scrum立会报告&plus;燃尽图 10

    作业要求[https://edu.cnblogs.com/campus/nenu/2018fall/homework/2411] 版本控制:https://git.coding.net/liuyy08 ...