场景一:自定义进度条
在很多应用中,我们会看到一些独特样式的进度条,接下来就实现一个简单的圆形进度条。
实现思路
- 继承
View
类。 - 重写
onDraw
方法,在该方法里使用Canvas
和Paint
来绘制圆形进度条。 - 提供更新进度的方法。
示例代码
java
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
public class CustomProgressBar extends View {
private Paint backgroundPaint;
private Paint progressPaint;
private int progress = 0;
private RectF rectF;
public CustomProgressBar(Context context) {
super(context);
init();
}
public CustomProgressBar(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CustomProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
backgroundPaint = new Paint();
backgroundPaint.setColor(Color.GRAY);
backgroundPaint.setStyle(Paint.Style.STROKE);
backgroundPaint.setStrokeWidth(20);
backgroundPaint.setAntiAlias(true);
progressPaint = new Paint();
progressPaint.setColor(Color.BLUE);
progressPaint.setStyle(Paint.Style.STROKE);
progressPaint.setStrokeWidth(20);
progressPaint.setAntiAlias(true);
rectF = new RectF();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int centerX = getWidth() / 2;
int centerY = getHeight() / 2;
int radius = Math.min(centerX, centerY) - 20;
rectF.set(centerX - radius, centerY - radius, centerX + radius, centerY + radius);
// 绘制背景圆形
canvas.drawArc(rectF, 0, 360, false, backgroundPaint);
// 绘制进度弧形
float sweepAngle = (progress / 100.0f) * 360;
canvas.drawArc(rectF, -90, sweepAngle, false, progressPaint);
}
public void setProgress(int progress) {
if (progress < 0) {
progress = 0;
} else if (progress > 100) {
progress = 100;
}
this.progress = progress;
invalidate();
}
}
在布局文件中使用
XML
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center">
<com.example.customview.CustomProgressBar
android:id="@+id/customProgressBar"
android:layout_width="200dp"
android:layout_height="200dp" />
</LinearLayout>
在 Activity 中更新进度
java
import android.os.Bundle;
import android.os.Handler;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private CustomProgressBar customProgressBar;
private int currentProgress = 0;
private Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
customProgressBar = findViewById(R.id.customProgressBar);
// 模拟进度更新
new Thread(() -> {
while (currentProgress < 100) {
currentProgress++;
handler.post(() -> customProgressBar.setProgress(currentProgress));
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
handler.post(() -> Toast.makeText(MainActivity.this, "进度完成", Toast.LENGTH_SHORT).show());
}).start();
}
}
场景二:自定义星级评分控件
在电商、社交等应用里,星级评分控件是很常见的。下面来实现一个简单的星级评分控件。
实现思路
- 继承
View
类。 - 重写
onDraw
方法,绘制星星图标。 - 重写
onTouchEvent
方法,处理触摸事件,实现星级选择。
示例代码
java
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import androidx.core.content.ContextCompat;
public class CustomStarRating extends View {
private Drawable starFilled;
private Drawable starEmpty;
private int starCount = 5;
private int rating = 0;
private int starSize = 50;
private int starSpacing = 10;
public CustomStarRating(Context context) {
super(context);
init();
}
public CustomStarRating(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CustomStarRating(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
starFilled = ContextCompat.getDrawable(getContext(), android.R.drawable.star_big_on);
starEmpty = ContextCompat.getDrawable(getContext(), android.R.drawable.star_big_off);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (int i = 0; i < starCount; i++) {
int left = i * (starSize + starSpacing);
int top = 0;
int right = left + starSize;
int bottom = top + starSize;
Drawable drawable = (i < rating) ? starFilled : starEmpty;
drawable.setBounds(left, top, right, bottom);
drawable.draw(canvas);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
float x = event.getX();
int newRating = (int) (x / (starSize + starSpacing)) + 1;
if (newRating > starCount) {
newRating = starCount;
} else if (newRating < 0) {
newRating = 0;
}
rating = newRating;
invalidate();
return true;
}
return super.onTouchEvent(event);
}
public int getRating() {
return rating;
}
public void setRating(int rating) {
if (rating < 0) {
rating = 0;
} else if (rating > starCount) {
rating = starCount;
}
this.rating = rating;
invalidate();
}
}
在布局文件中使用
XML
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center">
<com.example.customview.CustomStarRating
android:id="@+id/customStarRating"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
在 Activity 中获取评分
java
import android.os.Bundle;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private CustomStarRating customStarRating;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
customStarRating = findViewById(R.id.customStarRating);
// 设置初始评分
customStarRating.setRating(3);
// 获取评分
int rating = customStarRating.getRating();
Toast.makeText(this, "当前评分:" + rating, Toast.LENGTH_SHORT).show();
}
}
场景三:实现一个自定义的圆角ImageView
实现思路
- 继承
ImageView
:创建一个新的类,继承自ImageView
。 - 重写
onDraw
方法 :在onDraw
方法里,运用Canvas
和Paint
来绘制圆角矩形,并且把图片绘制到这个圆角矩形内。 - 处理图片缩放:要保证图片能够正确地缩放以适应圆角矩形。
java
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.util.AttributeSet;
import androidx.appcompat.widget.AppCompatImageView;
public class RoundedImageView extends AppCompatImageView {
private float cornerRadius = 20; // 默认圆角半径
public RoundedImageView(Context context) {
super(context);
}
public RoundedImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public RoundedImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
// 可以在这里从属性中获取圆角半径
// TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RoundedImageView);
// cornerRadius = a.getDimension(R.styleable.RoundedImageView_cornerRadius, cornerRadius);
// a.recycle();
}
@Override
protected void onDraw(Canvas canvas) {
int width = getWidth();
int height = getHeight();
// 创建一个圆角矩形路径
Path path = new Path();
RectF rect = new RectF(0, 0, width, height);
path.addRoundRect(rect, cornerRadius, cornerRadius, Path.Direction.CW);
canvas.clipPath(path);
super.onDraw(canvas);
}
public void setCornerRadius(float radius) {
this.cornerRadius = radius;
invalidate();
}
}
使用方法
在布局文件中使用自定义的 RoundedImageView
:
java
<com.example.yourpackage.RoundedImageView
android:layout_width="200dp"
android:layout_height="200dp"
android:src="@drawable/your_image" />
代码解释
RoundedImageView
类 :继承自AppCompatImageView
,它是ImageView
的兼容版本。cornerRadius
变量:用来存储圆角的半径,默认值为 20。init
方法:能够从属性中获取圆角半径,不过当前处于注释状态。onDraw
方法 :- 创建一个圆角矩形路径。
- 运用
canvas.clipPath
方法把画布裁剪成圆角矩形。 - 调用
super.onDraw(canvas)
来绘制图片。
setCornerRadius
方法 :用于动态设置圆角半径,并且调用invalidate
方法重新绘制视图。
之后还会有补充的,感谢观看!!!