1. /**
  2. * @author Raghav Sood
  3. * @version 1
  4. * @date 26 January, 2013
  5. */
  6. package com.appaholics.circularseekbar;
  7.  
  8. import android.content.Context;
  9. import android.graphics.Bitmap;
  10. import android.graphics.BitmapFactory;
  11. import android.graphics.Canvas;
  12. import android.graphics.Color;
  13. import android.graphics.Paint;
  14. import android.graphics.RectF;
  15. import android.util.AttributeSet;
  16. import android.view.MotionEvent;
  17. import android.view.View;
  18.  
  19. /**
  20. * The Class CircularSeekBar.
  21. */
  22. public class CircularSeekBar extends View {
  23.  
  24. /** The context */
  25. private Context mContext;
  26.  
  27. /** The listener to listen for changes */
  28. private OnSeekChangeListener mListener;
  29.  
  30. /** The color of the progress ring */
  31. private Paint circleColor;
  32.  
  33. /** the color of the inside circle. Acts as background color */
  34. private Paint innerColor;
  35.  
  36. /** The progress circle ring background */
  37. private Paint circleRing;
  38.  
  39. /** The angle of progress */
  40. private int angle = 0;
  41.  
  42. /** The start angle (12 O'clock */
  43. private int startAngle = 270;
  44.  
  45. /** The width of the progress ring */
  46. private int barWidth = 5;
  47.  
  48. /** The width of the view */
  49. private int width;
  50.  
  51. /** The height of the view */
  52. private int height;
  53.  
  54. /** The maximum progress amount */
  55. private int maxProgress = 100;
  56.  
  57. /** The current progress */
  58. private int progress;
  59.  
  60. /** The progress percent */
  61. private int progressPercent;
  62.  
  63. /** The radius of the inner circle */
  64. private float innerRadius;
  65.  
  66. /** The radius of the outer circle */
  67. private float outerRadius;
  68.  
  69. /** The circle's center X coordinate */
  70. private float cx;
  71.  
  72. /** The circle's center Y coordinate */
  73. private float cy;
  74.  
  75. /** The left bound for the circle RectF */
  76. private float left;
  77.  
  78. /** The right bound for the circle RectF */
  79. private float right;
  80.  
  81. /** The top bound for the circle RectF */
  82. private float top;
  83.  
  84. /** The bottom bound for the circle RectF */
  85. private float bottom;
  86.  
  87. /** The X coordinate for the top left corner of the marking drawable */
  88. private float dx;
  89.  
  90. /** The Y coordinate for the top left corner of the marking drawable */
  91. private float dy;
  92.  
  93. /** The X coordinate for 12 O'Clock */
  94. private float startPointX;
  95.  
  96. /** The Y coordinate for 12 O'Clock */
  97. private float startPointY;
  98.  
  99. /**
  100. * The X coordinate for the current position of the marker, pre adjustment
  101. * to center
  102. */
  103. private float markPointX;
  104.  
  105. /**
  106. * The Y coordinate for the current position of the marker, pre adjustment
  107. * to center
  108. */
  109. private float markPointY;
  110.  
  111. /**
  112. * The adjustment factor. This adds an adjustment of the specified size to
  113. * both sides of the progress bar, allowing touch events to be processed
  114. * more user friendly (yes, I know that's not a word)
  115. */
  116. private float adjustmentFactor = 100;
  117.  
  118. /** The progress mark when the view isn't being progress modified */
  119. private Bitmap progressMark;
  120.  
  121. /** The progress mark when the view is being progress modified. */
  122. private Bitmap progressMarkPressed;
  123.  
  124. /** The flag to see if view is pressed */
  125. private boolean IS_PRESSED = false;
  126.  
  127. /**
  128. * The flag to see if the setProgress() method was called from our own
  129. * View's setAngle() method, or externally by a user.
  130. */
  131. private boolean CALLED_FROM_ANGLE = false;
  132.  
  133. private boolean SHOW_SEEKBAR = true;
  134.  
  135. /** The rectangle containing our circles and arcs. */
  136. private RectF rect = new RectF();
  137.  
  138. {
  139. mListener = new OnSeekChangeListener() {
  140.  
  141. @Override
  142. public void onProgressChange(CircularSeekBar view, int newProgress) {
  143.  
  144. }
  145. };
  146.  
  147. circleColor = new Paint();
  148. innerColor = new Paint();
  149. circleRing = new Paint();
  150.  
  151. circleColor.setColor(Color.parseColor("#ff33b5e5")); // Set default
  152. // progress
  153. // color to holo
  154. // blue.
  155. innerColor.setColor(Color.BLACK); // Set default background color to
  156. // black
  157. circleRing.setColor(Color.GRAY);// Set default background color to Gray
  158.  
  159. circleColor.setAntiAlias(true);
  160. innerColor.setAntiAlias(true);
  161. circleRing.setAntiAlias(true);
  162.  
  163. circleColor.setStrokeWidth(5);
  164. innerColor.setStrokeWidth(5);
  165. circleRing.setStrokeWidth(5);
  166.  
  167. circleColor.setStyle(Paint.Style.FILL);
  168. }
  169.  
  170. /**
  171. * Instantiates a new circular seek bar.
  172. *
  173. * @param context
  174. * the context
  175. * @param attrs
  176. * the attrs
  177. * @param defStyle
  178. * the def style
  179. */
  180. public CircularSeekBar(Context context, AttributeSet attrs, int defStyle) {
  181. super(context, attrs, defStyle);
  182. mContext = context;
  183. initDrawable();
  184. }
  185.  
  186. /**
  187. * Instantiates a new circular seek bar.
  188. *
  189. * @param context
  190. * the context
  191. * @param attrs
  192. * the attrs
  193. */
  194. public CircularSeekBar(Context context, AttributeSet attrs) {
  195. super(context, attrs);
  196. mContext = context;
  197. initDrawable();
  198. }
  199.  
  200. /**
  201. * Instantiates a new circular seek bar.
  202. *
  203. * @param context
  204. * the context
  205. */
  206. public CircularSeekBar(Context context) {
  207. super(context);
  208. mContext = context;
  209. initDrawable();
  210. }
  211.  
  212. /**
  213. * Inits the drawable.
  214. */
  215. public void initDrawable() {
  216. progressMark = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.scrubber_control_normal_holo);
  217. progressMarkPressed = BitmapFactory.decodeResource(mContext.getResources(),
  218. R.drawable.scrubber_control_pressed_holo);
  219. }
  220.  
  221. /*
  222. * (non-Javadoc)
  223. *
  224. * @see android.view.View#onMeasure(int, int)
  225. */
  226. @Override
  227. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  228. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  229.  
  230. width = getWidth(); // Get View Width
  231. height = getHeight();// Get View Height
  232.  
  233. int size = (width > height) ? height : width; // Choose the smaller
  234. // between width and
  235. // height to make a
  236. // square
  237.  
  238. cx = width / 2; // Center X for circle
  239. cy = height / 2; // Center Y for circle
  240. outerRadius = size / 2; // Radius of the outer circle
  241.  
  242. innerRadius = outerRadius - barWidth; // Radius of the inner circle
  243.  
  244. left = cx - outerRadius; // Calculate left bound of our rect
  245. right = cx + outerRadius;// Calculate right bound of our rect
  246. top = cy - outerRadius;// Calculate top bound of our rect
  247. bottom = cy + outerRadius;// Calculate bottom bound of our rect
  248.  
  249. startPointX = cx; // 12 O'clock X coordinate
  250. startPointY = cy - outerRadius;// 12 O'clock Y coordinate
  251. markPointX = startPointX;// Initial locatino of the marker X coordinate
  252. markPointY = startPointY;// Initial locatino of the marker Y coordinate
  253.  
  254. rect.set(left, top, right, bottom); // assign size to rect
  255. }
  256.  
  257. /*
  258. * (non-Javadoc)
  259. *
  260. * @see android.view.View#onDraw(android.graphics.Canvas)
  261. */
  262. @Override
  263. protected void onDraw(Canvas canvas) {
  264.  
  265. canvas.drawCircle(cx, cy, outerRadius, circleRing);
  266. canvas.drawArc(rect, startAngle, angle, true, circleColor);
  267. canvas.drawCircle(cx, cy, innerRadius, innerColor);
  268. if(SHOW_SEEKBAR){
  269. dx = getXFromAngle();
  270. dy = getYFromAngle();
  271. drawMarkerAtProgress(canvas);
  272. }
  273. super.onDraw(canvas);
  274. }
  275.  
  276. /**
  277. * Draw marker at the current progress point onto the given canvas.
  278. *
  279. * @param canvas
  280. * the canvas
  281. */
  282. public void drawMarkerAtProgress(Canvas canvas) {
  283. if (IS_PRESSED) {
  284. canvas.drawBitmap(progressMarkPressed, dx, dy, null);
  285. } else {
  286. canvas.drawBitmap(progressMark, dx, dy, null);
  287. }
  288. }
  289.  
  290. /**
  291. * Gets the X coordinate of the arc's end arm's point of intersection with
  292. * the circle
  293. *
  294. * @return the X coordinate
  295. */
  296. public float getXFromAngle() {
  297. int size1 = progressMark.getWidth();
  298. int size2 = progressMarkPressed.getWidth();
  299. int adjust = (size1 > size2) ? size1 : size2;
  300. float x = markPointX - (adjust / 2);
  301. return x;
  302. }
  303.  
  304. /**
  305. * Gets the Y coordinate of the arc's end arm's point of intersection with
  306. * the circle
  307. *
  308. * @return the Y coordinate
  309. */
  310. public float getYFromAngle() {
  311. int size1 = progressMark.getHeight();
  312. int size2 = progressMarkPressed.getHeight();
  313. int adjust = (size1 > size2) ? size1 : size2;
  314. float y = markPointY - (adjust / 2);
  315. return y;
  316. }
  317.  
  318. /**
  319. * Get the angle.
  320. *
  321. * @return the angle
  322. */
  323. public int getAngle() {
  324. return angle;
  325. }
  326.  
  327. /**
  328. * Set the angle.
  329. *
  330. * @param angle
  331. * the new angle
  332. */
  333. public void setAngle(int angle) {
  334. this.angle = angle;
  335. float donePercent = (((float) this.angle) / 360) * 100;
  336. float progress = (donePercent / 100) * getMaxProgress();
  337. setProgressPercent(Math.round(donePercent));
  338. CALLED_FROM_ANGLE = true;
  339. setProgress(Math.round(progress));
  340. }
  341.  
  342. /**
  343. * Sets the seek bar change listener.
  344. *
  345. * @param listener
  346. * the new seek bar change listener
  347. */
  348. public void setSeekBarChangeListener(OnSeekChangeListener listener) {
  349. mListener = listener;
  350. }
  351.  
  352. /**
  353. * Gets the seek bar change listener.
  354. *
  355. * @return the seek bar change listener
  356. */
  357. public OnSeekChangeListener getSeekBarChangeListener() {
  358. return mListener;
  359. }
  360.  
  361. /**
  362. * Gets the bar width.
  363. *
  364. * @return the bar width
  365. */
  366. public int getBarWidth() {
  367. return barWidth;
  368. }
  369.  
  370. /**
  371. * Sets the bar width.
  372. *
  373. * @param barWidth
  374. * the new bar width
  375. */
  376. public void setBarWidth(int barWidth) {
  377. this.barWidth = barWidth;
  378. }
  379.  
  380. /**
  381. * The listener interface for receiving onSeekChange events. The class that
  382. * is interested in processing a onSeekChange event implements this
  383. * interface, and the object created with that class is registered with a
  384. * component using the component's
  385. * <code>setSeekBarChangeListener(OnSeekChangeListener)<code> method. When
  386. * the onSeekChange event occurs, that object's appropriate
  387. * method is invoked.
  388. *
  389. * @see OnSeekChangeEvent
  390. */
  391. public interface OnSeekChangeListener {
  392.  
  393. /**
  394. * On progress change.
  395. *
  396. * @param view
  397. * the view
  398. * @param newProgress
  399. * the new progress
  400. */
  401. public void onProgressChange(CircularSeekBar view, int newProgress);
  402. }
  403.  
  404. /**
  405. * Gets the max progress.
  406. *
  407. * @return the max progress
  408. */
  409. public int getMaxProgress() {
  410. return maxProgress;
  411. }
  412.  
  413. /**
  414. * Sets the max progress.
  415. *
  416. * @param maxProgress
  417. * the new max progress
  418. */
  419. public void setMaxProgress(int maxProgress) {
  420. this.maxProgress = maxProgress;
  421. }
  422.  
  423. /**
  424. * Gets the progress.
  425. *
  426. * @return the progress
  427. */
  428. public int getProgress() {
  429. return progress;
  430. }
  431.  
  432. /**
  433. * Sets the progress.
  434. *
  435. * @param progress
  436. * the new progress
  437. */
  438. public void setProgress(int progress) {
  439. if (this.progress != progress) {
  440. this.progress = progress;
  441. if (!CALLED_FROM_ANGLE) {
  442. int newPercent = (this.progress * 100) / this.maxProgress;
  443. int newAngle = (newPercent * 360) / 100 ;
  444. this.setAngle(newAngle);
  445. this.setProgressPercent(newPercent);
  446. }
  447. mListener.onProgressChange(this, this.getProgress());
  448. CALLED_FROM_ANGLE = false;
  449. }
  450. }
  451.  
  452. /**
  453. * Gets the progress percent.
  454. *
  455. * @return the progress percent
  456. */
  457. public int getProgressPercent() {
  458. return progressPercent;
  459. }
  460.  
  461. /**
  462. * Sets the progress percent.
  463. *
  464. * @param progressPercent
  465. * the new progress percent
  466. */
  467. public void setProgressPercent(int progressPercent) {
  468. this.progressPercent = progressPercent;
  469. }
  470.  
  471. /**
  472. * Sets the ring background color.
  473. *
  474. * @param color
  475. * the new ring background color
  476. */
  477. public void setRingBackgroundColor(int color) {
  478. circleRing.setColor(color);
  479. }
  480.  
  481. /**
  482. * Sets the back ground color.
  483. *
  484. * @param color
  485. * the new back ground color
  486. */
  487. public void setBackGroundColor(int color) {
  488. innerColor.setColor(color);
  489. }
  490.  
  491. /**
  492. * Sets the progress color.
  493. *
  494. * @param color
  495. * the new progress color
  496. */
  497. public void setProgressColor(int color) {
  498. circleColor.setColor(color);
  499. }
  500.  
  501. /*
  502. * (non-Javadoc)
  503. *
  504. * @see android.view.View#onTouchEvent(android.view.MotionEvent)
  505. */
  506. @Override
  507. public boolean onTouchEvent(MotionEvent event) {
  508. float x = event.getX();
  509. float y = event.getY();
  510. boolean up = false;
  511. switch (event.getAction()) {
  512. case MotionEvent.ACTION_DOWN:
  513. moved(x, y, up);
  514. break;
  515. case MotionEvent.ACTION_MOVE:
  516. moved(x, y, up);
  517. break;
  518. case MotionEvent.ACTION_UP:
  519. up = true;
  520. moved(x, y, up);
  521. break;
  522. }
  523. return true;
  524. }
  525.  
  526. /**
  527. * Moved.
  528. *
  529. * @param x
  530. * the x
  531. * @param y
  532. * the y
  533. * @param up
  534. * the up
  535. */
  536. private void moved(float x, float y, boolean up) {
  537. float distance = (float) Math.sqrt(Math.pow((x - cx), 2) + Math.pow((y - cy), 2));
  538. if (distance < outerRadius + adjustmentFactor && distance > innerRadius - adjustmentFactor && !up) {
  539. IS_PRESSED = true;
  540.  
  541. markPointX = (float) (cx + outerRadius * Math.cos(Math.atan2(x - cx, cy - y) - (Math.PI /2)));
  542. markPointY = (float) (cy + outerRadius * Math.sin(Math.atan2(x - cx, cy - y) - (Math.PI /2)));
  543.  
  544. float degrees = (float) ((float) ((Math.toDegrees(Math.atan2(x - cx, cy - y)) + 360.0)) % 360.0);
  545. // and to make it count 0-360
  546. if (degrees < 0) {
  547. degrees += 2 * Math.PI;
  548. }
  549.  
  550. setAngle(Math.round(degrees));
  551. invalidate();
  552.  
  553. } else {
  554. IS_PRESSED = false;
  555. invalidate();
  556. }
  557.  
  558. }
  559.  
  560. /**
  561. * Gets the adjustment factor.
  562. *
  563. * @return the adjustment factor
  564. */
  565. public float getAdjustmentFactor() {
  566. return adjustmentFactor;
  567. }
  568.  
  569. /**
  570. * Sets the adjustment factor.
  571. *
  572. * @param adjustmentFactor
  573. * the new adjustment factor
  574. */
  575. public void setAdjustmentFactor(float adjustmentFactor) {
  576. this.adjustmentFactor = adjustmentFactor;
  577. }
  578.  
  579. /**
  580. * To display seekbar
  581. */
  582. public void ShowSeekBar() {
  583. SHOW_SEEKBAR = true;
  584. }
  585.  
  586. /**
  587. * To hide seekbar
  588. */
  589. public void hideSeekBar() {
  590. SHOW_SEEKBAR = false;
  591. }
  592. }

CircularSeekBar的更多相关文章

  1. android CircularSeekBar

    Android 中的 seekBar会被开发者经常用到,用的最多的空拍是控制音量.但是有时后为了更好的UI效果,横着的拖动条不能满足我们项目的需要,我们可能需要竖直的或者圆形的拖动条,那这两种样式的类 ...

  2. wesome-android

    awesome-android Introduction android libs from github System requirements Android Notice If the lib ...

随机推荐

  1. MongoDB学习笔记-06 数据库命令、固定集合、GridFS、javascript脚本

    介绍MongoDB支持的一些高级功能: 数据库命令 固定大小的集合 GridFS存储大文件 MongoDB对服务端JavaScript的支持 数据库命令 命令的原理 MongoDB中的命令其实是作为一 ...

  2. 8.2 辅助 xUtils 3.0

    主要有四大模块: DbUtils模块: android中的orm(对象关系映射)框架,一行代码就可以进行增删改查: 支持事务,默认关闭: 可通过注解自定义表名,列名,外键,唯一性约束,NOT NULL ...

  3. HashMap LinkedHashMap源码分析笔记

    MapClassDiagram

  4. HttpURLConnection使用getInputStream无法执行

    url = new URL(urlStr); urlConn = (HttpURLConnection) url.openConnection(); // 设置请求方式为"GET" ...

  5. 3.一起来学hibernate之配置文件2

    之前的映射文件配置都是简单的.基础的配置,只涉及到单个javabean,对于单个javabean的增删改查都能很好的.简单的去完成. 但是知道简单配置远远不够,并不能完成很多复杂的情况,比如对象与对象 ...

  6. Ubuntu 12.04 改造指南

    文章转自:http://www.lupaworld.com/article-217719-1.html 升级12.04已经有一段时间了.作为一个从08年就开始用Ubuntu的老用户,我觉得作为一个LT ...

  7. 【设计模式之单例模式InJava】

    1. 单例模式 1.1饿汉式(开发常用) class SingleFirst { /* 添加其他成员信息 */ private static SingleFirst s1 = new SingleFi ...

  8. anyncTask的3个参数

    AnyncTask异步处理数据并将数据应用到视图的操作场合 一  其中包含这几个方法 1 onPreExcute() 初始化控件,例如进度条2 doInBackground() 具体的执行动作请求数据 ...

  9. 微信公共平台开发-(.net实现)4--发送图文消息

    之前说了让微信发送给关注我们的粉丝普通的文本信息,下面我们来看看如何发送图文信息,需要注意的是这里说的是,让微信发给我们,而不是我们拍个图片发给微信处理,上传图片在以后的再讲.下面是发送图文消息的函数 ...

  10. listview(3、动态刷新)

    listview的动态刷新主要是调用adapter的notifyDataSetChanged. 在下面的例子中除了记录正常的刷新外,还记录一种错误的情况(注释掉的),作为备忘. notifyDataS ...