Android 는 경 량 선형 과 백분율 도 표를 실현 하 는 방법

머리말
도표 통계 데 이 터 를 자주 사용 해 야 하 는데 WEB 개발 에서 도 표를 그 리 는 것 은 간단 한 일이 다.왜냐하면 비교적 많은 오픈 소스 방안 이 있 기 때문이다.하지만 안 드 로 이 드 에 서 는 오픈 소스 방안 이 많 지 않다.그러나 현재 github 에는 도표 에 관 한 프레임 워 크 가 여러 개 있 습 니 다.예 를 들 어 MPAndroidChart 는 좋 지만 매우 큽 니 다.작은 아이콘 하나 로 인해 프로젝트 를 많이 확대 할 필요 가 없습니다.그리고 경량급 의 프레임 워 크 도 있 지만 개인 적 으로 자신의 수 요 를 만족 시 키 기 어렵 습 니 다.게다가 좋 은 프레임 워 크 라 고 해도 다른 사람의 것 입 니 다.자신 이 직접 써 서 앞 뒤의 구 덩이 를 이해 해 야 합 니 다.자신 이 성장 할 수 있 고 쓰 는 과정 에서 우 리 는 더 많은 세부 사항 을 발견 할 수 있 습 니 다.예 를 들 어 그 릴 때 메모리 배분 문제,Canvas 가 직접 그리 고 Bitmap 을 통 해 그 리 는 등 이 있 기 때문에 이 글 의 목적 은:
      1.사용자 정의 view 그리 기 아 이 디 어 를 제공 합 니 다.
      2.사용자 정의 view 의 일부 영역 을 미 끄 러 뜨리 는 방법
      3.path 애니메이션 그리 기 실현
      4.canvas 의 api 를 잘 알 고 있 습 니 다.아무튼 직접 손 을 쓸 수 있 습 니 다.그러면 사용자 정의 view 가 통관 되 기 때문에 이 글 을 쓰 는 것 은 여러분 들 이 많이 실현 하도록 격려 하 는 것 입 니 다.
효과 도

선형 도표 실현 의 사고:
선형 표 는 가장 기본 적 이 고 간단 하 며 가장 자주 사용 하 는 데이터 구조 이다.선형 표 에서 데이터 요소 간 의 관 계 는 일대일 관계 이다.즉,첫 번 째 와 마지막 데이터 요 소 를 제외 하고 다른 데이터 요 소 는 모두 앞 뒤 가 연결 되 어 있 으 니 주의 하 세 요.이 말 은 대부분 선형 표 만 적용 되 고 전부 가 아 닙 니 다.
화면의 너비 가 제한 되 어 있 기 때문에 우 리 는 한 화면 에 계산 을 거 쳐 가장 좋 은 7 개의 점 을 표시 해 야 합 니 다.그래서 우 리 는 먼저 우리 의 view 폭 을 계산 해 야 합 니 다.먼저 화면의 너 비 를 가 져 온 다음 에/7 을 진행 하여 각 간격의 너 비 를 얻 은 다음 에 우리 x 의 앉 은 구두점 의 개 수 를 곱 해 야 합 니 다.그 중의 onMeasure 방법:

 int widthParentMeasureMode = MeasureSpec.getMode(widthMeasureSpec);
 int widthParentMeasureSize = MeasureSpec.getSize(widthMeasureSpec);
 int heightParentMeasureMode = MeasureSpec.getMode(heightMeasureSpec);
 int heightParentMeasureSize = MeasureSpec.getSize(heightMeasureSpec);
 int resultWidthSize = 0;
 int resultHeightSize = 0;
 int resultWidthMode = MeasureSpec.EXACTLY;//   childView     
 int resultHeightMode = MeasureSpec.EXACTLY;
 int paddingWidth = getPaddingLeft() + getPaddingRight();
 int paddingHeight = getPaddingTop() + getPaddingBottom();
 ViewGroup.LayoutParams thisLp = getLayoutParams();
 switch (widthParentMeasureMode) {
  //         
  case MeasureSpec.UNSPECIFIED:
   //            
   if (thisLp.width > 0) {
    resultWidthSize = thisLp.width;
    resultWidthMode = MeasureSpec.EXACTLY;
   } else {
    resultWidthSize = (int) (getYMaxTextWidth() + mXinterval * mXdots.length);
    resultWidthMode = MeasureSpec.UNSPECIFIED;
   }
   break;
  case MeasureSpec.AT_MOST:
   //            
   if (thisLp.width > 0) {
    resultWidthSize = thisLp.width;
    resultWidthMode = MeasureSpec.EXACTLY;
   } else if (thisLp.width == ViewGroup.LayoutParams.MATCH_PARENT) {
    resultWidthSize = Math.max(0, widthParentMeasureSize - paddingWidth);
    resultWidthMode = MeasureSpec.AT_MOST;
   } else if (thisLp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
    resultWidthSize = (int) (getYMaxTextWidth() + mXinterval * mXdots.length);
    resultWidthMode = MeasureSpec.AT_MOST;
   }
   break;
  case MeasureSpec.EXACTLY:
   //            
   if (thisLp.width > 0) {
    resultWidthSize = Math.min(widthParentMeasureSize, thisLp.width);
    resultWidthMode = MeasureSpec.EXACTLY;
   } else if (thisLp.width == ViewGroup.LayoutParams.MATCH_PARENT) {
    resultWidthSize = widthParentMeasureSize;
    resultWidthMode = MeasureSpec.EXACTLY;
   } else if (thisLp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
    resultWidthSize = (int) (getYMaxTextWidth() + mXinterval * mXdots.length);
    resultWidthMode = MeasureSpec.AT_MOST;
   }
   break;
 }

 switch (heightParentMeasureMode) {
  // view    
  case MeasureSpec.UNSPECIFIED:
   //            
   if (thisLp.height > 0) {
    resultHeightSize = thisLp.height;
    resultHeightMode = MeasureSpec.EXACTLY;
   } else {
    resultHeightSize = (int) (getYMaxTextHeight() + mYvisibleNum * mYinterval + getXMaxTextHeight());
    resultHeightMode = MeasureSpec.UNSPECIFIED;
   }
   break;
  case MeasureSpec.AT_MOST:
   if (thisLp.height > 0) {
    resultHeightSize = heightParentMeasureSize;
    resultHeightMode = MeasureSpec.EXACTLY;
   } else if (thisLp.height == ViewGroup.LayoutParams.MATCH_PARENT) {
    resultHeightSize = Math.max(0, heightParentMeasureSize - paddingHeight);
    resultHeightMode = MeasureSpec.AT_MOST;
   } else if (thisLp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
    resultHeightSize = (int) (getYMaxTextHeight() + mYvisibleNum * mYinterval + getXMaxTextHeight());
    resultHeightMode = MeasureSpec.UNSPECIFIED;
   }
   break;
  case MeasureSpec.EXACTLY:
   //            
   if (thisLp.height > 0) {
    resultHeightSize = Math.min(heightParentMeasureSize, getMeasuredWidth());
    resultHeightMode = MeasureSpec.EXACTLY;
   } else if (thisLp.width == ViewGroup.LayoutParams.MATCH_PARENT) {
    resultHeightSize = heightParentMeasureSize;
    resultHeightMode = MeasureSpec.EXACTLY;
   } else if (thisLp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
    resultHeightSize = (int) (getYMaxTextHeight() + mYvisibleNum * mYinterval + getXMaxTextHeight());
    resultHeightMode = MeasureSpec.AT_MOST;
   }
   break;
 }
 setMeasuredDimension(MeasureSpec.makeMeasureSpec(resultWidthSize, resultWidthMode),
   MeasureSpec.makeMeasureSpec(resultHeightSize, resultHeightMode));
사 이 즈 를 설정 하면 우 리 는 화면 을 그 릴 수 있 습 니 다.여기 서 우리 온 드 로 우 는 가로줄 과 세로 줄 을 차례대로 그립 니 다.가로줄 을 그 릴 때 Y 좌표 의 숫자 를 함께 그 릴 수 있 습 니 다.마찬가지 로 세로 줄 을 그 릴 때 x 좌표 의 숫자 를 그 립 니 다.접 는 선 은 숫자 에 따라 좌표 점 을 계산 한 다음 에 path 를 만 듭 니 다.먼저moveTo(firstX,firstY) 그리고 lineto 아래 의 점 을 그리 면 됩 니 다.마지막 으로 path 를 그립 니 다.그러면 우 리 는 미 끄 러 질 때 이 view 가 함께 구 르 는 것 을 발견 할 수 있 습 니 다.그러면 우 리 는 어떻게 해야만 view 의 부분 pinned 를 실현 할 수 있 습 니까?이 럴 때,우 리 는 먼저 비트 맵 을 만들어 서 미 끄 러 져 야 할 부분 을 이 비트 맵 에 그 려 야 합 니 다.그리고 비트 맵 은 이 canvas 에 그 려 질 때 고정된 위 치 를 유지 하면 됩 니 다.자,그리고 나 서 어리둥절 합 니 다.코드 를 올 리 는 것 이 좋 겠 습 니 다.

 float tempTableLeftPadding = getYMaxTextWidth();
 if (mBitmap == null || mYNumCanvas == null) {
  mBitmap = Bitmap.createBitmap((int) (getMeasuredWidth() - getYMaxTextWidth()), getMeasuredHeight(), Bitmap.Config.ARGB_8888);
  mYNumCanvas = new Canvas(mBitmap);
 }
 mYNumCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
 mYNumCanvas.translate(mScrollPosX,0);//              

 //    
 for (int y = 0, size = mYdots.length; y < size; y++) {
  String tempText = String.valueOf(mYdots[mYdots.length - 1 - y]);
  mYNumCanvas.drawLine(0, (float) (mYinterval * y), (float) (mXdots.length * mXinterval), (float) (mYinterval * y), mXlinePaint);
  canvas.drawText(tempText, getYMaxTextWidth() - mYNumPaint.measureText(tempText), getYMaxTextHeight() + (float) (mYinterval * y), mYNumPaint);
 }
 //    
 for (int x = 0, size = mXdots.length; x <= size; x++) {
  mYNumCanvas.drawLine((float) (mXinterval * x), 0, (float) (mXinterval * x), (float) (mYinterval * mYvisibleNum), mXlinePaint);
  if (x >= 1) {
   String tempText = mXdots[x - 1];
   mYNumCanvas.drawText(tempText, (float) (mXinterval * x) - mYNumPaint.measureText(tempText) / 2, (float) (mYvisibleNum * mYinterval + getYMaxTextHeight()), mYNumPaint);
  }
 }
 if (isAnimationOpen)//          ,           
  mYNumCanvas.drawPath(mLineDrawPath, mLinePaint);
 else
  mYNumCanvas.drawPath(mLinePath, mLinePaint);
 canvas.drawBitmap(mBitmap, tempTableLeftPadding, getYMaxTextHeight() / 2, null);
위의 mScrollPosX 는 제스처 감청 류 Gesture Detector 에 따라 가 져 옵 니 다.

@Override
public boolean onTouchEvent(MotionEvent event) {
 if (!isAnimationOpen || isDrawOver)
  return mGestureDetector.onTouchEvent(event);
 return super.onTouchEvent(event);
}
그러나 그림 을 그 렸 습 니 다.우 리 는 무엇이 부족 하 다 고 느 꼈 습 니 다.네,바로 애니메이션 효과 입 니 다.여기 서 우리 가 사용 하 는 path 를 통 해 애니메이션 을 실현 하 는 방안 은 Path Measure 를 통 해 path 의 길 이 를 얻 은 다음 에 애니메이션 시간 에 따라 ValueAnimator 를 통 해 특정한 시간의 좌 표를 계산 한 다음 에 path 경 로 를 다시 그 리 는 것 입 니 다.

private void startPathAnim(long duration) {
 ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, mLineLength);
 valueAnimator.setDuration(duration);
 valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
  @Override
  public void onAnimationUpdate(ValueAnimator animation) {
   float value = (Float) animation.getAnimatedValue();
   //           mCurrentPosition
   mPathMeasure.getPosTan(value, mCurrentPosition, null);
   mLineDrawPath.lineTo(mCurrentPosition[0], mCurrentPosition[1]);
   invalidate();
  }
 });
 valueAnimator.start();
}
백분율 원형 도표 실현

사실 이 실현 은 이전 보다 많이 줄 어 들 었 습 니 다.대부분이 onDraw 방법 에 집중 되 었 습 니 다.관건 은 백분율 의 숫자 입 니 다.부채 형 구역 에 어떻게 가로로 표시 하 느 냐 입 니 다.여기 서 저 는 주로 이 계산 규칙 을 제시 합 니 다.

private void drawText(Canvas canvas, float sweepAngle, float startAngle, ArcVo temp) {
 float middleAngle;
 middleAngle = startAngle + sweepAngle / 2;
 float startX;
 float startY;
 float endX;
 float endY;
 String drawText = temp.getPercentInCircle() * 100 + "%";
 if (middleAngle <= 90) {
  //     
  double angle = middleAngle;
  angle = Math.toRadians(angle);
  startY = endY = (float) (Math.sin(angle) * mRaduis + mRaduis);
  endX = (float) (mRaduis + Math.cos(angle) * mRaduis);
  startX = endX - UiUtils.getTextWidth(drawText, mTextPaint);
 } else if (middleAngle <= 180) {
  //     
  double angle = 180 - middleAngle;
  angle = Math.toRadians(angle);
  startY = endY = (float) (Math.sin(angle) * mRaduis + mRaduis);
  startX = (float) (mRaduis - Math.cos(angle) * mRaduis);
  endX = startX + UiUtils.getTextWidth(drawText, mTextPaint);
 } else if (middleAngle <= 270) {
  //     
  double angle = 270 - middleAngle;
  angle = Math.toRadians(angle);
  startY = endY = (float) (mRaduis - Math.cos(angle) * mRaduis);
  startX = (float) (mRaduis - Math.sin(angle) * mRaduis);
  endX = startX + UiUtils.getTextWidth(drawText, mTextPaint);
 } else {
  //     
  double angle = 360 - middleAngle;
  angle = Math.toRadians(angle);
  startY = endY = (float) (mRaduis - Math.sin(angle) * mRaduis);
  endX = (float) (mRaduis + Math.cos(angle) * mRaduis);
  startX = endX - UiUtils.getTextWidth(drawText, mTextPaint);
 }

 mTextPath.reset();
 mTextPath.moveTo(startX, startY);
 mTextPath.lineTo(endX, endY);
 if (middleAngle > 180) {
  canvas.drawTextOnPath(drawText, mTextPath, 0, UiUtils.getTextHeight(drawText, mTextPaint), mTextPaint);
 } else {
  canvas.drawTextOnPath(drawText, mTextPath, 0, -UiUtils.getTextHeight(drawText, mTextPaint), mTextPaint);

 }
}
 @Override
protected void onDraw(Canvas canvas) {
 if (!canDraw()) return;
 float sweepAngle;
 float startAngle = 0;
 for (int i = 0, size = mDisArcList.size(); i < size; i++) {
  ArcVo temp = mDisArcList.get(i);
  mArcPaint.setColor(temp.getScanColor());
  sweepAngle = temp.getPercentInCircle() * 360;
  canvas.drawArc(mDrawCircleRect, startAngle, sweepAngle, true, mArcPaint);
  drawText(canvas, sweepAngle, startAngle, temp);
  startAngle = startAngle + sweepAngle;
 }
}
사용 방법:
프로젝트 에 유사 한 아이콘 을 사용 해 야 한다 고 생각한다 면 프로젝트 의 gradle 파일 에 copile'wellijohn.org.simplelinechart:linechart:0.00.2'구체 적 인 방법 을 추가 하 십시오.github 로 이동 하 는 것 을 환영 합 니 다.라 이브 러 리 로 봉 하여 jcenter 에 올 렸 습 니 다.위 에 구체 적 인 사용 방법(도표 주소)이 있 습 니 다.현재 노출 된 방법 이 많 지 않 습 니 다.메 시 지 를 남 겨 서 추가 할 수 있 습 니 다.
github 주소:https://github.com/WelliJohn/LineChart
로 컬 다운로드:http://xiazai.jb51.net/201712/yuanma/LineChart(jb51.net).rar
총결산
이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가치 가 있 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.

좋은 웹페이지 즐겨찾기