How can I get a working vertical SeekBar in Android?

I have implemented the public VerticalSeekBar post here . Be that as it may, SeekBar works a little freaky. Here is my slightly adapted onTouchEvent() from this example:

 public boolean onTouchEvent(MotionEvent event) { xPos = event.getX(); yPos = event.getY(); oOffset = this.getThumbOffset(); oProgress = this.getProgress(); //Code from example - Not working //this.setThumbOffset( progress * (this.getBottom()-this.getTop()) ); this.setProgress((int)(29*yPos/this.getBottom())); return true; } 

I managed to implement one VerticalSeekBar, in which progress is updated, as expected, and is fully functional, but the thumb does not fit. This is just a graphic glitch, so I don’t notice it right now. But it would be nice if it worked. This SeekBar has max = 20 .

However, I tried to implement another VerticalSeekBar using max = 1000 . Obviously, it uses the same code, so you accept the same behavior. I can achieve 0 ~ 35 progress even when my finger slides out of the SeekBar and, ultimately, off the screen. If I just touch the end of the progress bar (which should be progress ~ 900 ), it returns a progress of about 35, and the yellow progress bar reflects this value, staying near the top.

My question is: does anyone have a link to a working vertical SeekBar or know how to adapt this particular example?

+49
android seekbar
Feb 03 2018-11-21T00:
source share
8 answers

Here is a working implementation of VerticalSeekBar:

 package android.widget; import android.content.Context; import android.graphics.Canvas; import android.util.AttributeSet; import android.view.MotionEvent; 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; } } 

To implement it, create a new class in your project by selecting the correct package:

There, paste the code and save it. Now use it in your XML layout:

 <android.widget.VerticalSeekBar android:id="@+id/seekBar1" android:layout_width="wrap_content" android:layout_height="200dp" /> 
+139
Sep 07 '11 at 23:16
source share

The code provided in the accepted answer did not catch the onStartTrackingTouch and onStopTrackingTouch events, so I changed it to have more control over these two events.

Here is my code:

 public class VerticalSeekBar extends SeekBar { private OnSeekBarChangeListener myListener; 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 void setOnSeekBarChangeListener(OnSeekBarChangeListener mListener){ this.myListener = 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: if(myListener!=null) myListener.onStartTrackingTouch(this); break; case MotionEvent.ACTION_MOVE: setProgress(getMax() - (int) (getMax() * event.getY() / getHeight())); onSizeChanged(getWidth(), getHeight(), 0, 0); myListener.onProgressChanged(this, getMax() - (int) (getMax() * event.getY() / getHeight()), true); break; case MotionEvent.ACTION_UP: myListener.onStopTrackingTouch(this); break; case MotionEvent.ACTION_CANCEL: break; } return true; } } 
+29
Oct 31 '11 at 18:05
source share

I am having trouble using this code using the setProgress method. To solve them, I suggest redefining setProgress and adding an onSizeChanged call to it.

+12
Oct 29 2018-11-11T00:
source share

I am having a problem using this code using the setProgress method. To solve them, I suggest redefining setProgress and adding an onSizeChanged call to it. Added code here.

  private int x,y,z,w; 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 public synchronized void setProgress(int progress) { super.setProgress(progress); onSizeChanged(x, y, z, w); } 

Selected guidance actions are performed by adding the following code:

1.setPressed (true); setSelected (true); // Add this to ACTION_DOWN

2.setPressed (false); setSelected (false); // Add This To ACTION_UP

And write the code for the selected guidance parameters in ur xml.

 <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true" android:state_window_focused="true" android:drawable="@drawable/thumb_h" /> <item android:state_selected="true" android:state_window_focused="true" android:drawable="@drawable/thumb_h" /> <item android:drawable="@drawable/thumb" /> </selector> 

This works for me ...

+11
Nov 02 2018-11-11T00:
source share

For API 11 and later you can use seekbar XML attributes ( android:rotation="270" ) for a vertical effect.

 <SeekBar android:id="@+id/seekBar1" android:layout_width="match_parent" android:layout_height="wrap_content" android:rotation="270"/> 

For an older API level (ex API10) use: https://github.com/AndroSelva/Vertical-SeekBar-Android

+7
Feb 08 '15 at 18:18
source share

Thanks to Paul Tsupikoff, Fatal1ty2787 and Ramesh for this great code.

Personally, I need a vertical slider that is in the reverse order compared to this code. In other words, the value increases, not decreases, the lower the thumb. This seems to have changed four lines.

First, I changed the onDraw() method, as Paul originally gave it. Now calls to rotate() and translate() have the following arguments:

 c.rotate(90); c.translate(0, -getWidth()); 

Then I made two changes in the case of ACTION_MOVE onTouchEvent() , as indicated by Fatal1ty2787. The call to setProgress() now looks like this:

 setProgress((int) (getMax() * event.getY() / getHeight())); 

Finally, the call to onProgressChanged() looks like this:

 myListener.onProgressChanged(this, (int) (getMax() * event.getY() / getHeight()), true); 

Now, if Google shared our interest in this feature ....

+6
Jul 03 '13 at 0:14
source share

Another idea is to change the X and Y coordinates of the MotionEvent and pass them to the super implementation:

 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); } @Override public boolean onTouchEvent(MotionEvent event) { if (!isEnabled()) { return false; } float x = (getHeight() - event.getY()) * getWidth() / getHeight(); float y = event.getX(); MotionEvent verticalEvent = MotionEvent .obtain(event.getDownTime(), event.getEventTime(), event.getAction(), x, y, event.getPressure(), event.getSize(), event.getMetaState(), event.getYPrecision(), event.getXPrecision(), event.getDeviceId(), event.getEdgeFlags()); return super.onTouchEvent(verticalEvent); } protected void onDraw(Canvas c) { c.rotate(-90); c.translate(-getHeight(), 0); super.onDraw(c); } @Override protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(heightMeasureSpec, widthMeasureSpec); setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth()); } protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(h, w, oldh, oldw); } } 

In this case, there is no need to call the setProgress (int) method, and therefore you can use the boolean-flag "fromUser" in OnSeekBarChangeListener.onProgressChanged () to determine if the search was created by user interaction.

+2
Dec 17 '13 at 11:52
source share

Target platforms

from Android 2.3.x (Gingerbread) to Android 7.x (nougat)

Beginning of work

This library is published in jCenter. Just add these lines to build.gradle.

 dependencies { compile 'com.h6ah4i.android.widget.verticalseekbar:verticalseekbar:0.7.2' } 

Using

XML Layout

 <!-- This library requires pair of the VerticalSeekBar and VerticalSeekBarWrapper classes --> <com.h6ah4i.android.widget.verticalseekbar.VerticalSeekBarWrapper android:layout_width="wrap_content" android:layout_height="150dp"> <com.h6ah4i.android.widget.verticalseekbar.VerticalSeekBar android:id="@+id/mySeekBar" android:layout_width="0dp" android:layout_height="0dp" android:max="100" android:progress="0" android:splitTrack="false" app:seekBarRotation="CW90" /> <!-- Rotation: CW90 or CW270 --> </com.h6ah4i.android.widget.verticalseekbar.VerticalSeekBarWrapper> 

NOTE: android:splitTrack="false" is required for Android N +.

Java code

 public class TestVerticalSeekbar extends AppCompatActivity { private SeekBar volumeControl = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test_vertical_seekbar); volumeControl = (SeekBar) findViewById(R.id.mySeekBar); volumeControl.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { int progressChanged = 0; public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { progressChanged = progress; } public void onStartTrackingTouch(SeekBar seekBar) { // TODO Auto-generated method stub } public void onStopTrackingTouch(SeekBar seekBar) { Toast.makeText(getApplicationContext(), "seek bar progress:" + progressChanged, Toast.LENGTH_SHORT).show(); } }); } } 
0
Sep 07 '17 at 7:53 on
source share



All Articles