小夥伴們你們好呀,此次介紹一個稍微有點意思的View,在不少閱讀類、新聞類的APP上都標配的字體大小調整功能。100多行代碼就能夠實現,來看看效果吧!java
思路分析android
一、刻度線表明着每一個字體的大小取值,是否是SeekBar
就是這樣的功能呀,改一下刻度浮標的樣式便可。git
二、刻度條上面的標註的文本表明着字體大小的說明,假設用一個LinearLayout
包着3個TextView
的方法很難實現文本跟刻度對齊,只能畫出來了。github
開始寫代碼canvas
咱們以SeekBar
做爲基礎,對它進行重寫onDraw()
的方法,在這以前先來初始化一下基本屬性。數組
/** * 字體大小調整滑桿 * Created by ChenRui on 2017/10/13 0013 12:50. */
public class RaeSeekBar extends AppCompatSeekBar {
// 刻度說明文本,數組數量跟刻度數量一致,跟mTextSize的長度要一致
private String[] mTickMarkTitles = new String[]{
"A",
"標準",
"",
"",
"A"
};
// 刻度表明的字體大小
private int[] mTextSize = new int[]{
16,
18,
24,
26,
28
};
// 刻度文本畫筆
private final Paint mTickMarkTitlePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
// 刻度文本字體大小
private float mTickMarkTitleTextSize = 18;
// 刻度文本跟刻度之間的間隔
private float mOffsetY = 40;
// 刻度線的高度
private int mLineHeight = 10;
// 保存位置大小信息
private final Rect mRect = new Rect();
// ...省略一些其餘構造函數
public RaeSeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
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.ph1));
// 設置最大刻度值爲字體大小數組的長度
setMax(mTextSize.length);
// 設置當前的刻度
setProgress(1);
}
}
複製代碼
測量佈局ide
由於要在原來的SeekBar
的基礎 上添加文本,那就應該在原來的SeekBar
的 高度上再增長最大刻度的文字的高度就是控件佈局的高度。函數
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 原來的佈局大小
int wm = MeasureSpec.getMode(widthMeasureSpec);
int hm = MeasureSpec.getMode(heightMeasureSpec);
int w = getMeasuredWidth();
int h = getMeasuredHeight();
// 以最大的字體爲基礎,加上刻度字體大小
h += getSize(mTextSize[mTextSize.length - 1]);
// 加上與刻度之間的間距大小
h += mOffsetY;
// 保存測量結果
setMeasuredDimension(MeasureSpec.makeMeasureSpec(w, wm), MeasureSpec.makeMeasureSpec(h, hm));
}
複製代碼
重繪佈局
總結一下畫的思路,這樣能夠比較好理解代碼的實現。整個過程一共須要咱們畫3部分:字體
固然還有個滑動塊,這個咱們可使用SeekBar
自帶的效果,便可以自定義樣式,又能偷下懶。下面來一個個解析畫的具體步驟。
一、畫直線
咱們先理解成外部是一個矩形,直線位於中間,左右兩邊的間距爲滑塊的一半。經過研究發現getPaddingLeft()
getPaddingRight()
正好就是這個一半值。
二、刻度線
很容易看得出來,刻度線實際是把直線進行等分,等分的多少取決於setMax()
的取值,也至關於mTextSize.length
,這樣咱們經過畫直線就能輕鬆實現了。
三、刻度文本
最重要的是肯定文本所在的(x,y) 座標值
便可,不難發現文本的座標是跟隨刻度線的位置變化的,因此在畫刻度線的時候就能夠一塊兒把文本也畫出來了。
四、滑塊位置
系統滑塊的位置實際上是跟分割線的位置同樣的。等分直線,處於分割線中心。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 刻度長度
int maxLength = getMax();
int width = getWidth();
int height = getHeight();
int h2 = height / 2; // 居中
// 畫刻度背景
mRect.left = getPaddingLeft();
mRect.right = width - getPaddingRight();
mRect.top = h2 - getSize(1); // 居中
mRect.bottom = mRect.top + getSize(1.5f); // 1.5f爲直線的高度
// 直線的長度
int lineWidth = mRect.width();
// 畫直線
canvas.drawRect(mRect, mTickMarkTitlePaint);
// 遍歷刻度,畫分割線和刻度文本
for (int i = 0; i <= maxLength; i++) {
// 刻度的起始間隔 = 左間距 + (線條的寬度 * 當前刻度位置 / 刻度長度)
int thumbPos = getPaddingLeft() + (lineWidth * i / maxLength);
// 畫分割線
mRect.top = h2 - mLineHeight / 2;
mRect.bottom = h2 + mLineHeight / 2;
mRect.left = thumbPos;
mRect.right = thumbPos + getSize(1.5f); // 直線的寬度爲1.5
canvas.drawRect(mRect, mTickMarkTitlePaint);
// 畫刻度文本
String title = mTickMarkTitles[i % mTickMarkTitles.length]; // 拿到刻度文本
mTickMarkTitlePaint.getTextBounds(title, 0, title.length(), mRect); // 計算刻度文本的大小以及位置
mTickMarkTitlePaint.setTextSize(getSize(mTextSize[i])); // 設置刻度文字大小
// 畫文本
canvas.drawText(title, thumbPos, getSize(mTextSize[mTextSize.length - 1]), mTickMarkTitlePaint);
}
}
複製代碼
畫好了是否是等不及了來實際應用一下呢?
具體應用示例
<!--thumb屬性爲滑塊的圖片-->
<com.rae.cnblogs.widget.RaeSeekBar android:id="@+id/seekBar" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@android:color/transparent" android:progressDrawable="@android:color/transparent" android:theme="@style/Widget.AppCompat.SeekBar" android:thumb="@drawable/seekbar_thumb_material_anim_font_setting" />
複製代碼
<selector xmlns:android="http://schemas.android.com/apk/res/android" android:constantSize="true">
<item>
<shape android:shape="oval">
<solid android:color="@color/badge_color" />
<size android:width="24dp" android:height="24dp" />
</shape>
</item>
</selector>
複製代碼
mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int value, boolean b) {
// 獲取滑塊所在位置對應的字體大小
int size = mSeekBar.getRawTextSize(value);
mMessage.setTextSize(size);
}
//... 省略其餘方法
});
複製代碼
源碼
好啦,本篇文章到這裏結束了。忍不住想試試的,能夠參考源代碼來作,在博客園Android開源客戶端項目中,喜歡的給個Star
~~
源碼主要類: