Android自定义垂直拖动seekbar进度条

Android自带的SeekBar是水平的,要垂直的,必须自己写一个类,继承SeekBar。

一个简单的垂直SeekBar的例子:

(但是它其实是存在一些问题的。不过要是满足基本需要还是可以凑合的)

package com.example.helloverticalseekbar;

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.SeekBar;

public class VerticalSeekBar extends SeekBar
{

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

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

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

  @Override
  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
  protected synchronized void onDraw(Canvas canvas)
  {
    canvas.rotate(-90);
    canvas.translate(-getHeight(), 0);
    super.onDraw(canvas);
  }

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

}

Demo中加上一个水平SeekBar作为对比,代码如下:

Activity:

HelloSeekBarActivity

package com.example.helloverticalseekbar;

import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.SeekBar.OnSeekBarChangeListener;

public class HelloSeekBarActivity extends Activity
{
  private SeekBar horiSeekBar = null;
  private TextView horiText = null;

  private VerticalSeekBar verticalSeekBar = null;
  private TextView verticalText = null;

  @Override
  protected void onCreate(Bundle savedInstanceState)
  {
    Log.d(AppConstants.LOG_TAG, "onCreate");
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_hello_seek_bar);

    horiSeekBar = (SeekBar) findViewById(R.id.horiSeekBar);
    horiText = (TextView)findViewById(R.id.horiText);
    horiSeekBar.setOnSeekBarChangeListener(horiSeekBarListener);

    verticalSeekBar = (VerticalSeekBar)findViewById(R.id.verticalSeekBar);
    verticalText = (TextView)findViewById(R.id.verticalText);
    verticalSeekBar.setOnSeekBarChangeListener(verticalSeekBarChangeListener);

  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu)
  {
    getMenuInflater().inflate(R.menu.hello_seek_bar, menu);
    return true;
  }

  private OnSeekBarChangeListener horiSeekBarListener = new OnSeekBarChangeListener()
  {

    @Override
    public void onStopTrackingTouch(SeekBar seekBar)
    {

    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar)
    {

    }

    @Override
    public void onProgressChanged(SeekBar seekBar, int progress,
        boolean fromUser)
    {
      Log.d(AppConstants.LOG_TAG, "Horizontal SeekBar --> onProgressChanged");
      horiText.setText(Integer.toString(progress));

    }
  };

  private OnSeekBarChangeListener verticalSeekBarChangeListener = new OnSeekBarChangeListener()
  {

    @Override
    public void onStopTrackingTouch(SeekBar seekBar)
    {

    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar)
    {

    }

    @Override
    public void onProgressChanged(SeekBar seekBar, int progress,
        boolean fromUser)
    {
      Log.d(AppConstants.LOG_TAG, "Vertical SeekBar --> onProgressChanged");
      verticalText.setText(Integer.toString(progress));

    }
  };

}

布局:

activity_hello_seek_bar.xml

<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"
  android:paddingBottom="@dimen/activity_vertical_margin"
  android:paddingLeft="@dimen/activity_horizontal_margin"
  android:paddingRight="@dimen/activity_horizontal_margin"
  android:paddingTop="@dimen/activity_vertical_margin"
  tools:context=".HelloSeekBarActivity" >

  <TextView
    android:id="@+id/myTextView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentTop="true"
    android:text="@string/hello_world" />

  <SeekBar
    android:id="@+id/horiSeekBar"
    android:layout_width="match_parent"
    android:layout_height="20dp"
    android:layout_below="@id/myTextView" />

  <TextView
    android:id="@+id/horiText"
    android:layout_width="wrap_content"
    android:layout_height="20dp"
    android:layout_below="@id/horiSeekBar"
    android:text="horizontal" />

  <com.example.helloverticalseekbar.VerticalSeekBar
    android:id="@+id/verticalSeekBar"
    android:layout_width="wrap_content"
    android:layout_height="200dp"
    android:layout_below="@id/horiText" />

  <TextView
    android:id="@+id/verticalText"
    android:layout_width="wrap_content"
    android:layout_height="20dp"
    android:layout_below="@id/verticalSeekBar"
    android:text="vertical" />

</RelativeLayout>

运行截图:

一个改进版的SeekBar

package com.example.helloverticalseekbarv2;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.SeekBar;

public class VerticalSeekBar extends SeekBar
{
  private boolean mIsDragging;
  private float mTouchDownY;
  private int mScaledTouchSlop;
  private boolean isInScrollingContainer = false;

  public boolean isInScrollingContainer()
  {
    return isInScrollingContainer;
  }

  public void setInScrollingContainer(boolean isInScrollingContainer)
  {
    this.isInScrollingContainer = isInScrollingContainer;
  }

  /**
   * On touch, this offset plus the scaled value from the position of the
   * touch will form the progress value. Usually 0.
   */
  float mTouchProgressOffset;

  public VerticalSeekBar(Context context, AttributeSet attrs, int defStyle)
  {
    super(context, attrs, defStyle);
    mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();

  }

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

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

  @Override
  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
  protected synchronized void onDraw(Canvas canvas)
  {
    canvas.rotate(-90);
    canvas.translate(-getHeight(), 0);
    super.onDraw(canvas);
  }

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

    switch (event.getAction())
    {
      case MotionEvent.ACTION_DOWN:
        if (isInScrollingContainer())
        {

          mTouchDownY = event.getY();
        }
        else
        {
          setPressed(true);

          invalidate();
          onStartTrackingTouch();
          trackTouchEvent(event);
          attemptClaimDrag();

          onSizeChanged(getWidth(), getHeight(), 0, 0);
        }
        break;

      case MotionEvent.ACTION_MOVE:
        if (mIsDragging)
        {
          trackTouchEvent(event);

        }
        else
        {
          final float y = event.getY();
          if (Math.abs(y - mTouchDownY) > mScaledTouchSlop)
          {
            setPressed(true);

            invalidate();
            onStartTrackingTouch();
            trackTouchEvent(event);
            attemptClaimDrag();

          }
        }
        onSizeChanged(getWidth(), getHeight(), 0, 0);
        break;

      case MotionEvent.ACTION_UP:
        if (mIsDragging)
        {
          trackTouchEvent(event);
          onStopTrackingTouch();
          setPressed(false);

        }
        else
        {
          // Touch up when we never crossed the touch slop threshold
          // should
          // be interpreted as a tap-seek to that location.
          onStartTrackingTouch();
          trackTouchEvent(event);
          onStopTrackingTouch();

        }
        onSizeChanged(getWidth(), getHeight(), 0, 0);
        // ProgressBar doesn't know to repaint the thumb drawable
        // in its inactive state when the touch stops (because the
        // value has not apparently changed)
        invalidate();
        break;
    }
    return true;

  }

  private void trackTouchEvent(MotionEvent event)
  {
    final int height = getHeight();
    final int top = getPaddingTop();
    final int bottom = getPaddingBottom();
    final int available = height - top - bottom;

    int y = (int) event.getY();

    float scale;
    float progress = 0;

    // 下面是最小值
    if (y > height - bottom)
    {
      scale = 0.0f;
    }
    else if (y < top)
    {
      scale = 1.0f;
    }
    else
    {
      scale = (float) (available - y + top) / (float) available;
      progress = mTouchProgressOffset;
    }

    final int max = getMax();
    progress += scale * max;

    setProgress((int) progress);

  }

  /**
   * This is called when the user has started touching this widget.
   */
  void onStartTrackingTouch()
  {
    mIsDragging = true;
  }

  /**
   * This is called when the user either releases his touch or the touch is
   * canceled.
   */
  void onStopTrackingTouch()
  {
    mIsDragging = false;
  }

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

  @Override
  public synchronized void setProgress(int progress)
  {

    super.setProgress(progress);
    onSizeChanged(getWidth(), getHeight(), 0, 0);

  }

}

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

(0)

相关推荐

  • Android自定义SeekBar实现视频播放进度条

    首先来看一下效果图,如下所示: 其中进度条如下: 接下来说一说我的思路,上面的进度拖动条有自定义的Thumb,在Thumb正上方有一个PopupWindow窗口,窗口里面显示当前的播放时间.在SeekBar右边有一个文本框显示当前播放时间/总时间. step1.先来看一看PopupWindow的布局文件,seek_popu.xml,效果如下图所示: <?xml version="1.0" encoding="utf-8"?> <RelativeLa

  • Android控件之SeekBar的用法总结

    1 SeekBar简介 SeekBar是进度条.我们使用进度条时,可以使用系统默认的进度条:也可以自定义进度条的图片和滑块图片等. 2 SeekBar示例 创建一个activity,包含2个SeekBar. 第1个SeekBar是系统默认的SeekBar. 第2个SeekBar是自定义SeekBar,使用自定义的背景图和滑块图片. 应用层代码 package com.skywang.control; import android.os.Bundle; import android.app.Act

  • Android 七种进度条的样式

    当一个应用在后台执行时,前台界面就不会有什么信息,这时用户根本不知道程序是否在执行.执行进度如何.应用程序是否遇到错误终止等,这时需要使用进度条来提示用户后台程序执行的进度.Android系统提供了两大类进度条样式,长形进度条(progress-BarStyleHorizontal) 和圆形进度条(progressBarStyleLarge).进度条用处很多,比如,应用程序装载资源和网络连接时,可以提示用户稍等,这一类进度条只是代表应用程序中某一部分的执行情况,而整个应用程序执行情况呢,则可以通

  • Android 可拖动的seekbar自定义进度值

    最近接了个项目其中有需要要实现此功能:seekbar需要显示最左和最右值,进度要跟随进度块移动.下面通过此图给大家展示下效果,可能比文字描述要更清晰. 其实实现起来很简单,主要是思路.自定义控件的话也不难,之前我的博客也有专门介绍,这里就不再多说. 实现方案 这里是通过继承seekbar来自定义控件,这样的方式最快.主要难点在于进度的显示,其实我很的是最笨的方法,就是用了一个popwindow显示在进度条的上方,然后在移动滑块的时候实时的改变它显示的横坐标.看进度显示的核心代码: private

  • Android下修改SeekBar样式的解决办法

    SeekBar配置文件:Xml代码 复制代码 代码如下: <SeekBar              android:id="@+id/player_seekbar"             android:layout_width="245px"             android:layout_height="25px"             android:progressDrawable="@drawable/see

  • Android自定义竖直方向SeekBar多色进度条

    写在前面 因为有这样的一个场景,需要实现竖直方向的多色进度条,然后在网上也找了下,没看到符合需要的,于是自定义了一个,效果如下: 具体实现 本来想定义水平的,然后旋转一下,后来发现还不如直接定义竖直方向来的直接,就直接在竖直方向画了下. 首先讲一下思路,就是通过继承View,然后通过onDraw()方法进行绘制.具体绘制的时候,需要处理一些小细节. 比如,我们需要画一个圆形的滑动块,那么我们的背景色带就不能把整个宽度占满,要不然,小圆块只能和色带一样宽了,效果不是很好看,所以在绘制的时候应该把背

  • android之SeekBar控件用法详解

    MainActivity.java package com.example.mars_2400_seekbar; import android.support.v7.app.ActionBarActivity; import android.support.v7.app.ActionBar; import android.support.v4.app.Fragment; import android.app.Activity; import android.os.Bundle; import a

  • android自定义进度条渐变色View的实例代码

    最近在公司,项目不是很忙了,偶尔看见一个兄台在CSDN求助,帮忙要一个自定义的渐变色进度条,我当时看了一下进度条,感觉挺漂亮的,就尝试的去自定义view实现了一个,废话不说,先上图吧! 这个自定义的view,完全脱离了android自带的ProgressView,并且没使用一张图片,这样就能更好的降低程序代码上的耦合性! 下面我贴出代码  ,大概讲解一下实现思路吧! 复制代码 代码如下: package com.spring.progressview; import android.conten

  • Android 动态改变SeekBar进度条颜色与滑块颜色的实例代码

    遇到个动态改变SeekBar进度条颜色与滑块颜色的需求,有的是根据不同进度改变成不同颜色. 对于这个怎么做呢?大家都知道设置下progressDrawable与thumb即可,但是这样设置好就是确定的了,要动态更改需要在代码里实现. 用shape进度条与滑块 SeekBar设置 代码里动态设置setProgressDrawable与setThumb 画图形,大家都比较熟悉,background是背景图,secondaryProgress第二进度条,progress进度条: <layer-list

  • Android中实现Webview顶部带进度条的方法

    写这篇文章,做份备忘,简单滴展示一个带进度条的Webview示例,进度条位于Webview上面. 示例图如下: 主Activity代码: 复制代码 代码如下: package com.droidyue.demo.webviewprogressbar; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.View; import android.vi

随机推荐