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