VerticalRangeSeekBar.java 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. package com.jaygoo.widget;
  2. import android.content.Context;
  3. import android.content.res.TypedArray;
  4. import android.graphics.Canvas;
  5. import android.graphics.Paint;
  6. import android.text.TextUtils;
  7. import android.util.AttributeSet;
  8. import android.view.MotionEvent;
  9. import android.view.ViewGroup;
  10. import androidx.annotation.IntDef;
  11. import java.lang.annotation.Retention;
  12. import java.lang.annotation.RetentionPolicy;
  13. /**
  14. * ================================================
  15. * 作 者:JayGoo
  16. * 版 本:
  17. * 创建日期:2018/5/10
  18. * 描 述:
  19. * ================================================
  20. */
  21. public class VerticalRangeSeekBar extends RangeSeekBar {
  22. //text direction of VerticalRangeSeekBar. include indicator and tickMark
  23. /**
  24. * @hide
  25. */
  26. @IntDef({TEXT_DIRECTION_VERTICAL, TEXT_DIRECTION_HORIZONTAL})
  27. @Retention(RetentionPolicy.SOURCE)
  28. public @interface TextDirectionDef {
  29. }
  30. public final static int TEXT_DIRECTION_VERTICAL = 1;
  31. public final static int TEXT_DIRECTION_HORIZONTAL = 2;
  32. //direction of VerticalRangeSeekBar
  33. /**
  34. * @hide
  35. */
  36. @IntDef({DIRECTION_LEFT, DIRECTION_RIGHT})
  37. @Retention(RetentionPolicy.SOURCE)
  38. public @interface DirectionDef {
  39. }
  40. public final static int DIRECTION_LEFT = 1;
  41. public final static int DIRECTION_RIGHT = 2;
  42. private int orientation = DIRECTION_LEFT;
  43. private int tickMarkDirection = TEXT_DIRECTION_VERTICAL;
  44. private int maxTickMarkWidth;
  45. public VerticalRangeSeekBar(Context context) {
  46. this(context, null);
  47. }
  48. public VerticalRangeSeekBar(Context context, AttributeSet attrs) {
  49. super(context, attrs);
  50. initAttrs(attrs);
  51. initSeekBar(attrs);
  52. }
  53. private void initAttrs(AttributeSet attrs) {
  54. try {
  55. TypedArray t = getContext().obtainStyledAttributes(attrs, R.styleable.VerticalRangeSeekBar);
  56. orientation = t.getInt(R.styleable.VerticalRangeSeekBar_rsb_orientation, DIRECTION_LEFT);
  57. tickMarkDirection = t.getInt(R.styleable.VerticalRangeSeekBar_rsb_tick_mark_orientation, TEXT_DIRECTION_VERTICAL);
  58. t.recycle();
  59. } catch (Exception e) {
  60. e.printStackTrace();
  61. }
  62. }
  63. protected void initSeekBar(AttributeSet attrs) {
  64. leftSB = new VerticalSeekBar(this, attrs, true);
  65. rightSB = new VerticalSeekBar(this, attrs, false);
  66. rightSB.setVisible(getSeekBarMode() != SEEKBAR_MODE_SINGLE);
  67. }
  68. @Override
  69. protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  70. super.onSizeChanged(h, w, oldh, oldw);
  71. }
  72. @Override
  73. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  74. int widthSize = MeasureSpec.getSize(widthMeasureSpec);
  75. int widthMode = MeasureSpec.getMode(widthMeasureSpec);
  76. /*
  77. * onMeasure传入的widthMeasureSpec和heightMeasureSpec不是一般的尺寸数值,而是将模式和尺寸组合在一起的数值
  78. * MeasureSpec.EXACTLY 是精确尺寸
  79. * MeasureSpec.AT_MOST 是最大尺寸
  80. * MeasureSpec.UNSPECIFIED 是未指定尺寸
  81. */
  82. if (widthMode == MeasureSpec.EXACTLY) {
  83. widthSize = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY);
  84. } else if (widthMode == MeasureSpec.AT_MOST && getParent() instanceof ViewGroup
  85. && widthSize == ViewGroup.LayoutParams.MATCH_PARENT) {
  86. widthSize = MeasureSpec.makeMeasureSpec(((ViewGroup) getParent()).getMeasuredHeight(), MeasureSpec.AT_MOST);
  87. } else {
  88. int heightNeeded;
  89. if (getGravity() == Gravity.CENTER) {
  90. heightNeeded = 2 * getProgressTop() + getProgressHeight();
  91. } else {
  92. heightNeeded = (int) getRawHeight();
  93. }
  94. widthSize = MeasureSpec.makeMeasureSpec(heightNeeded, MeasureSpec.EXACTLY);
  95. }
  96. super.onMeasure(widthSize, heightMeasureSpec);
  97. }
  98. @Override
  99. protected void onDraw(Canvas canvas) {
  100. if (orientation == DIRECTION_LEFT) {
  101. canvas.rotate(-90);
  102. canvas.translate(-getHeight(), 0);
  103. } else {
  104. canvas.rotate(90);
  105. canvas.translate(0, -getWidth());
  106. }
  107. super.onDraw(canvas);
  108. }
  109. @Override
  110. protected void onDrawTickMark(Canvas canvas, Paint paint) {
  111. if (getTickMarkTextArray() != null) {
  112. int arrayLength = getTickMarkTextArray().length;
  113. int trickPartWidth = getProgressWidth() / (arrayLength - 1);
  114. for (int i = 0; i < arrayLength; i++) {
  115. final String text2Draw = getTickMarkTextArray()[i].toString();
  116. if (TextUtils.isEmpty(text2Draw)) continue;
  117. paint.getTextBounds(text2Draw, 0, text2Draw.length(), tickMarkTextRect);
  118. paint.setColor(getTickMarkTextColor());
  119. //平分显示
  120. float x;
  121. if (getTickMarkMode() == TRICK_MARK_MODE_OTHER) {
  122. if (getTickMarkGravity() == TICK_MARK_GRAVITY_RIGHT) {
  123. x = getProgressLeft() + i * trickPartWidth - tickMarkTextRect.width();
  124. } else if (getTickMarkGravity() == TICK_MARK_GRAVITY_CENTER) {
  125. x = getProgressLeft() + i * trickPartWidth - tickMarkTextRect.width() / 2f;
  126. } else {
  127. x = getProgressLeft() + i * trickPartWidth;
  128. }
  129. } else {
  130. float num = Utils.parseFloat(text2Draw);
  131. SeekBarState[] states = getRangeSeekBarState();
  132. if (Utils.compareFloat(num, states[0].value) != -1 && Utils.compareFloat(num, states[1].value) != 1 && (getSeekBarMode() == SEEKBAR_MODE_RANGE)) {
  133. paint.setColor(getTickMarkInRangeTextColor());
  134. }
  135. //按实际比例显示
  136. x = getProgressLeft() + getProgressWidth() * (num - getMinProgress()) / (getMaxProgress() - getMinProgress())
  137. - tickMarkTextRect.width() / 2f;
  138. }
  139. float y;
  140. if (getTickMarkLayoutGravity() == Gravity.TOP) {
  141. y = getProgressTop() - getTickMarkTextMargin();
  142. } else {
  143. y = getProgressBottom() + getTickMarkTextMargin() + tickMarkTextRect.height();
  144. }
  145. int degrees = 0;
  146. float rotateX = (x + tickMarkTextRect.width() / 2f);
  147. float rotateY = (y - tickMarkTextRect.height() / 2f);
  148. if (tickMarkDirection == TEXT_DIRECTION_VERTICAL) {
  149. if (orientation == DIRECTION_LEFT) {
  150. degrees = 90;
  151. } else if (orientation == DIRECTION_RIGHT) {
  152. degrees = -90;
  153. }
  154. }
  155. if (degrees != 0) {
  156. canvas.rotate(degrees, rotateX, rotateY);
  157. }
  158. canvas.drawText(text2Draw, x, y, paint);
  159. if (degrees != 0) {
  160. canvas.rotate(-degrees, rotateX, rotateY);
  161. }
  162. }
  163. }
  164. }
  165. @Override
  166. protected int getTickMarkRawHeight() {
  167. if (maxTickMarkWidth > 0) return getTickMarkTextMargin() + maxTickMarkWidth;
  168. if (getTickMarkTextArray() != null && getTickMarkTextArray().length > 0) {
  169. int arrayLength = getTickMarkTextArray().length;
  170. maxTickMarkWidth = Utils.measureText(String.valueOf(getTickMarkTextArray()[0]), getTickMarkTextSize()).width();
  171. for (int i = 1; i < arrayLength; i++) {
  172. int width = Utils.measureText(String.valueOf(getTickMarkTextArray()[i]), getTickMarkTextSize()).width();
  173. if (maxTickMarkWidth < width) {
  174. maxTickMarkWidth = width;
  175. }
  176. }
  177. return getTickMarkTextMargin() + maxTickMarkWidth;
  178. }
  179. return 0;
  180. }
  181. @Override
  182. public void setTickMarkTextSize(int tickMarkTextSize) {
  183. super.setTickMarkTextSize(tickMarkTextSize);
  184. maxTickMarkWidth = 0;
  185. }
  186. @Override
  187. public void setTickMarkTextArray(CharSequence[] tickMarkTextArray) {
  188. super.setTickMarkTextArray(tickMarkTextArray);
  189. maxTickMarkWidth = 0;
  190. }
  191. @Override
  192. protected float getEventX(MotionEvent event) {
  193. if (orientation == DIRECTION_LEFT) {
  194. return getHeight() - event.getY();
  195. } else {
  196. return event.getY();
  197. }
  198. }
  199. @Override
  200. protected float getEventY(MotionEvent event) {
  201. if (orientation == DIRECTION_LEFT) {
  202. return event.getX();
  203. } else {
  204. return -event.getX() + getWidth();
  205. }
  206. }
  207. /**
  208. * if is single mode, please use it to get the SeekBar
  209. *
  210. * @return left seek bar
  211. */
  212. public VerticalSeekBar getLeftSeekBar() {
  213. return (VerticalSeekBar) leftSB;
  214. }
  215. public VerticalSeekBar getRightSeekBar() {
  216. return (VerticalSeekBar) rightSB;
  217. }
  218. public int getOrientation() {
  219. return orientation;
  220. }
  221. /**
  222. * set VerticalRangeSeekBar Orientation
  223. * {@link #DIRECTION_LEFT}
  224. * {@link #DIRECTION_RIGHT}
  225. * @param orientation
  226. */
  227. public void setOrientation(@DirectionDef int orientation) {
  228. this.orientation = orientation;
  229. }
  230. public int getTickMarkDirection() {
  231. return tickMarkDirection;
  232. }
  233. /**
  234. * set tick mark text direction
  235. * {@link #TEXT_DIRECTION_VERTICAL}
  236. * {@link #TEXT_DIRECTION_HORIZONTAL}
  237. * @param tickMarkDirection
  238. */
  239. public void setTickMarkDirection(@TextDirectionDef int tickMarkDirection) {
  240. this.tickMarkDirection = tickMarkDirection;
  241. }
  242. }