Android 사용자 정의 View 링 진도 바 의 사고 와 인 스 턴 스 실현

머리말
얼마 전에 콩잎 FM 의 음악 재생 화면 을 보 았 는데 링 모양 의 진도 가 있어 서 너무 예 뻤 어 요.그래서 왜 혼자 만 들 지 않 았 을 까 하 는 생각 이 들 었 어 요.그래서 사용자 정의 과정 을 시 작 했 어 요.
콩짜개 FM 의 재생 화면 은 아래 그림 과 같다.

기능 분석
비록 기능 이 비교적 간단 하지만,여전히 자세하게 분석 해 야 한다.
     1.아이콘 밖 에 동그라미 가 하나 더 있어 너비 설정 가능
     2.원형 진도 바 와 진도 바 밑 에 너비,색상 등 을 설정 할 수 있 습 니 다.
     3.내부 에 둥 근 그림 이 있어 회전 이 가능
사고 분석 을 실현 하 다.
1.원 폭 설정 가능
이것 은 비교적 쉽 습 니 다.onDraw 방법 에서 canvas 로 직접 그리 면 됩 니 다.물론 간격 과 반지름 의 처리 에 있어 서 자세 해 야 합 니 다.컨트롤 본 체 는 긴 사각형 입 니 다.우 리 는 비교적 짧 은 쪽 을 지름 으로 선택 하 는 동시에 내부 의 padding 도 처리 해 야 합 니 다.
2.원형 진도 바 와 진도 바 밑 에 너비,색상 등 을 설정 할 수 있 습 니 다.
이것 은 canvas 의 draw Arc 방법 으로 이 루어 질 수 있 습 니 다.서로 다른 길이 의 원호 형 을 그 려 서 진 도 를 나타 내 는 목적 을 달성 할 수 있 습 니 다.그러나 주의해 야 할 것 은 원호 형의 반지름 과 시작 과 끝 점 을 잘 계산 해 야 합 니 다.
3.내부 에 둥 근 그림 이 있어 회전 이 가능
이 수 요 는 그림,원형,회전 이 가능 한 세 부분 으로 나 눌 수 있다.
먼저 그림 이 있 습 니 다.간단 합 니 다.canvas 의 drawbitmap 방법 으로 그립 니 다.
그리고 원형 은 복잡 하지만 전체적으로 canvas 를 사용 하여 bitmap 를 조작 하고 코드 에서 자세히 말 합 니 다.
마지막 으로 회전 할 수 있 습 니 다.canvas 의 rotate 방법 으로 할 수 있 습 니 다.
효과 전시
이렇게 많은 말 을 했 는데 마지막 효 과 는 어 떨 까요?말 만 으로 는 증거 가 없 으 니 코드 전시 에 들 어가 기 전에 마지막 효 과 를 보 세 요.
이것 은 제 가 직접 만 든 정시 잠 금 화면 프로젝트 입 니 다.주 소 는 여기주소또는로 컬 다운로드입 니 다.
이것 은 이 프로젝트 가 잠 금 화면 을 실행 할 때의 움 직 이 는 그림 입 니 다.

코드 구현
다음은 코드 를 보 여 주 며 분석 을 시작 하 겠 습 니 다.
우리 의 주요 업 무 는 사용자 정의 view 의 onDraw 방법 으로 이 루어 집 니 다.그래서 우 리 는 View 류 를 계승 하 는 하위 클래스 가 필요 합 니 다.우 리 는 그 를 MyProgress 라 고 부 릅 시다.
저희 가 보 여 드 린 게 바로 이 MyProgress 의 onDraw 방법 입 니 다.
1.원 폭 설정 가능
아주 간단 합 니 다.우 리 는 canvas 의 drawCircle 방법 만 호출 하면 됩 니 다.그러나 padding 에 대한 처 리 를 주의해 야 합 니 다.처리 하지 않 으 면 무효 이기 때 문 입 니 다.

super.onDraw(canvas); //               onDraw
 
  final int paddingLeft = getPaddingLeft();
  final int paddingRight = getPaddingRight();
  final int paddingTop = getPaddingTop();
  final int paddingBottom = getPaddingBottom(); //  padding
 
  //get the view's width and height and decide the radiu
  int width = getWidth() - paddingLeft - paddingRight;
  int height = getHeight() - paddingTop - paddingBottom;
  radiu = Math.min(width , height) / 2 - boundWidth - progressWidth; //    ,            ,boundWidth      ,progressWidth       
 
  //setup the paint
  paint.setStyle(Paint.Style.STROKE); //  paint    
  paint.setStrokeWidth(boundWidth); //    
  paint.setColor(Color.BLACK);  //    
 
  //draw the inner circle
  int centerX = paddingLeft + getWidth()/2;
  int centerY = paddingTop + getHeight() / 2; //       
  canvas.drawCircle(centerX,centerY, radiu, paint); //    
2.원형 진도 바 와 진도 바 밑 에 너비,색상 등 을 설정 할 수 있 습 니 다.
여기 서 주의해 야 할 것 은 바로 시작 하 는 각도 와 끝 나 는 각도 입 니 다.진도 항목 의 목적 을 달성 하기 위해 우 리 는 업무 상태의 변화 에 따라 이 값 을 바 꿔 야 합 니 다.

  //set paint for arc
  paint.setStrokeWidth(progressWidth);
  paint.setStrokeCap(Paint.Cap.ROUND);//      ,         
 
  //prepare for draw arc
  RectF oval = new RectF();
  oval.left = centerX -totalRadiu ;
  oval.top =centerY- totalRadiu ;
  oval.right = centerX + totalRadiu;
  oval.bottom = centerY+ totalRadiu; //      ,         
  paint.setColor(progressBackColor);//          
 
  //draw background arc
  canvas.drawArc(oval, arcStar, arcEnd, false, paint); //         ,    
 
  //draw progress arc
  paint.setColor(progressColor);//        
  canvas.drawArc(oval, arcStar, progress, false, paint);//     
3.내부 에 둥 근 그림 이 있어 회전 이 가능
이 단락 은 비교적 복잡 해서 직접 코드 로 설명 한다.

  float totalRadiu = radiu +boundWidth +progressWidth/2;//    
 
  //draw the circlr pic
  if (drawable != null&&bitmap == null) {
   image = ((BitmapDrawable) drawable).getBitmap();//     bitmap  
 
   bitmap = Bitmap.createBitmap((int)(2*totalRadiu),(int)(2*totalRadiu), Bitmap.Config.ARGB_8888);
   Canvas bitmapCanvas = new Canvas(bitmap);//    bitmap     canvas    
 
   Paint bitmapPaint = new Paint();
   bitmapPaint.setAntiAlias(true);//    paint      
 
   bitmapCanvas.drawCircle(totalRadiu, totalRadiu, radiu, bitmapPaint);//    
 
   bitmapPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));//    ,       ,               
   bitmapCanvas.drawBitmap(image,null,new RectF(0,0,2*totalRadiu,2*totalRadiu) , bitmapPaint);//             
 
  }
  Rect rect = new Rect((int)(centerX -totalRadiu),(int)(centerY-totalRadiu),(int)(centerX+totalRadiu),(int)(centerY+ totalRadiu));//    rect,     
  canvas.save();
  if(isRotate)
  canvas.rotate(rotateDegree,centerX,centerY);//    ,          ,rotateDegree     
  canvas.drawBitmap(bitmap,null ,rect, paint);//        
위의 코드 가 있 으 면 저 희 는 View 의 주체 부분 을 사용자 정의 하면 완 성 됩 니 다.물론 보조 적 인 부분 도 있 습 니 다.예 를 들 어 진도 업데이트 와 각도 선택 함수,색상 과 너비 등 매개 변 수 를 설정 합 니 다.
전체 코드
MyProgress

public class MyProgressBar extends View {
 float progress = 360;
 float arcStar = 270;
 float arcEnd = 360;
 double rotateStep = 0.2;
 Bitmap bitmap;
 int totalTime;
 Bitmap image;
 Drawable drawable;
 int boundWidth = 5;
 private int progressWidth = 30;
 private boolean isRotate = false;
 private int progressColor = Color.GREEN;
 private int progressBackColor = Color.GREEN;
 private float rotateDegree = 0;
 
 
 public MyProgressBar(Context context) {
  super(context);
 }
 
 public MyProgressBar(Context context, AttributeSet attrs) {
  super(context, attrs);
 }
 
 public MyProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);
 }
 
 private float radiu;
 private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
 
 public void setRadiu(float radiu) {
  this.radiu = radiu;
  invalidate();
 }
//start      countDownTimer    progress     
 public void start(long time) {
  bitmap = null;
 
  time *= 60000;
  final float step = (float) 360 / (time / 30);
  CountDownTimer mTimer = new CountDownTimer(time, 30) {
   public void onTick(long millisUntilFinished) {
    progress -= step;
    rotateDegree -= rotateStep;
    invalidate();
   }
 
   @Override
   public void onFinish() {
    end(step);
   }
 
  };
  mTimer.start();
 }
 
 private void end(float step) {
  progress -= step;
  invalidate();
  progress = 0;
  rotateDegree = 0;
  invalidate();
 }
 
 public void setBoundWidth(int width) {
  boundWidth = width;
 }
 
 public void setProgressWidth(int width) {
  progressWidth = width;
 }
 
 public void setProgressColor(int color) {
  progressColor = color;
 }
 
 public void setProgressBackColor(int color) {
  progressBackColor = color;
 }
 
 public void setDrawable(Drawable drawable) {
  this.drawable = drawable;
  invalidate();
 }
 public void setIsRote(boolean rotate)
 {
  this.isRotate = rotate;
  invalidate();
 }
 
 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
 
  final int paddingLeft = getPaddingLeft();
  final int paddingRight = getPaddingRight();
  final int paddingTop = getPaddingTop();
  final int paddingBottom = getPaddingBottom();
 
  //get the view's width and height and decide the radiu
  int width = getWidth() - paddingLeft - paddingRight;
  int height = getHeight() - paddingTop - paddingBottom;
  radiu = Math.min(width , height) / 2 - boundWidth - progressWidth;
 
  //setup the paint
  paint.setStyle(Paint.Style.STROKE);
  paint.setStrokeWidth(boundWidth);
  paint.setColor(Color.BLACK);
 
  //draw the inner circle
  int centerX = paddingLeft + getWidth()/2;
  int centerY = paddingTop + getHeight() / 2;
  canvas.drawCircle(centerX,centerY, radiu, paint);
  
 
  float totalRadiu = radiu +boundWidth +progressWidth/2;
 
  //draw the circlr pic
  if (drawable != null&&bitmap == null) {
   image = ((BitmapDrawable) drawable).getBitmap();
 
   bitmap = Bitmap.createBitmap((int)(2*totalRadiu),(int)(2*totalRadiu), Bitmap.Config.ARGB_8888);
   Canvas bitmapCanvas = new Canvas(bitmap);
 
   Paint bitmapPaint = new Paint();
   bitmapPaint.setAntiAlias(true);
 
   bitmapCanvas.drawCircle(totalRadiu, totalRadiu, radiu, bitmapPaint);
 
   bitmapPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
   bitmapCanvas.drawBitmap(image,null,new RectF(0,0,2*totalRadiu,2*totalRadiu) , bitmapPaint);
 
 
  }
  Rect rect = new Rect((int)(centerX -totalRadiu),(int)(centerY-totalRadiu),(int)(centerX+totalRadiu),(int)(centerY+ totalRadiu));
  canvas.save();
  if(isRotate)
  canvas.rotate(rotateDegree,centerX,centerY);
  canvas.drawBitmap(bitmap,null ,rect, paint);
 
  canvas.restore();
  //set paint for arc
  paint.setStrokeWidth(progressWidth);
  paint.setStrokeCap(Paint.Cap.ROUND);
 
  //prepare for draw arc
  RectF oval = new RectF();
  oval.left = centerX -totalRadiu ;
  oval.top =centerY- totalRadiu ;
  oval.right = centerX + totalRadiu;
  oval.bottom = centerY+ totalRadiu;
  paint.setColor(progressBackColor);
 
  //draw background arc
  canvas.drawArc(oval, arcStar, arcEnd, false, paint);
 
  //draw progress arc
  paint.setColor(progressColor);
  canvas.drawArc(oval, arcStar, progress, false, paint);
 }
 
}
이 사용자 정의 VIEW 를 포함 한 전체 프로젝트 는 GitHub 의 프로젝트 주소여기 있 습 니 다.를 참고 할 수도 있 고로 컬 다운로드
총결산
간단 해 보 이 는 사용자 정의 View 제작 에서 생각 할 만 한 문제 가 적지 않 은 것 도 이 글 이 있 는 이유 다.
      1.원형 커팅 그림 을 처리 할 때 커팅 된 canvas 가 사용 하 는 좌 표 는 전체 좌표 가 아니 라 그림 을 처리 하 는 것 에 대비 해 야 합 니 다.
      2.그림 을 그 릴 때 반복 되 는 처 리 를 최소 화해 야 한다.예 를 들 어 원형 그림 을 자 르 면 한 번 이면 충분 하 다.만약 에 횟수 가 너무 많 으 면 진 도 를 업데이트 할 때마다 한 번 씩 진행 하기 때문에 전체 View 가 비교적 카드 가 되 고 진도 가 정확 하지 않다.
      3.사용자 정의 View 의 몇 가지 관건 적 인 좌표 에 대해 비교적 간단 하고 알 기 쉬 운 표현 식 으로 표시 해 야 한다.그렇지 않 으 면 후기 에 헷 갈 리 고 좌표 의 수렁 에 빠 질 수 있다.
      4.어떤 강력 해 보 이 는 효 과 는 합 리 적 으로 분석 하고 단계별 로 실현 하 는 것 이 어렵 지 않다.
자,이상 이 이 글 의 모든 내용 입 니 다.본 논문 의 내용 이 안 드 로 이 드 개발 자 여러분 에 게 어느 정도 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.

좋은 웹페이지 즐겨찾기