Android 自定义星评控件

来源:互联网 发布:长者风靡网络的原因 编辑:程序博客网 时间:2024/06/07 03:40

没事做用自定义view方式写一个星评控件,虽说网上很多这个控件,但是这是自己写的,在这里记录一下。
首先需要自定义属性

 <declare-styleable name="Rate">        <!--属性分别是:单个的宽,高,之间的距离,激活的数量,总数量,激活的drawable,没有激活的drawable,是否可以选择数量-->        <attr name="custom_rate_width" format="dimension"/>        <attr name="custom_rate_height" format="dimension"/>        <attr name="custom_rate_padding" format="dimension"/>        <attr name="custom_rate_active_size" format="integer"/>        <attr name="custom_rate_size" format="integer"/>        <attr name="custom_rate_active_drawable" format="reference"/>        <attr name="custom_rate_disactive_drawable" format="reference"/>        <attr name="custom_rate_touch" format="boolean"/>    </declare-styleable>

初始化代码

 protected void init(Context context, AttributeSet attrs) {        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.Rate);        int activeId = 0;        int disactiveId = 0;        if (array != null) {            size = array.getInt(R.styleable.Rate_custom_rate_size, 5);            activeSize = array.getInt(R.styleable.Rate_custom_rate_active_size, 3);            rateWidth = array.getDimensionPixelOffset(R.styleable.Rate_custom_rate_width, 0);            rateHeight = array.getDimensionPixelOffset(R.styleable.Rate_custom_rate_height, 0);            activeId = array.getResourceId(R.styleable.Rate_custom_rate_active_drawable, 0);            disactiveId = array.getResourceId(R.styleable.Rate_custom_rate_disactive_drawable, 0);            padding = array.getDimensionPixelOffset(R.styleable.Rate_custom_rate_padding, 0);            isTouch = array.getBoolean(R.styleable.Rate_custom_rate_touch, false);            array.recycle();        }        //如果没有宽高就设置一个默认值        if (rateHeight <= 0){            rateHeight = 80;        }        if (rateWidth <= 0){            rateWidth = 80;        }        if (activeId!=0){            activeBitmap = BitmapFactory.decodeResource(getResources(), activeId);            //如果没有设置宽高时候            if (rateWidth <= 0) {                rateWidth = activeBitmap.getWidth();            }            //把图片压缩到设置的宽高            activeBitmap = Bitmap.createScaledBitmap(activeBitmap, (int) rateWidth, (int) rateHeight, false);        }        if (disactiveId != 0){            disactiveBitmap = BitmapFactory.decodeResource(getResources(), disactiveId);            if (rateHeight <= 0) {                rateHeight = activeBitmap.getHeight();            }            disactiveBitmap = Bitmap.createScaledBitmap(disactiveBitmap, (int) rateWidth, (int) rateHeight, false);        }        mPaint = new Paint();//初始化bitmap的画笔        mPaint.setAntiAlias(true);        activPaint = new Paint();//初始化选中星星的画笔        activPaint.setAntiAlias(true);        activPaint.setColor(Color.YELLOW);        disactivPaint = new Paint();//初始化未选中星星的画笔        disactivPaint.setAntiAlias(true);        disactivPaint.setColor(Color.GRAY);    }

onMeasure方法设置View的宽高,如果设置的每一个星星控件的宽高大于实际view的宽高,就用星星空间的宽高作于view的宽高

@Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        int widthMode = MeasureSpec.getMode(widthMeasureSpec);        int widthSize = MeasureSpec.getSize(widthMeasureSpec);        int heightMode = MeasureSpec.getMode(heightMeasureSpec);        int heightSize = MeasureSpec.getSize(heightMeasureSpec);        //计算宽        if (widthMode == MeasureSpec.EXACTLY) {            //如果view的宽度小于设置size*星星的宽度,就用size * (int) (padding + rateWidth)做为控件的宽度度            if (widthSize < size * (int) (padding + rateWidth)) {                width = size * (int) (padding + rateWidth);            } else {                width = widthSize;            }        } else {            width = size * (int) (padding + rateWidth)-padding;        }        //计算高        if (heightMode == MeasureSpec.EXACTLY) {            //如果view的高度小于设置星星的高度,就用星星高度做为控件的高度            if (heightSize < rateHeight) {                height = (int) rateHeight + 5;            } else {                height = heightSize;            }        } else {            height = (int) rateHeight + 5;        }        setMeasuredDimension(width, height);    }

onDraw方法中绘制

//开始画active        for (int i = 0; i < activeSize; i++) {            if (activeBitmap != null){                if (i == 0) {                    canvas.drawBitmap(activeBitmap, rateWidth * i, (height - rateHeight) / 2, mPaint);                } else {                    canvas.drawBitmap(activeBitmap, (rateWidth + padding) * i, (height - rateHeight) / 2, mPaint);                }            }else {                drawActivRate(i,canvas);            }        }//        //开始画disactive        for (int i = activeSize; i < size; i++) {            if (disactiveBitmap != null){                if (i == 0) {                    canvas.drawBitmap(disactiveBitmap, rateWidth * i, (height - rateHeight) / 2, mPaint);                } else {                    canvas.drawBitmap(disactiveBitmap, (rateWidth + padding) * i, (height - rateHeight) / 2, mPaint);                }            }else {                drawDisActivRate(i,canvas);            }        }

上面用到两个方法drawActivRate和drawDisActivRate,分别是在没有设置活动中的星星和不在活动中星星的图片的时候,绘制在活动和不在活动的默认星星:

/**     * 绘制黄色的五角星(在活动的)     * */    private void drawActivRate(int position,Canvas canvas){        float radius = rateWidth/2;//根據每一個星星的位置繪製園,確定五角星五個點的位置        float angle = 360/5;        float centerX = (rateWidth+padding)*(position+1)-padding-radius;//獲取每一個星星空間的中心位置的X坐標        float centerY =height/2;//獲取每一個星星空間的中心位置的y坐標        Path mPath = new Path();        mPath.moveTo(centerX,centerY-radius);        mPath.lineTo(centerX+(float) Math.cos((angle*2-90)*Math.PI / 180)*radius,centerY+(float)Math.sin((angle*2-90)*Math.PI / 180)*radius);        mPath.lineTo( centerX-(float)Math.sin(angle*Math.PI / 180)*radius,centerY-(float)Math.cos(angle*Math.PI / 180)*radius);        mPath.lineTo( centerX+(float)Math.sin(angle*Math.PI / 180)*radius,centerY-(float)Math.cos(angle*Math.PI / 180)*radius);        mPath.lineTo( centerX-(float)Math.sin((angle*3-180)*Math.PI / 180)*radius,centerY+(float)Math.cos((angle*3-180)*Math.PI / 180)*radius);//        mPath.lineTo(centerX,centerY-radius);        mPath.close();        canvas.drawPath(mPath,activPaint);    }    /**     * 绘制灰色的五角星     * */    private void drawDisActivRate(int position,Canvas canvas){        float radius = rateWidth/2;        float angle = 360/5;        float centerX = (rateWidth+padding)*(position+1)-padding-radius;        float centerY =height/2;        Path mPath = new Path();        mPath.moveTo(centerX,centerY-radius);        mPath.lineTo(centerX+(float) Math.cos((angle*2-90)*Math.PI / 180)*radius,centerY+(float)Math.sin((angle*2-90)*Math.PI / 180)*radius);        mPath.lineTo( centerX-(float)Math.sin(angle*Math.PI / 180)*radius,centerY-(float)Math.cos(angle*Math.PI / 180)*radius);        mPath.lineTo( centerX+(float)Math.sin(angle*Math.PI / 180)*radius,centerY-(float)Math.cos(angle*Math.PI / 180)*radius);        mPath.lineTo( centerX-(float)Math.sin((angle*3-180)*Math.PI / 180)*radius,centerY+(float)Math.cos((angle*3-180)*Math.PI / 180)*radius);//        mPath.lineTo(centerX,centerY-radius);        mPath.close();        canvas.drawPath(mPath,disactivPaint);    }

最后在onTouchEvent方法中处理选中和未选中星星的处理

@Override    public boolean onTouchEvent(MotionEvent event) {        if (!isTouch){//如果不支持觸摸            return false;        }        switch (event.getAction()) {            case MotionEvent.ACTION_DOWN:                touchX = event.getX();                touchY = event.getY();                for (int i = 0; i < size; i++) {                    if (i == 0) {                        if (0.0 < touchX && touchX < rateWidth+padding/2) {                            activeSize = 1;                        }                    }else {                        if ((rateWidth+padding)*i-padding/2<touchX&&touchX<(rateWidth+padding)*(i+1)-padding/2){                            activeSize = i+1;                        }                    }                }                invalidate();                break;            case MotionEvent.ACTION_UP:                if ( null!= changeListener){                    changeListener.change(activeSize);                }                break;            case MotionEvent.ACTION_MOVE:                touchX = event.getX();                touchY = event.getY();                for (int i = 0; i < size; i++) {                    if (i == 0) {                        if (0.0 < touchX && touchX < rateWidth+padding/2) {                            activeSize = 1;                        }                    }else {                        if ((rateWidth+padding)*i-padding/2<touchX&&touchX<(rateWidth+padding)*(i+1)-padding/2){                            activeSize = i+1;                        }                    }                }                invalidate();                if (touchX<=0){                    activeSize = 0;                }                break;        }        return true;    }

以上就是自定义view写的星评控件,代码中的注解已经比较详细了,就不多说了,
源码地址