Android用來替代RatingBar的自定義ImageRatingView

xinewedngcp 7年前發布 | 6K 次閱讀 安卓開發 Android開發 移動開發

因為android自帶的RatingBar用起來不是很方便,于是決定自己寫一個替代品。

控件介紹:

示意圖

<declare-styleable name="ImageRatingView">
        //設置評分最大值
        <attr name="maxCount" format="integer" />  
         //設置評分之間的跨度,示意圖中為0.5
        <attr name="minStep" format="float" />      
        //設置評分時的圖片 
        <attr name="frontImage" format="reference"/>   
        //設置未評分的圖片(需和評分的圖片等寬等高)
        <attr name="backImage" format="reference"/>   
        //圖片之間的間隔
        <attr name="spanSize" format="dimension"/>    
        //默認評分
        <attr name="rating" format="float"/>       
        //是否可觸摸評分
        <attr name="touchable" format="boolean"/>    
        //設定圖片的寬(layout_width設置為wrap_content即可)
        <attr name="imageWidth" format="dimension"/>   
        //設定圖片的高(layout_height設置為wrap_content即可)   
        <attr name="imageHeight" format="dimension"/>  
    </declare-styleable>

在代碼中支持設定默認評分以及獲取評分,還可以通過設置 OnRatingChangedListener 來監聽評分的變化。

基本思路:

利用 canvas.drawBitmap(bitmap,src,dst,paint) 來繪制評分的圖標。照圖上來講分三部分進行繪制:①繪制前三個黃色的星星、②繪制后面三個白色的星星、③第四個星星單獨繪制。

代碼實現:

  • 繪制前三個黃色的星星
    private void drawFront(Canvas canvas) {
          //src是指圖片要顯示的部分,這里為顯示整個星星。
          Rect src = new Rect(0, 0, mFront.getWidth(), mFront.getHeight());
          for (int i = 0; i < (int) mRating; i++) {
              int left = i * (mBitmapDstWidth + mSpanSize);
              int right = (i + 1) * mBitmapDstWidth + i * mSpanSize;
              //dst指圖片在view中顯示的位置,這里動態計算出每個星星的坐標位置。
              Rect dst = new Rect(left, 0, right, mBitmapDstHeight);
              canvas.drawBitmap(mFront, src, dst, null);
          }
      }
  • 繪制后三個白色的星星
    private void drawBack(Canvas canvas) {
          Rect src = new Rect(0, 0, mFront.getWidth(), mFront.getHeight());
          //和繪制前三個的主要區別是這里的起始值不同
          for (int i = (int) (mRating + 1); i < mMaxCount; i++) {
              //mBitmapDstWidth是圖片指定的寬度
              int left = i * (mBitmapDstWidth + mSpanSize);
              int right = (i + 1) * mBitmapDstWidth + i * mSpanSize;
              Rect dst = new Rect(left, 0, right, mBitmapDstHeight);
              canvas.drawBitmap(mBack, src, dst, null);
           }
       }
  • 繪制第四個星星

    private void drawLastFront(Canvas canvas) {
          //先畫front部分即黃色的部分
          //rating小數點前的值。
          int rating = (int) mRating;
          //算出rating小數點后的值,圖中實例為0.5
          float frontPart = mRating - rating;
          int frontWidth = (int) (frontPart * mFront.getWidth());
          //這里src的寬度就是圖片的一半
          Rect srcFront = new Rect(0, 0, frontWidth, mFront.getHeight());
          //位置的起始值和之前的一樣
          int leftFront = rating * (mBitmapDstWidth + mSpanSize);
          //區別在結束值,按照圖中實例來理解就是3.5*圖片的寬度+3*圖片之間的間隔
          int rightFront = (int) (mRating* mBitmapDstWidth + rating * mSpanSize);
          Rect dstFront = new Rect(leftFront, 0, rightFront, mBitmapDstHeight);
          canvas.drawBitmap(mFront, srcFront, dstFront, null);
    
          //back部分即白色的部分
          int backWidth = (int) (frontPart * mFront.getWidth());
          Rect srcBack = new Rect(backWidth, 0, mFront.getWidth(), mFront.getHeight());
          //位置的起始值即剛才畫前半部分的結束值
          int leftBack = (int) (mRating * mBitmapDstWidth + rating * mSpanSize);
          int rightBack = (rating + 1) * mBitmapDstWidth + rating * mSpanSize;
          Rect dstBack = new Rect(leftBack, 0, rightBack, mBitmapDstHeight);
          canvas.drawBitmap(mBack, srcBack, dstBack, null);
      }

其他細節:

因為本控件支持設定最小評分的跨度,例如設置step為0.5,如果這時傳進來3.3分,就要四舍五入到3.5。代碼如下:

private void correctedRatingValue() {
        if (mRating > mMaxCount) {
            mRating = mMaxCount;
        } else if (mRating < 0) {
            mRating = 0;
        }
        //最后一個跨度 進行四舍五入的判斷
        float after = mRating % mMinStep > mMinStep / 2 ? mMinStep : 0;
        //除去最后個跨度
        float front = mRating - mRating % mMinStep;
        mRating = after +front;
    }

但在觸摸控件評分時上面的算法就不能用了,舉個例子例如我觸摸得到的評分是3.1,那么按照上面的算法會得到3分,最后就顯示為3個星星。這樣顯示就很怪異,因為正常情況你的手指觸摸在了星星上就表示這個星星會亮,因此這時候要換一種算法:

private void correctedRatingValueForTouch() {
        if (mRating % mMinStep == 0)
            return;
        mRating = mRating - mRating % mMinStep + mMinStep;
    }

 

 

 

 本文由用戶 xinewedngcp 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!