0

I know this question was asked and somewhat answered before, but none of the solutions I found so far really worked out for me: I have a custom seekBar with a large square block for the thumb, which I draw on the fly, and I want the seekBar progress to change only when the thumb is being dragged. Large thumb seekBar

I looked around and tried out all of the proposed solutions I could find, and some worked better then others, but they all have a big issue (for me at least): if I detect the boundaries of the thumb in order to start dragging the thumb, the onTouch ACTION_DOWN event makes the thumb jump to whatever position the pointer is on the screen, within the thumb's boundaries, of course.

If the thumb size is small, this is almost a non issue, but on a large thumb, this behavior is really annoying.

To make matters worse, if I declare a thumb offset of 0 to keep the thumb inside the seekBar, the jumping behavior changes with respect to where on the seekbar the thumb is: indetermined jump direction right in the middle of the seekbar, or it jumps to the right if the thumb is on the left half of the seekbar, or to the left if the thumb is on the right half of the seekbar.

Here's my starting code, I removed all of my failed attempts to make the seekBar's thumb move only when a drag starts:

activity_main.xml

   <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <TextView
        android:id="@+id/progressText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="0"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/mySeekbar"
        app:layout_constraintVertical_bias="0.154" />

    <com.example.thumbonlyseekbar.MySeekBar
        android:id="@+id/mySeekbar"
        android:layout_width="0dp"
        android:layout_height="50dp"
        android:layout_marginStart="20dp"
        android:layout_marginTop="150dp"
        android:layout_marginEnd="20dp"
        android:indeterminate="false"
        android:max="99"
        android:progress="0"
        android:progressDrawable="@drawable/my_seekbar"
        android:thumb="@drawable/thumb"
        android:thumbOffset="0dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
  
</androidx.constraintlayout.widget.ConstraintLayout>

MySeekbar.java

package com.example.thumbonlyseekbar;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import androidx.annotation.NonNull;


public class MySeekBar extends androidx.appcompat.widget.AppCompatSeekBar {

    Drawable mThumb;

    public MySeekBar(@NonNull Context context) {
        super(context);
    }

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

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


    @Override
    public void setThumb(Drawable thumb) {
        super.setThumb(thumb);
        mThumb = thumb;
    }
    public Drawable getSeekBarThumb() {
        return mThumb;
    }

}

MainActivity.java

package com.example.thumbonlyseekbar;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.widget.SeekBar;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    MySeekBar customSeekBar;
    TextView progressValueText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        customSeekBar = findViewById(R.id.mySeekbar);

        progressValueText = findViewById(R.id.progressText);
        progressValueText.setText(String.valueOf(customSeekBar.getProgress()));


        customSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                progressValueText.setText(String.valueOf(progress));
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        });

    }
}

thumb.xml

package com.example.thumbonlyseekbar;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.widget.SeekBar;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    MySeekBar customSeekBar;
    TextView progressValueText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        customSeekBar = findViewById(R.id.mySeekbar);

        progressValueText = findViewById(R.id.progressText);
        progressValueText.setText(String.valueOf(customSeekBar.getProgress()));


        customSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                progressValueText.setText(String.valueOf(progress));
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        });

    }
}

my_seekbar.xml

package com.example.thumbonlyseekbar;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.widget.SeekBar;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    MySeekBar customSeekBar;
    TextView progressValueText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        customSeekBar = findViewById(R.id.mySeekbar);

        progressValueText = findViewById(R.id.progressText);
        progressValueText.setText(String.valueOf(customSeekBar.getProgress()));


        customSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                progressValueText.setText(String.valueOf(progress));
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        });

    }
}

If you would like to see an example of what I mean by a no-thumb-jump seekBar, please take a look at the AMPLIFi Remote app in Google Play Store (it may only work on older devices, it works on my OREO 8.1, you may need to try it in an emulator that allows downloads from Google Play if you don't have an older device). The thumb's progress is unbelievably smooth, and there's absolutely no jumping around. Whoever wrote that app did an awesome job!

Many, many thanks, any suggestion is much appreciated!

  • check [this](https://stackoverflow.com/questions/59641829/seekbar-change-progress-only-when-dragging-thumb),may this helpful. – EAS Feb 25 '22 at 05:23
  • Please trim your code to make it easier to find your problem. Follow these guidelines to create a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example). – Abhishek Dutt Feb 25 '22 at 05:47
  • @EAS - thank you kindly for the link, I am well aware of that thread, but unfortunately that solution doesn't work either, the thumb is still jumping when touched on the edges of the bounds. – Var Delean Feb 25 '22 at 16:23
  • @Abhishek Dutt - thank you for your comments, yes, I can trim the code, but I was trying to be as complete as possible, which is also a requirement when posting... I totally understand that some people do not need all the files I posted, but for a beginner like me, it helps seeing all the pieces of the puzzle, so to me at least, that was the "minimal" code required. I apologize if I took too much of your time for going through my code. – Var Delean Feb 25 '22 at 16:28

0 Answers0