LBes LBes - 3 months ago 35
Java Question

Vertical SeekBar Android, how to update the slider position with SetProgress()

I know I'm not the first one having issue with a VerticalSlider on android but even though I recall struggling to make it work in the first place this is the first time that I have a partially working setProgress().

So here is the thing.
The blue line that represents the slider is properly updated but the tiny "button" that is supposed to moved as well does not move at all. (see images)

The blue line is moving according to to the values I send, but the "button" is not. It is moving a little, but not at all following the blue line---which is right. (If you have better terms for "button" and blue-line, feel free to edit. Progress line maybe?)

So this is the code I have for the vertical slider:

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.SeekBar;

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

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

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

protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(h, w, oldh, oldw);
}

@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(heightMeasureSpec, widthMeasureSpec);
setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
}

protected void onDraw(Canvas canvas) {
canvas.rotate(-90);
canvas.translate(-getHeight(), 0);
super.onDraw(canvas);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
if (!isEnabled())
return false;

boolean result = false;

if (event.getAction() != MotionEvent.ACTION_MOVE) {
// Prevent duplicate haptic feedback events (due to
// setProgress() below)
boolean hf = isHapticFeedbackEnabled();
setHapticFeedbackEnabled(false); {
// This is required for OnSeekBarChangeListener.on{Start,Stop}TrackingTouch()
result = super.onTouchEvent(event);
} setHapticFeedbackEnabled(hf);
}

switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_MOVE:
// Vertical scrolling
setProgress(getMax() - (int)(getMax() * event.getY()/getHeight()));
onSizeChanged(getWidth(), getHeight(), 0, 0);
result = true;
break;
}

return result;
}

public void customSetProgress(int progress) {
setProgress(progress);
onSizeChanged(getWidth(), getHeight(), 0, 0);
}
}


And this how I'm updating the slider:

float value = //... Get the value here from other computations
// We need to use int for the slider
final int step = 1;
final int max = (int)MAXPRECISION * 100;
final int min = (int)MINPRECISION * 100;
final double initialPosition = (double)max ;
final int valueInt = (int) (value * 100) ;

final VerticalSeekBar sliderPrecision = (VerticalSeekBar)findViewById(R.id.verticalSliderPrecision);

sliderPrecision.setProgress(valueInt);
sliderPrecision.setMax( (max - min) / step ); //To make sure it is updated as seen in some SO post.


I am pretty confident that my VerticalSlider class is good as I have been able to use it properly years ago. So there is surely something wrong with the rest of the code, but I can't find what that may be.

As for the images here they are:

Slider 01Slider 02

Answer

So I found out that this is solved by calling onSizeChanged(getWidth(), getHeight(), 0, 0);

So I have created an updated VerticalSeekBar that works just fine now. I do hope it will help other people struggling with them.

Here is the updated class:

import android.content.Context; import android.graphics.Canvas; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.widget.SeekBar;

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

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

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

    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(h, w, oldh, oldw);
    }

    @Override
    protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(heightMeasureSpec, widthMeasureSpec);
        setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
    }

    protected void onDraw(Canvas canvas) {
        canvas.rotate(-90);
        canvas.translate(-getHeight(), 0);
        super.onDraw(canvas);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (!isEnabled())
            return false;

        boolean result = false;

        if (event.getAction() != MotionEvent.ACTION_MOVE) {
            // Prevent duplicate haptic feedback events (due to
            // setProgress() below)
            boolean hf = isHapticFeedbackEnabled();
            setHapticFeedbackEnabled(false); {
                // This is required for OnSeekBarChangeListener.on{Start,Stop}TrackingTouch()
                result = super.onTouchEvent(event);
            } setHapticFeedbackEnabled(hf);
        }

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_MOVE:
                // Vertical scrolling
                setProgress(getMax() - (int)(getMax() * event.getY()/getHeight()));
                onSizeChanged(getWidth(), getHeight(), 0, 0);
                result = true;
                break;
        }

        return result;
    }

    public void customSetProgress(int progress) {
        setProgress(progress);
        onSizeChanged(getWidth(), getHeight(), 0, 0);
    }
}
Comments