1. 程式人生 > >Android常用控制元件之SeekBar的使用

Android常用控制元件之SeekBar的使用

SeekBar的應用非常廣,比如用來顯示音量條、播放進度條,有水平顯示也有垂直顯示,但Android只給我們提供了水平的,可以用系統預設的樣式也可以用我們自定義的樣式,總之進度條的用法多種多樣,如果Android沒有提供也能我們自己去定製,先上圖


使用圖片自定義水平進度條時有個缺陷,就是圖片不能根據進度條的大小進行拉伸,也就是自適應進度條的長度。當然也可以通過改變進度條的寬度跟圖片寬度一致,這樣就不會出現上面的情況。我想讓圖片適應進度條的大小,但還沒找到解決辦法,我想通過廣大網友一起想想辦法如何解決這樣問題,有知道的朋友可以告訴我,感激不盡!

上圖顯示的第一個進度條是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目錄下可以找到。來看下修改過後的效果


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

當然如果用了9.png的圖片,選擇圖片的配置也需要修改

<?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">
        <nine-patch android:src="@drawable/seek_bg" />
    </item>
    <item android:id="@android:id/progress">
        <clip>
            <nine-patch android:src="@drawable/seek_progress" />
        </clip>
    </item>

</layer-list>

這樣進度條就能正常顯示了。

在這裡需要感謝石同事給我的幫助!