7

I have a listview with seekbar, each seekbar represents 100% of a value of product. By moving the seekbar the % value can be changed, I want to show the change in value along the seekbar while the user is dragging the seekbar. I do not wish to add another text box where the value is updated.

I am more looking at options to show a small view on top of the seekbar pointer, which appears onStartTracking and disappears onStopTracking event.

Is there a way to achieve this?

Quintin Balsdon
  • 5,484
  • 10
  • 54
  • 95
user2622786
  • 779
  • 3
  • 9
  • 21

7 Answers7

34

Here is a one simple way,

  • Add a textView in your XML
  • Change it's position with the movement of the seekBar
  • That will position it using setX()
  • If you want you can give setY() for its Y position as well
  • If you want to hide write some logic and make textView Visibility GONE when you need.

example:

seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                @Override
                public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {

                    int val = (progress * (seekBar.getWidth() - 2 * seekBar.getThumbOffset())) / seekBar.getMax();
                    textView.setText("" + progress);
                    textView.setX(seekBar.getX() + val + seekBar.getThumbOffset() / 2);
                    //textView.setY(100); just added a value set this properly using screen with height aspect ratio , if you do not set it by default it will be there below seek bar 

                }

or you can use Paint with your custom SeekBar class without any TextView

Create a class

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.widget.SeekBar;


public class MySeekBar extends SeekBar {
    public MySeekBar (Context context) {
        super(context);
    }

    public MySeekBar (Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public MySeekBar (Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onDraw(Canvas c) {
        super.onDraw(c);
        int thumb_x = (int) (( (double)this.getProgress()/this.getMax() ) * (double)this.getWidth());
        float middle = (float) (this.getHeight());

        Paint paint = new Paint();
        paint.setColor(Color.BLACK);
        paint.setTextSize(20);
        c.drawText(""+this.getProgress(), thumb_x, middle, paint);
    }
}

Set/create your SeekBar in your XML

  <yourPackageName.MySeekBar
            android:id="@+id/my_seek_bar"
            android:layout_width="300dp"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_alignParentTop="true"
            android:layout_marginTop="26dp"
            android:max="10"/>

Now from your Activity

seekBar = (MySeekBar) findViewById(R.id.my_seek_bar);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {
    }

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
    }
});
AjCodez
  • 360
  • 3
  • 10
Charuක
  • 12,953
  • 5
  • 50
  • 88
  • 2
    Super, thank you! I think the correct position of the text view is calculated as follows (Kotlin): `val offset = (seekBar.width - seekBar.paddingLeft - seekBar.paddingRight) * progress / seekBar.max` and then `textView.x = seekBar.x + seekBar.paddingLeft + offset` – thando Oct 02 '19 at 15:15
  • 2
    PS: Plus `textView.x = [...] - textView.width / 2` to center the text view. – thando Oct 02 '19 at 15:21
4

add a text view in your xml file, you can use a linrarlayout like this:

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <SeekBar
            android:id="@+id/seekBar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:max="1000" />

        <TextView
            android:id="@+id/textView4"
            android:layout_width="80dp"
            android:layout_height="wrap_content"
            android:layout_weight="1" />

    </LinearLayout>

and in java file, change text view text in onProgressChanged method of seekbar:

    SeekBar sk = (SeekBar) findViewById(R.id.seekBar);
    sk.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {

        @Override
        public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
            TextView t=(TextView)findViewById(R.id.textView4);
            t.setText(String.valueOf(i));
        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {

        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {

        }
    });
amir_a14
  • 1,478
  • 10
  • 15
4

To make the text view really align with center of thumb position X

@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean b) {
    progressTextView.setText(String.valueOf(progress));

    int width = seekBar.getWidth() - seekBar.getPaddingLeft() - seekBar.getPaddingRight();
    int thumbPos = seekBar.getPaddingLeft() + width * seekBar.getProgress() / seekBar.getMax();

    progressTextView.measure(0, 0);
    int txtW = progressTextView.getMeasuredWidth();
    int delta = txtW / 2;
    progressTextView.setX(seekBar.getX() + thumbPos - delta);
}
xuanzhui
  • 1,300
  • 4
  • 12
  • 30
2

Try this Discrete Seekbar Library I found here

The Easiest way out is to use Materila Slider which add the value label for you without you needing to code a textView to track.

   <com.google.android.material.slider.Slider
        android:id="@+id/continuous_slider"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:valueFrom="0"
       android:stepSize="1"
        app:labelBehavior="withinBounds"
        android:valueTo="100"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"/>
Tonnie
  • 4,865
  • 3
  • 34
  • 50
0

Check this library out. You can use the 'range seekbar with single thumb to true'.

Abhriya Roy
  • 1,338
  • 17
  • 23
0

The accepted answer is probably good enough for most situations. However, if you want precision so that the text is exactly in the middle of your seek bar thumb, you have to a little more calculations. This is because the width of the text is different. Say, you want to show numbers from 0 to 150. Width of 188 will be different from 111. Because of this, the text you are showing will always tilt to some side.

The way to solve it is to measure the width of the text, remove that from the width of the seekbar thumb, divide it by 2, and add that to the result that was given in the accepted answer. Now you would not care about how large the number range. Here is the code:

 override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
                    val value = progress * (seekBar.width - 2 * seekBar.thumbOffset) / seekBar.max
                    label.text = progress.toString()
                    label.measure(0, 0)
                    val textWidth =  label.measuredWidth
                    val firstRemainder = seekThumbWidth - textWidth
                    val result = firstRemainder / 2
                    label.x = (seekBar.x + value + result)
                }
Sermilion
  • 1,920
  • 3
  • 35
  • 54
0

Using below code I was able to achieve live tracking of textview with seekbar. I had to modify according to the need

<RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:visibility="visible">

            <TextView
                android:id="@+id/tvProgress"
                android:layout_width="@dimen/_50sdp"
                android:layout_height="@dimen/_30sdp"
                 android:background="@drawable/bg_box_border_unselected"
                android:backgroundTint="@color/black"
                android:fontFamily="@font/open_sans_regular"
                android:gravity="center"
                android:paddingStart="@dimen/_3sdp"
                android:paddingEnd="@dimen/_3sdp"
                android:text="CAD 20"
                android:textColor="@color/white" />

            <androidx.appcompat.widget.AppCompatSeekBar
                android:id="@+id/seekBar"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@+id/tvProgress"
                 android:max="28"
                android:maxHeight="@dimen/_5sdp"
                android:min="20"
                android:minHeight="@dimen/_5sdp"
                android:padding="@dimen/_10sdp"
                android:progress="20"
                android:progressDrawable="@drawable/custom_seekbar"
                android:thumb="@drawable/ic_thumb_seekbar" />
        </RelativeLayout>



 seekBar?.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
        override fun onProgressChanged(seekBar: SeekBar, progress: Int,
                                       fromUser: Boolean) {

            tvProgress.text = "CAD "+ progress.toString()
            val bounds: Rect = seekBar.thumb.bounds
            tvProgress.x = (seekBar.left + bounds.left + seekBar.thumbOffset).toFloat()

         }

        override fun onStartTrackingTouch(seekBar: SeekBar) {
         }

        override fun onStopTrackingTouch(seekBar: SeekBar) {
            seekBarValue = seekBar.progress
         }
    })
Praveen
  • 430
  • 3
  • 11