DtRatingBar

一个使用在android上的RatingBar。GitHub地址:DtRatingBar
使用依赖:

implementation 'com.yetland.dtratingbar:dtratingbar:1.0.1'

功能

  • 图片自定义
  • 大小自定义
  • 数量自定义
  • 可以打开或关闭半星
  • 支持横向和纵向的滑动评分

效果图

demo.gif

主要参数

  • rating_sum 总数
  • rating_check 得分数
  • rating_width RatingView的宽度
  • rating_height RatingView的高度
  • rating_padding_left RatingView的paddingLeft
  • rating_padding_right RatingView的paddingRight
  • rating_padding_top RatingView的paddingTop
  • rating_padding_bottom RatingView的paddingBottom
  • rating_star_img 全星的图片
  • rating_half_star_img 半星的图片
  • rating_un_star_img 没星的图片
  • rating_support_half 是否支持半星

使用方法

  • 通过xml形式配置
  • 通过builder的形式配置
RatingView.Builder builder = new RatingView.Builder()                .context(this)                .width(30)                .height(30)                .paddingLeft(2)                .paddingRight(2)                .paddingBottom(2)                .paddingTop(2)                .star(R.mipmap.ic_star2)                .unStar(R.mipmap.ic_un_star2)                .halfStar(R.mipmap.ic_half_star2);

或者

RatingView.Builder builder = RatingView.with()                .context(this)                .width(30)                .height(30)                .paddingLeft(2)                .paddingRight(2)                .paddingBottom(2)                .paddingTop(2)                .star(R.mipmap.ic_star2)                .unStar(R.mipmap.ic_un_star2)                .halfStar(R.mipmap.ic_half_star2);

实现原理

通过自定义view的形式,将每颗星星(RatingView)通过addView的形式,添加到DtRatingView中。其实我们所有的属性都是基于RatingView,而不是DtRatingView,因为DtRatingView只是一个呈现,而RatingView才是本体。对于参数的设置,通过Builder的形式去设置,而这个Builder也是属于RatingView的。

DtRatingView

构造方法中主要实现了参数的初始化。

public DtRatingBar(Context context, AttributeSet attrs) {        super(context, attrs);        mContext = context;        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.DtRatingBar);        mRating = typedArray.getFloat(R.styleable.DtRatingBar_rating_check, 0f);        mStars = typedArray.getInt(R.styleable.DtRatingBar_rating_sum, 5);        mSupportHalf = typedArray.getBoolean(R.styleable.DtRatingBar_rating_support_half, true);        mRating = getRatingValue(mRating);        int childViewWidth = typedArray.getInt(R.styleable.DtRatingBar_rating_width, 12);        int childViewHeight = typedArray.getInt(R.styleable.DtRatingBar_rating_height, 12);        int childViewPaddingLeft = typedArray.getInt(R.styleable.DtRatingBar_rating_padding_left, 2);        int childViewPaddingRight = typedArray.getInt(R.styleable.DtRatingBar_rating_padding_right, 2);        int childViewPaddingTop = typedArray.getInt(R.styleable.DtRatingBar_rating_padding_top, 0);        int childViewPaddingBottom = typedArray.getInt(R.styleable.DtRatingBar_rating_padding_bottom, 0);        int childViewStarImg = typedArray.getResourceId(R.styleable.DtRatingBar_rating_star_img, R.drawable.ic_star);        int childViewHalfStarImg = typedArray.getResourceId(R.styleable.DtRatingBar_rating_half_star_img, R.drawable.ic_half_star);        int childViewUnStarImg = typedArray.getResourceId(R.styleable.DtRatingBar_rating_un_star_img, R.drawable.ic_un_star);        mBuilder = new RatingView.Builder()                .context(mContext)                .width(childViewWidth)                .height(childViewHeight)                .paddingLeft(childViewPaddingLeft)                .paddingRight(childViewPaddingRight)                .paddingBottom(childViewPaddingBottom)                .paddingTop(childViewPaddingTop)                .star(childViewStarImg)                .halfStar(childViewHalfStarImg)                .unStar(childViewUnStarImg);        typedArray.recycle();        setEnabled(false);// 默认不让滑动        initView();    }

实现一个评分改变的回调接口

public interface OnRatingChangeListener {        /**         * on rating change         *         * @param rating rating         * @param stars  stars sum         */        void onChange(float rating, int stars);    }

对触摸事件的处理,复写onTouchEvent方法

@Override    public boolean onTouchEvent(MotionEvent event) {        if (isEnabled()) {            switch (event.getAction()) {                case MotionEvent.ACTION_DOWN:                    performClick();                    break;                case MotionEvent.ACTION_UP:                case MotionEvent.ACTION_CANCEL:                    break;                default:                    break;            }            // 布局方向的判断,如果是水平方向的,判断x            if (getOrientation() == LinearLayout.HORIZONTAL) {                int width = getWidth();                float x = event.getX();                // 对x的大小限制,最大为view的宽度,最小为0                x = x > width ? width : x;                x = x < 0 ? 0 : x;                mRating = x / mChildWidth;            } else {                // 垂直方向,判断y                int height = getHeight();                float y = event.getY();                y = y > height ? height : y;                y = y < 0 ? 0 : y;                mRating = y / mChildHeight;            }            // 得分的转换,因为我们只需要两位数的精确度,而且需要判断是否支持半星            mRating = getRatingValue(mRating);            if (mOnRatingChangeListener != null) {                mOnRatingChangeListener.onChange(mRating, mStars);            }            updateView();            return true;        } else {            return false;        }    }

对评分精度的转换

private float getRatingValue(float rating) {        // half        int half = RATE / 2;        rating = rating * RATE;        int xx = (int) (rating % RATE);        int yy = (int) (rating / RATE);        if (xx > 0) {            if (mSupportHalf) {                // support half                if (xx <= half) {                    // <= half ,  plus 0.5                    rating = (float) (yy + 0.5);                } else {                    // > half , plus 1                    rating = yy + 1;                }            } else {                // if not support half ,plus 1                rating = yy + 1;            }        } else {            rating = yy;        }        return rating;    }

RatingView

这里我们所设置的大小,包括宽高和padding,都是像素px,而不是dp。因为我们得到的设计稿一般标注都为px。这里的转换,我们需要转两次而不是一次。因为第一次是px转dp,这应该是设计稿对应的dp值,第二次是转换,从dp转px才是我们需要的px值。

  • 状态
    一共分成了三种状态:
    private static final int STATE_UN_STAR = 0;// 没星    private static final int STATE_HALF_STAR = 1;// 半星    private static final int STATE_STAR = 2;// 一星
  • 获得状态
    /**     * @param position position     * @param rating   rating     * @return status     * {@link #STATE_STAR,#STATE_HALF_STAR,#STATE_UN_STAR}     */    private int getState(int position, float rating) {        position++;        float dis = rating - position;        if (dis >= 0) {            return STATE_STAR;        } else {            if (dis >= -0.5) {                return STATE_HALF_STAR;            } else {                return STATE_UN_STAR;            }        }    }
  • 根据状态,获取对应的图片
/**     * get status     *     * @param position position     * @param rating   rating     * @return image id     */    private int getImageRes(int position, float rating) {        int id = R.drawable.ic_un_star;        switch (getState(position, rating)) {            case STATE_UN_STAR:                id = getUnStarImageId();                break;            case STATE_HALF_STAR:                id = getHalfStarImageId();                break;            case STATE_STAR:                id = getStarImageId();                break;            default:                break;        }        return id;    }

FINAL

至此大概的流程就写完了整个DtRatingView的过程。其实并不复杂,只是在写的过程中,可以学习到很多东西。毕竟自己动手后得到了一些成果。

更多相关文章

  1. Android(安卓)ImageView手势缩放完整的实现
  2. Android多分辨率适配(dp、px、sp互转),图片分辨率对应手机分辨率
  3. Android手动绘制ninepath(.9.png)图片
  4. Android热更新之dx工具jar转换dex
  5. android实现图片触摸旋转
  6. Android(安卓)ImageButton Example 图片按钮
  7. Android——ImageView.ScaleType设置图解
  8. Bitmap 的加载和 Cache
  9. No resource found that matches the given name (at 'thumb' wi

随机推荐

  1. 《高可用可伸缩微服务架构:基于 Dubbo、S
  2. 移动Web App开发之实战美团外卖
  3. 初识C语言2
  4. Python主讲移动端自动化测试框架Appium
  5. 【大云制造】为云而生 - 大云BEK内核
  6. 【干货分享】Kubernetes容器网络之CNI漫
  7. 【干货分享】Linux操作系统自动化测试平
  8. 知道 Redis-Cluster 么?说说其中可能不可
  9. 【干货分享】硬件加速介绍及Cyborg项目代
  10. PHP数组常用函数