一、專案需求:

因為產品物件用於中老年人,所以產品設計添加了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 = ;

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

效果圖:

後續補上。

個人思路,實現的侷限性是有的,大家有修改意見歡迎提出。