如何在Android中以编程方式设置SeekBar进度图形

13
我在通过编程方式设置SeekBar的进度条时遇到了问题。但是,当我在XML文件中设置时,一切都正常。
<SeekBar
 android:id="@+id/sb"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 .....
 android:progressDrawable="@drawable/seek_bar"/>

从 .xml 设置

但是,当我尝试像这样从代码中设置时,遇到了问题:

seekBar.setProgressDrawable(getResources().getDrawable(R.drawable.seek_bar));
背景可绘制物占据整个 SeekBar,导致我无法在后面修改进度 - 拇指移动但进度可绘制物仍然填充整个 SeekBar。此外,SeekBar 失去了其圆角。似乎进度可绘制物位于 SeekBar 顶部。 when set in code 我尝试了 Android ProgressBar does not update progress view/drawable 中提供的解决方案,但对我没有起作用。
4个回答

28

我通过使用.xml形状作为SeekBar的背景来解决了这个问题。 可以通过setProgressDrawable()方法使用的完整SeekBar解决方案应该像这样:

//seek_bar.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item
    android:id="@android:id/background"
    android:drawable="@drawable/seek_bar_background"/>
<item android:id="@android:id/progress"
    android:drawable="@drawable/seek_bar_progress" />
</layer-list>

//seek_bar_background.xml
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >

<gradient
    android:angle="270"
    android:startColor="#8a8c8f"
    android:endColor="#58595b" />

<corners android:radius="5dip" />

</shape>

//seek_bar_progress.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item
    android:id="@android:id/background"
    android:drawable="@drawable/seek_bar_background"/>
<item android:id="@android:id/progress">
    <clip android:drawable="@drawable/seek_bar_progress_fill" />
</item>

</layer-list>

//seek_bar_progress_fill.xml
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >

<gradient
    android:startColor="#b3d27e"       
    android:endColor="#93c044"
    android:angle="270"
 />
 <corners android:radius="5dip" />  

</shape>

在代码中,您可以像这样使用它:

progressBar.setProgressDrawable(getResources().getDrawable(R.drawable.seek_bar));

9
上面给出的答案是使用XML的,但如果有人想以编程方式实现这个功能,我可以提供以下代码:
public class SeekBarBackgroundDrawable extends Drawable {

private Paint mPaint = new Paint();
private float dy;

public SeekBarBackgroundDrawable(Context ctx) {
    mPaint.setColor(Color.WHITE);
    dy = ctx.getResources().getDimension(R.dimen.one_dp);
}

@Override
public void draw(Canvas canvas) {
    canvas.drawRect(getBounds().left,getBounds().centerY()-dy/2,getBounds().right,getBounds().centerY()+dy/2,mPaint);
}

@Override
public void setAlpha(int i) {
    mPaint.setAlpha(i);
}

@Override
public void setColorFilter(ColorFilter colorFilter) {

}

@Override
public int getOpacity() {
    return PixelFormat.TRANSLUCENT;
}

上面的类是用于SeekBar的背景(始终存在于进度绘制下方的部分)。

public class SeekBarProgressDrawable extends ClipDrawable {

private Paint mPaint = new Paint();
private float dy;
private Rect mRect;


public SeekBarProgressDrawable(Drawable drawable, int gravity, int orientation, Context ctx) {
    super(drawable, gravity, orientation);
    mPaint.setColor(Color.WHITE);
    dy = ctx.getResources().getDimension(R.dimen.two_dp);
}

@Override
public void draw(Canvas canvas) {
    if (mRect==null) {
        mRect = new Rect(getBounds().left, (int)(getBounds().centerY() - dy / 2), getBounds().right, (int)(getBounds().centerY() + dy / 2));
        setBounds(mRect);
    }

    super.draw(canvas);
}


@Override
public void setAlpha(int i) {
    mPaint.setAlpha(i);
}

@Override
public void setColorFilter(ColorFilter colorFilter) {

}

@Override
public int getOpacity() {
    return PixelFormat.TRANSLUCENT;
}

上面是进度可绘制对象。注意它是一个剪辑可绘制对象。这里很酷的部分是我可以将边界设置为我想要的任何形状和颜色。这允许您对可绘制对象进行精细调整。

//Custom background drawable allows you to draw how you want it to look if needed
    SeekBarBackgroundDrawable backgroundDrawable = new SeekBarBackgroundDrawable(mContext);
    ColorDrawable progressDrawable = new ColorDrawable(Color.BLUE);
    //Custom seek bar progress drawable. Also allows you to modify appearance.
    SeekBarProgressDrawable clipProgressDrawable = new SeekBarProgressDrawable(progressDrawable,Gravity.LEFT,ClipDrawable.HORIZONTAL,mContext);
    Drawable[] drawables = new Drawable[]{backgroundDrawable,clipProgressDrawable};

    //Create layer drawables with android pre-defined ids
    LayerDrawable layerDrawable = new LayerDrawable(drawables);
    layerDrawable.setId(0,android.R.id.background);
    layerDrawable.setId(1,android.R.id.progress);

    //Set to seek bar
    seekBar.setProgressDrawable(layerDrawable);

上面的代码使用自定义可绘制对象来编辑搜索栏。我这样做的主要原因是我将编辑背景可绘制对象的外观,使其具有“刻度”(尽管尚未实现)。使用xml定义的可绘制对象无法轻松地实现这一点。
另一件我注意到的事情是,这个过程防止搜索栏变得与拇指可绘制对象一样宽。它设置可绘制对象的边界,使它们永远不会过高。

我已经尝试了你的解决方案,但是你能否调整一下,使得角落变成圆形?更加复杂的是,它需要在左侧进行圆角处理,但右侧不需要(除非是完整的进度条),虽然我不知道它实际上是如何工作的。 - user1122069
如果您正在引用背景可绘制对象,则可以。在SeeBarBackgroundDrawable.draw()内部,使用canvas.drawRoundRect而不是canvas.drawRect来绘制左侧。然后再使用canvas.drawRect来绘制右半边,该半边与圆角矩形的右侧重叠。这将为您提供一个具有左侧圆角和右侧尖角的矩形。 - Danuofr

7

我之前曾经在代码中尝试修改 seek 和 progress bars 的样式,但是遇到了一些问题。有时候我需要加载两次 drawable 才能让修改的效果生效,我觉得这可能与修改图片后的 padding 相关。

虽然我不确定,但你可以尝试在设置图片之后再设置 padding。

 getResources().getDrawable(R.drawable.seek_bar) // once
 seekBar.setProgressDrawable(getResources().getDrawable(R.drawable.seek_bar)); //twice
 seekBar.setPadding(int,int,int,int)

而且无妨将其作废。

 seekBar.postInvalidate()

这种方法很“hacky”,我并不喜欢,但它曾经帮我解决过类似的问题。


1

您可以在XML中使用android: maxHeight来限制背景高度。

<SeekBar
    android:id="@+id/original_volume"
    android:layout_width="120dp"
    android:layout_height="wrap_content"
    android:maxHeight="2dp"/>

并且它不会裁剪缩略图


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接