樣式是:
需求概述
我們需要一個類似原生RatingBar的這樣一個評分View,但是RatingBar不夠靈活,我們需要有不同顏色,不同間距,而且可調的一個評分Bar。
分析
我們主要是定義ratingbar,不和文字一起定義。
首先是:單個星星的高和寬,然後是需要知道每個星星之間的間距,還有就是那幾顆星星是active那幾顆是disactivie的。同時,我們需要計算在這個View中的什麼位置開始畫,最後就是需要指定我們的星星的resource了。
實現
屬性定義
需要定義的屬性有:
<declare-styleable name="CustomRatingStyle">
<!--寬,高,間距,啟用的數量,沒有啟用的數量,啟用的icon,沒有啟用的icon-->
<!--屬性分別是:單個的寬,高,之間的距離,啟用的數量,總數量,啟用的drawable,沒有啟用的drawable-->
<attr name="custom_rate_width" format="dimension"/>
<attr name="custom_rate_height" format="dimension"/>
<attr name="custom_rate_padding" format="dimension"/>
<attr name="custom_rate_active_size" format="integer"/>
<attr name="custom_rate_size" format="integer"/>
<attr name="custom_rate_active_drawable" format="reference"/>
<attr name="custom_rate_disactive_drawable" format="reference"/>
</declare-styleable>複製程式碼
程式碼實現:
我們繼承自View就好,不要ViewGroup。然後獲取xml檔案中的自定義屬性值,獲取屬性值完成,同時給定預設值。同時,我們需要計算一個步長,作用是知道我們畫下一個星星開始的座標,他的計算是星星的width+星星之間的padding。同時,還有一點是可能active和disactivie的drawable大小不同,所以我們需要按照其中一個區計算步長,同時縮放到等同大小。比如我們按照active的drawable大小為標準,當disactive的drawable大小不同的時候,就對他進行比例縮放,直到相同。程式碼如下:
程式碼實現
//單個高
private float singleWidth;
//單個寬
private float singleHeight;
//間距
private int padding;
//總數量
private int size = 5;
//預設啟用數量
private int activeSize = 3;
//啟用的bitmap
private Bitmap activeBitmap;
//沒有啟用的bitmap
private Bitmap disactiveBitmap;
//畫筆
private Paint mPaint;
//步長
private int stepSize;
//開始畫的x座標
private int drawStartX;
//開始畫的y座標
private int drawStartY;複製程式碼
初始化程式碼:
int activeId = 0;
int disactiveId = 0;
if (attrs != null) {
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CustomRatingStyle);
singleWidth = array.getDimensionPixelOffset(R.styleable.CustomRatingStyle_custom_rate_width, 0);
singleHeight = array.getDimensionPixelOffset(R.styleable.CustomRatingStyle_custom_rate_height, 0);
activeId = array.getResourceId(R.styleable.CustomRatingStyle_custom_rate_active_drawable, R.drawable.custom_rateingbar_active);
disactiveId = array.getResourceId(R.styleable.CustomRatingStyle_custom_rate_disactive_drawable, R.drawable.custom_rateingbar_disactive);
size = array.getInteger(R.styleable.CustomRatingStyle_custom_rate_size, 5);
activeSize = array.getInteger(R.styleable.CustomRatingStyle_custom_rate_active_size, 3);
padding = array.getDimensionPixelOffset(R.styleable.CustomRatingStyle_custom_rate_padding, 10);
array.recycle();
}
activeBitmap = BitmapFactory.decodeResource(getResources(), activeId);
disactiveBitmap = BitmapFactory.decodeResource(getResources(), disactiveId);
stepSize = padding + activeBitmap.getWidth();
mPaint = new Paint();
if (singleHeight <= 0) {
singleHeight = activeBitmap.getHeight();
}
if (singleWidth <= 0) {
singleWidth = activeBitmap.getWidth();
}
//大小不同的話,對Bitmap進行壓縮,
if (activeBitmap.getWidth() != disactiveBitmap.getWidth() || activeBitmap.getHeight() != disactiveBitmap.getHeight()) {
//把dis壓縮或者是放大的active的大小
disactiveBitmap = Bitmap.createScaledBitmap(disactiveBitmap, activeBitmap.getWidth(), activeBitmap.getHeight(), false);
}複製程式碼
邏輯實現
測量步長計算:我們是把五角星放在這個View的center位置,然後他所佔的長度是5width+4padding。
onMeasure 方法:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width;
int height;
//計算寬
if (widthMode == MeasureSpec.EXACTLY) {
width = widthSize;
} else {
width = 5 * stepSize;
}
//計算高
if (heightMode == MeasureSpec.EXACTLY) {
height = heightSize;
} else {
height = (int) singleHeight;
}
//總共應該的寬
int drawWidth = (int) (size * singleWidth + (size <= 1 ? 0 : (size - 1) * padding));
//開始的y位置
int drawHeight = (int) ((height - singleHeight) / 2);
drawStartX = (width - drawWidth) / 2;
drawStartY = drawHeight > 0 ? drawHeight : 0;
setMeasuredDimension(width, height);
}複製程式碼
onDraw方法:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//開始畫active
for (int i = 0; i < activeSize; i++) {
canvas.drawBitmap(activeBitmap, drawStartX + i * stepSize, drawStartY, mPaint);
}
//開始畫disactive
for (int i = activeSize; i < size; i++) {
canvas.drawBitmap(disactiveBitmap, drawStartX + i * stepSize, drawStartY, mPaint);
}
}複製程式碼
然後,我們在對外提供一個設定activie的方法:
/**
* 設定啟用的數量
*
* @param activeSize
*/
public void setActiveSize(int activeSize) {
this.activeSize = activeSize;
if (CommentUtil.isUIThread()) {
invalidate();
} else {
postInvalidate();
}
}複製程式碼
這樣子就完成了星星評分的UI了。
結果截圖: