github地址:https://github.com/Ed1sonJ/Ratingbar
實現(xiàn)了的功能:
1明垢、可以自己設(shè)置星星的圖片神得。
2、可以設(shè)置星星之間的padding饥侵。
3鸵赫、可以設(shè)置星星初始的個數(shù)。
4躏升、可以設(shè)置星星的大小辩棒。
為什么要自定義:
1、原生的Ratingbar不能設(shè)置star的padding膨疏。
2一睁、自定義的Ratingbar更加好擴展。
實現(xiàn)的效果:
1佃却、設(shè)置自定義屬性
star的總數(shù)量者吁、star的padding、star的size(長寬目前設(shè)置統(tǒng)一)饲帅、star空白的pic复凳、star被點亮的pic、star初始化的數(shù)量灶泵。
<declare-styleable name="Ratingbar">
<attr name="starNum" format="integer"/>
<attr name="starPadding" format="dimension"/>
<attr name="starSize" format="dimension"/>
<attr name="starEmptyPic" format="reference"/>
<attr name="starFullPic" format="reference"/>
<attr name="starInitNum" format="integer"/>
</declare-styleable>
2育八、計算高寬
計算的公式為:
寬度:左右padding + starPadding *(starNum-1)+ starSize * starNum。
高度:上下padding + starSize丘逸。
//計算寬度
private int measureWidth(int measureSpec) {
int result;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else {
//padding + 星星間距*(num-1)+星星大小*num
result = getPaddingLeft() + getPaddingRight() + starPadding * (starNum - 1) + starSize * starNum;
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize);
}
}
return result;
}
//計算高度
private int measuredHeight(int measureSpec) {
int result;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else {
//padding + 星星高度
result = getPaddingTop() + getPaddingBottom() + starSize;
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize);
}
}
return result;
}
3单鹿、初始繪出星星
3.1,首先繪制星星時要先將畫板移動到特定的位置:
canvas.translate(0, getMeasuredHeight() / 2 - starSize / 2);
將畫板的左上角坐標(biāo)移動到整個View高度的一半再偏上一個pic高度的一半深纲,畫出的圖就能正中顯示在View中。
3.2劲妙,畫出底層的星星(starEmptyPic)
//先畫出灰色的星星
for (int i = 1; i <= starNum; i++) {
left = getPaddingLeft() + (i - 1) * starPadding + (i - 1) * starSize;//算出左坐標(biāo)
canvas.drawBitmap(starEmptyBitmap, left, top, mPaint);
}
3.3湃鹊,畫出初始化的星星(starFullPic)
//判斷是否第一次初始化,是就畫出默認(rèn)點亮的星星
if (isFirstDraw) {
for (int i = 1; i <= starInitNum; i++) {
left = getPaddingLeft() + (i - 1) * starPadding + (i - 1) * starSize;//算出左坐標(biāo)
canvas.drawBitmap(starFullBitmap, left, top, mPaint);
}
}
isFirstDraw的值在View的觸摸事件上改變镣奋,觸摸View后就不再繪制默認(rèn)點亮的星星币呵。
4、觸摸及滑動畫出點亮的星星
4.1,觸摸事件的處理
@Override
public boolean onTouchEvent(MotionEvent event) {
isFirstDraw = false;
if (isCanTouch) {//可以滑動觸摸
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
caculateStarFullPicNum(event.getX());
break;
case MotionEvent.ACTION_MOVE:
caculateStarFullPicNum(event.getX());
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
return false;
}
1.isFirstDraw用于控制onDraw()中是否需要畫出初始化被點亮的星星余赢。
2.isCanTouch提供一個開關(guān)來控制觸摸畫星星芯义。
3.down和move的時候,計算應(yīng)該要畫的星星的數(shù)量妻柒。
4.2扛拨,計算被點亮的星星
計算的方法如下,分3種情況:
1举塔,觸摸的位置在第一個星星的左側(cè)绑警,這時候應(yīng)該顯示最小的星星數(shù)量(通常為0或者1)。
2央渣,觸摸的位置在倒數(shù)第二個星星的末端到View的右邊界计盒,這時候應(yīng)該顯示最大的星星數(shù)量。(為什么這樣想:將一個星星和星星padding看成一個單位長度unitLength芽丹,這樣觸摸到最后邊的星星和View的padding就直接表示為最大的星星數(shù)量)北启。
3,觸摸的位置在第一個星星到第n-1個星星之間拔第,則以第一個星星的左邊界作為X軸坐標(biāo)的原坐標(biāo)咕村,觸摸的長度除以單位長度unitLength再加上1即可計算出要繪制的星星的個數(shù)。
private int starFullPicNum = 1;
private int unitLength;//一個星星大小加上一個間距
/**
* 根據(jù)X軸坐標(biāo)計算當(dāng)前的星星num
*
* @param startX
*/
private void caculateStarFullPicNum(float startX) {
if (startX < getPaddingLeft()) {//觸摸位置在星星左側(cè)
starFullPicNum = DEFAULT_STAR_MININUM;
} else if (startX > (getMeasuredWidth() - getPaddingRight() - starSize)) {//觸摸位置在右側(cè)星星邊界加上倒數(shù)第一個星星的距離
starFullPicNum = starNum;
} else {//觸摸在第一個星星到第(n-1)個星星之間楼肪,用坐標(biāo)軸的思想考慮
starFullPicNum = (int) ((startX - getPaddingLeft()) / unitLength) + 1;
}
if (listener != null) {
listener.OnStarChange(starFullPicNum);
}
invalidate();
Logger.e("Ratingbar:要繪制的星星數(shù)量:" + starFullPicNum);
}
5培廓、收尾工作
5.1,提供接口回調(diào)春叫,當(dāng)繪制的星星數(shù)量改變時回調(diào)出去肩钠。
5.2,向外提供設(shè)置當(dāng)前要繪制星星的方法暂殖,方便設(shè)置了不能觸摸時可以直接通過方法設(shè)置价匠。
/**
* 設(shè)置畫的星星num,并重畫
*/
public void setCurrentStarFullNum(int num) {
this.starFullPicNum = num;
invalidate();
}
5.3呛每,向外提供設(shè)置能否觸摸來繪制星星的開關(guān)
/**
* 設(shè)置能否滑動
*/
public void setIsCanTouch(Boolean isCanTouch) {
this.isCanTouch = isCanTouch;
}