pic of wrong seekbar I am using custom vertical seekbar in a fragment, it was working fine before but suddenly it started showing wrongly. The seekbar thumb is being misplaced in some devices, in my case I am using an HTC desire which is running on API 21.
I am posting my seekbar code snippets here.
This is the xml version of the vertical seekbar
<com.sampleApp.progressbars.VerticalProgressBar
android:id="#+id/exposureSlider"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_above="#id/icBrightnessDim"
android:layout_below="#id/icBrightnessBright"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp"
android:maxWidth="50dp"
android:minHeight="50dp"
android:minWidth="50dp"
android:progressDrawable="#drawable/custom_seekbar_progress"
android:thumb="#drawable/seek_bar_thumb"
app:ssbPopupBackgroundColor="#color/grey"
app:ssbPopupEnabled="true"
app:ssbPopupHeight="80dp"
app:ssbPopupThumbColor="#color/grey"
app:ssbPopupWidth="20dp"
app:ssbThrottleEnabled="false"
app:ssbTouchAreaOffset="16dp"
/>
This is Vertical seekbar code
public class VerticalProgressBar extends android.support.v7.widget.AppCompatSeekBar {
public VerticalProgressBar(Context context) {
super(context);
}
public VerticalProgressBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public VerticalProgressBar(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 c) {
c.rotate(-90);
c.translate(-getHeight(), 0);
super.onDraw(c);
}
private OnSeekBarChangeListener onChangeListener;
#Override
public void setOnSeekBarChangeListener(OnSeekBarChangeListener onChangeListener){
this.onChangeListener = onChangeListener;
}
private int lastProgress = 0;
#Override
public boolean onTouchEvent(MotionEvent event) {
if (!isEnabled()) {
return false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
onChangeListener.onStartTrackingTouch(this);
setPressed(true);
setSelected(true);
break;
case MotionEvent.ACTION_MOVE:
super.onTouchEvent(event);
int progress = getMax() - (int) (getMax() * event.getY() / getHeight());
// Ensure progress stays within boundaries
if(progress < 0) {progress = 0;}
if(progress > getMax()) {progress = getMax();}
setProgress(progress); // Draw progress
if(progress != lastProgress) {
// Only enact listener if the progress has actually changed
lastProgress = progress;
onChangeListener.onProgressChanged(this, progress, true);
}
onSizeChanged(getWidth(), getHeight() , 0, 0);
setPressed(true);
setSelected(true);
break;
case MotionEvent.ACTION_UP:
onChangeListener.onStopTrackingTouch(this);
setPressed(false);
setSelected(false);
break;
case MotionEvent.ACTION_CANCEL:
super.onTouchEvent(event);
setPressed(false);
setSelected(false);
break;
}
return true;
}
Related
I made vertical seekbar. Now I want to display progress on seekbar thumb. I successfully implemented this but now my text is showing below seekbar thumb. I want to draw text on top of seekbar thumb How can I achieve this? I also add my code
public class TextThumbSeekBar extends SeekBar {
public TextThumbSeekBar(Context context) {
super(context);
}
private int mThumbSize;
private TextPaint mTextPaint;
public TextThumbSeekBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mThumbSize = 50;
mTextPaint = new TextPaint();
mTextPaint.setColor(Color.BLACK);
mTextPaint.setTextSize(50);
mTextPaint.setTypeface(Typeface.DEFAULT_BOLD);
mTextPaint.setTextAlign(Paint.Align.CENTER);
}
public TextThumbSeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
mThumbSize = 50;
mTextPaint = new TextPaint();
mTextPaint.setColor(Color.BLACK);
mTextPaint.setTextSize(50);
mTextPaint.setTypeface(Typeface.DEFAULT_BOLD);
mTextPaint.setTextAlign(Paint.Align.CENTER);
}
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(h, w, oldh, oldw);
}
#Override
public synchronized void setProgress(int progress) // it is necessary for calling setProgress on click of a button
{
super.setProgress(progress);
onSizeChanged(getWidth(), getHeight(), 0, 0);
}
#Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(heightMeasureSpec, widthMeasureSpec);
setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
}
protected void onDraw(Canvas c) {
String progressText = String.valueOf(getProgress());
c.drawText(progressText, getThumb().getBounds().centerY(), getHeight() - getThumb().getBounds().centerX(), mTextPaint);
c.rotate(-90);
c.translate(-getHeight(), 0);
super.onDraw(c);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (!isEnabled()) {
return false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
super.onTouchEvent(event);
setProgress(getMax() - (int) (getMax() * event.getY() / getHeight()));
onSizeChanged(getWidth(), getHeight(), 0, 0);
break;
case MotionEvent.ACTION_CANCEL:
break;
}
return true;
}
}
Here how I used this class in my xml
<demo.smart.com.smartchargeboxdemoapp.TextThumbSeekBar
android:max="100"
android:thumb="#drawable/shape_seek_bar_text_thumb"
android:layout_gravity="center"
android:id="#+id/seekbar"
android:layout_width="30dp"
android:layout_height="match_parent" />
And here's the result that I get
Although the question is old, I did in this case the thumbTint transparent and before the drawText I did 'drawRect' to draw my thumb that won't be rotated.
Hope I helped.
I am using a custom Vertical Seekbar and everything works great, except for the Thumb highlight.
As I scroll the left seekbar up and down, the thumb highlight continues to scroll left to right at the top of the screen as if the seekbar is still horizontal. My custom vertical seekbar is as follows:
public class VerticalSeekBar extends SeekBar {
protected OnSeekBarChangeListener changeListener;
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());
}
#Override
public synchronized void setProgress(int progress) {
super.setProgress(progress);
onSizeChanged(getWidth(), getHeight(), 0, 0);
}
#Override public void setOnSeekBarChangeListener(OnSeekBarChangeListener mListener)
{
this.changeListener = mListener;
}
protected void onDraw(Canvas c) {
c.rotate(-90);
c.translate(-getHeight(),0);
super.onDraw(c);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (!isEnabled()) {
return false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
setProgress(getMax() - (int) (getMax() * event.getY() / getHeight()));
if (changeListener != null)
changeListener.onStartTrackingTouch(this);
setSelected(true);
setPressed(true);
break;
case MotionEvent.ACTION_UP:
if (changeListener != null)
changeListener.onStopTrackingTouch(this);
setSelected(false);
setPressed(false);
break;
case MotionEvent.ACTION_MOVE:
int i=getMax() - (int) (getMax() * event.getY() / getHeight());
setProgress(i);
onSizeChanged(getWidth(), getHeight(), 0, 0);
if (changeListener != null)
changeListener.onProgressChanged(this, i, true);
setPressed(true);
setSelected(true);
break;
case MotionEvent.ACTION_CANCEL:
break;
}
return true;
}
}
I can eliminate the highlight entirely by removing
setSelected(true);
setPressed(true);
But ideally I want to keep the standard design pattern and have the highlight follow where the thumb is. Is there anyway to access the location and position of the highlight so I can rotate that as well?
I had the same question and came across this similar post for an answer:
Android SeekBar custom rectangle thumb visual bug
Set the Background to null. I added "setBackground(null);" to the constructor of my extended SeekBar class, but the suggested solution does this in the activity.xml file under the "SeekBar" section.
I have been stuck on this problem since a long time. I left it then came back to it but so far I haven't found a working solution. Problem is simple, I have a vertical seekbar and I want to update it programmatically without touching it, but it doesn't happen. This is my vertical seekbar code
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 c) {
c.rotate(-90);
c.translate(-getHeight(), 0);
super.onDraw(c);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (!isEnabled()) {
return false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
setProgress(getMax() - (int) (getMax() * event.getY() / getHeight()));
onSizeChanged(getWidth(), getHeight(), 0, 0);
break;
case MotionEvent.ACTION_CANCEL:
break;
}
return true;
}
}
This is how the seekbar is declared in the xml
<com.gnr.kumar.varun.songapp.views.VerticalSeekBar
android:id="#+id/slider_1"
android:layout_width="wrap_content"
android:layout_height="200dp"
android:max="100"
android:padding="10dp"
android:progress="50"
android:progressBackgroundTint="#9cf2ec"
android:progressTint="#9cf2ec"
android:thumb="#drawable/thumb" />
I try to do things like
SeekBar sliders[] = new SeekBar[NUM_OF_SLIDERS];
sliders[0] = (SeekBar) findViewById(R.id.slider_1);
sliders[0].setProgress(100);
But it just changes the seekbar position to slightly more than 0 when in fact it should be at its maxima. No matter how big number I use instead of 100, it is the same. Can someone please help !! Thanks in advance !!!
I was finally able to solve my problem after a long time. All I had to do was to override this in Vertical Seekbar class. A comment on the accepted answer to this question helped me.
#Override public synchronized void setProgress(int progress){
super.setProgress(progress);
onSizeChanged(getWidth(), getHeight(), 0, 0);
}
Here is my VerticalSeeker Class:
public class VerticalSeekBar extends SeekBar implements SeekBar.OnSeekBarChangeListener{
public VerticalSeekBar(Context context) {
super(context);
this.setOnSeekBarChangeListener(this);
}
public VerticalSeekBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public VerticalSeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
}
public 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 c) {
c.rotate(-90);
c.translate(-getHeight(), 0);
super.onDraw(c);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (!isEnabled()) {
return false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
setProgress((int) (getMax() * event.getY() / getHeight()) - 0);
onSizeChanged(getWidth(), getHeight(), 0, 0);
break;
case MotionEvent.ACTION_CANCEL:
break;
}
return true;
}
#Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
}
#Override
public void onStartTrackingTouch(SeekBar seekBar)
{
Toast.makeText(this.getContext(), "Start", Toast.LENGTH_SHORT).show();
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
Toast.makeText(this.getContext(), "Stop", Toast.LENGTH_SHORT).show();
}
}
Can someone explain, why only the "onProgressChanged"-event is firing? How to get "onStartTrackingTouch" and "onStopTrackingTouch" to work?
At the minimum change your Motion event switch case code to
case MotionEvent.ACTION_UP:
setProgress(getMax()- (int) (getMax() * event.getY() / getHeight()));
onSizeChanged(getWidth(), getHeight(), 0, 0);
onChangeListener.onStopTrackingTouch(this);
Found complete implementation at http://hackskrieg.wordpress.com/2012/04/20/working-vertical-seekbar-for-android/
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 c) {
c.rotate(-90);
c.translate(-getHeight(), 0);
super.onDraw(c);
}
private OnSeekBarChangeListener onChangeListener;
#Override
public void setOnSeekBarChangeListener(OnSeekBarChangeListener onChangeListener){
this.onChangeListener = onChangeListener;
}
private int lastProgress = 0;
#Override
public boolean onTouchEvent(MotionEvent event) {
if (!isEnabled()) {
return false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
onChangeListener.onStartTrackingTouch(this);
setPressed(true);
setSelected(true);
break;
case MotionEvent.ACTION_MOVE:
super.onTouchEvent(event);
int progress = getMax() - (int) (getMax() * event.getY() / getHeight());
// Ensure progress stays within boundaries
if(progress < 0) {progress = 0;}
if(progress > getMax()) {progress = getMax();}
setProgress(progress); // Draw progress
if(progress != lastProgress) {
// Only enact listener if the progress has actually changed
lastProgress = progress;
onChangeListener.onProgressChanged(this, progress, true);
}
onSizeChanged(getWidth(), getHeight() , 0, 0);
setPressed(true);
setSelected(true);
break;
case MotionEvent.ACTION_UP:
onChangeListener.onStopTrackingTouch(this);
setPressed(false);
setSelected(false);
break;
case MotionEvent.ACTION_CANCEL:
super.onTouchEvent(event);
setPressed(false);
setSelected(false);
break;
}
return true;
}
public synchronized void setProgressAndThumb(int progress) {
setProgress(progress);
onSizeChanged(getWidth(), getHeight() , 0, 0);
if(progress != lastProgress) {
// Only enact listener if the progress has actually changed
lastProgress = progress;
onChangeListener.onProgressChanged(this, progress, true);
}
}
public synchronized void setMaximum(int maximum) {
setMax(maximum);
}
public synchronized int getMaximum() {
return getMax();
}
}
How can I rotate the RatingBar?
Is there an example for a vertical custom RatingBar?
This is sample code for vertical rating bar...
public class VerticalRatingBar extends RatingBar {
private int x, y, z, w;
#Override
protected void drawableStateChanged() {
// TODO Auto-generated method stub
super.drawableStateChanged();
}
public VerticalRatingBar(Context context) {
super(context);
}
public VerticalRatingBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public VerticalRatingBar(Context context, AttributeSet attrs) {
super(context, attrs);
}
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(h, w, oldh, oldw);
this.x = w;
this.y = h;
this.z = oldw;
this.w = oldh;
}
#Override
protected synchronized void onMeasure(int widthMeasureSpec,
int heightMeasureSpec) {
super.onMeasure(heightMeasureSpec, widthMeasureSpec);
setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
}
protected void onDraw(Canvas c) {
c.rotate(-90);
c.translate(-getHeight(), 0);
super.onDraw(c);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (!isEnabled()) {
return false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
setSelected(true);
setPressed(true);
break;
case MotionEvent.ACTION_MOVE:
setProgress(getMax()
- (int) (getMax() * event.getY() / getHeight()));
onSizeChanged(getWidth(), getHeight(), 0, 0);
break;
case MotionEvent.ACTION_UP:
setSelected(false);
setPressed(false);
break;
case MotionEvent.ACTION_CANCEL:
break;
}
return true;
}
#Override
public synchronized void setProgress(int progress) {
if (progress >= 0)
super.setProgress(progress);
else
super.setProgress(0);
onSizeChanged(x, y, z, w);
}
}
There's a setRotation method on the view which will hopefully achieve what you're after.