Android惯用控件之SeekBar的使用

Android常用控件之SeekBar的使用


SeekBar的应用非常广,比如用来显示音量条、播放进度条,有水平显示也有垂直显示,但Android只给我们提供了水平的,可以用系统默认的样式也可以用我们自定义的样式,总之进度条的用法多种多样,如果Android没有提供也能我们自己去定制,先上图

Android惯用控件之SeekBar的使用

使用图片自定义水平进度条时有个缺陷,就是图片不能根据进度条的大小进行拉伸,也就是自适应进度条的长度。当然也可以通过改变进度条的宽度跟图片宽度一致,这样就不会出现上面的情况。我想让图片适应进度条的大小,但还没找到解决办法,我想通过广大网友一起想想办法如何解决这样问题,有知道的朋友可以告诉我,感激不尽!

上图显示的第一个进度条是Android定义的,我们不需要做任何更新,只需要在布局文件中添加就可以,如

<SeekBar
        android:id="@+id/seekbar"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true" />

然后在Activity中根据相应的ID获取对象,并添加监听器


下面看下第二个进度条的在布局文件中的定义

<SeekBar
        android:id="@+id/proSeek"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/seekbar"
        android:layout_gravity="center_vertical"
        android:paddingLeft="5dp"
        android:paddingRight="5dp"
        android:progressDrawable="@drawable/seekbar_style"
        android:secondaryProgress="0"
        android:thumb="@drawable/thumb_selector" />

进度条样式seekbar_style.xml定义 以下是使用图片定义的

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" 
    android:opacity="transparent">

    <item
        android:id="@android:id/background"
        android:drawable="@drawable/player_progress_bg"/>
    <item
        android:id="@android:id/secondaryProgress"
        android:drawable="@drawable/player_progress_buffering">
    </item>
    <item
        android:id="@android:id/progress"
        android:drawable="@drawable/player_progress_playing">
    </item>

</layer-list>


滑块thumb_selector.xml 定义

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@drawable/voice_thumb_press" 
        android:state_pressed="true"/>
    <item android:drawable="@drawable/voice_thumb_normal" 
        android:state_enabled="true" 
        android:state_focused="true" 
        android:state_window_focused="true"/>
    <item android:drawable="@drawable/voice_thumb_normal"/>

</selector>
至此一个用图片定义的进度条就完成了。

第三个进度条是修改了滑块,这就需要重写SeekBar

关键代码如下:

在布局文件中声明自定义的控件  com.example.seekbar.mSeekBar

<com.example.seekbar.mSeekBar
        android:id="@+id/proSeek2"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/proSeek"
        android:layout_gravity="center_vertical"
        android:paddingLeft="5dp"
        android:paddingRight="5dp"
        android:progressDrawable="@drawable/seekbar_style_1"
        android:secondaryProgress="0"
        android:thumb="@drawable/thumb_selector" />

修改滑块的关键代码

public mSeekBar(Context context, AttributeSet attrs) {
		super(context, attrs);
		paint = new Paint();
		paint.setTextAlign(Paint.Align.CENTER);
		paint.setColor(Color.BLUE);
		res = context.getResources();
		bmp = BitmapFactory.decodeResource(res, R.drawable.voice_thumb_press);
		thumb = new BitmapDrawable(res, bmp);
		bmpPro = BitmapFactory.decodeResource(res, R.drawable.player_progress_bg);
		Progress = new BitmapDrawable(res, bmpPro);
		// 判断屏幕大小 符合条件进行缩放thumb
		if (Pixels.getpixels_x(100) < ScreenWidth
				&& Pixels.getpixels_y(100) < screenHeight) {
			thumb = zoomDrawable(thumb, bmp.getWidth(), bmp.getHeight());
		} else {
			paint.setTextSize(20);
		}
		Progress = zoomDrawable(Progress, bmpPro.getWidth(), bmpPro.getHeight());
		// 设置拖动的图片
		setThumb(thumb);
		// 图片的位置
		setThumbOffset(thumb.getIntrinsicWidth());
		setBackgroundDrawable(Progress);
	}

第四个进度条是用颜色来填充

主要是下面这个样式文件   

seekbar_style_own.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >

    <item android:id="@android:id/background">
        <shape>
            <corners android:radius="5dip" />

            <gradient
                android:angle="270"
                android:centerColor="#ff5a5d5a"
                android:centerY="0.75"
                android:endColor="#ff747674"
                android:startColor="#ff9d9e9d" />
        </shape>
    </item>
    <item android:id="@android:id/secondaryProgress">
        <clip>
            <shape>
                <corners android:radius="5dip" />

                <gradient
                    android:angle="270"
                    android:centerColor="#80ffb600"
                    android:centerY="0.75"
                    android:endColor="#a0ffcb00"
                    android:startColor="#80ffd300" />
            </shape>
        </clip>
    </item>
    <item android:id="@android:id/progress">
        <clip>
            <shape>
                <corners android:radius="5dip" />

                <gradient
                    android:angle="270"
                    android:centerColor="#ff3399CC"
                    android:centerY="0.75"
                    android:endColor="#ff6699CC"
                    android:startColor="#ff0099CC" />
            </shape>
        </clip>
    </item>

</layer-list>

布局文件中声明如下:

<SeekBar
        android:id="@+id/proSeek1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/proSeek2"
        android:paddingBottom="10dp"
        android:paddingLeft="5dp"
        android:paddingRight="5dp"
        android:paddingTop="10dp"
        android:progressDrawable="@drawable/seekbar_style_own"
        android:secondaryProgress="0"
        android:thumb="@drawable/thumb_selector" />

再下面就是垂直滑动条的实现

布局文件中声明

<com.example.seekbar.verSeekBar
        android:id="@+id/verBar"
        android:layout_width="30dip"
        android:layout_height="match_parent"
        android:layout_below="@id/proSeek1"
        android:progressDrawable="@drawable/seekbar_style_own" />

verSeekBar.java文件
package com.example.seekbar;

/*
 *Author: tanrui
 *Date: 20/1/2010
 */

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AbsSeekBar;

public class verSeekBar extends AbsSeekBar {
	private Drawable mThumb;
	private int height;
	private int width;
	
	public static final int TOP = 0;
	public static final int BUTTOM = 1;
	
	private int mntype = TOP;
	

	public interface OnSeekBarChangeListener {
		void onProgressChanged(verSeekBar VerticalSeekBar, int progress,
				boolean fromUser);

		void onStartTrackingTouch(verSeekBar VerticalSeekBar);

		void onStopTrackingTouch(verSeekBar VerticalSeekBar);
	}

	private OnSeekBarChangeListener mOnSeekBarChangeListener;

	public verSeekBar(Context context) {
		this(context, null);
	}

	public verSeekBar(Context context, AttributeSet attrs) {
		this(context, attrs, android.R.attr.seekBarStyle);
	}

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

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

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

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

	void onProgressRefresh(float scale, boolean fromUser) {
		Log.i("6", "onProgressRefresh==>scale"+scale);
		Drawable thumb = mThumb;
		if (thumb != null) {
			setThumbPos(getHeight(), thumb, scale, Integer.MIN_VALUE);
			invalidate();
		}
		if (mOnSeekBarChangeListener != null) {
			mOnSeekBarChangeListener.onProgressChanged(this, getProgress(),
					fromUser);
		}
	}
	
	public void setType(int type)
	{
		mntype = type;
	}

	private void setThumbPos(int w, Drawable thumb, float scale, int gap) {
		Log.i("6", "setThumbPos==>w"+w);
		int available = w + getPaddingLeft() - getPaddingRight();
		int thumbWidth = thumb.getIntrinsicWidth();
		int thumbHeight = thumb.getIntrinsicHeight();
		available -= thumbWidth;
		// The extra space for the thumb to move on the track
		available += getThumbOffset()* 2;
		int thumbPos = (int) (scale * available);
		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);
	}

	protected void onDraw(Canvas c) {
		Log.i("6", "onDraw==>height"+height);
		if(mntype == TOP)
		{
		c.rotate(90);
		c.translate(0, -width);
		}
		else {
			c.rotate(-90);
			c.translate(-height, 0);
		}
		super.onDraw(c);
	}

	protected synchronized void onMeasure(int widthMeasureSpec,
			int heightMeasureSpec) {
		// width = 200;
		// height = 120;
		height = View.MeasureSpec.getSize(heightMeasureSpec);
		width = View.MeasureSpec.getSize(widthMeasureSpec);
		Log.i("6", "onMeasure==>height,,width"+height+"     "+width);
		this.setMeasuredDimension(width, height);

	}

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

	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		Log.i("6", "onSizeChanged==>w,,h,,oldw,,oldh"+w+"     "+h+"     "+oldw+"     "+oldh);
		super.onSizeChanged(h, w, oldw, oldh);
	}

	public boolean onTouchEvent(MotionEvent event) {
		if (!isEnabled()) {
			return false;
		}
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			setPressed(true);
			onStartTrackingTouch();
			trackTouchEvent(event);
			break;

		case MotionEvent.ACTION_MOVE:
			trackTouchEvent(event);
			attemptClaimDrag();
			break;

		case MotionEvent.ACTION_UP:
			trackTouchEvent(event);
			onStopTrackingTouch();
			setPressed(false);
			break;

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

	private void trackTouchEvent(MotionEvent event) {
		final int Height = getHeight();
		Log.i("6", "trackTouchEvent==>Height"+Height);
		final int available = Height - getPaddingBottom() - getPaddingTop();
		int Y = (int) event.getY();
		Log.i("6", "trackTouchEvent==>Y"+Y);
		float scale;
		float progress = 0;
		if (Y > Height - getPaddingBottom()) {
			scale = 1.0f;
		} else if (Y < getPaddingTop()) {
			scale = 0.0f;
		} else {
			scale = (float) (Y)
					/ (float) available;
		}

		final int max = getMax();
		progress = scale * max;
		int temp;
		if(mntype == TOP)
		{
			temp = (int) progress;
		}
		else
		{
			temp = (int) (max - progress);
		}
		setProgress(temp);
	}

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

	public boolean dispatchKeyEvent(KeyEvent event) {
		if (event.getAction() == KeyEvent.ACTION_DOWN) {
			KeyEvent newEvent = null;
			switch (event.getKeyCode()) {
			case KeyEvent.KEYCODE_DPAD_UP:
				newEvent = new KeyEvent(KeyEvent.ACTION_DOWN,
						KeyEvent.KEYCODE_DPAD_RIGHT);
				break;
			case KeyEvent.KEYCODE_DPAD_DOWN:
				newEvent = new KeyEvent(KeyEvent.ACTION_DOWN,
						KeyEvent.KEYCODE_DPAD_LEFT);
				break;
			case KeyEvent.KEYCODE_DPAD_LEFT:
				newEvent = new KeyEvent(KeyEvent.ACTION_DOWN,
						KeyEvent.KEYCODE_DPAD_DOWN);
				break;
			case KeyEvent.KEYCODE_DPAD_RIGHT:
				newEvent = new KeyEvent(KeyEvent.ACTION_DOWN,
						KeyEvent.KEYCODE_DPAD_UP);
				break;
			default:
				newEvent = new KeyEvent(KeyEvent.ACTION_DOWN, event
						.getKeyCode());
				break;
			}
			return newEvent.dispatch(this);
		}
		return false;
	}
}

另外一个只是更新样式就可以,这里就不写出来了,附上源码供大家参考

点击打开链接

上面提到的图片不能根据控件大小进行拉伸找到解决办法了,原来Android给我们提供了一个工具制作9.png格式的文件,这种格式的图片可以根据控件大小自适应调节大小而不失真。这个工具是draw9patch.bat  在Android  SDK的tools目录下可以找到。来看下修改过后的效果

Android惯用控件之SeekBar的使用

是不是比上面那张好看多了,只需要把.png格式的图片用工具改成9.png格式就OK了。

在这里需要感谢石同事给我的帮助!