Search code examples
javaandroidandroid-custom-viewandroid-seekbar

How to make vertical seekbar with progress text as thumb


I want to create a vertical seekbar with progress displaying near to thumb.

requirement

I created vertical seekbar by overriding Seekbar class and rotate the canvas. But I don't know how to make the text near to thumb.

 @Override
protected final void onDraw(@NonNull final Canvas c) {
    if (null == mPaint) {
        mPaint = new Paint();
        mPaint.setColor(Color.BLACK);
        mPaint.setTextSize(50);
    }
    c.rotate(ROTATION_ANGLE);
    c.translate(-getHeight(), 0);
    super.onDraw(c);
    Rect rect = getThumb().getBounds();
    c.drawText(getProgress()+"%", rect.exactCenterX(), rect.exactCenterY(), mPaint);
}

So the problem is If I drawText like this the text also rotated. So how to fix this?

Meanwhile, I tried some custom View implementation and I am a noob on that.


Solution

  • Update to Khemraj's answer

    Actually changing the thumb is the simple trick as said by Khemraj. But the problem is when rotating the canvas all its contents will rotate(simple logic). When updating the thumb also will reflect this problem. So the simple thing is to make a rotated CustomTextView.

    Method to make thumb

     public Drawable getThumb(int progress) {
        int width = getWidth();
    
        ((TextView) mThumbView.findViewById(R.id.tvProgress)).setText(String.format(Locale.getDefault(), "%d%%", progress));
        mThumbView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
        Bitmap bitmap = Bitmap.createBitmap(mThumbView.getMeasuredWidth(), mThumbView.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        mThumbView.layout(0, 0, mThumbView.getMeasuredWidth(), mThumbView.getMeasuredHeight());
        mThumbView.draw(canvas);
        return new BitmapDrawable(getResources(), bitmap);
    }
    

    The layout

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center">
    
    <ImageView
        android:layout_marginTop="30dp"
        android:id="@+id/imageView6"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/seek_thumb_gray"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    
    <com.samsung.lighting.presentation.ui.custom_views.RotatedTextView
        android:id="@+id/tvProgress"
        android:layout_width="wrap_content"
        android:layout_height="40dp"
        android:gravity="center"
        android:text="20%"
        android:textColor="#000000"
        android:textSize="12sp"
        app:angle="90"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/imageView6" />
    </android.support.constraint.ConstraintLayout>
    

    The RotatedTextView

    public class RotatedTextView extends AppCompatTextView {
    private int mRotationAngle = 90;
    
    
    @Override
    protected void onDraw(Canvas canvas) {
        if (mRotationAngle == 90) {
            canvas.rotate(mRotationAngle);
            canvas.translate(0, -getWidth());
        } else if (mRotationAngle == -90) {
            canvas.rotate(mRotationAngle);
            canvas.translate(-getHeight(), 0);
        }
        super.onDraw(canvas);
    } 
    }
    

    So first we will rotate the Text to 90 or -90 degrees and set as thumb to VerticalSeekBar and in vertical seekbar rotate the canvas to 90 or -90 degrees. So finally we will get the actual result

    Here I posted the working example.

    Thanks, Khemraj