Android实现垂直进度条VerticalSeekBar

时间:2018-07-20
这篇文章主要为大家详细介绍了Android实现垂直进度条VerticalSeekBar的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了Android实现垂直进度条的具体代码,供大家参考,具体内容如下

水平的进度条见多了,总会想见个垂直的进度条开开眼。今天咱就试试。
要说原理也简单,就是把宽高倒置,其他的理论上都不需要动,发现问题再补补也就行了。

官方提供

官方是提供了垂直进度条的例子源码的,位置在android-sdk-windowssourcesandroid-23comandroidexamplerscameraVerticalSeekBar.java,当然首先你SDK中要有Android 6.0。

VerticalSeekBar.java

/**
 * Class to create a vertical slider
 */
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;
  }
}

继承SeekBar是最简单快捷的,不用重写太多方法,只需要把

onMeasure
onSizeChanged
onDraw

三个方法作一些改动;但也有一些问题,比如只能响应onPregress方法,为了让他能响应onStartTrackingTouch和onStopTrackingTouch方法,只好再加一些代码,于是有了改进版。

稍作改进

VerticalSeekBar2.java

public class VerticalSeekBar2 extends SeekBar {
  private Drawable mThumb;
  private OnSeekBarChangeListener mOnSeekBarChangeListener;

  public VerticalSeekBar2(Context context) {
    super(context);
  }

  public VerticalSeekBar2(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  public VerticalSeekBar2(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
  }

  public void setOnSeekBarChangeListener(OnSeekBarChangeListener l) {
    mOnSeekBarChangeListener = l;
  }

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

  void onProgressRefresh(float scale, boolean fromUser) {
    Drawable thumb = mThumb;
    if (thumb != null) {
      setThumbPos(getHeight(), thumb, scale, Integer.MIN_VALUE);
      invalidate();
    }
    if (mOnSeekBarChangeListener != null) {
      mOnSeekBarChangeListener.onProgressChanged(this, getProgress(), fromUser);
    }
  }

  private void setThumbPos(int w, Drawable thumb, float scale, int gap) {
    int available = w - getPaddingLeft() - getPaddingRight();

    int thumbWidth = thumb.getIntrinsicWidth();
    int thumbHeight = thumb.getIntrinsicHeight();

    int thumbPos = (int) (scale * available + 0.5f);

    // int topBound = getWidth() / 2 - thumbHeight / 2 - getPaddingTop();
    // int bottomBound = getWidth() / 2 + thumbHeight / 2 - getPaddingTop();
    int topBound, bottomBound;
    if (gap == Integer.MIN_VALUE) {
      Rect oldBounds = thumb.getBounds();
      topBound = oldBounds.top;
      bottomBound = oldBounds.bottom;
    } else {
      topBound = gap;
      bottomBound = gap + thumbHeight;
    }
    thumb.setBounds(thumbPos, topBound, thumbPos + thumbWidth, bottomBound);
  }

  public void setThumb(Drawable thumb) {
    mThumb = thumb;
    super.setThumb(thumb);
  }

  void onStartTrackingTouch() {
    if (mOnSeekBarChangeListener != null) {
      mOnSeekBarChangeListener.onStartTrackingTouch(this);
    }
  }

  void onStopTrackingTouch() {
    if (mOnSeekBarChangeListener != null) {
      mOnSeekBarChangeListener.onStopTrackingTouch(this);
    }
  }

  private void attemptClaimDrag() {
    if (getParent() != null) {
      getParent().requestDisallowInterceptTouchEvent(true);
    }
  }

  @Override
  public boolean onTouchEvent(MotionEvent event) {
    if (!isEnabled()) {
      return false;
    }

    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
      setPressed(true);
      onStartTrackingTouch();
      break;

    case MotionEvent.ACTION_MOVE:
      attemptClaimDrag();
      setProgress(getMax() - (int) (getMax() * event.getY() / getHeight()));
      break;
    case MotionEvent.ACTION_UP:
      onStopTrackingTouch();
      setPressed(false);
      break;

    case MotionEvent.ACTION_CANCEL:
      onStopTrackingTouch();
      setPressed(false);
      break;
    }
    return true;
  }

为了响应另外两个不知道怎么就被onPregress抛弃的方法,添了这么多代码真是罪过,不过都是从SeekBar的父类AbsSeekBar中仿写过来的,逻辑稍作改动就能用。

对比测试

上图。

左边是官方例子中的,右边是改进过的。

测试源码:垂直进度条VerticalSeekBar

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。