android CircularSeekBar

时间:2024-01-07 13:29:08

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

android CircularSeekBar   android CircularSeekBar   android CircularSeekBar

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

/values/attr.xml:  

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <resources>
  3. <declare-styleable name="HoloCircleSeekBar">
  4. <attr name="wheel_size" format="integer" />
  5. <attr name="pointer_size" format="integer" />
  6. <attr name="max" format="integer"></attr>
  7. <attr name="show_text" format="boolean"></attr>
  8. <attr name="start_angle" format="integer"></attr>
  9. <attr name="end_angle" format="integer"></attr>
  10. <attr name="text_size" format="integer"></attr>
  11. <attr name="init_position" format="integer"></attr>
  12. <attr name="color" format="string"></attr>
  13. <attr name="wheel_active_color" format="string"></attr>
  14. <attr name="wheel_unactive_color" format="string"></attr>
  15. <attr name="pointer_color" format="string"></attr>
  16. <attr name="pointer_halo_color" format="string"></attr>
  17. <attr name="text_color" format="string"></attr>
  18. </declare-styleable>
  19. </resources>

ZJBCircleSeekBar.java:

  1. package com.example.circleseekbar;
  2. import android.content.Context;
  3. import android.content.res.TypedArray;
  4. import android.graphics.Bitmap;
  5. import android.graphics.BitmapFactory;
  6. import android.graphics.Canvas;
  7. import android.graphics.Color;
  8. import android.graphics.Paint;
  9. import android.graphics.Rect;
  10. import android.graphics.RectF;
  11. import android.graphics.SweepGradient;
  12. import android.os.Bundle;
  13. import android.os.Parcelable;
  14. import android.util.AttributeSet;
  15. import android.view.MotionEvent;
  16. import android.view.View;
  17. /**
  18. * @author zjbpku
  19. * @time 2013-08-21
  20. * @blog http://blog.csdn.net/zjbpku
  21. */
  22. public class ZJBCircleSeekBar extends View {
  23. /**
  24. * 保存状态
  25. */
  26. private static final String STATE_PARENT = "parent";
  27. private static final String STATE_ANGLE = "angle";
  28. /***
  29. * 事件监听
  30. */
  31. private OnCircleSeekBarChangeListener mOnCircleSeekBarChangeListener;
  32. /**
  33. * 圆环paint对象
  34. */
  35. private Paint mColorWheelPaint;
  36. /**
  37. * 游标paint对象
  38. */
  39. private Paint mPointerHaloPaint;
  40. /**
  41. * 游标为图画时的paint对象
  42. */
  43. private Paint mPointerColor;
  44. /**
  45. * 圆环的宽度
  46. */
  47. private final int mColorWheelStrokeWidth = 10;
  48. /**
  49. * 游标所在圆环半径
  50. */
  51. private final int mPointerRadius = 80;
  52. /**
  53. * The rectangle enclosing the color wheel.
  54. */
  55. private RectF mColorWheelRectangle = new RectF();
  56. /**
  57. * {@code true} 点击游标 {@code false} 停止
  58. *
  59. * @see #onTouchEvent(MotionEvent)
  60. */
  61. private boolean mUserIsMovingPointer = false;
  62. /**
  63. *
  64. */
  65. private float mTranslationOffset;
  66. /**
  67. * 圆环半径 Note: (Re)在onMeasure计算{@link #onMeasure(int, int)}
  68. */
  69. private float mColorWheelRadius;
  70. private float mAngle;
  71. private String text;
  72. private int conversion = 0;
  73. private int max = 100;
  74. private String color_attr;
  75. private SweepGradient s;
  76. private Paint mArcColor;
  77. private String wheel_color_attr, wheel_unactive_color_attr,
  78. pointer_color_attr, pointer_halo_color_attr;
  79. private int init_position;
  80. private boolean block_end = false;
  81. private float lastX;
  82. private int last_radians = 0;
  83. private boolean block_start = false;
  84. private int arc_finish_radians = 270;
  85. // 左下角开始
  86. private int start_arc = 135;
  87. private float[] pointerPosition;
  88. private Paint mColorCenterHalo;
  89. private RectF mColorCenterHaloRectangle = new RectF();
  90. private int end_wheel;
  91. private Bitmap pointerBitmap;
  92. private boolean show_text = false;
  93. public ZJBCircleSeekBar(Context context) {
  94. super(context);
  95. init(null, 0);
  96. }
  97. public ZJBCircleSeekBar(Context context, AttributeSet attrs) {
  98. super(context, attrs);
  99. init(attrs, 0);
  100. }
  101. public ZJBCircleSeekBar(Context context, AttributeSet attrs, int defStyle) {
  102. super(context, attrs, defStyle);
  103. init(attrs, defStyle);
  104. }
  105. private void init(AttributeSet attrs, int defStyle) {
  106. final TypedArray a = getContext().obtainStyledAttributes(attrs,
  107. R.styleable.HoloCircleSeekBar, defStyle, 0);
  108. initAttributes(a);
  109. a.recycle();
  110. // mAngle = (float) (-Math.PI / 2);
  111. mColorWheelPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
  112. mColorWheelPaint.setShader(s);
  113. mColorWheelPaint.setColor(Color.BLACK);
  114. mColorWheelPaint.setStyle(Paint.Style.STROKE);
  115. mColorWheelPaint.setStrokeWidth(mColorWheelStrokeWidth);
  116. mColorCenterHalo = new Paint(Paint.ANTI_ALIAS_FLAG);
  117. mColorCenterHalo.setColor(Color.CYAN);
  118. mColorCenterHalo.setAlpha(0xCC);
  119. // mColorCenterHalo.setStyle(Paint.Style.STROKE);
  120. // mColorCenterHalo.setStrokeWidth(mColorCenterHaloRectangle.width() /
  121. // 2);
  122. mPointerHaloPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
  123. mPointerHaloPaint.setColor(Color.GREEN);
  124. mPointerHaloPaint.setStrokeWidth(mPointerRadius + 10);
  125. // mPointerHaloPaint.setAlpha(150);
  126. // 游标图片
  127. pointerBitmap = BitmapFactory.decodeResource(this.getResources(),
  128. R.drawable.pointer);
  129. mPointerColor = new Paint(Paint.ANTI_ALIAS_FLAG);
  130. mPointerColor.setStrokeWidth(mPointerRadius);
  131. // 设置游标指针的颜色
  132. mPointerColor.setColor(Color.GREEN);
  133. // 设置游标滑过的背景属性
  134. mArcColor = new Paint(Paint.ANTI_ALIAS_FLAG);
  135. mArcColor.setColor(Color.GREEN);
  136. mArcColor.setStyle(Paint.Style.STROKE);
  137. mArcColor.setStrokeWidth(mColorWheelStrokeWidth);
  138. arc_finish_radians = (int) calculateAngleFromText(init_position) - 90;
  139. if (arc_finish_radians > end_wheel)
  140. arc_finish_radians = end_wheel;
  141. mAngle = calculateAngleFromRadians(arc_finish_radians > end_wheel ? end_wheel
  142. : arc_finish_radians);
  143. text = String.valueOf(calculateTextFromAngle(arc_finish_radians));
  144. invalidate();
  145. }
  146. private void initAttributes(TypedArray a) {
  147. max = a.getInteger(R.styleable.HoloCircleSeekBar_max, 100);
  148. color_attr = a.getString(R.styleable.HoloCircleSeekBar_color);
  149. wheel_color_attr = a
  150. .getString(R.styleable.HoloCircleSeekBar_wheel_active_color);
  151. wheel_unactive_color_attr = a
  152. .getString(R.styleable.HoloCircleSeekBar_wheel_unactive_color);
  153. pointer_color_attr = a
  154. .getString(R.styleable.HoloCircleSeekBar_pointer_color);
  155. pointer_halo_color_attr = a
  156. .getString(R.styleable.HoloCircleSeekBar_pointer_halo_color);
  157. a.getString(R.styleable.HoloCircleSeekBar_text_color);
  158. a.getInteger(R.styleable.HoloCircleSeekBar_text_size, 95);
  159. init_position = a.getInteger(
  160. R.styleable.HoloCircleSeekBar_init_position, 0);
  161. start_arc = a.getInteger(R.styleable.HoloCircleSeekBar_start_angle, 0);
  162. end_wheel = a.getInteger(R.styleable.HoloCircleSeekBar_end_angle, 360);
  163. show_text = a.getBoolean(R.styleable.HoloCircleSeekBar_show_text, true);
  164. last_radians = end_wheel;
  165. if (init_position < start_arc)
  166. init_position = calculateTextFromStartAngle(start_arc);
  167. // mAngle = (float) calculateAngleFromText(init_position);
  168. if (color_attr != null) {
  169. try {
  170. Color.parseColor(color_attr);
  171. } catch (IllegalArgumentException e) {
  172. }
  173. Color.parseColor(color_attr);
  174. } else {
  175. }
  176. if (wheel_color_attr != null) {
  177. try {
  178. Color.parseColor(wheel_color_attr);
  179. } catch (IllegalArgumentException e) {
  180. }
  181. } else {
  182. }
  183. if (wheel_unactive_color_attr != null) {
  184. try {
  185. Color.parseColor(wheel_unactive_color_attr);
  186. } catch (IllegalArgumentException e) {
  187. }
  188. } else {
  189. }
  190. if (pointer_color_attr != null) {
  191. try {
  192. Color.parseColor(pointer_color_attr);
  193. } catch (IllegalArgumentException e) {
  194. }
  195. } else {
  196. }
  197. if (pointer_halo_color_attr != null) {
  198. try {
  199. Color.parseColor(pointer_halo_color_attr);
  200. } catch (IllegalArgumentException e) {
  201. }
  202. } else {
  203. }
  204. }
  205. @Override
  206. protected void onDraw(Canvas canvas) {
  207. canvas.translate(mTranslationOffset, mTranslationOffset);
  208. // 滑过的弧
  209. canvas.drawArc(mColorWheelRectangle, start_arc + 270, end_wheel
  210. - (start_arc), false, mColorWheelPaint);
  211. // 背景弧
  212. canvas.drawArc(mColorWheelRectangle, start_arc + 270,
  213. (arc_finish_radians) > (end_wheel) ? end_wheel - (start_arc)
  214. : arc_finish_radians - start_arc, false, mArcColor);
  215. // 游标为圆形
  216. // canvas.drawCircle(pointerPosition[0], pointerPosition[1],
  217. // mPointerRadius, mPointerHaloPaint);
  218. //
  219. // canvas.drawCircle(pointerPosition[0], pointerPosition[1],
  220. // (float) (mPointerRadius / 1.2), mPointerColor);
  221. // 游标为方形
  222. // canvas.drawRect(pointerPosition[0] - 50, pointerPosition[1] - 30,
  223. // pointerPosition[0] + 50, pointerPosition[1] + 30, mPointerColor);
  224. // 游标为图片
  225. canvas.drawBitmap(pointerBitmap, pointerPosition[0] - 50,
  226. pointerPosition[1] - 115, null);
  227. // 添加游标上的文字
  228. Paint pai = new Paint();
  229. pai.setColor(Color.BLACK);
  230. pai.setTextSize(50);
  231. canvas.drawText(text, pointerPosition[0] - 30, pointerPosition[1] - 40,
  232. pai);
  233. }
  234. @Override
  235. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  236. int height = getDefaultSize(getSuggestedMinimumHeight(),
  237. heightMeasureSpec);
  238. int width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
  239. int min = Math.min(width, height);
  240. setMeasuredDimension(min, min);
  241. mTranslationOffset = min * 0.5f;
  242. mColorWheelRadius = mTranslationOffset - mPointerRadius;
  243. mColorWheelRectangle.set(-mColorWheelRadius, -mColorWheelRadius,
  244. mColorWheelRadius, mColorWheelRadius);
  245. mColorCenterHaloRectangle.set(-mColorWheelRadius / 2,
  246. -mColorWheelRadius / 2, mColorWheelRadius / 2,
  247. mColorWheelRadius / 2);
  248. pointerPosition = calculatePointerPosition(mAngle);
  249. }
  250. private int calculateTextFromAngle(float angle) {
  251. float m = angle - start_arc;
  252. float f = (float) ((end_wheel - start_arc) / m);
  253. return (int) (max / f);
  254. }
  255. private int calculateTextFromStartAngle(float angle) {
  256. float m = angle;
  257. float f = (float) ((end_wheel - start_arc) / m);
  258. return (int) (max / f);
  259. }
  260. private double calculateAngleFromText(int position) {
  261. if (position == 0 || position >= max)
  262. return (float) 90;
  263. double f = (double) max / (double) position;
  264. double f_r = 360 / f;
  265. double ang = f_r + 90;
  266. return ang;
  267. }
  268. private int calculateRadiansFromAngle(float angle) {
  269. float unit = (float) (angle / (2 * Math.PI));
  270. if (unit < 0) {
  271. unit += 1;
  272. }
  273. int radians = (int) ((unit * 360) - ((360 / 4) * 3));
  274. if (radians < 0)
  275. radians += 360;
  276. return radians;
  277. }
  278. private float calculateAngleFromRadians(int radians) {
  279. return (float) (((radians + 270) * (2 * Math.PI)) / 360);
  280. }
  281. public int getValue() {
  282. return conversion;
  283. }
  284. @Override
  285. public boolean onTouchEvent(MotionEvent event) {
  286. // Convert coordinates to our internal coordinate system
  287. float x = event.getX() - mTranslationOffset;
  288. float y = event.getY() - mTranslationOffset;
  289. switch (event.getAction()) {
  290. case MotionEvent.ACTION_DOWN:
  291. // Check whether the user pressed on (or near) the pointer
  292. mAngle = (float) java.lang.Math.atan2(y, x);
  293. block_end = false;
  294. block_start = false;
  295. mUserIsMovingPointer = true;
  296. arc_finish_radians = calculateRadiansFromAngle(mAngle);
  297. if (arc_finish_radians > end_wheel) {
  298. arc_finish_radians = end_wheel;
  299. block_end = true;
  300. }
  301. if (!block_end && !block_start) {
  302. text = String
  303. .valueOf(calculateTextFromAngle(arc_finish_radians));
  304. pointerPosition = calculatePointerPosition(mAngle);
  305. invalidate();
  306. }
  307. break;
  308. case MotionEvent.ACTION_MOVE:
  309. if (mUserIsMovingPointer) {
  310. mAngle = (float) java.lang.Math.atan2(y, x);
  311. int radians = calculateRadiansFromAngle(mAngle);
  312. if (last_radians > radians && radians < (360 / 6) && x > lastX
  313. && last_radians > (360 / 6)) {
  314. if (!block_end && !block_start)
  315. block_end = true;
  316. } else if (last_radians >= start_arc
  317. && last_radians <= (360 / 4) && radians <= (360 - 1)
  318. && radians >= ((360 / 4) * 3) && x < lastX) {
  319. if (!block_start && !block_end)
  320. block_start = true;
  321. } else if (radians >= end_wheel && !block_start
  322. && last_radians < radians) {
  323. block_end = true;
  324. } else if (radians < end_wheel && block_end
  325. && last_radians > end_wheel) {
  326. block_end = false;
  327. } else if (radians < start_arc && last_radians > radians
  328. && !block_end) {
  329. block_start = true;
  330. } else if (block_start && last_radians < radians
  331. && radians > start_arc && radians < end_wheel) {
  332. block_start = false;
  333. }
  334. if (block_end) {
  335. arc_finish_radians = end_wheel - 1;
  336. text = String.valueOf(0);
  337. mAngle = calculateAngleFromRadians(arc_finish_radians);
  338. pointerPosition = calculatePointerPosition(mAngle);
  339. } else if (block_start) {
  340. arc_finish_radians = start_arc;
  341. mAngle = calculateAngleFromRadians(arc_finish_radians);
  342. text = String.valueOf(0);
  343. pointerPosition = calculatePointerPosition(mAngle);
  344. } else {
  345. // text = String.valueOf(calculateTextFromAngle(mAngle));
  346. arc_finish_radians = calculateRadiansFromAngle(mAngle);
  347. text = String
  348. .valueOf(calculateTextFromAngle(arc_finish_radians));
  349. pointerPosition = calculatePointerPosition(mAngle);
  350. }
  351. invalidate();
  352. if (mOnCircleSeekBarChangeListener != null)
  353. mOnCircleSeekBarChangeListener.onProgressChanged(this,
  354. Integer.parseInt(text), true);
  355. last_radians = radians;
  356. }
  357. break;
  358. case MotionEvent.ACTION_UP:
  359. mUserIsMovingPointer = false;
  360. break;
  361. }
  362. if (event.getAction() == MotionEvent.ACTION_MOVE && getParent() != null) {
  363. getParent().requestDisallowInterceptTouchEvent(true);
  364. }
  365. lastX = x;
  366. return true;
  367. }
  368. /**
  369. * Calculate the pointer's coordinates on the color wheel using the supplied
  370. * angle.
  371. *
  372. * @param angle
  373. *            The position of the pointer expressed as angle (in rad).
  374. *
  375. * @return The coordinates of the pointer's center in our internal
  376. *         coordinate system.
  377. */
  378. private float[] calculatePointerPosition(float angle) {
  379. // if (calculateRadiansFromAngle(angle) > end_wheel)
  380. // angle = calculateAngleFromRadians(end_wheel);
  381. float x = (float) (mColorWheelRadius * Math.cos(angle));
  382. float y = (float) (mColorWheelRadius * Math.sin(angle));
  383. return new float[] { x, y };
  384. }
  385. @Override
  386. protected Parcelable onSaveInstanceState() {
  387. Parcelable superState = super.onSaveInstanceState();
  388. Bundle state = new Bundle();
  389. state.putParcelable(STATE_PARENT, superState);
  390. state.putFloat(STATE_ANGLE, mAngle);
  391. return state;
  392. }
  393. @Override
  394. protected void onRestoreInstanceState(Parcelable state) {
  395. Bundle savedState = (Bundle) state;
  396. Parcelable superState = savedState.getParcelable(STATE_PARENT);
  397. super.onRestoreInstanceState(superState);
  398. mAngle = savedState.getFloat(STATE_ANGLE);
  399. arc_finish_radians = calculateRadiansFromAngle(mAngle);
  400. text = String.valueOf(calculateTextFromAngle(arc_finish_radians));
  401. pointerPosition = calculatePointerPosition(mAngle);
  402. }
  403. public void setOnSeekBarChangeListener(OnCircleSeekBarChangeListener l) {
  404. mOnCircleSeekBarChangeListener = l;
  405. }
  406. public interface OnCircleSeekBarChangeListener {
  407. public abstract void onProgressChanged(ZJBCircleSeekBar seekBar,
  408. int progress, boolean fromUser);
  409. }
  410. }

/layout/activity_main.xml:

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="fill_parent"
  4. android:layout_height="fill_parent"
  5. android:layout_gravity="center_horizontal"
  6. tools:context=".MainActivity" >
  7. <TextView
  8. android:id="@+id/text"
  9. android:layout_width="fill_parent"
  10. android:layout_height="wrap_content"
  11. android:layout_centerHorizontal="true"
  12. android:layout_marginTop="80dp"
  13. android:gravity="center_horizontal"
  14. android:textSize="60sp"
  15. android:textColor="#ffff0000"
  16. />
  17. <com.example.circleseekbar.HoloCircleSeekBar
  18. android:id="@+id/c"
  19. android:layout_width="500px"
  20. android:layout_height="500px"
  21. android:layout_centerInParent="true" />
  22. </RelativeLayout>

MainActivity.java:

  1. package com.example.circleseekbar;
  2. import android.app.Activity;
  3. import android.os.Bundle;
  4. import android.widget.TextView;
  5. import com.example.circleseekbar.ZJBCircleSeekBar.OnCircleSeekBarChangeListener;
  6. /**
  7. * @author zjbpku
  8. * @time 2013-08-21
  9. * @blog http://blog.csdn.net/zjbpku
  10. */
  11. public class MainActivity extends Activity implements
  12. OnCircleSeekBarChangeListener {
  13. private ZJBCircleSeekBar circleSeekBar;
  14. TextView textView;
  15. @Override
  16. protected void onCreate(Bundle savedInstanceState) {
  17. // TODO Auto-generated method stub
  18. super.onCreate(savedInstanceState);
  19. setContentView(R.layout.activity_main);
  20. circleSeekBar = (ZJBCircleSeekBar) findViewById(R.id.c);
  21. textView = (TextView) findViewById(R.id.text);
  22. circleSeekBar.setOnSeekBarChangeListener(this);
  23. }
  24. @Override
  25. public void onProgressChanged(ZJBCircleSeekBar seekBar, int progress,
  26. boolean fromUser) {
  27. // TODO Auto-generated method stub
  28. textView.setText(progress + "");
  29. }
  30. }

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