原文地址: http://blog.csdn.net/ly0904010214/article/details/42805363
由于android系统提供的SeekBar是直线型的。但是有些时候我们需要用到其他形状的SeekBar,那么就需要自定义View来实现。这里只是实现了一个环形的,其他形状的类似。
效果图如下
CircleSeekBar文件如下
- package com.lee.circleseekbar.view;
-
- import com.lee.circleseekbar.R;
-
- import android.content.Context;
- import android.content.res.TypedArray;
- import android.graphics.Canvas;
- import android.graphics.Color;
- import android.graphics.Paint;
- import android.graphics.RectF;
- import android.graphics.drawable.Drawable;
- import android.util.AttributeSet;
- import android.util.Log;
- import android.view.MotionEvent;
- import android.view.View;
-
-
-
-
-
-
-
-
-
- public class CircleSeekBar extends View {
-
- private final boolean DEBUG = true;
- private final String TAG = "CircleSeekBar";
-
- private Context mContext = null;
-
- private Drawable mThumbDrawable = null;
- private int mThumbHeight = 0;
- private int mThumbWidth = 0;
- private int[] mThumbNormal = null;
- private int[] mThumbPressed = null;
-
- private int mSeekBarMax = 0;
- private Paint mSeekBarBackgroundPaint = null;
- private Paint mSeekbarProgressPaint = null;
- private RectF mArcRectF = null;
-
- private boolean mIsShowProgressText = false;
- private Paint mProgressTextPaint = null;
- private int mProgressTextSize = 0;
-
- private int mViewHeight = 0;
- private int mViewWidth = 0;
- private int mSeekBarSize = 0;
- private int mSeekBarRadius = 0;
- private int mSeekBarCenterX = 0;
- private int mSeekBarCenterY = 0;
- private float mThumbLeft = 0;
- private float mThumbTop = 0;
-
- private float mSeekBarDegree = 0;
- private int mCurrentProgress = 0;
-
- private OnSeekBarChangeListener mOnSeekBarChangeListener = null;
-
- public interface OnSeekBarChangeListener {
-
- void onProgressChanged(int progress);
-
- void onStartTrackingTouch();
-
- void onStopTrackingTouch();
- }
-
- public CircleSeekBar(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- mContext = context;
- initViewAttrs(attrs);
- mArcRectF = new RectF();
- }
-
- public CircleSeekBar(Context context, AttributeSet attrs) {
- super(context, attrs);
- mContext = context;
- initViewAttrs(attrs);
- mArcRectF = new RectF();
- }
-
- public CircleSeekBar(Context context) {
- super(context);
- mContext = context;
- initViewDefault();
- mArcRectF = new RectF();
- }
-
- private void initViewAttrs(AttributeSet attrs){
- if(DEBUG) Log.d(TAG, "initView");
- TypedArray localTypedArray = mContext.obtainStyledAttributes(attrs, R.styleable.CircleSeekBar);
-
-
-
-
- mThumbDrawable = localTypedArray.getDrawable(R.styleable.CircleSeekBar_android_thumb);
- mThumbWidth = mThumbDrawable.getIntrinsicWidth();
- mThumbHeight = mThumbDrawable.getIntrinsicHeight();
-
- mThumbNormal = new int[]{-android.R.attr.state_focused, -android.R.attr.state_pressed,
- -android.R.attr.state_selected, -android.R.attr.state_checked};
- mThumbPressed = new int[]{android.R.attr.state_focused, android.R.attr.state_pressed,
- android.R.attr.state_selected, android.R.attr.state_checked};
-
- float progressWidth = localTypedArray.getDimension(R.styleable.CircleSeekBar_progress_width, 5);
- int progressBackgroundColor = localTypedArray.getColor(R.styleable.CircleSeekBar_progress_background, Color.GRAY);
- int progressFrontColor = localTypedArray.getColor(R.styleable.CircleSeekBar_progress_front, Color.BLUE);
- mSeekBarMax = localTypedArray.getInteger(R.styleable.CircleSeekBar_progress_max, 100);
-
- mSeekbarProgressPaint = new Paint();
- mSeekBarBackgroundPaint = new Paint();
-
- mSeekbarProgressPaint.setColor(progressFrontColor);
- mSeekBarBackgroundPaint.setColor(progressBackgroundColor);
-
- mSeekbarProgressPaint.setAntiAlias(true);
- mSeekBarBackgroundPaint.setAntiAlias(true);
-
- mSeekbarProgressPaint.setStyle(Paint.Style.STROKE);
- mSeekBarBackgroundPaint.setStyle(Paint.Style.STROKE);
-
- mSeekbarProgressPaint.setStrokeWidth(progressWidth);
- mSeekBarBackgroundPaint.setStrokeWidth(progressWidth);
-
- mIsShowProgressText = localTypedArray.getBoolean(R.styleable.CircleSeekBar_show_progress_text, false);
- int progressTextStroke = (int) localTypedArray.getDimension(R.styleable.CircleSeekBar_progress_text_stroke_width, 5);
- int progressTextColor = localTypedArray.getColor(R.styleable.CircleSeekBar_progress_text_color, Color.GREEN);
- mProgressTextSize = (int) localTypedArray.getDimension(R.styleable.CircleSeekBar_progress_text_size, 50);
-
- mProgressTextPaint = new Paint();
- mProgressTextPaint.setColor(progressTextColor);
- mProgressTextPaint.setAntiAlias(true);
- mProgressTextPaint.setStrokeWidth(progressTextStroke);
- mProgressTextPaint.setTextSize(mProgressTextSize);
-
- localTypedArray.recycle();
- }
-
- private void initViewDefault(){
- mThumbDrawable = null;
- mThumbWidth = 0;
- mThumbHeight = 0;
-
- mThumbNormal = new int[]{-android.R.attr.state_focused, -android.R.attr.state_pressed,
- -android.R.attr.state_selected, -android.R.attr.state_checked};
- mThumbPressed = new int[]{android.R.attr.state_focused, android.R.attr.state_pressed,
- android.R.attr.state_selected, android.R.attr.state_checked};
-
- float progressWidth = 5;
- int progressBackgroundColor = Color.GRAY;
- int progressFrontColor = Color.BLUE;
- mSeekBarMax = 100;
-
- mSeekbarProgressPaint = new Paint();
- mSeekBarBackgroundPaint = new Paint();
-
- mSeekbarProgressPaint.setColor(progressFrontColor);
- mSeekBarBackgroundPaint.setColor(progressBackgroundColor);
-
- mSeekbarProgressPaint.setAntiAlias(true);
- mSeekBarBackgroundPaint.setAntiAlias(true);
-
- mSeekbarProgressPaint.setStyle(Paint.Style.STROKE);
- mSeekBarBackgroundPaint.setStyle(Paint.Style.STROKE);
-
- mSeekbarProgressPaint.setStrokeWidth(progressWidth);
- mSeekBarBackgroundPaint.setStrokeWidth(progressWidth);
-
- mIsShowProgressText = false;
- int progressTextStroke = 5;
- int progressTextColor = Color.GREEN;
- mProgressTextSize = 50;
-
- mProgressTextPaint = new Paint();
- mProgressTextPaint.setColor(progressTextColor);
- mProgressTextPaint.setAntiAlias(true);
- mProgressTextPaint.setStrokeWidth(progressTextStroke);
- mProgressTextPaint.setTextSize(mProgressTextSize);
- }
-
- @Override
- protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- if(DEBUG) Log.d(TAG, "onMeasure");
- mViewWidth = getWidth();
- mViewHeight = getHeight();
-
- mSeekBarSize = mViewWidth > mViewHeight ? mViewHeight : mViewWidth;
-
- mSeekBarCenterX = mViewWidth / 2;
- mSeekBarCenterY = mViewHeight / 2;
-
- mSeekBarRadius = mSeekBarSize / 2 - mThumbWidth / 2;
-
- int left = mSeekBarCenterX - mSeekBarRadius;
- int right = mSeekBarCenterX + mSeekBarRadius;
- int top = mSeekBarCenterY - mSeekBarRadius;
- int bottom = mSeekBarCenterY + mSeekBarRadius;
- mArcRectF.set(left, top, right, bottom);
-
-
- setThumbPosition(Math.toRadians(mSeekBarDegree));
- }
-
- @Override
- protected synchronized void onDraw(Canvas canvas) {
- canvas.drawCircle(mSeekBarCenterX, mSeekBarCenterY, mSeekBarRadius,
- mSeekBarBackgroundPaint);
- canvas.drawArc(this.mArcRectF, 0.0F, mSeekBarDegree, false, mSeekbarProgressPaint);
- drawThumbBitmap(canvas);
- drawProgressText(canvas);
-
- super.onDraw(canvas);
- }
-
- private void drawThumbBitmap(Canvas canvas) {
- if(null != mThumbDrawable){
- mThumbDrawable.setBounds((int) mThumbLeft, (int) mThumbTop,
- (int) (mThumbLeft + mThumbWidth), (int) (mThumbTop + mThumbHeight));
- mThumbDrawable.draw(canvas);
- }
- }
-
- private void drawProgressText(Canvas canvas) {
- if (true == mIsShowProgressText){
- float textWidth = mProgressTextPaint.measureText("" + mCurrentProgress);
- canvas.drawText("" + mCurrentProgress, mSeekBarCenterX - textWidth / 2, mSeekBarCenterY
- + mProgressTextSize / 2, mProgressTextPaint);
- }
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- float eventX = event.getX();
- float eventY = event.getY();
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- if(null != mOnSeekBarChangeListener){
- mOnSeekBarChangeListener.onStartTrackingTouch();
- }
- seekTo(eventX, eventY, false);
- break ;
-
- case MotionEvent.ACTION_MOVE:
- seekTo(eventX, eventY, false);
- break ;
-
- case MotionEvent.ACTION_UP:
- if(null != mOnSeekBarChangeListener){
- mOnSeekBarChangeListener.onStopTrackingTouch();
- }
- seekTo(eventX, eventY, true);
- break ;
- }
- return true;
- }
-
- private void seekTo(float eventX, float eventY, boolean isUp) {
- if (true == isPointOnThumb(eventX, eventY) && false == isUp) {
- if(null != mThumbDrawable){
- mThumbDrawable.setState(mThumbPressed);
- }
- double radian = Math.atan2(eventY - mSeekBarCenterY, eventX - mSeekBarCenterX);
-
-
-
-
- if (radian < 0){
- radian = radian + 2*Math.PI;
- }
- if(DEBUG) Log.e(TAG, "seekTo radian = " + radian);
- setThumbPosition(radian);
-
- mSeekBarDegree = (float) Math.round(Math.toDegrees(radian));
- mCurrentProgress = (int) (mSeekBarMax * mSeekBarDegree / 360);
- if(null != mOnSeekBarChangeListener){
- mOnSeekBarChangeListener.onProgressChanged(mCurrentProgress);
- }
- invalidate();
- }else{
- if(null != mThumbDrawable){
- mThumbDrawable.setState(mThumbNormal);
- }
- invalidate();
- }
- }
-
- private boolean isPointOnThumb(float eventX, float eventY) {
- boolean result = false;
- double distance = Math.sqrt(Math.pow(eventX - mSeekBarCenterX, 2)
- + Math.pow(eventY - mSeekBarCenterY, 2));
- if (distance < mSeekBarSize && distance > (mSeekBarSize / 2 - mThumbWidth)){
- result = true;
- }
- return result;
- }
-
- private void setThumbPosition(double radian) {
- if(DEBUG) Log.v(TAG, "setThumbPosition radian = " + radian);
- double x = mSeekBarCenterX + mSeekBarRadius * Math.cos(radian);
- double y = mSeekBarCenterY + mSeekBarRadius * Math.sin(radian);
- mThumbLeft = (float) (x - mThumbWidth / 2);
- mThumbTop = (float) (y - mThumbHeight / 2);
- }
-
-
-
-
- public synchronized void setProgress(int progress) {
- if(DEBUG) Log.v(TAG, "setProgress progress = " + progress);
- if (progress > mSeekBarMax){
- progress = mSeekBarMax;
- }
- if (progress < 0){
- progress = 0;
- }
- mCurrentProgress = progress;
- mSeekBarDegree = (progress * 360 / mSeekBarMax);
- if(DEBUG) Log.d(TAG, "setProgress mSeekBarDegree = " + mSeekBarDegree);
- setThumbPosition(Math.toRadians(mSeekBarDegree));
-
- invalidate();
- }
-
- public synchronized int getProgress(){
- return mCurrentProgress;
- }
-
- public synchronized void setProgressMax(int max){
- if(DEBUG) Log.v(TAG, "setProgressMax max = " + max);
- mSeekBarMax = max;
- }
-
- public synchronized int getProgressMax(){
- return mSeekBarMax;
- }
-
- public void setProgressThumb(int thumbId){
- mThumbDrawable = mContext.getResources().getDrawable(thumbId);
- mThumbWidth = mThumbDrawable.getIntrinsicWidth();
- mThumbHeight = mThumbDrawable.getIntrinsicHeight();
- }
-
- public void setProgressWidth(int width){
- if(DEBUG) Log.v(TAG, "setProgressWidth width = " + width);
- mSeekbarProgressPaint.setStrokeWidth(width);
- mSeekBarBackgroundPaint.setStrokeWidth(width);
- }
-
- public void setProgressBackgroundColor(int color){
- mSeekBarBackgroundPaint.setColor(color);
- }
-
- public void setProgressFrontColor(int color){
- mSeekbarProgressPaint.setColor(color);
- }
-
- public void setProgressTextColor(int color){
- mProgressTextPaint.setColor(color);
- }
-
- public void setProgressTextSize(int size){
- if(DEBUG) Log.v(TAG, "setProgressTextSize size = " + size);
- mProgressTextPaint.setTextSize(size);
- }
-
- public void setProgressTextStrokeWidth(int width){
- if(DEBUG) Log.v(TAG, "setProgressTextStrokeWidth width = " + width);
- mProgressTextPaint.setStrokeWidth(width);
- }
-
- public void setIsShowProgressText(boolean isShow){
- mIsShowProgressText = isShow;
- }
-
-
-
-
-
- public void setOnSeekBarChangeListener(OnSeekBarChangeListener onSeekBarChangeListener){
- mOnSeekBarChangeListener = onSeekBarChangeListener;
- }
- }
xml文件如下
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:circle_seekbar="http://schemas.android.com/apk/res/com.lee.circleseekbar"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
-
- <com.lee.circleseekbar.view.CircleSeekBar
- android:id="@+id/circle_seekbar"
- android:layout_width="200dp"
- android:layout_height="200dp"
- android:layout_centerInParent="true"
- android:thumb="@drawable/thumb"
- circle_seekbar:progress_background="@android:color/darker_gray"
- circle_seekbar:progress_front="@android:color/holo_blue_light"
- circle_seekbar:progress_max="1000"
- circle_seekbar:progress_text_color="@android:color/holo_green_light"
- circle_seekbar:progress_text_size="30dp"
- circle_seekbar:progress_text_stroke_width="4dp"
- circle_seekbar:progress_width="2dp"
- circle_seekbar:show_progress_text="true" />
-
- RelativeLayout>
attrs属性文件如下
- xml version="1.0" encoding="utf-8"?>
- <resources>
-
- <declare-styleable name="CircleSeekBar">
- <attr name="android:thumb" />
- <attr name="progress_width" format="dimension" />
- <attr name="progress_background" format="color" />
- <attr name="progress_front" format="color" />
- <attr name="progress_max" format="integer" />
- <attr name="show_progress_text" format="boolean" />
- <attr name="progress_text_stroke_width" format="dimension" />
- <attr name="progress_text_color" format="color" />
- <attr name="progress_text_size" format="dimension" />
- declare-styleable>
-
- resources>
activity文件如下
- package com.lee.circleseekbar;
-
- import android.app.Activity;
- import android.graphics.Color;
- import android.os.Bundle;
- import android.util.Log;
- import android.view.LayoutInflater;
- import android.widget.RelativeLayout;
-
- import com.lee.circleseekbar.view.CircleSeekBar;
- import com.lee.circleseekbar.view.CircleSeekBar.OnSeekBarChangeListener;
-
- public class MainActivity extends Activity {
-
- private final boolean DEBUG = true;
- private final String TAG = "MainActivity";
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- RelativeLayout mainLayout = (RelativeLayout) LayoutInflater.from(this).inflate(R.layout.activity_main, null);
- setContentView(mainLayout);
-
- CircleSeekBar circleSeekBar = (CircleSeekBar) findViewById(R.id.circle_seekbar);
- circleSeekBar.setProgress(100);
- circleSeekBar.setProgressFrontColor(Color.RED);
- circleSeekBar.setOnSeekBarChangeListener(new CircleSeekBarOnChangeListener());
-
- CircleSeekBar circleSeekBar2 = new CircleSeekBar(this);
- circleSeekBar2.setProgress(10);
- circleSeekBar2.setProgressFrontColor(Color.RED);
- circleSeekBar2.setProgressThumb(R.drawable.thumb);
- circleSeekBar2.setOnSeekBarChangeListener(new CircleSeekBarOnChangeListener());
- RelativeLayout.LayoutParams circleSeekBarParams = new RelativeLayout.LayoutParams(200, 200);
- circleSeekBarParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
- mainLayout.addView(circleSeekBar2, circleSeekBarParams);
- }
-
- private class CircleSeekBarOnChangeListener implements OnSeekBarChangeListener{
-
- @Override
- public void onProgressChanged(int progress) {
- if(DEBUG) Log.d(TAG, "onProgressChanged progress = " + progress);
- }
-
- @Override
- public void onStartTrackingTouch() {
- if(DEBUG) Log.d(TAG, "onStartTrackingTouch");
- }
-
- @Override
- public void onStopTrackingTouch() {
- if(DEBUG) Log.d(TAG, "onStopTrackingTouch");
- }
-
- }
-
- }
Demo下载地址
http://download.csdn.net/detail/ly0904010214/8373347