Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android seekbar with custom thumb having dynamic text inside it

I want to create android custom SeekBar having thumb with text inside it to show current seek position.

Here is my code:

SeekBar sb;

@Override
public void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.custom_seek_bar_activity);

    sb = (SeekBar)findViewById(R.id.slider);
    sb.setMax(100);
    sb.setProgress(10);
    BitmapDrawable bd = writeOnDrawable(R.drawable.star2, Double.toString(50));

    sb.setThumb(bd);

    sb.setOnSeekBarChangeListener(new OnSeekBarChangeListener(){
        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
        {
            int pos = sb.getProgress();
            double star = pos/(20.0);
            TextView tv = (TextView)findViewById(R.id.percent);
            tv.setText(Double.toString(star)+"%");
            BitmapDrawable bd = writeOnDrawable(R.drawable.star2, Double.toString(star));
            bd.setBounds(new Rect(0,0, 
                bd.getIntrinsicWidth(), 
                bd.getIntrinsicHeight()
            ));
            seekBar.setThumb(bd);
        }

        @Override
        public void onStartTrackingTouch(SeekBar arg0) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onStopTrackingTouch(SeekBar arg0) {
            // TODO Auto-generated method stub

        }
    });

}   

public BitmapDrawable writeOnDrawable(int drawableId, String text){

    Bitmap bm = BitmapFactory.decodeResource(getResources(), drawableId).copy(Bitmap.Config.ARGB_8888, true);

    Paint paint = new Paint(); 
    paint.setStyle(Style.FILL);  
    paint.setColor(Color.BLACK); 
    paint.setTextSize(10); 

    Canvas canvas = new Canvas(bm);
    canvas.drawText(text, 0, bm.getHeight()/2, paint);

    return new BitmapDrawable(bm);
}

but when I move thumb it goes to the beginning of the seek bar. Does anyone have solution to move custom thumb with seekbar position?

like image 837
RBL Avatar asked Oct 01 '12 13:10

RBL


3 Answers

I use SeekBar to display a timer countdown in my app. Inside the timer thumb I show the current SeekBar progress number using the below code:

    SeekBar timerBar = (SeekBar) findViewById(R.id.seekBarTimer);
    if (timerBar != null) {
        timerBar.setMax((int) (Settings.countdownSeconds + 1));
        timerBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

            @Override
            public void onStopTrackingTouch(SeekBar arg0) {
            }

            @Override
            public void onStartTrackingTouch(SeekBar arg0) {
            }

            @Override
            public void onProgressChanged(SeekBar timerBar, int arg1, boolean arg2) {
                Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.seek_thumb);
                Bitmap bmp = bitmap.copy(Bitmap.Config.ARGB_8888, true);
                Canvas c = new Canvas(bmp);
                String text = Integer.toString(timerBar.getProgress());
                Paint p = new Paint();
                p.setTypeface(Typeface.DEFAULT_BOLD);
                p.setTextSize(14);
                p.setColor(0xFFFFFFFF);
                int width = (int) p.measureText(text);
                int yPos = (int) ((c.getHeight() / 2) - ((p.descent() + p.ascent()) / 2));
                c.drawText(text, (bmp.getWidth()-width)/2, yPos, p);
                timerBar.setThumb(new BitmapDrawable(getResources(), bmp));
            }
        });
        timerBar.setProgress(0);
    }

The R.drawable.seek_thumb drawable is my thumb drawable.

like image 147
dangel Avatar answered Nov 18 '22 05:11

dangel


I got solution now, in setBound() method I was passing top left as 0, that's why it is showing seek bar at beginning. After doing following change I got it works.

Call setThumbPos() method in onProgressChanged() event

public void setThumbPosition(SeekBar seekBar){
    int max = seekBar.getMax();

    int available = seekBar.getWidth() - seekBar.getPaddingLeft() - seekBar.getPaddingRight();
    float scale = max > 0 ? (float) seekBar.getProgress() / (float) max : 0;

    //scale = 1;
    int pos = sb.getProgress();
    double star = pos/(20.0);

    BitmapDrawable bd = writeOnDrawable(R.drawable.star2, Double.toString(star));

    int thumbWidth = bd.getIntrinsicWidth();
    int thumbHeight = bd.getIntrinsicHeight();
    //available -= thumbWidth;

    int thumbPos = (int) (scale * available);
    if(thumbPos <= 0+thumbWidth){
        thumbPos += (thumbWidth/2);
    }else if(thumbPos >= seekBar.getWidth()-thumbWidth){
        thumbPos -= (thumbWidth/2);
    }

    bd.setBounds(new Rect(thumbPos,0, 
            thumbPos+bd.getIntrinsicWidth(), 
        bd.getIntrinsicHeight()
    ));

    seekBar.setThumb(bd);

    TextView tv = (TextView)findViewById(R.id.percent);
    tv.setText(Double.toString(star)+"%");
}
like image 4
RBL Avatar answered Nov 18 '22 07:11

RBL


I ended up using this simple solution. Its probably not as high-performance as say a proper custom SeekBar, however its really easy to plug into an existing layout, and use any label or other view on top of the SeekBar thumb.

protected void positionThumbLabel(SeekBar seekBar, TextView label)
{
  Rect tr = seekBar.getThumb().getBounds();
  label.setWidth(tr.width());
  label.setX(tr.left + seekBar.getPaddingLeft());
}

With some minor changes you can position an overlay relative to the center of the thumb:

protected void positionThumbOverlayCenter(SeekBar seekBar, View overlay)
{
  Rect tr = seekBar.getThumb().getBounds();
  overlay.setX(tr.centerX() - (overlay.getWidth() * 0.5f) + seekBar.getPaddingLeft());
}
like image 2
Atorian Avatar answered Nov 18 '22 06:11

Atorian