自定义View三部曲:onMeasure()\onDraw()\onTouch()
1.效果实现分析
1.1 分析:
1.刚进来初始化的样子,
2.用户需要触摸,处理用户交互的部分(onTouch)
2.自定义属性
两张图片资源、 评分的等级数量
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="RatingBar">
<attr name="starPadding" format="dimension"/>
<attr name="origin" format="reference"/>
<attr name="change" format="reference"/>
<attr name="starNumber" format="integer"/>
</declare-styleable>
</resources>
3.使用属性
<com.example.progress.RatingBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@color/purple_200"
app:starPadding="50dp"
app:change="@drawable/star_final"
app:origin="@drawable/star"
app:starNumber="5" />
4.自定义View--获取、测量、绘制、触碰
4.1 获取
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);
starNumber = typedArray.getInt(R.styleable.RatingBar_starNumber,starNumber);
RatingBar_origin = typedArray.getResourceId(R.styleable.RatingBar_origin,RatingBar_origin);
RatingBar_change = typedArray.getResourceId(R.styleable.RatingBar_change,RatingBar_change);
starPadding = typedArray.getDimensionPixelSize(R.styleable.RatingBar_starPadding,starPadding);
if(RatingBar_origin == 0 || RatingBar_change == 0){
throw new RuntimeException("加星星");
}
RatingBar_origin_pic = BitmapFactory.decodeResource(getResources(),RatingBar_origin);
RatingBar_change_pic = BitmapFactory.decodeResource(getResources(),RatingBar_change);
typedArray.recycle();
}
4.2 测量
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = (RatingBar_origin_pic.getWidth()+10)*starNumber + starPadding*2;
int height = RatingBar_origin_pic.getHeight();
setMeasuredDimension(width,height);
}
4.3 绘制
@Override
protected void onDraw(Canvas canvas) {
Log.d(TAG,"onDraw");
for(int i = 0;i<starNumber;i++){
int x = i*(RatingBar_origin_pic.getWidth()+10)+starPadding;
if(mCurrentStarNum > i){
canvas.drawBitmap(RatingBar_change_pic,x,0,null);
}else{
canvas.drawBitmap(RatingBar_origin_pic,x,0,null);
}
}
}
4.4 触摸
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_DOWN:
float x = event.getX();
int currentStarNum = (int) (x /(float)RatingBar_origin_pic.getWidth()+1);
if(currentStarNum < 0){
currentStarNum = 0;
}
if(currentStarNum > starNumber){
currentStarNum = starNumber;
}
if(mCurrentStarNum == currentStarNum){
return true;
}
mCurrentStarNum = currentStarNum;
invalidate();
}
return true;
}
5.附件
5.1 View
package com.example.progress;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.Nullable;
public class RatingBar extends View {
private static final String TAG = "RatingBar";
private int starNumber = 5;
private int RatingBar_origin = 5;
private int starPadding;
private int RatingBar_change = 5;
private Bitmap RatingBar_origin_pic,RatingBar_change_pic;
private int mCurrentStarNum = 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);
starNumber = typedArray.getInt(R.styleable.RatingBar_starNumber,starNumber);
RatingBar_origin = typedArray.getResourceId(R.styleable.RatingBar_origin,RatingBar_origin);
RatingBar_change = typedArray.getResourceId(R.styleable.RatingBar_change,RatingBar_change);
starPadding = typedArray.getDimensionPixelSize(R.styleable.RatingBar_starPadding,starPadding);
if(RatingBar_origin == 0 || RatingBar_change == 0){
throw new RuntimeException("加星星");
}
RatingBar_origin_pic = BitmapFactory.decodeResource(getResources(),RatingBar_origin);
RatingBar_change_pic = BitmapFactory.decodeResource(getResources(),RatingBar_change);
typedArray.recycle();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = (RatingBar_origin_pic.getWidth()+10)*starNumber + starPadding*2;
int height = RatingBar_origin_pic.getHeight();
setMeasuredDimension(width,height);
}
@Override
protected void onDraw(Canvas canvas) {
Log.d(TAG,"onDraw");
for(int i = 0;i<starNumber;i++){
int x = i*(RatingBar_origin_pic.getWidth()+10)+starPadding;
if(mCurrentStarNum > i){
canvas.drawBitmap(RatingBar_change_pic,x,0,null);
}else{
canvas.drawBitmap(RatingBar_origin_pic,x,0,null);
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_DOWN:
float x = event.getX();
int currentStarNum = (int) (x /(float)RatingBar_origin_pic.getWidth()+1);
if(currentStarNum < 0){
currentStarNum = 0;
}
if(currentStarNum > starNumber){
currentStarNum = starNumber;
}
if(mCurrentStarNum == currentStarNum){
return true;
}
mCurrentStarNum = currentStarNum;
invalidate();
}
return true;
}
}
5.2 activity_main.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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.example.progress.RatingBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@color/purple_200"
app:starPadding="50dp"
app:change="@drawable/star_final"
app:origin="@drawable/star"
app:starNumber="5" />
</LinearLayout>
5.3 AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.progress">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MVC">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>