上一篇文章介绍了如何用xml及Java代码实现progressBar的双重背景,这次我想介绍一下如何实现进度带光晕的ProgressBar。
在开始自定义ProgressBar之前,我想介绍一下Paint下实现毛玻璃效果的方法setMaskFilter:
MaskFilter setMaskFilter (MaskFilter maskfilter)
设置或清除maskfilter对象,画笔设置BlurMaskFilter 可以画出毛玻璃效果,具体效果与BlurMaskFilter 有关
使用方法:mPaint.setMaskFilter(new BlurMaskFilter(strokeWidth, BlurMaskFilter.Blur.SOLID))
strokeWidth为画笔的宽度,BlurMaskFilter.Blur.SOLID为BlurMaskFilter中的枚举类Blur中的值(具体见下图)
了解了这个方法后,我们开始自定义Drawable吧
首先是我们的布局文件,由于要给进度的光晕留空间,所以我们需要把布局文件中的ProgressBar的layout_height设置的大一点(进度高实际才6dp),布局文件代码如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:id="@+id/hqLoading_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#012345"
xmlns:android="http://schemas.android.com/apk/res/android">
<ProgressBar
android:id="@+id/loading_bar"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_width="400dp"
android:layout_height="24dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="200dp"
android:max="100"
android:progress="30"
/>
</RelativeLayout>
接下来是自定义进度条底层背景ProgressBgDrawable,代码如下:
public class ProgressBgDrawable extends GradientDrawable {
private int mStrokeWidth;
private float mRight;
private float mBottom;
public ProgressBgDrawable() {
mPaint = new Paint();
mPaint.setStyle(Paint.Style.FILL);
mPaint.setDither(true);
mPaint.setAlpha(128);
}
private Paint mPaint;
private int mColor;
private float mRadius;
public void setColor(int mColor) {
this.mColor = mColor;
}
@Override
public void draw(@NonNull Canvas canvas) {
mPaint.setColor(mColor);
mPaint.setStrokeWidth(mStrokeWidth);
canvas.drawRoundRect(new RectF(mStrokeWidth, 13.5f, mRight - mStrokeWidth, mBottom + 13.5f), mRadius, mRadius, mPaint);
}
public void setStrokeWidth(int mStrokeWidth) {
this.mStrokeWidth = mStrokeWidth;
}
public void setRight(float mRight) {
this.mRight = mRight;
}
public void setBottom(float mBottom) {
this.mBottom = mBottom;
}
public void setmRadius(float mRadius) {
this.mRadius = mRadius;
}
@Override
public void setAlpha(int alpha) {
mPaint.setAlpha(alpha);
}
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
mPaint.setColorFilter(colorFilter);
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
}
这里需要解释一下draw方法中的
canvas.drawRoundRect(new RectF(mStrokeWidth, 13.5f, mRight - mStrokeWidth, mBottom + 13.5f), mRadius, mRadius, mPaint);
这里画了一个圆角的矩形,该方法第一个参数是一个浮点数矩形,浮点数矩形的构造方法中四个参数分别对应矩形左边的X坐标,矩形顶部的Y坐标,矩形右边的X坐标,矩形底部的Y坐标,而我们绘制时留了画笔的宽度大小的位置是为了给光晕左边展示留位置,同样矩形顶部留13.5f也是这个道理。换句话说我们ProgressBar的宽度是24dp,但是我们进度条的底层背景宽度是要小点的。
弄好了进度条底层背景后,我们再弄一下进度条进度的Drawable,其代码如下:
public class ProgressDrawable extends Drawable {
private Paint mPaint;
private int mColor;
private float mRadius;
private int mStrokeWidth;
private float mRight;
private float mBottom;
public ProgressDrawable() {
mPaint = new Paint();
mPaint.setStyle(Paint.Style.FILL);
mPaint.setDither(true);
}
public void setColor(int mColor) {
this.mColor = mColor;
}
@Override
public void draw(@NonNull Canvas canvas) {
mPaint.setColor(mColor);
mPaint.setStrokeWidth(mStrokeWidth);
mPaint.setMaskFilter(new BlurMaskFilter(mStrokeWidth, BlurMaskFilter.Blur.SOLID));
canvas.drawRoundRect(new RectF(mStrokeWidth, 13.5f, mRight - mStrokeWidth, mBottom + 13.5f), mRadius, mRadius, mPaint);
}
public void setStrokeWidth(int strokeWidth) {
this.mStrokeWidth = strokeWidth;
}
public void setmRight(float mRight) {
this.mRight = mRight;
invalidateSelf();
}
public void setmBottom(float mBottom) {
this.mBottom = mBottom;
}
public void setmRadius(float mRadius) {
this.mRadius = mRadius;
}
@Override
public void setAlpha(int alpha) {
mPaint.setAlpha(alpha);
invalidateSelf();
}
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
mPaint.setColorFilter(colorFilter);
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
}
这里在自定义Drawable的时候给画笔设置了毛玻璃效果,就是我一开始介绍的那个方法,这个效果能让我们的ProgressBar看起来是进度带光晕的,再接下来是在Activity中进行设置和展示,代码如下:
public class TestActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
ProgressBar progressBar = findViewById(R.id.loading_bar);
ProgressDrawable p = new ProgressDrawable();
p.setColor(Color.rgb(0x00, 0xdd, 0x4d));
p.setmRight(dpToPx(this, 300));
p.setmBottom(dpToPx(this, 6));
p.setmRadius(10);
p.setStrokeWidth(12);
ClipDrawable progress = new ClipDrawable(p, Gravity.LEFT, ClipDrawable.HORIZONTAL);
ProgressBgDrawable background = new ProgressBgDrawable();
background.setColor(Color.argb(128, 0xff, 0xff, 0xff));
background.setmRadius(10);
background.setRight(dpToPx(this, 400));
background.setBottom(dpToPx(this, 6));
background.setStrokeWidth(12);
LayerDrawable pd=new LayerDrawable(new Drawable[]{background,progress});
progressBar.setProgressDrawable(pd);
progressBar.setProgress(100);
}
public static float dpToPx(Context context, float dp) {
return dp * ((float)context.getResources().getDisplayMetrics().densityDpi / (float) DisplayMetrics.DENSITY_DEFAULT);
}
}
效果图如下:
大功告成,不过如果网友们有更好的实现想法也可以分享分享,我实在是想不到其他的只好这样子实现了。