自定义进度条的可绘制对象不适合
Custom Progress Bar's drawable does not fit
我正在尝试实现以下进度条:
我得到的结果是:
这里的问题是线条不适合进度条,因为它在图像的左侧和右侧很清楚。原因是我是用进度条的高度和宽度来画线的,但是进度条有一个角半径,在获取高度和宽度的时候没有考虑到。'
我尝试向进度栏添加填充,但我不想要任何空的 space,如上图第一张所示。
这是我的主要内容 类:
ProgressDrawable.java
class ProgressDrawable extends Drawable {
private static final int NUM_LINES = 60;
private Paint mPaint = new Paint();
private ProgressBar progressBar;
public ProgressDrawable(Context context, ProgressBar progressBar){
super();
init(context);
this.progressBar = progressBar;
}
@Override
protected boolean onLevelChange(int level) {
invalidateSelf();
return true;
}
@Override
public void draw(Canvas canvas) {
float width = progressBar.getWidth();
float height = progressBar.getHeight();
for (int i = 0; i < NUM_LINES; i++) {
float startX = width * i / NUM_LINES;
float stopX = startX + 2f * width / NUM_LINES;
//mPaint.setColor((i + 1) * 10000 / NUM_LINES <= getLevel()? 0xff888888 : 0xCACACA);
mPaint.setShader((i + 1) * 10000 / NUM_LINES <= getLevel()? new LinearGradient(0, 0, 0, height, Color.parseColor("#77F5FF"), Color.parseColor("#31AFF5"), Shader.TileMode.MIRROR) : new LinearGradient(0, 0, 0, height, Color.parseColor("#D9D9D9"), Color.parseColor("#D9D9D9"), Shader.TileMode.MIRROR));
canvas.drawLine(startX, height, stopX, 0, mPaint);
}
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(ColorFilter cf) {
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
private void init(Context context)
{
Resources resources = context.getResources();
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStrokeWidth(resources.getDimension(R.dimen.vertical_divider_width));
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
LinearLayout mainLayout;
ProgressBar pb;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mainLayout = findViewById(R.id.mainLayout);
LinearLayout ll = new LinearLayout(this);
ll.setOrientation(LinearLayout.VERTICAL);
mainLayout.addView(ll);
pb = findViewById(R.id.progressBar);
Drawable d = new ProgressDrawable(this, pb);
pb.setProgressDrawable(d);
SeekBar.OnSeekBarChangeListener l = new SeekBar.OnSeekBarChangeListener() {
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
int newProgress = pb.getMax() * progress / seekBar.getMax();
Log.d(MainActivity.class.getSimpleName(), "onProgressChanged " + newProgress);
pb.setProgress(newProgress);
}
};
startProgress();
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/mainLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" android:orientation="vertical" android:gravity="center">
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="600dp"
android:layout_height="50dp"
android:max="60"
style="?android:attr/progressBarStyleHorizontal"
android:background="@drawable/rounded_layout"/>
</LinearLayout>
rounded_layout.xml
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#D9D9D9"/>
<corners android:radius="15dp" />
</shape>
任何帮助将不胜感激。
提前致谢。
感谢@0X0nousugar 对 的回答。
剪裁 canvas 是正确的方法,但我的主要错误是我用 canvas 绘制线条,进度条的圆形在 xml 中完成。我的解决方案是删除 rounded_layout.xml 作为 preogress 栏的背景,绘制一个剪裁的矩形,然后确保在其中绘制线条。
下面是代码片段:
@Override
public void draw(Canvas canvas) {
mPaint = new Paint();
mPaint.setAntiAlias(true);
// get the height and width of the progress bar
float width = progressBar.getWidth();
float height = progressBar.getHeight();
Path rectPath = new Path();
RectF rect = new RectF(0, 0, 0,0);
// set the size of the rectangle to the size of the progress bar
rect.set(0, 0, width, height);
// set the corner radius (mine is 15) to have a rounded rectangle
rectPath.addRoundRect(rect, 15, 15, Path.Direction.CW);
// set the color for the rectangle
mPaint.setColor(Color.parseColor("#D9D9D9"));
// clip and draw the rectangle
canvas.clipPath(rectPath);
canvas.drawRect(rect, mPaint);
// a loop to create the lines inside the rectangle, one at a time
for (int i = 0; i < NUM_LINES; i++) {
float startX = width * i / NUM_LINES;
float stopX = startX + 2f * width / NUM_LINES;
mPaint.setShader((i + 1) * 10000 / NUM_LINES <= getLevel()?
new LinearGradient(0, 0, 0, height,
Color.parseColor("#77F5FF"), Color.parseColor("#31AFF5"),
Shader.TileMode.MIRROR) : new LinearGradient(0, 0, 0,
height, Color.parseColor("#D9D9D9"),
Color.parseColor("#D9D9D9"), Shader.TileMode.MIRROR));
canvas.drawLine(startX, height, stopX, 0, mPaint);
}
}
注意:确保所有的线都画在矩形内。
我正在尝试实现以下进度条:
我得到的结果是:
这里的问题是线条不适合进度条,因为它在图像的左侧和右侧很清楚。原因是我是用进度条的高度和宽度来画线的,但是进度条有一个角半径,在获取高度和宽度的时候没有考虑到。'
我尝试向进度栏添加填充,但我不想要任何空的 space,如上图第一张所示。
这是我的主要内容 类:
ProgressDrawable.java
class ProgressDrawable extends Drawable {
private static final int NUM_LINES = 60;
private Paint mPaint = new Paint();
private ProgressBar progressBar;
public ProgressDrawable(Context context, ProgressBar progressBar){
super();
init(context);
this.progressBar = progressBar;
}
@Override
protected boolean onLevelChange(int level) {
invalidateSelf();
return true;
}
@Override
public void draw(Canvas canvas) {
float width = progressBar.getWidth();
float height = progressBar.getHeight();
for (int i = 0; i < NUM_LINES; i++) {
float startX = width * i / NUM_LINES;
float stopX = startX + 2f * width / NUM_LINES;
//mPaint.setColor((i + 1) * 10000 / NUM_LINES <= getLevel()? 0xff888888 : 0xCACACA);
mPaint.setShader((i + 1) * 10000 / NUM_LINES <= getLevel()? new LinearGradient(0, 0, 0, height, Color.parseColor("#77F5FF"), Color.parseColor("#31AFF5"), Shader.TileMode.MIRROR) : new LinearGradient(0, 0, 0, height, Color.parseColor("#D9D9D9"), Color.parseColor("#D9D9D9"), Shader.TileMode.MIRROR));
canvas.drawLine(startX, height, stopX, 0, mPaint);
}
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(ColorFilter cf) {
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
private void init(Context context)
{
Resources resources = context.getResources();
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStrokeWidth(resources.getDimension(R.dimen.vertical_divider_width));
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
LinearLayout mainLayout;
ProgressBar pb;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mainLayout = findViewById(R.id.mainLayout);
LinearLayout ll = new LinearLayout(this);
ll.setOrientation(LinearLayout.VERTICAL);
mainLayout.addView(ll);
pb = findViewById(R.id.progressBar);
Drawable d = new ProgressDrawable(this, pb);
pb.setProgressDrawable(d);
SeekBar.OnSeekBarChangeListener l = new SeekBar.OnSeekBarChangeListener() {
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
int newProgress = pb.getMax() * progress / seekBar.getMax();
Log.d(MainActivity.class.getSimpleName(), "onProgressChanged " + newProgress);
pb.setProgress(newProgress);
}
};
startProgress();
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/mainLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" android:orientation="vertical" android:gravity="center">
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="600dp"
android:layout_height="50dp"
android:max="60"
style="?android:attr/progressBarStyleHorizontal"
android:background="@drawable/rounded_layout"/>
</LinearLayout>
rounded_layout.xml
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#D9D9D9"/>
<corners android:radius="15dp" />
</shape>
任何帮助将不胜感激。
提前致谢。
感谢@0X0nousugar 对
剪裁 canvas 是正确的方法,但我的主要错误是我用 canvas 绘制线条,进度条的圆形在 xml 中完成。我的解决方案是删除 rounded_layout.xml 作为 preogress 栏的背景,绘制一个剪裁的矩形,然后确保在其中绘制线条。
下面是代码片段:
@Override
public void draw(Canvas canvas) {
mPaint = new Paint();
mPaint.setAntiAlias(true);
// get the height and width of the progress bar
float width = progressBar.getWidth();
float height = progressBar.getHeight();
Path rectPath = new Path();
RectF rect = new RectF(0, 0, 0,0);
// set the size of the rectangle to the size of the progress bar
rect.set(0, 0, width, height);
// set the corner radius (mine is 15) to have a rounded rectangle
rectPath.addRoundRect(rect, 15, 15, Path.Direction.CW);
// set the color for the rectangle
mPaint.setColor(Color.parseColor("#D9D9D9"));
// clip and draw the rectangle
canvas.clipPath(rectPath);
canvas.drawRect(rect, mPaint);
// a loop to create the lines inside the rectangle, one at a time
for (int i = 0; i < NUM_LINES; i++) {
float startX = width * i / NUM_LINES;
float stopX = startX + 2f * width / NUM_LINES;
mPaint.setShader((i + 1) * 10000 / NUM_LINES <= getLevel()?
new LinearGradient(0, 0, 0, height,
Color.parseColor("#77F5FF"), Color.parseColor("#31AFF5"),
Shader.TileMode.MIRROR) : new LinearGradient(0, 0, 0,
height, Color.parseColor("#D9D9D9"),
Color.parseColor("#D9D9D9"), Shader.TileMode.MIRROR));
canvas.drawLine(startX, height, stopX, 0, mPaint);
}
}
注意:确保所有的线都画在矩形内。