android自定義星級評分控制元件,可實現只顯示實心星星
阿新 • • 發佈:2018-12-13
話不多說,上圖
近日app需求弄一個等級展示,看了下UI圖,只顯示實星(點亮的星星).如圖
但是網上關於星級評分的例子大多這樣
也展示虛心星星
通過自定義View
package com.starsbar; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; public class StarBar extends View { private int starDistance = 0; //星星間距 private int starCount = 5; //星星個數 private int starSize; //星星高度大小,星星一般正方形,寬度等於高度 private float starMark = 0.0F; //評分星星 private Bitmap starFillBitmap; //亮星星 private Drawable starEmptyDrawable; //暗星星 private OnStarChangeListener onStarChangeListener;//監聽星星變化介面 private Paint paint; //繪製星星畫筆 private boolean integerMark = false; private boolean clickAble = true; public StarBar(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs); } public StarBar(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context, attrs); } /** * 初始化UI元件 */ private void init(Context context, AttributeSet attrs) { setClickable(true); TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.StarBar); this.starDistance = (int) mTypedArray.getDimension(R.styleable.StarBar_starDistance, 0); this.starSize = (int) mTypedArray.getDimension(R.styleable.StarBar_starSize, 20); this.starCount = mTypedArray.getInteger(R.styleable.StarBar_starCount, 5); this.starEmptyDrawable = mTypedArray.getDrawable(R.styleable.StarBar_starEmpty); this.starFillBitmap = drawableToBitmap(mTypedArray.getDrawable(R.styleable.StarBar_starFill)); mTypedArray.recycle(); paint = new Paint(); paint.setAntiAlias(true); paint.setShader(new BitmapShader(starFillBitmap, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP)); } /** * 設定星星是否可以點選和滑動改變 */ public void setClickAble(boolean clickAble) { this.clickAble = clickAble; } /** * 設定是否需要整數評分 * * @param integerMark */ public void setIntegerMark(boolean integerMark) { this.integerMark = integerMark; } /** * 設定顯示的星星的分數 * * @param mark */ public void setStarMark(float mark) { if (integerMark) { starMark = (int) Math.ceil(mark); } else { starMark = Math.round(mark * 10) * 1.0f / 10; } if (this.onStarChangeListener != null) { this.onStarChangeListener.onStarChange(starMark); //呼叫監聽介面 } invalidate(); } /** * 獲取顯示星星的數目 * * @return starMark */ public float getStarMark() { return starMark; } /** * 定義星星點選的監聽介面 */ public interface OnStarChangeListener { void onStarChange(float mark); } /** * 設定監聽 * * @param onStarChangeListener */ public void setOnStarChangeListener(OnStarChangeListener onStarChangeListener) { this.onStarChangeListener = onStarChangeListener; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(starSize * starCount + starDistance * (starCount - 1), starSize); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (starFillBitmap == null || starEmptyDrawable == null) { return; } for (int i = 0; i < starCount; i++) { starEmptyDrawable.setBounds((starDistance + starSize) * i, 0, (starDistance + starSize) * i + starSize, starSize); starEmptyDrawable.draw(canvas); } if (starMark > 1) { canvas.drawRect(0, 0, starSize, starSize, paint); if (starMark - (int) (starMark) == 0) { for (int i = 1; i < starMark; i++) { canvas.translate(starDistance + starSize, 0); canvas.drawRect(0, 0, starSize, starSize, paint); } } else { for (int i = 1; i < starMark - 1; i++) { canvas.translate(starDistance + starSize, 0); canvas.drawRect(0, 0, starSize, starSize, paint); } canvas.translate(starDistance + starSize, 0); canvas.drawRect(0, 0, starSize * (Math.round((starMark - (int) (starMark)) * 10) * 1.0f / 10), starSize, paint); } } else { canvas.drawRect(0, 0, starSize * starMark, starSize, paint); } } /** * 設定星星總數 */ public void setStarCount(int count){ starCount = count; } /** * 設定星星亮的顆數 */ public void setRating(int rating){ if (integerMark) { starMark = (int) Math.ceil(rating); } else { starMark = Math.round(rating * 10) * 1.0f / 10; } if (this.onStarChangeListener != null) { this.onStarChangeListener.onStarChange(starMark); //呼叫監聽介面 } invalidate(); } @Override public boolean onTouchEvent(MotionEvent event) { if (clickAble) { int x = (int) event.getX(); if (x < 0) x = 0; if (x > getMeasuredWidth()) x = getMeasuredWidth(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: { setStarMark(x * 1.0f / (getMeasuredWidth() * 1.0f / starCount)); break; } case MotionEvent.ACTION_MOVE: { setStarMark(x * 1.0f / (getMeasuredWidth() * 1.0f / starCount)); break; } case MotionEvent.ACTION_UP: { break; } } invalidate(); } return super.onTouchEvent(event); } /** * drawable轉bitmap * * @param drawable * @return */ private Bitmap drawableToBitmap(Drawable drawable) { if (drawable == null) return null; Bitmap bitmap = Bitmap.createBitmap(starSize, starSize, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, starSize, starSize); drawable.draw(canvas); return bitmap; } }
解決方案,為了只顯示實心數,加了2個方法,注意:
/** * 設定星星總數 */ public void setStarCount(int count){ starCount = count; } /** * 設定星星亮的顆數 */ public void setRating(int rating){ if (integerMark) { starMark = (int) Math.ceil(rating); } else { starMark = Math.round(rating * 10) * 1.0f / 10; } if (this.onStarChangeListener != null) { this.onStarChangeListener.onStarChange(starMark); //呼叫監聽介面 } invalidate(); }
在activity中配合使用即可實現上述需求:
//不可選擇的starBar,只做顯示用 不顯示空心
starBar2=findViewById(R.id.starBar2);
starBar2.setClickAble(false);
starBar2.setStarCount(3);
starBar2.setRating(3);
另介紹另外一種星級評分 YStarView