Android 사용자 정의 View 그 라 데 이 션 컬러 계기판 구현

12988 단어 AndroidView계기판
앞에서 말 했 듯 이 최근 에 사용자 정의 View 에 관 한 지식 을 배우 고 있 습 니 다.이것 은 안 드 로 이 드 에서 매우 어 려 운 부분 이 라 고 생각 합 니 다.물론 이것 도 모든 프로그래머 가 반드시 거 쳐 야 할 길 입 니 다.마침 회사 프로젝트 는 계기판 과 유사 한 효 과 를 회사 데 이 터 를 직관 적 으로 표시 하 라 고 요구 하기 때문에 간단하게 demo 를 써 서 실현 과정 을 기록 합 니 다.전편'안 드 로 이 드 사용자 정의 뷰 원호 진도 효과 구현'원호 와 문자 의 그리 기 를 간단하게 기록 하고 그 라 데 이 션 색 의 계기판 효 과 는 canvas 와 paint 의 사용(예 를 들 어 캔버스 회전,paint 의 그 라 데 이 션 색 설정 등)을 더욱 향상 시 킬 것 이다.
지식 정리
1.원호 그 라 데 이 션(SweetGradient)
2.원호 에 눈금 그리 기
3.포인터 가 현재 데이터 위 치 를 표시 합 니 다(Bitmap)
4.데이터 텍스트 는 라디안 에 따라 표 시 됩 니 다(drawTextOnPath)
효과 그림:

1.뷰 계승
(1)구조 재 작성,Paint 초기 화

public DashBoardView(Context context) {
 this(context, null);
}

public DashBoardView(Context context, AttributeSet attrs) {
 this(context, attrs, 0);
}

public DashBoardView(Context context, AttributeSet attrs, int defStyleAttr) {
 super(context, attrs, defStyleAttr);
 init();
}
관련 페인트 초기 화

/**
 *    Paint
 */
private void init() {
 //       
 defaultSize = dp2px(260);

 //          
 mPaintFlagsDrawFilter = new PaintFlagsDrawFilter
   (0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);

 //           
 mOuterGradientPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 //         
 mOuterGradientPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
 float position[] = {0.1f, 0.3f, 0.8f};
 Shader mShader = new SweepGradient(width / 2, radius, mColors, position);
 mOuterGradientPaint.setShader(mShader);
 mOuterGradientPaint.setStrokeCap(Paint.Cap.ROUND);
 mOuterGradientPaint.setStyle(Paint.Style.STROKE);
 mOuterGradientPaint.setStrokeWidth(30);

 //           
 mCalibrationPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 mCalibrationPaint.setColor(Color.WHITE);
 mCalibrationPaint.setStyle(Paint.Style.STROKE);

 //        
 mMiddlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 mMiddlePaint.setStyle(Paint.Style.STROKE);
 mMiddlePaint.setStrokeCap(Paint.Cap.ROUND);
 mMiddlePaint.setStrokeWidth(5);
 mMiddlePaint.setColor(GRAY_COLOR);

 //        
 mInnerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 mInnerPaint.setStyle(Paint.Style.STROKE);
 mInnerPaint.setStrokeCap(Paint.Cap.ROUND);
 mInnerPaint.setStrokeWidth(4);
 mInnerPaint.setColor(GRAY_COLOR);
 PathEffect mPathEffect = new DashPathEffect(new float[]{5, 5, 5, 5}, 1);
 mInnerPaint.setPathEffect(mPathEffect);

 //          
 mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 mTextPaint.setColor(GRAY_COLOR);
 mTextPaint.setTextSize(dp2px(12));

 //        
 mCenterTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 mCenterTextPaint.setTextAlign(Paint.Align.CENTER);

 //          
 mMiddleProgressPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 mMiddleProgressPaint.setColor(GREEN_COLOR);
 mMiddleProgressPaint.setStrokeCap(Paint.Cap.ROUND);
 mMiddleProgressPaint.setStrokeWidth(5);
 mMiddleProgressPaint.setStyle(Paint.Style.STROKE);

 //      
 mPointerBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 mPointerBitmapPaint.setColor(GREEN_COLOR);

 //         
 mBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.pointer);
 mBitmapHeight = mBitmap.getHeight();
 mBitmapWidth = mBitmap.getWidth();
}
주:
A.가장 바깥쪽 원호 의 그 라 데 이 션 색 은 SweetGradient 류 를 사용 하여 이 루어 졌 고 SweetGradient 는 Shader 에서 계승 되 었 습 니 다.
B.그 라 데 이 션 색 의 시작 각도 문 제 를 주의 하 세 요.원호 의 시작 각도 와 일치 하지 않 으 면 행렬 전환 을 사용 하여 회전 시 킨 다음 에 paint 에 shader 를 설정 하 게 하 세 요.
C.SweetGradient 의 세 번 째 매개 변수 int[]colors 는 두 개 이상 의 색상 값 을 포함해 야 합 니 다.그렇지 않 으 면 오류 가 발생 할 수 있 습 니 다.
D.SweetGradient 의 네 번 째 매개 변수의 배열 크기 는 세 번 째 매개 변수의 배열 크기 와 같 아야 하고 null 도 입력 할 수 있 습 니 다.
(2)onMeasure 재 작성,view 너비 측정 에 사용
onMeasure 방법:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 setMeasuredDimension(remeasure(widthMeasureSpec, defaultSize),
   remeasure(heightMeasureSpec, defaultSize));
}
remeasure 방법:

/**
 *             
 */
public int remeasure(int measureSpec, int defaultSize) {

 int result;
 int specSize = MeasureSpec.getSize(measureSpec);
 switch (MeasureSpec.getMode(measureSpec)) {
  case MeasureSpec.UNSPECIFIED:
   //   
   result = defaultSize;
   break;
  case MeasureSpec.AT_MOST:
   //  warp_content      
   result = Math.min(specSize, defaultSize);
   break;
  case MeasureSpec.EXACTLY:
   //  math_parent          
   result=specSize;
   break;
  default:
   result = defaultSize;
 }
 return result;
}
(3)onChange 재 작성,view 너비 가 져 오기
onChange 방법 에서 현재 View 의 너비 와 원호 의 반지름 을 가 져 오고 원호 의 RectF 를 초기 화 합 니 다.

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
 super.onSizeChanged(w, h, oldw, oldh);

 //  View  
 width = w;
 height = h;

 //    
 radius = width / 2;

 //    
 float oval1 = radius - mOuterGradientPaint.getStrokeWidth() * 0.5f;
 mOuterRectF = new RectF(-oval1, -oval1, oval1, oval1);

 //       
 float oval2 = radius * 5 / 8;
 float oval3 = radius * 3 / 4;
 mInnerRectF = new RectF(-oval2 + dp2px(5), -oval2 + dp2px(5), oval2 - dp2px(5), oval2 - dp2px(5));
 mMiddleRectF = new RectF(-oval3 + dp2px(10), -oval3 + dp2px(10), oval3 - dp2px(10), oval3 - dp2px(10));

 //      
 oval4 = radius * 6 / 8;
 mMiddleProgressRectF = new RectF(-oval4+ dp2px(10), -oval4+ dp2px(10), oval4- dp2px(10), oval4- dp2px(10));
}
(4)onDraw 재 작성 방법,view 그리 기

@SuppressLint("DrawAllocation")
@Override
protected void onDraw(Canvas canvas) {
 //         
 canvas.setDrawFilter(mPaintFlagsDrawFilter);
 //    
 drawArc(canvas);
 //        
 drawCalibration(canvas);
 //      path   
 drawArcText(canvas);
 //        
 drawCenterText(canvas);
 //    bitmap      
 drawBitmapProgress(canvas);
}
2.Canvas 보기 그리 기
mStartAngle=105f,mEndAngle=250f
(1)원호 그리 기

/**
 *               
 */
private void drawArc(Canvas canvas) {

 canvas.save();
 canvas.translate(width / 2, height / 2);
 //    140°
 canvas.rotate(140);
 //        
 canvas.drawArc(mOuterRectF, -mStartAngle, -mEndAngle, false, mOuterGradientPaint);

 //        
 canvas.drawArc(mInnerRectF, -mStartAngle, -mEndAngle, false, mInnerPaint);
 //      
 canvas.drawArc(mMiddleRectF, -mStartAngle, -mEndAngle, false, mMiddlePaint);
 canvas.restore();
}
(2)그 라 데 이 션 원호 의 크기 눈금 그리 기

/**
 *                 
 */
private void drawCalibration(Canvas canvas) {
 int dst = (int) (2 * radius - mOuterGradientPaint.getStrokeWidth());
 for (int i = 0; i <= 40; i++) {
  canvas.save();
  canvas.rotate(-(-30 + 6 * i), radius, radius);
  if (i % 10 == 0) {
   mCalibrationPaint.setStrokeWidth(4);
   //     
   canvas.drawLine(dst, radius, 2 * radius, radius, mCalibrationPaint);
  } else {
   //   
   mCalibrationPaint.setStrokeWidth(1);
   canvas.drawLine(dst, radius, 2 * radius, radius, mCalibrationPaint);
  }
  canvas.restore();
 }
}
주:
A.원호 의 총 호 도 는 240 f 이 고 40 회 순환한다.
B.작은 눈금 은 매번 6 라디안 을 회전 하고 작은 눈금 을 10 번 그 릴 때마다 큰 눈금 을 그립 니 다.즉,큰 눈금 은 매번 60 라디안 을 회전 합 니 다.
(3)원호 호도 에 따 른 설명 문 자 를 그립 니 다.

/**
 *            
 */
private void drawArcText(Canvas canvas) {
 canvas.save();
 //      
 int rotateAngle = 30;
 //    
 canvas.rotate(-118, radius - dp2px(26), radius-dp2px(103));
 for (int i = 0; i < valueList.size(); i++) {
  //      
  int startAngle = 30 * i - 108;
  //          
  Path paths = new Path();
  paths.addArc(mInnerRectF, startAngle, rotateAngle);
  float textLen = mTextPaint.measureText(valueList.get(i));
  canvas.drawTextOnPath(valueList.get(i), paths, -textLen / 2 + dp2px(20), -dp2px(22), mTextPaint);
  //canvas.drawText(text[i], radius - 10, radius * 3 / 16+dp2px(10), mTextPaint);
 }
 canvas.restore();
}
주:
A.drawTextOnPath 는 문자 가 path 경로 에 따라 표시 되 고 drawTextOnPath 의 세 번 째 매개 변수 인 hOffset 는 문자 수평 방향의 오프셋 이 며 네 번 째 매개 변수 인 vOffset 는 문자 수직 방향의 오프셋 입 니 다.
B.포 인 트 는 캔버스 시작 시의 회전 각도 와 서로 다른 문자 의 시작 각도 입 니 다.
(4)원호 중심의 데이터 및 설명 정보 그리 기

/**
 *            
 */
private void drawCenterText(Canvas canvas) {

 //       
 mCenterTextPaint.setColor(GREEN_COLOR);
 mCenterTextPaint.setTextSize(dp2px(25));
 mCenterTextPaint.setStyle(Paint.Style.STROKE);
 canvas.drawText(String.valueOf(mAnimatorValue), radius, radius, mCenterTextPaint);

 //        
 mCenterTextPaint.setTextSize(dp2px(20));
 canvas.drawText(mCurrentDes, radius, radius + dp2px(25), mCenterTextPaint);

}
(5)현재 수치 에 대응 하 는 원호 및 포인터 그림 표시 그리 기

/**
 *            
 */
private void drawBitmapProgress(Canvas canvas) {
 //       0,        
 if (mCurrentAngle==0f){
  return;
 }
 canvas.save();
 canvas.translate(radius, radius);
 canvas.rotate(270);
 //       
 canvas.drawArc(mMiddleProgressRectF, -mStartAngle-20, mCurrentAngle+5, false, mMiddleProgressPaint);
 canvas.rotate(60 + mCurrentAngle);
 //                   
 Matrix matrix = new Matrix();
 matrix.preTranslate(-oval4 - mBitmapWidth * 3 / 8 + 10, -mBitmapHeight / 2);
 canvas.drawBitmap(mBitmap, matrix, mPointerBitmapPaint);
 canvas.restore();
}
주:포인터 그림 의 포인터 가 눈금 판 의 눈금 을 가리 키 도록 행렬 의 평 이 를 사용 합 니 다.
3.애니메이션 및 데이터 추가
(1)애니메이션 효과

/**
 *                    
 */
public void startRotateAnim() {

 ValueAnimator mAngleAnim = ValueAnimator.ofFloat(mCurrentAngle, mTotalAngle);
 mAngleAnim.setInterpolator(new AccelerateDecelerateInterpolator());
 mAngleAnim.setDuration(2500);
 mAngleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

  @Override
  public void onAnimationUpdate(ValueAnimator valueAnimator) {

   mCurrentAngle = (float) valueAnimator.getAnimatedValue();
   postInvalidate();
  }
 });
 mAngleAnim.start();

 ValueAnimator mNumAnim = ValueAnimator.ofInt(mAnimatorValue, mCurrentValue);
 mNumAnim.setDuration(2500);
 mNumAnim.setInterpolator(new LinearInterpolator());
 mNumAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

  @Override
  public void onAnimationUpdate(ValueAnimator valueAnimator) {

   mAnimatorValue = (int) valueAnimator.getAnimatedValue();
   postInvalidate();
  }
 });
 mNumAnim.start();
}
(2)데이터 설정 및 설명 정보

/**
 *     
 */
public void setValues(int values, List<String> valueList) {
 this.valueList=valueList;
 if (values <= 0) {
  mCurrentValue = values;
  mTotalAngle = 0f;
  mCurrentDes = "";
 } else if (values <= 14000) {
  mCurrentValue = values;
  mTotalAngle = values / 14000f * 60-2;
  Log.e("rcw","mTotalAngle="+mTotalAngle);
  mCurrentDes = "    ";
 } else if (values>14000&&values <= 17000) {
  mCurrentValue = values;
  mCurrentDes = "    ";
  mTotalAngle = values / 17000f * 120-2;
 } else if (values>17000&&values <= 21000) {
  mCurrentValue = values;
  mTotalAngle = values / 21000f * 180-2;
  mCurrentDes = "    ";
 } else {
  mCurrentValue=values;
  float ratio=values / 21000f;
  if (ratio<20){
   mTotalAngle = ratio+180;
  }else {
   mTotalAngle = (float) (ratio*0.2+200);
  }
  mCurrentDes = "    ";
 }

 startRotateAnim();
}
요약:사용자 정의 View 는 계기판 효 과 를 실현 하기 위해 canvas 의 회전 과 행렬 의 이동 을 사용 합 니 다.drawTextOnpath 에서 path 에 따라 텍스트 그리 기;SweetGradient 는 원호 의 그 라 데 이 션 효 과 를 실현 합 니 다.
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기