0d28a18363d469e65fab8e7ab68c43cd5f205b64.svn-base 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749
  1. package com.hjq.dialog.widget;
  2. import android.annotation.TargetApi;
  3. import android.content.Context;
  4. import android.content.res.Resources;
  5. import android.content.res.TypedArray;
  6. import android.graphics.Canvas;
  7. import android.graphics.Color;
  8. import android.graphics.ColorFilter;
  9. import android.graphics.Paint;
  10. import android.graphics.PixelFormat;
  11. import android.graphics.Rect;
  12. import android.graphics.RectF;
  13. import android.graphics.drawable.Animatable;
  14. import android.graphics.drawable.Drawable;
  15. import android.os.Build;
  16. import android.os.SystemClock;
  17. import android.support.annotation.NonNull;
  18. import android.support.annotation.Nullable;
  19. import android.util.AttributeSet;
  20. import android.util.TypedValue;
  21. import android.view.View;
  22. import android.view.animation.AnimationUtils;
  23. import android.view.animation.DecelerateInterpolator;
  24. import android.view.animation.Interpolator;
  25. import com.hjq.dialog.R;
  26. /**
  27. * desc : 圆形进度加载自定义控件
  28. */
  29. public final class CircleProgressView extends View {
  30. public static final long FRAME_DURATION = 1000 / 60;
  31. private static final int MODE_DETERMINATE = 0;
  32. private static final int MODE_INDETERMINATE = 1;
  33. private boolean isStart = false;
  34. private boolean isAutoStart = true;
  35. private CircularProgressDrawable mCircularProgressDrawable;
  36. public CircleProgressView(Context context) {
  37. this(context, null);
  38. }
  39. public CircleProgressView(Context context, @Nullable AttributeSet attrs) {
  40. this(context, attrs, 0);
  41. }
  42. public CircleProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
  43. super(context, attrs, defStyleAttr);
  44. mCircularProgressDrawable = new CircularProgressDrawable.Builder(context, R.style.CircularProgress).build();
  45. setBackground(mCircularProgressDrawable);
  46. }
  47. @Override
  48. public void setBackground(Drawable background) {
  49. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
  50. super.setBackground(background);
  51. }else {
  52. setBackgroundDrawable(background);
  53. }
  54. }
  55. public CircularProgressDrawable getCircularProgressDrawable() {
  56. return mCircularProgressDrawable;
  57. }
  58. public void setAutoStart(boolean autoStart) {
  59. isAutoStart = autoStart;
  60. }
  61. /**
  62. * set the stroke size with px
  63. */
  64. public void setStrokeSizePx(int px) {
  65. getCircularProgressDrawable().setStrokeSize(px);
  66. }
  67. /**
  68. * set the stroke size with dp
  69. */
  70. public void setStrokeSizeDp(float dp) {
  71. getCircularProgressDrawable().setStrokeSize((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getContext().getResources().getDisplayMetrics()));
  72. }
  73. /**
  74. * set the colors with int[]
  75. */
  76. public void setStrokeColors(int[] strokeColors) {
  77. getCircularProgressDrawable().setStrokeColors(strokeColors);
  78. }
  79. @Override
  80. protected void onAttachedToWindow() {
  81. super.onAttachedToWindow();
  82. if (isAutoStart) {
  83. start();
  84. }
  85. }
  86. @Override
  87. protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
  88. if (visibility == GONE || visibility == INVISIBLE && isStart) {
  89. stop();
  90. } else {
  91. if (isAutoStart) {
  92. start();
  93. }
  94. }
  95. }
  96. @Override
  97. protected void onDetachedFromWindow() {
  98. if (isStart && getVisibility() == View.VISIBLE) {
  99. stop();
  100. }
  101. super.onDetachedFromWindow();
  102. }
  103. /**
  104. * Start showing progress.
  105. */
  106. public void start() {
  107. if (mCircularProgressDrawable != null) {
  108. mCircularProgressDrawable.start();
  109. isStart = true;
  110. }
  111. }
  112. /**
  113. * Stop showing progress.
  114. */
  115. public void stop() {
  116. if (mCircularProgressDrawable != null && isStart) {
  117. mCircularProgressDrawable.stop();
  118. isStart = false;
  119. }
  120. }
  121. static class CircularProgressDrawable extends Drawable implements Animatable {
  122. private long mLastUpdateTime;
  123. private long mLastProgressStateTime;
  124. private long mLastRunStateTime;
  125. private int mProgressState;
  126. private static final int PROGRESS_STATE_HIDE = -1;
  127. private static final int PROGRESS_STATE_STRETCH = 0;
  128. private static final int PROGRESS_STATE_KEEP_STRETCH = 1;
  129. private static final int PROGRESS_STATE_SHRINK = 2;
  130. private static final int PROGRESS_STATE_KEEP_SHRINK = 3;
  131. private int mRunState = RUN_STATE_STOPPED;
  132. private static final int RUN_STATE_STOPPED = 0;
  133. private static final int RUN_STATE_STARTING = 1;
  134. private static final int RUN_STATE_STARTED = 2;
  135. private static final int RUN_STATE_RUNNING = 3;
  136. private static final int RUN_STATE_STOPPING = 4;
  137. private Paint mPaint;
  138. private RectF mRect;
  139. private float mStartAngle;
  140. private float mSweepAngle;
  141. private int mStrokeColorIndex;
  142. private int mPadding;
  143. private float mInitialAngle;
  144. private float mMaxSweepAngle;
  145. private float mMinSweepAngle;
  146. private int mStrokeSize;
  147. private int[] mStrokeColors;
  148. private boolean mReverse;
  149. private int mRotateDuration;
  150. private int mTransformDuration;
  151. private int mKeepDuration;
  152. private float mInStepPercent;
  153. private int[] mInColors;
  154. private int mInAnimationDuration;
  155. private int mOutAnimationDuration;
  156. private int mProgressMode;
  157. private Interpolator mTransformInterpolator;
  158. private CircularProgressDrawable(int padding, float initialAngle, float maxSweepAngle, float minSweepAngle,
  159. int strokeSize, int[] strokeColors, boolean reverse,
  160. int rotateDuration, int transformDuration, int keepDuration,
  161. Interpolator transformInterpolator, int progressMode, int inAnimDuration,
  162. float inStepPercent, int[] inStepColors, int outAnimDuration) {
  163. mPadding = padding;
  164. mInitialAngle = initialAngle;
  165. mMaxSweepAngle = maxSweepAngle;
  166. mMinSweepAngle = minSweepAngle;
  167. mStrokeSize = strokeSize;
  168. mStrokeColors = strokeColors;
  169. mReverse = reverse;
  170. mRotateDuration = rotateDuration;
  171. mTransformDuration = transformDuration;
  172. mKeepDuration = keepDuration;
  173. mTransformInterpolator = transformInterpolator;
  174. mProgressMode = progressMode;
  175. mInAnimationDuration = inAnimDuration;
  176. mInStepPercent = inStepPercent;
  177. mInColors = inStepColors;
  178. mOutAnimationDuration = outAnimDuration;
  179. mPaint = new Paint();
  180. mPaint.setAntiAlias(true);
  181. mPaint.setStrokeCap(Paint.Cap.ROUND);
  182. mPaint.setStrokeJoin(Paint.Join.ROUND);
  183. mRect = new RectF();
  184. }
  185. @Override
  186. public void draw(@NonNull Canvas canvas) {
  187. drawIndeterminate(canvas);
  188. }
  189. private int getIndeterminateStrokeColor() {
  190. if (mProgressState != PROGRESS_STATE_KEEP_SHRINK || mStrokeColors.length == 1)
  191. return mStrokeColors[mStrokeColorIndex];
  192. float value = Math.max(0f, Math.min(1f, (float) (SystemClock.uptimeMillis() - mLastProgressStateTime) / mKeepDuration));
  193. int prev_index = mStrokeColorIndex == 0 ? mStrokeColors.length - 1 : mStrokeColorIndex - 1;
  194. return getMiddleColor(mStrokeColors[prev_index], mStrokeColors[mStrokeColorIndex], value);
  195. }
  196. private void drawIndeterminate(Canvas canvas) {
  197. if (mRunState == RUN_STATE_STARTING) {
  198. Rect bounds = getBounds();
  199. float x = (bounds.left + bounds.right) / 2f;
  200. float y = (bounds.top + bounds.bottom) / 2f;
  201. float maxRadius = (Math.min(bounds.width(), bounds.height()) - mPadding * 2) / 2f;
  202. float stepTime = 1f / (mInStepPercent * (mInColors.length + 2) + 1);
  203. float time = (float) (SystemClock.uptimeMillis() - mLastRunStateTime) / mInAnimationDuration;
  204. float steps = time / stepTime;
  205. float outerRadius = 0f;
  206. float innerRadius = 0f;
  207. for (int i = (int) Math.floor(steps); i >= 0; i--) {
  208. innerRadius = outerRadius;
  209. outerRadius = Math.min(1f, (steps - i) * mInStepPercent) * maxRadius;
  210. if (i >= mInColors.length)
  211. continue;
  212. if (innerRadius == 0) {
  213. mPaint.setColor(mInColors[i]);
  214. mPaint.setStyle(Paint.Style.FILL);
  215. canvas.drawCircle(x, y, outerRadius, mPaint);
  216. } else if (outerRadius > innerRadius) {
  217. float radius = (innerRadius + outerRadius) / 2;
  218. mRect.set(x - radius, y - radius, x + radius, y + radius);
  219. mPaint.setStrokeWidth(outerRadius - innerRadius);
  220. mPaint.setStyle(Paint.Style.STROKE);
  221. mPaint.setColor(mInColors[i]);
  222. canvas.drawCircle(x, y, radius, mPaint);
  223. } else
  224. break;
  225. }
  226. if (mProgressState == PROGRESS_STATE_HIDE) {
  227. if (steps >= 1 / mInStepPercent || time >= 1) {
  228. resetAnimation();
  229. mProgressState = PROGRESS_STATE_STRETCH;
  230. }
  231. } else {
  232. float radius = maxRadius - mStrokeSize / 2f;
  233. mRect.set(x - radius, y - radius, x + radius, y + radius);
  234. mPaint.setStrokeWidth(mStrokeSize);
  235. mPaint.setStyle(Paint.Style.STROKE);
  236. mPaint.setColor(getIndeterminateStrokeColor());
  237. canvas.drawArc(mRect, mStartAngle, mSweepAngle, false, mPaint);
  238. }
  239. } else if (mRunState == RUN_STATE_STOPPING) {
  240. float size = (float) mStrokeSize * Math.max(0, (mOutAnimationDuration - SystemClock.uptimeMillis() + mLastRunStateTime)) / mOutAnimationDuration;
  241. if (size > 0) {
  242. Rect bounds = getBounds();
  243. float radius = (Math.min(bounds.width(), bounds.height()) - mPadding * 2 - mStrokeSize * 2 + size) / 2f;
  244. float x = (bounds.left + bounds.right) / 2f;
  245. float y = (bounds.top + bounds.bottom) / 2f;
  246. mRect.set(x - radius, y - radius, x + radius, y + radius);
  247. mPaint.setStrokeWidth(size);
  248. mPaint.setStyle(Paint.Style.STROKE);
  249. mPaint.setColor(getIndeterminateStrokeColor());
  250. canvas.drawArc(mRect, mStartAngle, mSweepAngle, false, mPaint);
  251. }
  252. } else if (mRunState != RUN_STATE_STOPPED) {
  253. Rect bounds = getBounds();
  254. float radius = (Math.min(bounds.width(), bounds.height()) - mPadding * 2 - mStrokeSize) / 2f;
  255. float x = (bounds.left + bounds.right) / 2f;
  256. float y = (bounds.top + bounds.bottom) / 2f;
  257. mRect.set(x - radius, y - radius, x + radius, y + radius);
  258. mPaint.setStrokeWidth(mStrokeSize);
  259. mPaint.setStyle(Paint.Style.STROKE);
  260. mPaint.setColor(getIndeterminateStrokeColor());
  261. canvas.drawArc(mRect, mStartAngle, mSweepAngle, false, mPaint);
  262. }
  263. }
  264. public void setStrokeSize(int mStrokeSize) {
  265. this.mStrokeSize = mStrokeSize;
  266. }
  267. public void setStrokeColors(int[] mStrokeColors) {
  268. this.mStrokeColors = mStrokeColors;
  269. }
  270. @Override
  271. public void setAlpha(int alpha) {
  272. mPaint.setAlpha(alpha);
  273. }
  274. @Override
  275. public void setColorFilter(ColorFilter cf) {
  276. mPaint.setColorFilter(cf);
  277. }
  278. @Override
  279. public int getOpacity() {
  280. return PixelFormat.TRANSLUCENT;
  281. }
  282. private void resetAnimation() {
  283. mLastUpdateTime = SystemClock.uptimeMillis();
  284. mLastProgressStateTime = mLastUpdateTime;
  285. mStartAngle = mInitialAngle;
  286. mStrokeColorIndex = 0;
  287. mSweepAngle = mReverse ? -mMinSweepAngle : mMinSweepAngle;
  288. }
  289. @Override
  290. public void start() {
  291. start(mInAnimationDuration > 0);
  292. }
  293. @Override
  294. public void stop() {
  295. stop(mOutAnimationDuration > 0);
  296. }
  297. private void start(boolean withAnimation) {
  298. if (isRunning())
  299. return;
  300. resetAnimation();
  301. if (withAnimation) {
  302. mRunState = RUN_STATE_STARTING;
  303. mLastRunStateTime = SystemClock.uptimeMillis();
  304. mProgressState = PROGRESS_STATE_HIDE;
  305. }
  306. scheduleSelf(mUpdater, SystemClock.uptimeMillis() + FRAME_DURATION);
  307. invalidateSelf();
  308. }
  309. private void stop(boolean withAnimation) {
  310. if (!isRunning())
  311. return;
  312. if (withAnimation) {
  313. mLastRunStateTime = SystemClock.uptimeMillis();
  314. if (mRunState == RUN_STATE_STARTED) {
  315. scheduleSelf(mUpdater, SystemClock.uptimeMillis() + FRAME_DURATION);
  316. invalidateSelf();
  317. }
  318. mRunState = RUN_STATE_STOPPING;
  319. } else {
  320. mRunState = RUN_STATE_STOPPED;
  321. unscheduleSelf(mUpdater);
  322. invalidateSelf();
  323. }
  324. }
  325. @Override
  326. public boolean isRunning() {
  327. return mRunState != RUN_STATE_STOPPED;
  328. }
  329. @Override
  330. public void scheduleSelf(Runnable what, long when) {
  331. if (mRunState == RUN_STATE_STOPPED)
  332. mRunState = mInAnimationDuration > 0 ? RUN_STATE_STARTING : RUN_STATE_RUNNING;
  333. super.scheduleSelf(what, when);
  334. }
  335. private final Runnable mUpdater = new Runnable() {
  336. @Override
  337. public void run() {
  338. update();
  339. }
  340. };
  341. private void update() {
  342. switch (mProgressMode) {
  343. case CircleProgressView.MODE_DETERMINATE:
  344. updateDeterminate();
  345. break;
  346. case CircleProgressView.MODE_INDETERMINATE:
  347. updateIndeterminate();
  348. break;
  349. }
  350. }
  351. private void updateDeterminate() {
  352. long curTime = SystemClock.uptimeMillis();
  353. float rotateOffset = (curTime - mLastUpdateTime) * 360f / mRotateDuration;
  354. if (mReverse)
  355. rotateOffset = -rotateOffset;
  356. mLastUpdateTime = curTime;
  357. mStartAngle += rotateOffset;
  358. if (mRunState == RUN_STATE_STARTING) {
  359. if (curTime - mLastRunStateTime > mInAnimationDuration) {
  360. mRunState = RUN_STATE_RUNNING;
  361. }
  362. } else if (mRunState == RUN_STATE_STOPPING) {
  363. if (curTime - mLastRunStateTime > mOutAnimationDuration) {
  364. stop(false);
  365. return;
  366. }
  367. }
  368. if (isRunning())
  369. scheduleSelf(mUpdater, SystemClock.uptimeMillis() + FRAME_DURATION);
  370. invalidateSelf();
  371. }
  372. private void updateIndeterminate() {
  373. //update animation
  374. long curTime = SystemClock.uptimeMillis();
  375. float rotateOffset = (curTime - mLastUpdateTime) * 360f / mRotateDuration;
  376. if (mReverse)
  377. rotateOffset = -rotateOffset;
  378. mLastUpdateTime = curTime;
  379. switch (mProgressState) {
  380. case PROGRESS_STATE_STRETCH:
  381. if (mTransformDuration <= 0) {
  382. mSweepAngle = mReverse ? -mMinSweepAngle : mMinSweepAngle;
  383. mProgressState = PROGRESS_STATE_KEEP_STRETCH;
  384. mStartAngle += rotateOffset;
  385. mLastProgressStateTime = curTime;
  386. } else {
  387. float value = (curTime - mLastProgressStateTime) / (float) mTransformDuration;
  388. float maxAngle = mReverse ? -mMaxSweepAngle : mMaxSweepAngle;
  389. float minAngle = mReverse ? -mMinSweepAngle : mMinSweepAngle;
  390. mStartAngle += rotateOffset;
  391. mSweepAngle = mTransformInterpolator.getInterpolation(value) * (maxAngle - minAngle) + minAngle;
  392. if (value > 1f) {
  393. mSweepAngle = maxAngle;
  394. mProgressState = PROGRESS_STATE_KEEP_STRETCH;
  395. mLastProgressStateTime = curTime;
  396. }
  397. }
  398. break;
  399. case PROGRESS_STATE_KEEP_STRETCH:
  400. mStartAngle += rotateOffset;
  401. if (curTime - mLastProgressStateTime > mKeepDuration) {
  402. mProgressState = PROGRESS_STATE_SHRINK;
  403. mLastProgressStateTime = curTime;
  404. }
  405. break;
  406. case PROGRESS_STATE_SHRINK:
  407. if (mTransformDuration <= 0) {
  408. mSweepAngle = mReverse ? -mMinSweepAngle : mMinSweepAngle;
  409. mProgressState = PROGRESS_STATE_KEEP_SHRINK;
  410. mStartAngle += rotateOffset;
  411. mLastProgressStateTime = curTime;
  412. mStrokeColorIndex = (mStrokeColorIndex + 1) % mStrokeColors.length;
  413. } else {
  414. float value = (curTime - mLastProgressStateTime) / (float) mTransformDuration;
  415. float maxAngle = mReverse ? -mMaxSweepAngle : mMaxSweepAngle;
  416. float minAngle = mReverse ? -mMinSweepAngle : mMinSweepAngle;
  417. float newSweepAngle = (1f - mTransformInterpolator.getInterpolation(value)) * (maxAngle - minAngle) + minAngle;
  418. mStartAngle += rotateOffset + mSweepAngle - newSweepAngle;
  419. mSweepAngle = newSweepAngle;
  420. if (value > 1f) {
  421. mSweepAngle = minAngle;
  422. mProgressState = PROGRESS_STATE_KEEP_SHRINK;
  423. mLastProgressStateTime = curTime;
  424. mStrokeColorIndex = (mStrokeColorIndex + 1) % mStrokeColors.length;
  425. }
  426. }
  427. break;
  428. case PROGRESS_STATE_KEEP_SHRINK:
  429. mStartAngle += rotateOffset;
  430. if (curTime - mLastProgressStateTime > mKeepDuration) {
  431. mProgressState = PROGRESS_STATE_STRETCH;
  432. mLastProgressStateTime = curTime;
  433. }
  434. break;
  435. }
  436. if (mRunState == RUN_STATE_STARTING) {
  437. if (curTime - mLastRunStateTime > mInAnimationDuration) {
  438. mRunState = RUN_STATE_RUNNING;
  439. if (mProgressState == PROGRESS_STATE_HIDE) {
  440. resetAnimation();
  441. mProgressState = PROGRESS_STATE_STRETCH;
  442. }
  443. }
  444. } else if (mRunState == RUN_STATE_STOPPING) {
  445. if (curTime - mLastRunStateTime > mOutAnimationDuration) {
  446. stop(false);
  447. return;
  448. }
  449. }
  450. if (isRunning())
  451. scheduleSelf(mUpdater, SystemClock.uptimeMillis() + FRAME_DURATION);
  452. invalidateSelf();
  453. }
  454. public static class Builder {
  455. private int mPadding;
  456. private float mInitialAngle;
  457. private float mMaxSweepAngle;
  458. private float mMinSweepAngle;
  459. private int mStrokeSize;
  460. private int[] mStrokeColors;
  461. private boolean mReverse;
  462. private int mRotateDuration;
  463. private int mTransformDuration;
  464. private int mKeepDuration;
  465. private Interpolator mTransformInterpolator;
  466. private int mProgressMode;
  467. private float mInStepPercent;
  468. private int[] mInColors;
  469. private int mInAnimationDuration;
  470. private int mOutAnimationDuration;
  471. public Builder(Context context, int defStyleRes) {
  472. this(context, null, 0, defStyleRes);
  473. }
  474. public Builder(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
  475. TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CircularProgressDrawable, defStyleAttr, defStyleRes);
  476. int resId;
  477. padding(array.getDimensionPixelSize(R.styleable.CircularProgressDrawable_cpd_padding, 0));
  478. initialAngle(array.getInteger(R.styleable.CircularProgressDrawable_cpd_initialAngle, 0));
  479. maxSweepAngle(array.getInteger(R.styleable.CircularProgressDrawable_cpd_maxSweepAngle, 270));
  480. minSweepAngle(array.getInteger(R.styleable.CircularProgressDrawable_cpd_minSweepAngle, 1));
  481. strokeSize(array.getDimensionPixelSize(R.styleable.CircularProgressDrawable_cpd_strokeSize, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4, context.getResources().getDisplayMetrics())));
  482. strokeColors(array.getColor(R.styleable.CircularProgressDrawable_cpd_strokeColor, colorPrimary(context, 0xFF000000)));
  483. if ((resId = array.getResourceId(R.styleable.CircularProgressDrawable_cpd_strokeColors, 0)) != 0) {
  484. TypedArray ta = context.getResources().obtainTypedArray(resId);
  485. int[] colors = new int[ta.length()];
  486. for (int j = 0; j < ta.length(); j++)
  487. colors[j] = ta.getColor(j, 0);
  488. ta.recycle();
  489. strokeColors(colors);
  490. }
  491. reverse(array.getBoolean(R.styleable.CircularProgressDrawable_cpd_reverse, false));
  492. rotateDuration(array.getInteger(R.styleable.CircularProgressDrawable_cpd_rotateDuration, context.getResources().getInteger(android.R.integer.config_longAnimTime)));
  493. transformDuration(array.getInteger(R.styleable.CircularProgressDrawable_cpd_transformDuration, context.getResources().getInteger(android.R.integer.config_mediumAnimTime)));
  494. keepDuration(array.getInteger(R.styleable.CircularProgressDrawable_cpd_keepDuration, context.getResources().getInteger(android.R.integer.config_shortAnimTime)));
  495. if ((resId = array.getResourceId(R.styleable.CircularProgressDrawable_cpd_transformInterpolator, 0)) != 0)
  496. transformInterpolator(AnimationUtils.loadInterpolator(context, resId));
  497. progressMode(array.getResourceId(R.styleable.CircularProgressDrawable_pv_progressMode, CircleProgressView.MODE_INDETERMINATE));
  498. //progressMode(a.getInteger(R.styleable.CircularProgressDrawable_pv_progressMode, ProgressView.MODE_INDETERMINATE));
  499. inAnimDuration(array.getInteger(R.styleable.CircularProgressDrawable_cpd_inAnimDuration, context.getResources().getInteger(android.R.integer.config_mediumAnimTime)));
  500. if ((resId = array.getResourceId(R.styleable.CircularProgressDrawable_cpd_inStepColors, 0)) != 0) {
  501. TypedArray ta = context.getResources().obtainTypedArray(resId);
  502. int[] colors = new int[ta.length()];
  503. for (int j = 0; j < ta.length(); j++) {
  504. colors[j] = ta.getColor(j, 0);
  505. }
  506. ta.recycle();
  507. inStepColors(colors);
  508. }
  509. inStepPercent(array.getFloat(R.styleable.CircularProgressDrawable_cpd_inStepPercent, 0.5f));
  510. outAnimDuration(array.getInteger(R.styleable.CircularProgressDrawable_cpd_outAnimDuration, context.getResources().getInteger(android.R.integer.config_mediumAnimTime)));
  511. array.recycle();
  512. }
  513. public CircularProgressDrawable build() {
  514. if (mStrokeColors == null)
  515. mStrokeColors = new int[]{0xFF0099FF};
  516. if (mInColors == null && mInAnimationDuration > 0)
  517. mInColors = new int[]{0xFFB5D4FF, 0xFFDEEAFC, 0xFFFAFFFE};
  518. if (mTransformInterpolator == null)
  519. mTransformInterpolator = new DecelerateInterpolator();
  520. return new CircularProgressDrawable(mPadding, mInitialAngle, mMaxSweepAngle, mMinSweepAngle, mStrokeSize,
  521. mStrokeColors, mReverse, mRotateDuration, mTransformDuration, mKeepDuration,
  522. mTransformInterpolator, mProgressMode, mInAnimationDuration, mInStepPercent, mInColors, mOutAnimationDuration);
  523. }
  524. public Builder padding(int padding) {
  525. mPadding = padding;
  526. return this;
  527. }
  528. public Builder initialAngle(float angle) {
  529. mInitialAngle = angle;
  530. return this;
  531. }
  532. public Builder maxSweepAngle(float angle) {
  533. mMaxSweepAngle = angle;
  534. return this;
  535. }
  536. public Builder minSweepAngle(float angle) {
  537. mMinSweepAngle = angle;
  538. return this;
  539. }
  540. public Builder strokeSize(int strokeSize) {
  541. mStrokeSize = strokeSize;
  542. return this;
  543. }
  544. public Builder strokeColors(int... strokeColors) {
  545. mStrokeColors = strokeColors;
  546. return this;
  547. }
  548. public Builder reverse(boolean reverse) {
  549. mReverse = reverse;
  550. return this;
  551. }
  552. public Builder rotateDuration(int duration) {
  553. mRotateDuration = duration;
  554. return this;
  555. }
  556. public Builder transformDuration(int duration) {
  557. mTransformDuration = duration;
  558. return this;
  559. }
  560. public Builder keepDuration(int duration) {
  561. mKeepDuration = duration;
  562. return this;
  563. }
  564. public Builder transformInterpolator(Interpolator interpolator) {
  565. mTransformInterpolator = interpolator;
  566. return this;
  567. }
  568. public Builder progressMode(int mode) {
  569. mProgressMode = mode;
  570. return this;
  571. }
  572. public Builder inAnimDuration(int duration) {
  573. mInAnimationDuration = duration;
  574. return this;
  575. }
  576. public Builder inStepPercent(float percent) {
  577. mInStepPercent = percent;
  578. return this;
  579. }
  580. public Builder inStepColors(int... colors) {
  581. mInColors = colors;
  582. return this;
  583. }
  584. public Builder outAnimDuration(int duration) {
  585. mOutAnimationDuration = duration;
  586. return this;
  587. }
  588. }
  589. }
  590. private static int getMiddleValue(int prev, int next, float factor) {
  591. return Math.round(prev + (next - prev) * factor);
  592. }
  593. public static int getMiddleColor(int prevColor, int curColor, float factor) {
  594. if (prevColor == curColor)
  595. return curColor;
  596. if (factor == 0f)
  597. return prevColor;
  598. else if (factor == 1f)
  599. return curColor;
  600. int a = getMiddleValue(Color.alpha(prevColor), Color.alpha(curColor), factor);
  601. int r = getMiddleValue(Color.red(prevColor), Color.red(curColor), factor);
  602. int g = getMiddleValue(Color.green(prevColor), Color.green(curColor), factor);
  603. int b = getMiddleValue(Color.blue(prevColor), Color.blue(curColor), factor);
  604. return Color.argb(a, r, g, b);
  605. }
  606. private static int getColor(Context context, int id, int defaultValue) {
  607. TypedValue value = new TypedValue();
  608. try {
  609. Resources.Theme theme = context.getTheme();
  610. if (theme != null && theme.resolveAttribute(id, value, true)) {
  611. if (value.type >= TypedValue.TYPE_FIRST_INT && value.type <= TypedValue.TYPE_LAST_INT)
  612. return value.data;
  613. else if (value.type == TypedValue.TYPE_STRING)
  614. return context.getResources().getColor(value.resourceId);
  615. }
  616. } catch (Exception ignored) {}
  617. return defaultValue;
  618. }
  619. @TargetApi(Build.VERSION_CODES.LOLLIPOP)
  620. public static int colorPrimary(Context context, int defaultValue) {
  621. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  622. return getColor(context, android.R.attr.colorPrimary, defaultValue);
  623. } else {
  624. return getColor(context, R.attr.colorPrimary, defaultValue);
  625. }
  626. }
  627. }