美文网首页
自定义RatingBar

自定义RatingBar

作者: 飞奔吧牛牛 | 来源:发表于2019-04-02 15:04 被阅读0次

    自定义RatingBar,可设置图片大小、间隔,是否可触摸改变等级

    先看下效果:当手指滑动(或点击)时,RatingBar的等级会跟着改变

    QQ截图20190402143805.png

    第一步:自定义属性

        <declare-styleable name="MyRatingBar">
            <attr name="touchable" format="boolean" />
            <attr name="level" format="integer" />
            <attr name="item_size" format="dimension" />
            <attr name="item_gap" format="dimension" />
            <attr name="item_select_img" format="reference" />
            <attr name="item_unselect_img" format="reference" />
        </declare-styleable>
    

    touchable :是否可触摸,改变level
    level :等级
    item_size :每个图片大小
    item_gap :图片之间的间隔
    item_select_img :选中时的图片
    item_unselect_img :未选中时的图片

    第二步:自定义View-MyRatingBar继承View,获取自定义属性

        public MyRatingBar(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyRatingBar);
            touchable = ta.getBoolean(R.styleable.MyRatingBar_touchable, false);
            itemSize = ta.getDimensionPixelSize(R.styleable.MyRatingBar_item_size, 60);
            itemGap = ta.getDimensionPixelSize(R.styleable.MyRatingBar_item_gap, 0);
            level = ta.getInt(R.styleable.MyRatingBar_level, 0);
            selectImage = ta.getDrawable(R.styleable.MyRatingBar_item_select_img);
            unselectImage = ta.getDrawable(R.styleable.MyRatingBar_item_unselect_img);
            paint = new Paint();
        }
    

    第三步:重写onMeasure方法

    当设置宽高大小为warp_content的时候,需要手动计算控件的大小

        @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 = 0;
            switch (widthMode) {
                case MeasureSpec.AT_MOST:
                    width = itemSize * 5 + itemGap * 4 + getPaddingLeft() + getPaddingRight();
                    break;
                case MeasureSpec.EXACTLY:
                    width = widthSize;
                    break;
                case MeasureSpec.UNSPECIFIED:
                    width = itemSize * 5 + itemGap * 4 + getPaddingLeft() + getPaddingRight();
            }
            int height = 0;
            switch (heightMode) {
                case MeasureSpec.AT_MOST:
                    height = itemSize + getPaddingTop() + getPaddingBottom();
                    break;
                case MeasureSpec.EXACTLY:
                    height = heightSize;
                    break;
                case MeasureSpec.UNSPECIFIED:
                    height = itemSize + getPaddingTop() + getPaddingBottom();
                    break;
            }
            setMeasuredDimension(width, height);
        }
    

    第四步:重写onDraw方法

    先整理下思路,

    1. 我打算用for循环画出5个星星,每画一个,就将画布向左移动一段距离(itemSize+itemGap),接着画下一个,直到画完。
    2. 画每一个时要判断这个应该画哪个图片
      当touchable=false,比较简单,小于level的星星画成selectImage,大于level的为unselectImage.
      当touchable=true,应该根据当前手指触摸的位置到左边的距离,判断当前位置应该画哪个图片,并设置等级level。
    @Override
        protected void onDraw(Canvas canvas) {
            if (selectImage != null && unselectImage != null) {
                int left = getPaddingLeft();
                for (int i = 0; i < 5; i++) {
                    canvas.save();
                    canvas.translate(left, 0);
                    //是画选中状态的还是未选中状态的
                    Drawable drawable = null;
                    if (touchable && touchX != -1) {
                        if (touchX > getPaddingLeft() && touchX > left) {
                            if (touchX < left + itemSize + itemGap) {
                                level = i + 1;
                            }
                            drawable = selectImage;
                        } else {
                            drawable = unselectImage;
                        }
                    } else {
                        drawable = i < level ? selectImage : unselectImage;
                    }
                    int intrinsicWidth = drawable.getIntrinsicWidth();
                    int intrinsicHeight = drawable.getIntrinsicHeight();
                    //获取bitmap
                    Bitmap bitmap = Bitmap.createBitmap(intrinsicWidth, intrinsicHeight, Bitmap.Config.ARGB_8888);
                    Canvas bitmapCanvas = new Canvas(bitmap);
                    drawable.setBounds(0, 0, intrinsicWidth, intrinsicHeight);
                    drawable.draw(bitmapCanvas);
                    //伸缩图片,并绘制
                    Matrix matrix = new Matrix();
                    matrix.postScale((float) itemSize / intrinsicWidth, (float) itemSize / intrinsicHeight);
                    canvas.drawBitmap(bitmap, matrix, paint);
                    left += (itemSize + itemGap);
                    canvas.restore();
                }
            }
        }
    

    第五步:重写onTouchEvent方法

    获取触摸点的x坐标

        @Override
        public boolean onTouchEvent(MotionEvent event) {
            touchX = (int) event.getX();
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    invalidate();
                    break;
                case MotionEvent.ACTION_MOVE:
                    invalidate();
                    break;
                case MotionEvent.ACTION_UP:
                    invalidate();
                    break;
            }
            return true;
        }
    

    第六步:向外提供getter方法

        public int getLevel() {
            return level;
        }
    

    使用

    在xml中:

     <com.aomiao.ratingbar.MyRatingBar
            android:id="@+id/ratingBar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@color/colorPrimary"
            app:item_gap="10dp"
            app:item_select_img="@mipmap/ic_rating_select"
            app:item_size="30dp"
            app:item_unselect_img="@mipmap/ic_rating"
            app:level="3"
            app:touchable="true" />
    
        <Button
            android:id="@+id/btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="等级" />
    
    Toast.makeText(MainActivity.this,
                            "等级" + ratingBar.getLevel(),
                            Toast.LENGTH_SHORT).show();
    

    RatingBar完整代码

    
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.graphics.Bitmap;
    import android.graphics.Canvas;
    import android.graphics.Matrix;
    import android.graphics.Paint;
    import android.graphics.drawable.Drawable;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.view.View;
    
    public class MyRatingBar extends View {
        private boolean touchable;
        private int itemSize;
        private int itemGap;
        private int level;
        private Drawable selectImage;
        private Drawable unselectImage;
    
        private Paint paint;
        //触摸时的x坐标
        private int touchX = -1;
    
        public MyRatingBar(Context context) {
            this(context, null);
        }
    
        public MyRatingBar(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public MyRatingBar(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyRatingBar);
            touchable = ta.getBoolean(R.styleable.MyRatingBar_touchable, false);
            itemSize = ta.getDimensionPixelSize(R.styleable.MyRatingBar_item_size, 60);
            itemGap = ta.getDimensionPixelSize(R.styleable.MyRatingBar_item_gap, 0);
            level = ta.getInt(R.styleable.MyRatingBar_level, 0);
            selectImage = ta.getDrawable(R.styleable.MyRatingBar_item_select_img);
            unselectImage = ta.getDrawable(R.styleable.MyRatingBar_item_unselect_img);
            paint = new Paint();
        }
    
        @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 = 0;
            switch (widthMode) {
                case MeasureSpec.AT_MOST:
                    width = itemSize * 5 + itemGap * 4 + getPaddingLeft() + getPaddingRight();
                    break;
                case MeasureSpec.EXACTLY:
                    width = widthSize;
                    break;
                case MeasureSpec.UNSPECIFIED:
                    width = itemSize * 5 + itemGap * 4 + getPaddingLeft() + getPaddingRight();
            }
            int height = 0;
            switch (heightMode) {
                case MeasureSpec.AT_MOST:
                    height = itemSize + getPaddingTop() + getPaddingBottom();
                    break;
                case MeasureSpec.EXACTLY:
                    height = heightSize;
                    break;
                case MeasureSpec.UNSPECIFIED:
                    height = itemSize + getPaddingTop() + getPaddingBottom();
                    break;
            }
            setMeasuredDimension(width, height);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            if (selectImage != null && unselectImage != null) {
                int left = getPaddingLeft();
                for (int i = 0; i < 5; i++) {
                    canvas.save();
                    canvas.translate(left, 0);
                    //是画选中状态的还是未选中状态的
                    Drawable drawable = null;
                    if (touchable && touchX != -1) {
                        if (touchX > getPaddingLeft() && touchX > left) {
                            if (touchX < left + itemSize + itemGap) {
                                level = i + 1;
                            }
                            drawable = selectImage;
                        } else {
                            drawable = unselectImage;
                        }
                    } else {
                        drawable = i < level ? selectImage : unselectImage;
                    }
                    int intrinsicWidth = drawable.getIntrinsicWidth();
                    int intrinsicHeight = drawable.getIntrinsicHeight();
                    //获取bitmap
                    Bitmap bitmap = Bitmap.createBitmap(intrinsicWidth, intrinsicHeight, Bitmap.Config.ARGB_8888);
                    Canvas bitmapCanvas = new Canvas(bitmap);
                    drawable.setBounds(0, 0, intrinsicWidth, intrinsicHeight);
                    drawable.draw(bitmapCanvas);
                    //伸缩图片,并绘制
                    Matrix matrix = new Matrix();
                    matrix.postScale((float) itemSize / intrinsicWidth, (float) itemSize / intrinsicHeight);
                    canvas.drawBitmap(bitmap, matrix, paint);
                    left += (itemSize + itemGap);
                    canvas.restore();
                }
            }
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            touchX = (int) event.getX();
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    invalidate();
                    break;
                case MotionEvent.ACTION_MOVE:
                    invalidate();
                    break;
                case MotionEvent.ACTION_UP:
                    invalidate();
                    break;
            }
            return true;
        }
    
        public int getLevel() {
            return level;
        }
    }
    
    

    相关文章

      网友评论

          本文标题:自定义RatingBar

          本文链接:https://www.haomeiwen.com/subject/rshgbqtx.html