FunnelView.java 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. package com.xzjmyk.pm.activity.view;
  2. import android.animation.ObjectAnimator;
  3. import android.animation.ValueAnimator;
  4. import android.annotation.SuppressLint;
  5. import android.content.Context;
  6. import android.graphics.Canvas;
  7. import android.graphics.Color;
  8. import android.graphics.Paint;
  9. import android.graphics.Path;
  10. import android.util.AttributeSet;
  11. import android.util.Log;
  12. import android.util.TypedValue;
  13. import android.view.View;
  14. import android.view.WindowManager;
  15. import android.view.animation.AccelerateDecelerateInterpolator;
  16. import com.alibaba.fastjson.JSON;
  17. import com.xzjmyk.pm.activity.util.DisplayUtil;
  18. import java.util.ArrayList;
  19. import java.util.List;
  20. /**
  21. * Created by zhengjiong on 16/1/20.
  22. */
  23. @SuppressLint("NewApi")
  24. public class FunnelView extends View implements ValueAnimator.AnimatorUpdateListener {
  25. public static final float ANGLE_SCALE = 2.0f;
  26. private int maxMoney;
  27. private float phaseX = 1f;
  28. private int textAlpha = 255;
  29. private float mLastX;
  30. private float mLastY;
  31. private float mLastWidth;
  32. private int maxHight;
  33. private Paint mPaintLine;
  34. private Paint mPaintText;
  35. private ObjectAnimator xAnimator;
  36. private ObjectAnimator alphaAnimator;
  37. private List<Integer> mMoneys = new ArrayList<>();
  38. private ArrayList<Paint> mPaints = new ArrayList<>();
  39. private ArrayList<String> colors = new ArrayList<>();
  40. private ArrayList<Float> mPathHeights = new ArrayList<>();
  41. private ArrayList<Float> mPathAngleWidths = new ArrayList<>();
  42. private float mTotalHeight =
  43. TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 250, getResources().getDisplayMetrics());
  44. private float maxWidth =
  45. TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
  46. 355,
  47. getResources().getDisplayMetrics());
  48. private float maxLineH =
  49. TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 120, getResources().getDisplayMetrics());
  50. private float minLineH =
  51. TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 0, getResources().getDisplayMetrics());
  52. private float startOffsetX =
  53. TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, getResources().getDisplayMetrics());
  54. private float startOffsetY =
  55. TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, getResources().getDisplayMetrics());
  56. private float lineStartOffsetX =
  57. TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8, getResources().getDisplayMetrics());
  58. private float textStartOffsetX =
  59. TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 7, getResources().getDisplayMetrics());
  60. public FunnelView(Context context) {
  61. this(context, null);
  62. }
  63. public FunnelView(Context context, AttributeSet attrs) {
  64. this(context, attrs, 0);
  65. }
  66. public FunnelView(Context context, AttributeSet attrs, int defStyleAttr) {
  67. super(context, attrs, defStyleAttr);
  68. init();
  69. }
  70. public void setData(List<Integer> moneys, int maxMoney,ArrayList<String> colors) {
  71. this.mMoneys = moneys;
  72. this.maxMoney = maxMoney;
  73. this.colors=colors;
  74. Log.i("FunnelMain", "setData:px:" + ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getWidth() );
  75. Log.i("FunnelMain", "setData:dp:" + DisplayUtil.px2dip(getContext(),((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getWidth()));
  76. stopAnimator();
  77. init();
  78. calculate();
  79. getMaxHight();
  80. requestLayout();
  81. }
  82. private void getMaxHight() {
  83. Log.i("FunnelMain2", JSON.toJSONString(mPathHeights));
  84. for (int i=0;i<mMoneys.size();i++){
  85. if (i==0) {
  86. maxHight = (int) (startOffsetY + mPathHeights.get(i));
  87. }else{
  88. maxHight =(int)(maxHight+ mPathHeights.get(i));
  89. }
  90. }
  91. }
  92. private void calculate() {
  93. Log.i("Arison", "setData:moneys:" + JSON.toJSONString(mMoneys));
  94. Log.i("Arison", "setData:maxMoney:" + maxMoney);
  95. mPathHeights.clear();
  96. mPathAngleWidths.clear();
  97. for (int i = 0; i < mMoneys.size(); i++) {
  98. int money = mMoneys.get(i);
  99. float scale = (float) money / maxMoney;
  100. Float mPathHeight = mTotalHeight * scale * phaseX;
  101. if (mPathHeight < minLineH * phaseX) {
  102. mPathHeight = minLineH * phaseX;
  103. } else if (mPathHeight > maxLineH * phaseX) {
  104. mPathHeight = maxLineH * phaseX;
  105. }
  106. mPathHeights.add(i, mPathHeight);
  107. Float mPathAngleWidth = mPathHeight / ANGLE_SCALE;
  108. mPathAngleWidths.add(i, mPathAngleWidth);
  109. }
  110. }
  111. private void init() {
  112. mPaints.clear();
  113. for (int i = 0; i < mMoneys.size(); i++) {
  114. Paint mPaint = new Paint();
  115. mPaint.setColor(Color.parseColor(colors.get(i)));
  116. mPaint.setStyle(Paint.Style.FILL);
  117. mPaint.setDither(true);
  118. mPaint.setAntiAlias(true);
  119. mPaints.add(mPaint);
  120. }
  121. mPaintLine = new Paint();
  122. mPaintText = new Paint();
  123. mPaintLine.setColor(Color.parseColor("#A8ADB2"));
  124. mPaintLine.setStyle(Paint.Style.FILL);
  125. mPaintLine.setStrokeWidth(2);
  126. mPaintText.setColor(Color.parseColor("#A8ADB2"));
  127. mPaintText.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 14, getResources().getDisplayMetrics()));
  128. mPaintText.setAntiAlias(true);
  129. mPaintText.setTextAlign(Paint.Align.LEFT);
  130. }
  131. private Path mPath;
  132. private void draw2(Canvas canvas, Paint mPaint, Float mPathAngleWidth, Float mPathHeight,int i) {
  133. if (i==0){
  134. mLastX = startOffsetX;
  135. mLastY = startOffsetY;
  136. mLastWidth = maxWidth - startOffsetX;
  137. }
  138. mPath = new Path();
  139. mPath.moveTo(mLastX, mLastY);
  140. mPath.lineTo(mLastX + mLastWidth, mLastY);
  141. mPath.lineTo(mLastX + mLastWidth - mPathAngleWidth, mLastY + mPathHeight);
  142. mPath.lineTo(mLastX + mPathAngleWidth, mLastY + mPathHeight);
  143. mPath.close();
  144. canvas.drawPath(mPath, mPaint);
  145. mLastWidth = mLastWidth - 2 * mPathAngleWidth;
  146. mLastX = mLastX + mPathAngleWidth;
  147. mLastY = mLastY + mPathHeight;
  148. }
  149. @Override
  150. protected void onDraw(Canvas canvas) {
  151. super.onDraw(canvas);
  152. for (int i = 0; i < mMoneys.size(); i++) {
  153. draw2(canvas, mPaints.get(i), mPathAngleWidths.get(i), mPathHeights.get(i),i);
  154. }
  155. }
  156. public void animateY() {
  157. xAnimator = ObjectAnimator.ofFloat(this, "phaseX", 0, 1);
  158. xAnimator.setDuration(2000);
  159. xAnimator.addUpdateListener(this);
  160. xAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
  161. xAnimator.start();
  162. alphaAnimator = ObjectAnimator.ofInt(this, "textAlpha", 0, 255);
  163. alphaAnimator.setDuration(2000);
  164. alphaAnimator.addUpdateListener(this);
  165. alphaAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
  166. alphaAnimator.start();
  167. }
  168. private void stopAnimator(){
  169. if (xAnimator!=null&&alphaAnimator!=null)
  170. if (xAnimator.isRunning()) {
  171. xAnimator.end();
  172. alphaAnimator.end();
  173. }
  174. }
  175. @Override
  176. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  177. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  178. setMeasuredDimension(getMeasuredLength(widthMeasureSpec, true),
  179. getMeasuredLength(heightMeasureSpec, false));
  180. }
  181. private int getMeasuredLength(int length, boolean isWidth) {
  182. int specMode = MeasureSpec.getMode(length);
  183. int specSize = MeasureSpec.getSize(length);
  184. int size;
  185. if (specMode == MeasureSpec.EXACTLY) {
  186. size = specSize;
  187. } else {
  188. size = maxHight+(int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, getResources().getDisplayMetrics());
  189. Log.i("FunnelMain", "onMeasure:"+ size);
  190. }
  191. return size;
  192. }
  193. public float getPhaseX() {
  194. return phaseX;
  195. }
  196. public void setPhaseX(float phaseX) {
  197. this.phaseX = phaseX;
  198. }
  199. public int getTextAlpha() {
  200. return textAlpha;
  201. }
  202. public void setTextAlpha(int textAlpha) {
  203. this.textAlpha = textAlpha;
  204. }
  205. @Override
  206. public void onAnimationUpdate(ValueAnimator animation) {
  207. Log.i("Animation", "onAnimationUpdate:动画更新...." );
  208. calculate();
  209. postInvalidate();
  210. }
  211. @Override
  212. protected void onAnimationEnd() {
  213. super.onAnimationEnd();
  214. Log.i("Animation", "onAnimationUpdate:动画结束....");
  215. maxHight=0;
  216. }
  217. }