Android 从 0 开始学习自定义 View(六) 自定义星

2020-12-15  本文已影响0人  是刘航啊
先看看效果图
star.gif

1.自定义 View 的基本流程

1.1 创建 View Class
public class StarView extends View  {
    public StarView(Context context) {
        this(context, null);
    }

    public StarView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public StarView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
}
1.2 创建 attr
<declare-styleable name="StarView">
    <!--默认图片-->
    <attr name="normal" format="reference"/>
    <!--选中图片-->
    <attr name="focus" format="reference"/>
    <!--数量-->
    <attr name="starNumber" format="integer"/>
    <!--间隔-->
    <attr name="starPadding" format="dimension"/>
</declare-styleable>
1.3 绑定 attr
private void initAttr(Context context, AttributeSet attrs) {
    TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.StarView);
    //默认图片
    int mNormalId = array.getResourceId(R.styleable.StarView_normal, 0);
    if (mNormalId == 0) throw new RuntimeException("normal resource not set");
    mNormalBitmap = BitmapFactory.decodeResource(getResources(), mNormalId);

    //默认图片
    int mFocusId = array.getResourceId(R.styleable.StarView_focus, 0);
    if (mFocusId == 0) throw new RuntimeException("focus resource not set");
    mFocusBitmap = BitmapFactory.decodeResource(getResources(), mFocusId);

    //星星数量
    mStarNumber = array.getInt(R.styleable.StarView_starNumber, mStarNumber);
    //星星间隔
    mStarPadding = (int) array.getDimension(R.styleable.StarView_starPadding, mStarPadding);
    //回收
    array.recycle();
}
1.4 onMeasure
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    //宽 星星总宽度 + 间隔 + padding
    int width = mNormalBitmap.getWidth() * mStarNumber + mStarPadding * (mStarNumber - 1) + getPaddingLeft() + getPaddingRight();
    //高 星星高度 + padding
    int height = mNormalBitmap.getHeight() + getPaddingTop() + getPaddingBottom();
    //设置宽高
    setMeasuredDimension(width, height);
}
1.5 onDraw
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    //一个星星占的大小
    int starWidth = (getWidth() - getPaddingLeft() - getPaddingRight()) / mStarNumber;
    for (int i = 0; i < mStarNumber; i++) {
        if (CurrentNumber > i) {
            canvas.drawBitmap(mFocusBitmap, getPaddingLeft() + i * starWidth, getPaddingTop(), null);
        } else {
            canvas.drawBitmap(mNormalBitmap, getPaddingLeft() + i * starWidth, getPaddingTop(), null);
        }
    }
}

通过星星的数量循环绘制

1.6 onTouchEvent
public boolean onTouchEvent(MotionEvent event) {
    /**
     * 减少多次绘制,根据实际情况处理事件
     * 这里我们只处理 MOVE 事件
     */
    switch (event.getAction()) {
        //case MotionEvent.ACTION_DOWN:
        case MotionEvent.ACTION_MOVE:
        //case MotionEvent.ACTION_UP:
            //获取在当前 View 中的位置
            float moveX = event.getX();
            //获取一个星星大小
            int starWidth = (getWidth() - getPaddingLeft() - getPaddingRight()) / mStarNumber;
            //获取当前位置
            int current = (int) moveX / starWidth + 1;
            if (current < 0) current = 0;
            if (current > mStarNumber) current = mStarNumber;
            if (this.CurrentNumber == current) return true;
            this.CurrentNumber = current;
            invalidate();
            break;
    }
    return true;
}

下篇文字会分析 onTouchEvent 源码,为什么要设置返回 true

自定义星星就介绍到这里了,如果有什么写得不对的,可以在下方评论留言,我会第一时间改正。

Github 源码链接

上一篇 下一篇

猜你喜欢

热点阅读