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();
}
}
Related
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;
}
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.
Hey guys I am currently working on my own Android SeekBar and I want to make the progress color to be drawn from the center of the bar to the thumb. Currently, my SeekBar class looks like this:
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);
setThumb(getResources().getDrawable(R.drawable.slidera));
setProgressDrawable(getResources().getDrawable(R.drawable.sl_bg));
}
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) {
[...]
My Problem now is that I don't know what method I need to override in order to change the behaviour of the drawing of the ProgressDrawable, I am sure there must be some way.
Thanks in advance
So this is now the whole class. The getRekt methods get the size of the SeekBar and the other stuff you see in the onDraw method is pretty much self-explaining. The background drawable is a drawable consisting of the color value 0x00000000 so it doesn't cover the "new" progress background.
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);
setThumb(getResources().getDrawable(R.drawable.slidera));
setThumbOffset(0);
setProgressDrawable(getResources().getDrawable(R.drawable.sl_bg));
setPadding(0,0,0,0);
}
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);
Paint paint = new Paint();
paint.setColor(0xffff7700);
paint.setStrokeWidth(11);
BlurMaskFilter blurMaskFilter=new BlurMaskFilter(15.0f,BlurMaskFilter.Blur.OUTER);
c.drawLine(
getRectX()+(getProgress()-50)*getRHeight()/100, getRectY(),getRectX(), getRectY(), paint);
paint.setMaskFilter(blurMaskFilter);
c.drawLine(
getRectX()+(getProgress()-50)*getRHeight()/100, getRectY(),getRectX(), getRectY(), paint);
drawMeter(c);
super.onDraw(c);
}
public int getRectX(){
Rect MLG= getProgressDrawable().getBounds();
return MLG.centerX();
}
public int getRectY(){
Rect MLG= getProgressDrawable().getBounds();
return MLG.centerY();
}
public int getRHeight(){
Rect MLG= getProgressDrawable().getBounds();
return MLG.width();
}
public void drawMeter(Canvas c){
Paint paint = new Paint();
paint.setColor(0xffff7700);
paint.setStrokeWidth(2);
c.drawLine(
0,100,0, 0, paint);
c.drawLine(
getRHeight()/2,100,getRHeight()/2, 0, paint);
c.drawLine(
getRHeight(),100,getRHeight(), 0, paint);
}
#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 should then look like this:
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.