前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >自定义 View 实战 06 - 仿写 RatingBar

自定义 View 实战 06 - 仿写 RatingBar

作者头像
code_horse
发布2020-07-02 10:51:08
3250
发布2020-07-02 10:51:08
举报
文章被收录于专栏:Android NoteAndroid Note

RatingBar

效果分析:

star_normal.png

star_select.png

准备两张星星图,一张默认,一张选中。初始的时候绘制默认的 5 颗星星,然后根据手势绘制选中的星星。

自定义属性
代码语言:javascript
复制
<declare-styleable name="KRatingbar">
        //要绘制的个数
        <attr name="starNum" format="integer"/>
        //星星之间的间距
        <attr name="starPadding" format="integer" />
        //默认星星的 resId
        <attr name="starNormal" format="reference" />
        //选中星星的 resId
        <attr name="starSelect" format="reference" />
</declare-styleable>
具体实现
代码语言:javascript
复制
class KRatingbar @JvmOverloads constructor(
    context: Context,
    attributes: AttributeSet?,
    defStyle: Int = 0
) : View(context, attributes, defStyle) {

    private var mCount = 5
    private var mNormalBitmap: Bitmap
    private var mSelectBitmap: Bitmap
    private var mStarPadding = dp2Px(5, resources)
    private var mCurSelect = -1

    init {
        val ta = context.obtainStyledAttributes(attributes, R.styleable.KRatingbar)
        mCount = ta.getInt(R.styleable.KRatingbar_starNum, 5)
        mStarPadding = ta.getInt(R.styleable.KRatingbar_starPadding, dp2Px(5, resources))
        val normalId = ta.getResourceId(R.styleable.KRatingbar_starNormal, -1)
        if (normalId == 1.unaryMinus()) throw RuntimeException("starNormal can't be empty")
        mNormalBitmap = BitmapFactory.decodeResource(resources, normalId)
        val selectId = ta.getResourceId(R.styleable.KRatingbar_starSelect, -1)
        if (selectId == 1.unaryMinus()) throw RuntimeException("starSelect can't be empty")
        mSelectBitmap = BitmapFactory.decodeResource(resources, selectId)
        ta.recycle()
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        //图片宽度*绘制的个数+星星间的间隙+paddingLeft+paddingRight
        val width =
            mNormalBitmap.width * mCount + mStarPadding * (mCount - 1) + paddingLeft + paddingRight
        //图片的高度+paddingTop+paddingBottom
        val height = mNormalBitmap.height + paddingTop + paddingBottom
        setMeasuredDimension(width, height)
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        for (i in 0 until mCount) {
            var x = i * mNormalBitmap.width
            if (i != 0) {
                //平移画布,其实就是在绘制间隙
                canvas.translate(mStarPadding.toFloat(), 0f)
            }
            if (i < mCurSelect) {
                //绘制选中的星星
                canvas.drawBitmap(mSelectBitmap, x.toFloat(), 0f, null)
            } else {
                //绘制默认星星
                canvas.drawBitmap(mNormalBitmap, x.toFloat(), 0f, null)
            }

        }
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        when (event.action) {
            MotionEvent.ACTION_DOWN, MotionEvent.ACTION_MOVE, MotionEvent.ACTION_UP -> {
                //根据手指按下的 x 坐标去计算按压的是第几个星星
                //这里要 +1,因为 index 是从 0 开始的
                val count = event.x.toInt() / (mNormalBitmap.width+mStarPadding) + 1
                //当前选中的和之前一样不再重复绘制,count !=1 是为了处理,按压第一个时,无法滑动选中的 bug
                if (mCurSelect == count && count != 1) {
                    return false
                }
                //越界时为 0 
                if (count < 0) {
                    mCurSelect = 0
                }
                //越界时默认为最大的绘制个数
                if (count > mCount) {
                    mCurSelect = mCount
                }
                //当前选中了第几个
                mCurSelect = count
                //重绘
                invalidate()
            }
        }
        //这里要返回 true 才会处理 onTouchEvent 事件
        return true
    }

}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 自定义属性
  • 具体实现
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档