1. 思路分析
自定義View步驟:
1>:values__attrs.xml苦囱,自定義屬性;
2>:在第三個(gè)構(gòu)造方法中脾猛,獲取自定義屬性撕彤;
3>:onMeasure:不是必須的;
4>:onDraw:所有繪制的代碼都在寫(xiě)到onDraw方法中猛拴;
思路分析:
1>:從桌面進(jìn)入時(shí)初始化的樣子羹铅;
2>:處理用戶交互部分
2. 代碼如下
1>:attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 淘寶評(píng)分控件 -->
<declare-styleable name="RatingBar">
<!-- 未選中圖片 -->
<attr name="starNormal" format="reference"/>
<!-- 選中圖片 -->
<attr name="starFocus" format="reference"/>
<!-- 評(píng)分 -->
<attr name="gradeNumber" format="integer"/>
</declare-styleable>
</resources>
2>:RatingBar
/**
* ================================================
* Email: 2185134304@qq.com
* Created by Novate 2018/12/30 17:55
* Version 1.0
* Params:
* Description: 仿淘寶評(píng)分控件
* ================================================
*/
public class RatingBar extends View {
// 未選中、選中的五角星
private Bitmap mStarNormalBitmap , mStarFocusBitmap;
// 默認(rèn)評(píng)分
private int mGradeNumber = 5 ;
// 當(dāng)前評(píng)分
private int mCurrentGrade = 0 ;
public RatingBar(Context context) {
this(context,null);
}
public RatingBar(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public RatingBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// 獲取自定義屬性
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RatingBar);
// 未選中圖片資源id专肪,默認(rèn)傳遞0
int starNormalId = typedArray.getResourceId(R.styleable.RatingBar_starNormal,0);
if (starNormalId == 0){
throw new RuntimeException("請(qǐng)?jiān)O(shè)置屬性 starNormal") ;
}
// 用 BitmapFactory 解析資源
mStarNormalBitmap = BitmapFactory.decodeResource(getResources(),starNormalId);
// 選中圖片資源id诺苹,默認(rèn)傳遞0
int starFocusId = typedArray.getResourceId(R.styleable.RatingBar_starFocus,0);
if (starFocusId == 0){
throw new RuntimeException("請(qǐng)?jiān)O(shè)置屬性 starFocus") ;
}
// 用 BitmapFactory 解析資源
mStarFocusBitmap = BitmapFactory.decodeResource(getResources(),starFocusId);
// 評(píng)分分?jǐn)?shù)
mGradeNumber = typedArray.getInt(R.styleable.RatingBar_gradeNumber,mGradeNumber);
// 釋放資源
typedArray.recycle();
}
/**
* 測(cè)量
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 這里用 mStarNormalBitmap 和 mStarFocusBitmap 是一樣的
// 寬度 1個(gè)星星寬度*星星個(gè)數(shù)
int width = mStarFocusBitmap.getWidth()*mGradeNumber;
// 高度 1個(gè)星星的高度
int height = mStarFocusBitmap.getHeight();
// 測(cè)量大小
setMeasuredDimension(width,height);
}
/**
* 繪制
*/
@Override
protected void onDraw(Canvas canvas) {
// super.onDraw(canvas);
for (int i = 0; i < mGradeNumber; i++) {
// i * 星星寬度 1個(gè)星星寬度就是 1*寬度 2個(gè)星星寬度就是 2*寬度
int x = i * mStarFocusBitmap.getWidth();
// 觸摸的時(shí)候 mCurrentGrade的值是不斷變化的势篡,i從0開(kāi)始碍侦,mCurrentGrade從1開(kāi)始
if (mCurrentGrade > i){
canvas.drawBitmap(mStarFocusBitmap,x,0,null);
}else{
canvas.drawBitmap(mStarNormalBitmap,x,0,null);
}
}
}
/**
* 觸摸
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
// 移動(dòng)株旷、按下钞瀑、抬起處理邏輯一樣显晶,判斷手指位置唯笙,根據(jù)當(dāng)前位置計(jì)算分?jǐn)?shù),然后刷新
// 在按下時(shí)候:移動(dòng)、按下辑畦、抬起事件都會(huì)調(diào)用,把下邊的按下分扎、抬起事件注釋?zhuān)梢詼p少onDraw調(diào)用
switch (event.getAction()){
// case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
// case MotionEvent.ACTION_UP:
// getX: 相對(duì)于父控件 getRawX: 相對(duì)于屏幕
float moveX = event.getX() ;
// 當(dāng)前分?jǐn)?shù)
int currentGrade = (int)(moveX/mStarFocusBitmap.getWidth()+1);
// 范圍問(wèn)題
if (currentGrade < 0){
currentGrade=0;
}
if (currentGrade > mCurrentGrade){
currentGrade = mCurrentGrade;
}
// 分?jǐn)?shù)相同就不要再繪制了宏悦,盡量減少onDraw的調(diào)用
if (currentGrade == mCurrentGrade){
// return true:表示自己處理事件傀蓉,事件不會(huì)向下傳遞
return true;
}
mCurrentGrade = currentGrade ;
// 重新繪制
invalidate();
break;
}
// return true:表示自己處理事件屡拨,事件不會(huì)向下傳遞
return true;
}
}
3>:activity_ratingbar.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<com.novate.test.customview.RatingBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:starNormal="@drawable/star_normal"
app:starFocus="@drawable/star_selected"
app:gradeNumber="5"
/>
</LinearLayout>
4>:RatingBarActivity
public class RatingBarActivity extends AppCompatActivity {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ratingbar);
}
}