Can a seekbar be vertical? I am not very good at UI design, so how make seekbar more beautiful, please give me some templates and examples.
问题:
回答1:
Here is a very good implementation of vertical seekbar. Have a look.
http://560b.sakura.ne.jp/android/VerticalSlidebarExample.zip
And Here is my own implementation for 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; }
回答2:
For API 11 and later, can use seekbar's XML attributes(android:rotation="270") for vertical effect.
For older API level (ex API10), only use Selva's answer:
https://github.com/AndroSelva/Vertical-SeekBar-Android
回答3:
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:
Make sure to create a package android.widget
and create VerticalSeekBar.java
under this package
回答4:
Try:
回答5:
I used Selva's solution but had two kinds of issues:
- OnSeekbarChangeListener did not work properly
- Setting progress programmatically did not work properly.
I fixed these two issues. You can find the solution (within my own project package) at
回答6:
We made a vertical SeekBar by using android:rotation="270"
:
Screenshot for camera exposure compensation:
回答7:
Note, it appears to me that if you change the width the thumb width does not change correctly. I didn't take the time to fix it right, i just fixed it for my case. Here is what i did. Couldn't figure out how to contact the original creator.
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(); }
回答8:
When moving the thumb with an EditText, the Vertical Seekbar setProgress may not work. The following code can help:
@Override public synchronized void setProgress(int progress) { super.setProgress(progress); updateThumb(); } private void updateThumb() { onSizeChanged(getWidth(), getHeight(), 0, 0); }
This snippet code found here: https://stackoverflow.com/a/33064140/2447726
回答9:
This worked for me, just put it into any layout you want to.
回答10:
Getting started
Add these lines to build.gradle.
dependencies { compile 'com.h6ah4i.android.widget.verticalseekbar:verticalseekbar:0.7.2' }
Usage
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(); } }); } }
Layout XML
NOTE: android:splitTrack="false"
is required for Android N+.
回答11:
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); } }
回答12:
In my case, I used an ordinary seekBar and just flipped out the layout.
seekbark_layout.xml - my layout that containts seekbar which we need to make vertical.
activity_main.xml
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() } } }