仿淘寶京東評分控制元件
阿新 • • 發佈:2019-01-28
由於在專案中碰到了評分控制元件,使用的地方也比較多,像淘寶,京東這些都有,於是就寫了一個。
京東淘寶和我們自己最終實現的效果:
實現思路:繪製5張沒有選中的圖片,自定義屬性,屬性包括選中狀態下的圖片和正常狀態下的圖片,以及圖片數量,圖片間距。
然後去動態的處理我們的觸控事件,再去呼叫onDraw方法
attrs:
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="RatingView"> <!--正常狀態下的資源--> <attr name="starNormal" format="reference"/> <!--選中狀態資源--> <attr name="starSelected" format="reference"/> <!--星星數量--> <attr name="starNumbers" format="integer"/> <!--星星之間的間距--> <attr name="starSpace" format="dimension"/> </declare-styleable> </resources>
主要程式碼:
private Bitmap mStarNormal, mStarSelected; private int mStarNumbers = 5;//數量 private int mStarSpaceing = 5;//間距 private int mCurrentStar = 0;//當前星星 public RatingView(Context context) { this(context, null); } public RatingView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public RatingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.RatingView); int starNormalId = array.getResourceId(R.styleable.RatingView_starNormal, 0); if (starNormalId == 0) { throw new RuntimeException("請在xml檔案中為RatingView設定startNormal屬性"); } mStarNormal = BitmapFactory.decodeResource(getResources(), starNormalId); int starSelectedId = array.getResourceId(R.styleable.RatingView_starSelected, 0); if (starSelectedId == 0) { throw new RuntimeException("請在xml檔案中為RatingView設定startSelected屬性"); } mStarSelected = BitmapFactory.decodeResource(getResources(), starSelectedId); mStarNumbers = array.getInt(R.styleable.RatingView_starNumbers, mStarNumbers); mStarSpaceing = (int) array.getDimension(R.styleable.RatingView_starSpace, mStarSpaceing); array.recycle(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int height = mStarNormal.getHeight() + getPaddingTop() + getPaddingBottom(); int width = mStarNormal.getWidth() * mStarNumbers + (mStarNumbers + 1) * mStarSpaceing + getPaddingLeft() + getPaddingRight(); setMeasuredDimension(width, height); } @Override protected void onDraw(Canvas canvas) { //迴圈的來畫星星 for (int i = 0; i < mStarNumbers; i++) { int x = getPaddingLeft() + i * mStarNormal.getWidth() + (i + 1) * mStarSpaceing; int top = getPaddingTop(); if (mCurrentStar > i) { // 當前分數之前 canvas.drawBitmap(mStarSelected, x, top, null); } else { canvas.drawBitmap(mStarNormal, x, top, null); } } } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: float moveX = event.getX(); //計算當前手指在哪個星星 int currentStar = (int) ((moveX - getPaddingLeft()) / (mStarNormal.getWidth() + mStarSpaceing) + 1); // 範圍問題 if (currentStar < 0) { currentStar = 0; } if (currentStar > mStarNumbers) { currentStar = mStarNumbers; } // 分數相同的情況下不要繪製了 , 儘量減少onDraw()的呼叫 if (currentStar == mCurrentStar) { return true; } // 再去重新整理顯示 mCurrentStar = currentStar; invalidate();//重新繪製會呼叫onDraw() break; } return true; }
簡單說明一下:
//控制元件高度為圖片的高度加上上下的padding值 int height = mStarNormal.getHeight() + getPaddingTop() + getPaddingBottom(); //控制元件的寬高為五張圖片的寬度,加上左右的padding值,然後加上每張圖片的左邊間隔值,這裡每張圖片都會有一個左邊間隔,為了控制元件美觀右邊多加了一個間隔 int width = mStarNormal.getWidth() * mStarNumbers + (mStarNumbers + 1) * mStarSpaceing + getPaddingLeft() + getPaddingRight(); setMeasuredDimension(width, height);
畫圖邏輯:
github地址:點選開啟連結