Android 从 0 开始学习自定义 View(六) 自定义星
2020-12-15 本文已影响0人
是刘航啊
先看看效果图
star.gif1.自定义 View 的基本流程
- 创建 View Class
- 创建 attr 属性文件,确定属性
- View Class 绑定 attr 属性
- onMeasure 测量
- onDraw 绘制
- onTouchEvent ( 用户交互需要处理 )
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