1. 程式人生 > >仿淘寶京東評分控制元件

仿淘寶京東評分控制元件

由於在專案中碰到了評分控制元件,使用的地方也比較多,像淘寶,京東這些都有,於是就寫了一個。

京東淘寶和我們自己最終實現的效果:



實現思路:繪製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地址:點選開啟連結