android CircularSeekBar

Android 中的 seekBar会被开发者经常用到,用的最多的空拍是控制音量。但是有时后为了更好的UI效果,横着的拖动条不能满足我们项目的需要,我们可能需要竖直的或者圆形的拖动条,那这两种样式的类SeekBar的效果如何实现呢,接下来小编会一一给出效果和源码。接下来,先说一说圆形的效果吧,有图有真相,请看图:

       

看过图之后是不是觉得很炫,自己赞一个,下面给出源码:


/values/attr.xml:  

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="HoloCircleSeekBar">
        <attr name="wheel_size" format="integer" />
        <attr name="pointer_size" format="integer" />
        <attr name="max" format="integer"></attr>
        <attr name="show_text" format="boolean"></attr>
        <attr name="start_angle" format="integer"></attr>
        <attr name="end_angle" format="integer"></attr>
        <attr name="text_size" format="integer"></attr>
        <attr name="init_position" format="integer"></attr>
        <attr name="color" format="string"></attr>
        <attr name="wheel_active_color" format="string"></attr>
        <attr name="wheel_unactive_color" format="string"></attr>
        <attr name="pointer_color" format="string"></attr>
        <attr name="pointer_halo_color" format="string"></attr>
        <attr name="text_color" format="string"></attr>
    </declare-styleable>

</resources>

ZJBCircleSeekBar.java:

package com.example.circleseekbar;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.SweepGradient;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * @author zjbpku
 * @time 2013-08-21
 * @blog http://blog.csdn.net/zjbpku
 */

public class ZJBCircleSeekBar extends View {
	/**
	 * 保存状态
	 */
	private static final String STATE_PARENT = "parent";
	private static final String STATE_ANGLE = "angle";

	/***
	 * 事件监听
	 */
	private OnCircleSeekBarChangeListener mOnCircleSeekBarChangeListener;

	/**
	 * 圆环paint对象
	 */
	private Paint mColorWheelPaint;

	/**
	 * 游标paint对象
	 */
	private Paint mPointerHaloPaint;

	/**
	 * 游标为图画时的paint对象
	 */
	private Paint mPointerColor;

	/**
	 * 圆环的宽度
	 */
	private final int mColorWheelStrokeWidth = 10;

	/**
	 * 游标所在圆环半径
	 */
	private final int mPointerRadius = 80;

	/**
	 * The rectangle enclosing the color wheel.
	 */
	private RectF mColorWheelRectangle = new RectF();

	/**
	 * {@code true} 点击游标 {@code false} 停止
	 * 
	 * @see #onTouchEvent(MotionEvent)
	 */
	private boolean mUserIsMovingPointer = false;

	/**
	 * 
	 */
	private float mTranslationOffset;

	/**
	 * 圆环半径 Note: (Re)在onMeasure计算{@link #onMeasure(int, int)}
	 */
	private float mColorWheelRadius;

	private float mAngle;
	private String text;
	private int conversion = 0;
	private int max = 100;
	private String color_attr;
	private SweepGradient s;
	private Paint mArcColor;
	private String wheel_color_attr, wheel_unactive_color_attr,
			pointer_color_attr, pointer_halo_color_attr;
	private int init_position;
	private boolean block_end = false;
	private float lastX;
	private int last_radians = 0;
	private boolean block_start = false;

	private int arc_finish_radians = 270;
	// 左下角开始
	private int start_arc = 135;

	private float[] pointerPosition;
	private Paint mColorCenterHalo;
	private RectF mColorCenterHaloRectangle = new RectF();
	private int end_wheel;

	private Bitmap pointerBitmap;
	private boolean show_text = false;

	public ZJBCircleSeekBar(Context context) {
		super(context);
		init(null, 0);
	}

	public ZJBCircleSeekBar(Context context, AttributeSet attrs) {
		super(context, attrs);
		init(attrs, 0);
	}

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

	private void init(AttributeSet attrs, int defStyle) {
		final TypedArray a = getContext().obtainStyledAttributes(attrs,
				R.styleable.HoloCircleSeekBar, defStyle, 0);

		initAttributes(a);

		a.recycle();
		// mAngle = (float) (-Math.PI / 2);

		mColorWheelPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		mColorWheelPaint.setShader(s);
		mColorWheelPaint.setColor(Color.BLACK);
		mColorWheelPaint.setStyle(Paint.Style.STROKE);
		mColorWheelPaint.setStrokeWidth(mColorWheelStrokeWidth);

		mColorCenterHalo = new Paint(Paint.ANTI_ALIAS_FLAG);
		mColorCenterHalo.setColor(Color.CYAN);
		mColorCenterHalo.setAlpha(0xCC);
		// mColorCenterHalo.setStyle(Paint.Style.STROKE);
		// mColorCenterHalo.setStrokeWidth(mColorCenterHaloRectangle.width() /
		// 2);

		mPointerHaloPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		mPointerHaloPaint.setColor(Color.GREEN);
		mPointerHaloPaint.setStrokeWidth(mPointerRadius + 10);
		// mPointerHaloPaint.setAlpha(150);
		// 游标图片
		pointerBitmap = BitmapFactory.decodeResource(this.getResources(),
				R.drawable.pointer);

		mPointerColor = new Paint(Paint.ANTI_ALIAS_FLAG);
		mPointerColor.setStrokeWidth(mPointerRadius);

		// 设置游标指针的颜色
		mPointerColor.setColor(Color.GREEN);

		// 设置游标滑过的背景属性
		mArcColor = new Paint(Paint.ANTI_ALIAS_FLAG);
		mArcColor.setColor(Color.GREEN);
		mArcColor.setStyle(Paint.Style.STROKE);
		mArcColor.setStrokeWidth(mColorWheelStrokeWidth);

		arc_finish_radians = (int) calculateAngleFromText(init_position) - 90;

		if (arc_finish_radians > end_wheel)
			arc_finish_radians = end_wheel;
		mAngle = calculateAngleFromRadians(arc_finish_radians > end_wheel ? end_wheel
				: arc_finish_radians);
		text = String.valueOf(calculateTextFromAngle(arc_finish_radians));

		invalidate();
	}

	private void initAttributes(TypedArray a) {

		max = a.getInteger(R.styleable.HoloCircleSeekBar_max, 100);

		color_attr = a.getString(R.styleable.HoloCircleSeekBar_color);
		wheel_color_attr = a
				.getString(R.styleable.HoloCircleSeekBar_wheel_active_color);
		wheel_unactive_color_attr = a
				.getString(R.styleable.HoloCircleSeekBar_wheel_unactive_color);
		pointer_color_attr = a
				.getString(R.styleable.HoloCircleSeekBar_pointer_color);
		pointer_halo_color_attr = a
				.getString(R.styleable.HoloCircleSeekBar_pointer_halo_color);

		a.getString(R.styleable.HoloCircleSeekBar_text_color);

		a.getInteger(R.styleable.HoloCircleSeekBar_text_size, 95);

		init_position = a.getInteger(
				R.styleable.HoloCircleSeekBar_init_position, 0);

		start_arc = a.getInteger(R.styleable.HoloCircleSeekBar_start_angle, 0);
		end_wheel = a.getInteger(R.styleable.HoloCircleSeekBar_end_angle, 360);

		show_text = a.getBoolean(R.styleable.HoloCircleSeekBar_show_text, true);

		last_radians = end_wheel;

		if (init_position < start_arc)
			init_position = calculateTextFromStartAngle(start_arc);

		// mAngle = (float) calculateAngleFromText(init_position);

		if (color_attr != null) {
			try {
				Color.parseColor(color_attr);
			} catch (IllegalArgumentException e) {
			}
			Color.parseColor(color_attr);
		} else {
		}

		if (wheel_color_attr != null) {
			try {
				Color.parseColor(wheel_color_attr);
			} catch (IllegalArgumentException e) {
			}

		} else {
		}
		if (wheel_unactive_color_attr != null) {
			try {
				Color.parseColor(wheel_unactive_color_attr);
			} catch (IllegalArgumentException e) {
			}

		} else {
		}

		if (pointer_color_attr != null) {
			try {
				Color.parseColor(pointer_color_attr);
			} catch (IllegalArgumentException e) {
			}

		} else {
		}

		if (pointer_halo_color_attr != null) {
			try {
				Color.parseColor(pointer_halo_color_attr);
			} catch (IllegalArgumentException e) {
			}

		} else {
		}

	}

	@Override
	protected void onDraw(Canvas canvas) {
		canvas.translate(mTranslationOffset, mTranslationOffset);

		// 滑过的弧
		canvas.drawArc(mColorWheelRectangle, start_arc + 270, end_wheel
				- (start_arc), false, mColorWheelPaint);

		// 背景弧
		canvas.drawArc(mColorWheelRectangle, start_arc + 270,
				(arc_finish_radians) > (end_wheel) ? end_wheel - (start_arc)
						: arc_finish_radians - start_arc, false, mArcColor);
		// 游标为圆形
		// canvas.drawCircle(pointerPosition[0], pointerPosition[1],
		// mPointerRadius, mPointerHaloPaint);
		//
		// canvas.drawCircle(pointerPosition[0], pointerPosition[1],
		// (float) (mPointerRadius / 1.2), mPointerColor);

		// 游标为方形
		// canvas.drawRect(pointerPosition[0] - 50, pointerPosition[1] - 30,
		// pointerPosition[0] + 50, pointerPosition[1] + 30, mPointerColor);

		// 游标为图片
		canvas.drawBitmap(pointerBitmap, pointerPosition[0] - 50,
				pointerPosition[1] - 115, null);

		// 添加游标上的文字
		Paint pai = new Paint();
		pai.setColor(Color.BLACK);
		pai.setTextSize(50);
		canvas.drawText(text, pointerPosition[0] - 30, pointerPosition[1] - 40,
				pai);

	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		int height = getDefaultSize(getSuggestedMinimumHeight(),
				heightMeasureSpec);
		int width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
		int min = Math.min(width, height);
		setMeasuredDimension(min, min);

		mTranslationOffset = min * 0.5f;
		mColorWheelRadius = mTranslationOffset - mPointerRadius;

		mColorWheelRectangle.set(-mColorWheelRadius, -mColorWheelRadius,
				mColorWheelRadius, mColorWheelRadius);

		mColorCenterHaloRectangle.set(-mColorWheelRadius / 2,
				-mColorWheelRadius / 2, mColorWheelRadius / 2,
				mColorWheelRadius / 2);

		pointerPosition = calculatePointerPosition(mAngle);

	}

	private int calculateTextFromAngle(float angle) {
		float m = angle - start_arc;

		float f = (float) ((end_wheel - start_arc) / m);

		return (int) (max / f);
	}

	private int calculateTextFromStartAngle(float angle) {
		float m = angle;

		float f = (float) ((end_wheel - start_arc) / m);

		return (int) (max / f);
	}

	private double calculateAngleFromText(int position) {
		if (position == 0 || position >= max)
			return (float) 90;

		double f = (double) max / (double) position;

		double f_r = 360 / f;

		double ang = f_r + 90;

		return ang;

	}

	private int calculateRadiansFromAngle(float angle) {
		float unit = (float) (angle / (2 * Math.PI));
		if (unit < 0) {
			unit += 1;
		}
		int radians = (int) ((unit * 360) - ((360 / 4) * 3));
		if (radians < 0)
			radians += 360;
		return radians;
	}

	private float calculateAngleFromRadians(int radians) {
		return (float) (((radians + 270) * (2 * Math.PI)) / 360);
	}

	public int getValue() {
		return conversion;
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// Convert coordinates to our internal coordinate system
		float x = event.getX() - mTranslationOffset;
		float y = event.getY() - mTranslationOffset;

		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			// Check whether the user pressed on (or near) the pointer
			mAngle = (float) java.lang.Math.atan2(y, x);

			block_end = false;
			block_start = false;
			mUserIsMovingPointer = true;

			arc_finish_radians = calculateRadiansFromAngle(mAngle);

			if (arc_finish_radians > end_wheel) {
				arc_finish_radians = end_wheel;
				block_end = true;
			}

			if (!block_end && !block_start) {
				text = String
						.valueOf(calculateTextFromAngle(arc_finish_radians));
				pointerPosition = calculatePointerPosition(mAngle);
				invalidate();
			}
			break;
		case MotionEvent.ACTION_MOVE:
			if (mUserIsMovingPointer) {
				mAngle = (float) java.lang.Math.atan2(y, x);

				int radians = calculateRadiansFromAngle(mAngle);

				if (last_radians > radians && radians < (360 / 6) && x > lastX
						&& last_radians > (360 / 6)) {

					if (!block_end && !block_start)
						block_end = true;

				} else if (last_radians >= start_arc
						&& last_radians <= (360 / 4) && radians <= (360 - 1)
						&& radians >= ((360 / 4) * 3) && x < lastX) {
					if (!block_start && !block_end)
						block_start = true;

				} else if (radians >= end_wheel && !block_start
						&& last_radians < radians) {
					block_end = true;
				} else if (radians < end_wheel && block_end
						&& last_radians > end_wheel) {
					block_end = false;
				} else if (radians < start_arc && last_radians > radians
						&& !block_end) {
					block_start = true;
				} else if (block_start && last_radians < radians
						&& radians > start_arc && radians < end_wheel) {
					block_start = false;
				}

				if (block_end) {

					arc_finish_radians = end_wheel - 1;
					text = String.valueOf(0);
					mAngle = calculateAngleFromRadians(arc_finish_radians);
					pointerPosition = calculatePointerPosition(mAngle);
				} else if (block_start) {

					arc_finish_radians = start_arc;
					mAngle = calculateAngleFromRadians(arc_finish_radians);
					text = String.valueOf(0);
					pointerPosition = calculatePointerPosition(mAngle);
				} else {
					// text = String.valueOf(calculateTextFromAngle(mAngle));
					arc_finish_radians = calculateRadiansFromAngle(mAngle);
					text = String
							.valueOf(calculateTextFromAngle(arc_finish_radians));
					pointerPosition = calculatePointerPosition(mAngle);
				}
				invalidate();
				if (mOnCircleSeekBarChangeListener != null)
					mOnCircleSeekBarChangeListener.onProgressChanged(this,
							Integer.parseInt(text), true);

				last_radians = radians;

			}
			break;
		case MotionEvent.ACTION_UP:
			mUserIsMovingPointer = false;
			break;
		}
		if (event.getAction() == MotionEvent.ACTION_MOVE && getParent() != null) {
			getParent().requestDisallowInterceptTouchEvent(true);
		}
		lastX = x;

		return true;
	}

	/**
	 * Calculate the pointer's coordinates on the color wheel using the supplied
	 * angle.
	 * 
	 * @param angle
	 *            The position of the pointer expressed as angle (in rad).
	 * 
	 * @return The coordinates of the pointer's center in our internal
	 *         coordinate system.
	 */
	private float[] calculatePointerPosition(float angle) {
		// if (calculateRadiansFromAngle(angle) > end_wheel)
		// angle = calculateAngleFromRadians(end_wheel);
		float x = (float) (mColorWheelRadius * Math.cos(angle));
		float y = (float) (mColorWheelRadius * Math.sin(angle));

		return new float[] { x, y };
	}

	@Override
	protected Parcelable onSaveInstanceState() {
		Parcelable superState = super.onSaveInstanceState();

		Bundle state = new Bundle();
		state.putParcelable(STATE_PARENT, superState);
		state.putFloat(STATE_ANGLE, mAngle);

		return state;
	}

	@Override
	protected void onRestoreInstanceState(Parcelable state) {
		Bundle savedState = (Bundle) state;

		Parcelable superState = savedState.getParcelable(STATE_PARENT);
		super.onRestoreInstanceState(superState);

		mAngle = savedState.getFloat(STATE_ANGLE);
		arc_finish_radians = calculateRadiansFromAngle(mAngle);
		text = String.valueOf(calculateTextFromAngle(arc_finish_radians));
		pointerPosition = calculatePointerPosition(mAngle);

	}

	public void setOnSeekBarChangeListener(OnCircleSeekBarChangeListener l) {
		mOnCircleSeekBarChangeListener = l;
	}

	public interface OnCircleSeekBarChangeListener {

		public abstract void onProgressChanged(ZJBCircleSeekBar seekBar,
				int progress, boolean fromUser);

	}

}

/layout/activity_main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_gravity="center_horizontal"
    tools:context=".MainActivity" >

    <TextView
        android:id="@+id/text"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="80dp"
        android:gravity="center_horizontal"
        android:textSize="60sp" 
        android:textColor="#ffff0000"
        />

    <com.example.circleseekbar.HoloCircleSeekBar
        android:id="@+id/c"
        android:layout_width="500px"
        android:layout_height="500px"
        android:layout_centerInParent="true" />

</RelativeLayout>

MainActivity.java:

package com.example.circleseekbar;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

import com.example.circleseekbar.ZJBCircleSeekBar.OnCircleSeekBarChangeListener;

/**
 * @author zjbpku
 * @time 2013-08-21
 * @blog http://blog.csdn.net/zjbpku
 */
public class MainActivity extends Activity implements
		OnCircleSeekBarChangeListener {

	private ZJBCircleSeekBar circleSeekBar;
	TextView textView;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		circleSeekBar = (ZJBCircleSeekBar) findViewById(R.id.c);
		textView = (TextView) findViewById(R.id.text);
		circleSeekBar.setOnSeekBarChangeListener(this);
	}

	@Override
	public void onProgressChanged(ZJBCircleSeekBar seekBar, int progress,
			boolean fromUser) {
		// TODO Auto-generated method stub
		textView.setText(progress + "");
	}

}
小编很辛苦,请尊重菜鸟的劳动成果,转载请注明出处:http://blog.csdn.net/zjbpku/article/details/10140815

阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页