阅读 1973

自定义简单的RatingBar

样式是:

需求概述

我们需要一个类似原生RatingBar的这样一个评分View,但是RatingBar不够灵活,我们需要有不同颜色,不同间距,而且可调的一个评分Bar。

分析

我们主要是定义ratingbar,不和文字一起定义。
首先是:单个星星的高和宽,然后是需要知道每个星星之间的间距,还有就是那几颗星星是active那几颗是disactivie的。同时,我们需要计算在这个View中的什么位置开始画,最后就是需要指定我们的星星的resource了。

实现

属性定义

需要定义的属性有:

 <declare-styleable name="CustomRatingStyle">
        <!--宽,高,间距,激活的数量,没有激活的数量,激活的icon,没有激活的icon-->
        <!--属性分别是:单个的宽,高,之间的距离,激活的数量,总数量,激活的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"/>
    </declare-styleable>复制代码

代码实现:

我们继承自View就好,不要ViewGroup。然后获取xml文件中的自定义属性值,获取属性值完成,同时给定默认值。同时,我们需要计算一个步长,作用是知道我们画下一个星星开始的坐标,他的计算是星星的width+星星之间的padding。同时,还有一点是可能active和disactivie的drawable大小不同,所以我们需要按照其中一个区计算步长,同时缩放到等同大小。比如我们按照active的drawable大小为标准,当disactive的drawable大小不同的时候,就对他进行比例缩放,直到相同。代码如下:

代码实现

   //单个高
    private float singleWidth;
    //单个宽
    private float singleHeight;
    //间距
    private int padding;
    //总数量
    private int size = 5;
    //默认激活数量
    private int activeSize = 3;
    //激活的bitmap
    private Bitmap activeBitmap;
    //没有激活的bitmap
    private Bitmap disactiveBitmap;
    //画笔
    private Paint mPaint;
    //步长
    private int stepSize;
    //开始画的x坐标
    private int drawStartX;
    //开始画的y坐标
    private int drawStartY;复制代码

初始化代码:

    int activeId = 0;
        int disactiveId = 0;
        if (attrs != null) {
            TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CustomRatingStyle);
            singleWidth = array.getDimensionPixelOffset(R.styleable.CustomRatingStyle_custom_rate_width, 0);
            singleHeight = array.getDimensionPixelOffset(R.styleable.CustomRatingStyle_custom_rate_height, 0);
            activeId = array.getResourceId(R.styleable.CustomRatingStyle_custom_rate_active_drawable, R.drawable.custom_rateingbar_active);
            disactiveId = array.getResourceId(R.styleable.CustomRatingStyle_custom_rate_disactive_drawable, R.drawable.custom_rateingbar_disactive);
            size = array.getInteger(R.styleable.CustomRatingStyle_custom_rate_size, 5);
            activeSize = array.getInteger(R.styleable.CustomRatingStyle_custom_rate_active_size, 3);
            padding = array.getDimensionPixelOffset(R.styleable.CustomRatingStyle_custom_rate_padding, 10);
            array.recycle();
        }
        activeBitmap = BitmapFactory.decodeResource(getResources(), activeId);
        disactiveBitmap = BitmapFactory.decodeResource(getResources(), disactiveId);
        stepSize = padding + activeBitmap.getWidth();
        mPaint = new Paint();
        if (singleHeight <= 0) {
            singleHeight = activeBitmap.getHeight();
        }
        if (singleWidth <= 0) {
            singleWidth = activeBitmap.getWidth();
        }
        //大小不同的话,对Bitmap进行压缩,
        if (activeBitmap.getWidth() != disactiveBitmap.getWidth() || activeBitmap.getHeight() != disactiveBitmap.getHeight()) {
            //把dis压缩或者是放大的active的大小
            disactiveBitmap = Bitmap.createScaledBitmap(disactiveBitmap, activeBitmap.getWidth(), activeBitmap.getHeight(), false);
        }复制代码

逻辑实现

测量步长计算:我们是把五角星放在这个View的center位置,然后他所占的长度是5width+4padding。

onMeasure 方法:

 @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);
        int width;
        int height;
        //计算宽
        if (widthMode == MeasureSpec.EXACTLY) {
            width = widthSize;
        } else {
            width = 5 * stepSize;
        }
        //计算高
        if (heightMode == MeasureSpec.EXACTLY) {
            height = heightSize;
        } else {
            height = (int) singleHeight;
        }
        //总共应该的宽
        int drawWidth = (int) (size * singleWidth + (size <= 1 ? 0 : (size - 1) * padding));
        //开始的y位置
        int drawHeight = (int) ((height - singleHeight) / 2);
        drawStartX = (width - drawWidth) / 2;
        drawStartY = drawHeight > 0 ? drawHeight : 0;
        setMeasuredDimension(width, height);
    }复制代码

onDraw方法:

  @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //开始画active
        for (int i = 0; i < activeSize; i++) {
            canvas.drawBitmap(activeBitmap, drawStartX + i * stepSize, drawStartY, mPaint);
        }
        //开始画disactive
        for (int i = activeSize; i < size; i++) {
            canvas.drawBitmap(disactiveBitmap, drawStartX + i * stepSize, drawStartY, mPaint);
        }
    }复制代码

然后,我们在对外提供一个设置activie的方法:

    /**
     * 设置激活的数量
     *
     * @param activeSize
     */
    public void setActiveSize(int activeSize) {
        this.activeSize = activeSize;
        if (CommentUtil.isUIThread()) {
            invalidate();
        } else {
            postInvalidate();
        }
    }复制代码

这样子就完成了星星评分的UI了。
结果截图:

源码下载

关注下面的标签,发现更多相似文章
评论