How to make vertical SeekBar in Android?

Can the pointer be vertical? I am not very good at user interface design, therefore, how to make the search bar more beautiful, please give me some templates and examples.

+61
android seekbar
Jul 26 '10 at 9:34
source share
14 answers

Here is a very good implementation of a vertical search bar. Take a look.

http://560b.sakura.ne.jp/android/VerticalSlidebarExample.zip

And here is my own implementation for the vertical and inverted Seekbar based on this

https://github.com/AndroSelva/Vertical-SeekBar-Android

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: int i=0; i=getMax() - (int) (getMax() * event.getY() / getHeight()); setProgress(i); Log.i("Progress",getProgress()+""); onSizeChanged(getWidth(), getHeight(), 0, 0); break; case MotionEvent.ACTION_CANCEL: break; } return true; } 
+48
Jan 17 2018-12-12T00:
source share
  • For API 11 and later, you can use the XML search 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 only Selva's answer:
    https://github.com/AndroSelva/Vertical-SeekBar-Android

+58
Apr 25 '13 at 8:38
source share

Working example

 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 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) { 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; } } 

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" /> 

Be sure to create the android.widget package and create the VerticalSeekBar.java in this package

+22
Feb 08 '15 at 18:14
source share

Try:

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <SeekBar android:id="@+id/seekBar1" android:layout_width="match_parent" android:layout_height="wrap_content" android:rotation="270" /> </RelativeLayout> 
+13
Jul 24. 2018-12-21T00:
source share

I used the Selva solution, but I had two kinds of problems:

  • OnSeekbarChangeListener is not working properly
  • Setting progress programmatically did not work properly.

I fixed these two issues. You can find a solution (as part of my own project package) at

https://github.com/jeisfeld/Augendiagnose/blob/master/AugendiagnoseIdea/augendiagnoseLib/src/main/java/de/jeisfeld/augendiagnoselib/components/VerticalSeekBar.java

+9
Jun 05 '14 at 22:11
source share

We made a vertical SeekBar using android:rotation="270" :

 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> <SurfaceView android:id="@+id/camera_sv_preview" android:layout_width="match_parent" android:layout_height="match_parent"/> <LinearLayout android:id="@+id/camera_lv_expose" android:layout_width="32dp" android:layout_height="200dp" android:layout_centerVertical="true" android:layout_alignParentRight="true" android:layout_marginRight="15dp" android:orientation="vertical"> <TextView android:id="@+id/camera_tv_expose" android:layout_width="32dp" android:layout_height="20dp" android:textColor="#FFFFFF" android:textSize="15sp" android:gravity="center"/> <FrameLayout android:layout_width="32dp" android:layout_height="180dp" android:orientation="vertical"> <SeekBar android:id="@+id/camera_sb_expose" android:layout_width="180dp" android:layout_height="32dp" android:layout_gravity="center" android:rotation="270"/> </FrameLayout> </LinearLayout> <TextView android:id="@+id/camera_tv_help" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_alignParentBottom="true" android:layout_marginBottom="20dp" android:text="@string/camera_tv" android:textColor="#FFFFFF" /> </RelativeLayout> 

Screenshot to compensate for camera exposure:

enter image description here

+9
Aug 17 '16 at 6:35
source share

Notice, it seems to me that if you change the width, the width of the thumb will not change correctly. I did not find the time to fix it correctly, I just fixed it for my business. Here is what I did. Failed to figure out how to contact the original.

 public void setThumb(Drawable thumb) { if (thumb != null) { thumb.setCallback(this); // Assuming the thumb drawable is symmetric, set the thumb offset // such that the thumb will hang halfway off either edge of the // progress bar. //This was orginally divided by 2, seems you have to adjust here when you adjust width. mThumbOffset = (int)thumb.getIntrinsicHeight(); } 
+6
Mar 23 '11 at 0:30
source share

This worked for me, just put it in whatever layout you want.

 <FrameLayout android:layout_width="32dp" android:layout_height="192dp"> <SeekBar android:layout_width="192dp" android:layout_height="32dp" android:layout_gravity="center" android:rotation="270" /> </FrameLayout> 
+5
Jun 11 2018-02-17T00:
source share

When moving the thumb with EditText, the Vertical Seekbar setProgress may not work. The following code may help:

  @Override public synchronized void setProgress(int progress) { super.setProgress(progress); updateThumb(); } private void updateThumb() { onSizeChanged(getWidth(), getHeight(), 0, 0); } 

This snippet code is found here: stack overflow

+2
Apr 6 '16 at 6:19 06:19
source share

Beginning of work

Add these lines to build.gradle.

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

Using

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(); } }); } } 

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 +.

+1
Sep 07 '17 at 8:25
source share

Try this

 import android.content.Context; import android.graphics.Canvas; import android.support.annotation.NonNull; import android.util.AttributeSet; import android.view.MotionEvent; import android.widget.SeekBar; /** * Implementation of an easy vertical SeekBar, based on the normal SeekBar. */ public class VerticalSeekBar extends SeekBar { /** * The angle by which the SeekBar view should be rotated. */ private static final int ROTATION_ANGLE = -90; /** * A change listener registrating start and stop of tracking. Need an own listener because the listener in SeekBar * is private. */ private OnSeekBarChangeListener mOnSeekBarChangeListener; /** * Standard constructor to be implemented for all views. * * @param context The Context the view is running in, through which it can access the current theme, resources, etc. * @see android.view.View#View(Context) */ public VerticalSeekBar(final Context context) { super(context); } /** * Standard constructor to be implemented for all views. * * @param context The Context the view is running in, through which it can access the current theme, resources, etc. * @param attrs The attributes of the XML tag that is inflating the view. * @see android.view.View#View(Context, AttributeSet) */ public VerticalSeekBar(final Context context, final AttributeSet attrs) { super(context, attrs); } /** * Standard constructor to be implemented for all views. * * @param context The Context the view is running in, through which it can access the current theme, resources, etc. * @param attrs The attributes of the XML tag that is inflating the view. * @param defStyle An attribute in the current theme that contains a reference to a style resource that supplies default * values for the view. Can be 0 to not look for defaults. * @see android.view.View#View(Context, AttributeSet, int) */ public VerticalSeekBar(final Context context, final AttributeSet attrs, final int defStyle) { super(context, attrs, defStyle); } /* * (non-Javadoc) ${see_to_overridden} */ @Override protected final void onSizeChanged(final int width, final int height, final int oldWidth, final int oldHeight) { super.onSizeChanged(height, width, oldHeight, oldWidth); } /* * (non-Javadoc) ${see_to_overridden} */ @Override protected final synchronized void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { super.onMeasure(heightMeasureSpec, widthMeasureSpec); setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth()); } /* * (non-Javadoc) ${see_to_overridden} */ @Override protected final void onDraw(@NonNull final Canvas c) { c.rotate(ROTATION_ANGLE); c.translate(-getHeight(), 0); super.onDraw(c); } /* * (non-Javadoc) ${see_to_overridden} */ @Override public final void setOnSeekBarChangeListener(final OnSeekBarChangeListener listener) { // Do not use super for the listener, as this would not set the fromUser flag properly mOnSeekBarChangeListener = listener; } /* * (non-Javadoc) ${see_to_overridden} */ @Override public final boolean onTouchEvent(@NonNull final MotionEvent event) { if (!isEnabled()) { return false; } switch (event.getAction()) { case MotionEvent.ACTION_DOWN: setProgressInternally(getMax() - (int) (getMax() * event.getY() / getHeight()), true); if (mOnSeekBarChangeListener != null) { mOnSeekBarChangeListener.onStartTrackingTouch(this); } break; case MotionEvent.ACTION_MOVE: setProgressInternally(getMax() - (int) (getMax() * event.getY() / getHeight()), true); break; case MotionEvent.ACTION_UP: setProgressInternally(getMax() - (int) (getMax() * event.getY() / getHeight()), true); if (mOnSeekBarChangeListener != null) { mOnSeekBarChangeListener.onStopTrackingTouch(this); } break; case MotionEvent.ACTION_CANCEL: if (mOnSeekBarChangeListener != null) { mOnSeekBarChangeListener.onStopTrackingTouch(this); } break; default: break; } return true; } /** * Set the progress by the user. (Unfortunately, Seekbar.setProgressInternally(int, boolean) is not accessible.) * * @param progress the progress. * @param fromUser flag indicating if the change was done by the user. */ public final void setProgressInternally(final int progress, final boolean fromUser) { if (progress != getProgress()) { super.setProgress(progress); if (mOnSeekBarChangeListener != null) { mOnSeekBarChangeListener.onProgressChanged(this, progress, fromUser); } } onSizeChanged(getWidth(), getHeight(), 0, 0); } /* * (non-Javadoc) ${see_to_overridden} */ @Override public final void setProgress(final int progress) { setProgressInternally(progress, false); } } 
+1
Feb 27 '18 at 9:26
source share

In my case, I used the usual seekBar and just flipped the layout.

seekbark_layout.xml is my layout that contains seekbar, which we need to make vertical.

 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/rootView" android:layout_width="match_parent" android:layout_height="match_parent"> <SeekBar android:id="@+id/seekBar" android:layout_width="match_parent" android:layout_height="50dp" android:layout_alignParentBottom="true"/> </RelativeLayout> 

activity_main.xml

 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.vgfit.seekbarexample.MainActivity"> <View android:id="@+id/headerView" android:layout_width="match_parent" android:layout_height="100dp" android:background="@color/colorAccent"/> <View android:id="@+id/bottomView" android:layout_width="match_parent" android:layout_height="100dp" android:layout_alignParentBottom="true" android:background="@color/colorAccent"/> <include layout="@layout/seekbar_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@id/bottomView" android:layout_below="@id/headerView"/> </RelativeLayout> 

And in MainActivity I rotate seekbar_layout:

 import android.os.Bundle import android.support.v7.app.AppCompatActivity import android.widget.RelativeLayout import kotlinx.android.synthetic.main.seekbar_layout.* class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) rootView.post { val w = rootView.width val h = rootView.height rootView.rotation = 270.0f rootView.translationX = ((w - h) / 2).toFloat() rootView.translationY = ((h - w) / 2).toFloat() val lp = rootView.layoutParams as RelativeLayout.LayoutParams lp.height = w lp.width = h rootView.requestLayout() } } } 

As a result, we have the necessary vertical search bar: enter image description here

0
Mar 07 '18 at 9:28
source share

Wrap it inside a FrameLayout so that there are no size issues.

  <FrameLayout android:layout_width="@dimen/_20dp" android:layout_marginStart="@dimen/_15dp" android:layout_marginEnd="@dimen/_15dp" android:layout_height="match_parent" android:orientation="vertical"> <SeekBar android:layout_width="150dp" android:layout_height="30dp" android:layout_gravity="center" android:rotation="270" /> </FrameLayout> 
0
Aug 07 '18 at 13:40
source share

I tried in many ways, but the one that worked for me was. Seekbar user inside FrameLayout

 <FrameLayout android:id="@+id/VolumeLayout" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@id/MuteButton" android:layout_below="@id/volumeText" android:layout_centerInParent="true"> <SeekBar android:id="@+id/volume" android:layout_width="500dp" android:layout_height="60dp" android:layout_gravity="center" android:progress="50" android:secondaryProgress="40" android:progressDrawable="@drawable/seekbar_volume" android:secondaryProgressTint="@color/tint_neutral" android:thumbTint="@color/tint_neutral" /> 

And in the Code. Set up a callback before rendering on the Seekbar, where you can change the width and height of the Seekbar. I did this part in C #, so the code I used was

  var volumeSlider = view.FindViewById<SeekBar>(Resource.Id.home_link_volume); var volumeFrameLayout = view.FindViewById<FrameLayout>(Resource.Id.linkVolumeFrameLayout); void OnPreDrawVolume(object sender, ViewTreeObserver.PreDrawEventArgs e) { volumeSlider.ViewTreeObserver.PreDraw -= OnPreDrawVolume; var h = volumeFrameLayout.Height; volumeSlider.Rotation = 270.0f; volumeSlider.LayoutParameters.Width = h; volumeSlider.RequestLayout(); } volumeSlider.ViewTreeObserver.PreDraw += OnPreDrawVolume; 

Here I add a listener to the PreDraw event, and when it fires, I delete PreDraw so that it does not go into an infinite loop.

Therefore, when Pre Draw is executed, I select Height of FrameLayout and assign it to Seekbar. And set the rotation of the search bar to 270. Since my search bar is inside the Layout frame and its gravity is set to Center. I do not need to worry about the translation. Since Seekbar always stays in the middle of Frame Layout.

The reason I removed the EventHandler is because seekbar.RequestLayout (); Let's make this event executed again.

0
May 10 '19 at 4:36
source share



All Articles