안드로이드 사용자 정의 컨트롤:클록
14381 단어 Android
이러한 분석에 따르면 사용자 정의 시계는 매우 간단하다. 바로 원을 그리고 천의 회전을 통해 눈금선과 바늘을 그리는 것이다.
구체적 실현 과정
//
canvas.drawCircle(centerX, centerY, radius, circlePaint);
그 중에서centerX와centerY는 원심으로 현재 컨트롤러의 중심점을 사용하면되고radius는 원의 반경으로 현재 컨트롤러의 넓이가 가장 작은 값/2을 사용하거나 스스로 설정하면 된다.//
private final static int MARK_LENGTH = 20;
//
private final static int MARK_GAP = 12;
//
for (int i = 0; i < 12; i++) {
if (i % 3 == 0) {//
markPaint.setColor(mQuarterMarkColor);
} else {
markPaint.setColor(mMinuteMarkColor);
}
canvas.drawLine(
centerX,
centerY - radius + MARK_GAP,
centerX,
centerY - radius + MARK_GAP + MARK_LENGTH,
markPaint);
canvas.rotate(30, centerX, centerY);
}
canvas.save();
@Override
protected void onDraw(Canvas canvas) {
Calendar calendar = Calendar.getInstance();
int hour12 = calendar.get(Calendar.HOUR);
int minute = calendar.get(Calendar.MINUTE);
int second = calendar.get(Calendar.SECOND);
//
hourCanvas.save();
//
hourCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
//
hourCanvas.rotate(hour12 * 30, centerX, centerY);
// 12
hourCanvas.drawLine(centerX, centerY,
centerX, centerY - hourLineLength, hourPaint);
// , ,
hourCanvas.restore();
canvas.drawBitmap(hourBitmap, 0, 0, null);
// 1s
postInvalidateDelayed(1000);
}
를 붙인다. 그러나 우리는 약간의 부족함을 발견할 수 있다. 초침은 1초 1초로 돌지만 시계 바늘과 바늘은 항상 정수 위치에 있다. 60초가 지나야 시계 바늘이 다음 분으로 넘어간다. 60분이 지나야 시계 바늘이 다음 시간으로 넘어간다.우리가 평소에 보는 시계는 모두 초침의 회전에 따라 분침과 시침은 일정한 편이량을 가진다. 물론 우리의 시계도 이렇게 멋있어야 한다. 그러면 어떻게 계산합니까?시침: 앞에서 말했듯이 시침마다 30도 회전한다. 현재 시간의 시간이 h(12시간제)라고 가정하면 시침의 회전 각도는 h*30이다.그러면 분당 시곗바늘이 몇 도 회전하느냐에 따라 답은 30/60=0.5도(시간당 60분, 시간당 30도)입니다. 그래서 시곗바늘의 편이량은 m*0.5입니다. 그러면 현재 시간이 1:30이라고 가정하면 시곗바늘이 회전하는 각도는 1*30+30*0.5이고 45도입니다. 변수 공식으로 바꾸면 h*30+m*0.5입니다.그러면 위의 코드hourCanvas.rotate(hour12 * 30 + minute * 0.5f, centerX, centerY);
를 수정합니다. 분침: 현재 시간의 분이 m라고 가정하면 분침의 회전 각도는 m*6이고 초당 분침은 6/60(분당 60초, 분당 6도)이기 때문에 분침의 편이량은 s*0.1입니다. 그러면 분침화포가 회전하는 코드는 minuteCanvas.rotate(minute * 6 + second * 0.1f, centerX, centerY);
초침입니다. 초침은 초당 6도secondCanvas.rotate(second * 6, centerX, centerY);
총결산
위의 세 단계를 거쳐 우리는 천천히 움직이는 시계를 그렸다.
온전한 코드와 프로젝트는 저의github에서 보실 수 있습니다. 그 안에 관련 사용 방법이 있습니다. 또한 이 프로젝트는 마븐 창고에 업로드되어gradle을 통해 직접 사용할 수 있습니다.
compile 'com.don:clockviewlibrary:1.0.1'
github 주소:https://github.com/zhijieeeeee/ClockView
전체 코드
public class ClockView extends View {
// wrap_content
private final static int DEFAULT_SIZE = 400;
//
private final static int MARK_WIDTH = 8;
//
private final static int MARK_LENGTH = 20;
//
private final static int MARK_GAP = 12;
//
private final static int HOUR_LINE_WIDTH = 10;
//
private final static int MINUTE_LINE_WIDTH = 6;
//
private final static int SECOND_LINE_WIDTH = 4;
//
private int centerX;
private int centerY;
//
private int radius;
//
private Paint circlePaint;
//
private Paint markPaint;
//
private Paint hourPaint;
//
private Paint minutePaint;
//
private Paint secondPaint;
//
private int hourLineLength;
//
private int minuteLineLength;
//
private int secondLineLength;
private Bitmap hourBitmap;
private Bitmap minuteBitmap;
private Bitmap secondBitmap;
private Canvas hourCanvas;
private Canvas minuteCanvas;
private Canvas secondCanvas;
//
private int mCircleColor = Color.WHITE;
//
private int mHourColor = Color.BLACK;
//
private int mMinuteColor = Color.BLACK;
//
private int mSecondColor = Color.RED;
//
private int mQuarterMarkColor = Color.parseColor("#B5B5B5");
//
private int mMinuteMarkColor = Color.parseColor("#EBEBEB");
// 3
private boolean isDrawCenterCircle = false;
//
private OnCurrentTimeListener onCurrentTimeListener;
public void setOnCurrentTimeListener(OnCurrentTimeListener onCurrentTimeListener) {
this.onCurrentTimeListener = onCurrentTimeListener;
}
public ClockView(Context context) {
super(context);
init();
}
public ClockView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ClockView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ClockView);
mCircleColor = a.getColor(R.styleable.ClockView_circle_color, Color.WHITE);
mHourColor = a.getColor(R.styleable.ClockView_hour_color, Color.BLACK);
mMinuteColor = a.getColor(R.styleable.ClockView_minute_color, Color.BLACK);
mSecondColor = a.getColor(R.styleable.ClockView_second_color, Color.RED);
mQuarterMarkColor = a.getColor(R.styleable.ClockView_quarter_mark_color, Color.parseColor("#B5B5B5"));
mMinuteMarkColor = a.getColor(R.styleable.ClockView_minute_mark_color, Color.parseColor("#EBEBEB"));
isDrawCenterCircle = a.getBoolean(R.styleable.ClockView_draw_center_circle, false);
a.recycle();
init();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
reMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth();
int height = getMeasuredHeight();
centerX = width / 2 ;
centerY = height / 2;
radius = Math.min(width, height) / 2;
hourLineLength = radius / 2;
minuteLineLength = radius * 3 / 4;
secondLineLength = radius * 3 / 4;
//
hourBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
hourCanvas = new Canvas(hourBitmap);
//
minuteBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
minuteCanvas = new Canvas(minuteBitmap);
//
secondBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
secondCanvas = new Canvas(secondBitmap);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//
canvas.drawCircle(centerX, centerY, radius, circlePaint);
//
for (int i = 0; i < 12; i++) {
if (i % 3 == 0) {//
markPaint.setColor(mQuarterMarkColor);
} else {
markPaint.setColor(mMinuteMarkColor);
}
canvas.drawLine(
centerX,
centerY - radius + MARK_GAP,
centerX,
centerY - radius + MARK_GAP + MARK_LENGTH,
markPaint);
canvas.rotate(30, centerX, centerY);
}
canvas.save();
Calendar calendar = Calendar.getInstance();
int hour12 = calendar.get(Calendar.HOUR);
int minute = calendar.get(Calendar.MINUTE);
int second = calendar.get(Calendar.SECOND);
//( ) (3600 ) 30 , (1/120)
//( ) (60 ) 30 , (1/2)
hourCanvas.save();
//
hourCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
hourCanvas.rotate(hour12 * 30 + minute * 0.5f, centerX, centerY);
hourCanvas.drawLine(centerX, centerY,
centerX, centerY - hourLineLength, hourPaint);
if (isDrawCenterCircle)//
hourCanvas.drawCircle(centerX, centerY, 2 * HOUR_LINE_WIDTH, hourPaint);
hourCanvas.restore();
// (60 ) 6 , (1/10) ; minute 1 , second 0
minuteCanvas.save();
//
minuteCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
minuteCanvas.rotate(minute * 6 + second * 0.1f, centerX, centerY);
minuteCanvas.drawLine(centerX, centerY,
centerX, centerY - minuteLineLength, minutePaint);
if (isDrawCenterCircle)//
minuteCanvas.drawCircle(centerX, centerY, 2 * MINUTE_LINE_WIDTH, minutePaint);
minuteCanvas.restore();
// 6
secondCanvas.save();
//
secondCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
secondCanvas.rotate(second * 6, centerX, centerY);
secondCanvas.drawLine(centerX, centerY,
centerX, centerY - secondLineLength, secondPaint);
if (isDrawCenterCircle)//
secondCanvas.drawCircle(centerX, centerY, 2 * SECOND_LINE_WIDTH, secondPaint);
secondCanvas.restore();
canvas.drawBitmap(hourBitmap, 0, 0, null);
canvas.drawBitmap(minuteBitmap, 0, 0, null);
canvas.drawBitmap(secondBitmap, 0, 0, null);
// 1s
postInvalidateDelayed(1000);
if (onCurrentTimeListener != null) {
// 24
int h = calendar.get(Calendar.HOUR_OF_DAY);
String currentTime = intAdd0(h) + ":" + intAdd0(minute) + ":" + intAdd0(second);
onCurrentTimeListener.currentTime(currentTime);
}
}
/**
*
*/
private void init() {
circlePaint = new Paint();
circlePaint.setAntiAlias(true);
circlePaint.setStyle(Paint.Style.FILL);
circlePaint.setColor(mCircleColor);
markPaint = new Paint();
circlePaint.setAntiAlias(true);
markPaint.setStyle(Paint.Style.FILL);
markPaint.setStrokeCap(Paint.Cap.ROUND);
markPaint.setStrokeWidth(MARK_WIDTH);
hourPaint = new Paint();
hourPaint.setAntiAlias(true);
hourPaint.setColor(mHourColor);
hourPaint.setStyle(Paint.Style.FILL);
hourPaint.setStrokeCap(Paint.Cap.ROUND);
hourPaint.setStrokeWidth(HOUR_LINE_WIDTH);
minutePaint = new Paint();
minutePaint.setAntiAlias(true);
minutePaint.setColor(mMinuteColor);
minutePaint.setStyle(Paint.Style.FILL);
minutePaint.setStrokeCap(Paint.Cap.ROUND);
minutePaint.setStrokeWidth(MINUTE_LINE_WIDTH);
secondPaint = new Paint();
secondPaint.setAntiAlias(true);
secondPaint.setColor(mSecondColor);
secondPaint.setStyle(Paint.Style.FILL);
secondPaint.setStrokeCap(Paint.Cap.ROUND);
secondPaint.setStrokeWidth(SECOND_LINE_WIDTH);
}
/**
* view
*/
private void reMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int measureWidth = MeasureSpec.getSize(widthMeasureSpec);
int measureHeight = MeasureSpec.getSize(heightMeasureSpec);
int measureWidthMode = MeasureSpec.getMode(widthMeasureSpec);
int measureHeightMode = MeasureSpec.getMode(heightMeasureSpec);
if (measureWidthMode == MeasureSpec.AT_MOST
&& measureHeightMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(DEFAULT_SIZE, DEFAULT_SIZE);
} else if (measureWidthMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(DEFAULT_SIZE, measureHeight);
} else if (measureHeightMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(measureWidth, DEFAULT_SIZE);
}
}
public interface OnCurrentTimeListener {
void currentTime(String time);
}
/**
* int 10 0
*
* @param i
* @return
*/
private String intAdd0(int i) {
DecimalFormat df = new DecimalFormat("00");
if (i < 10) {
return df.format(i);
} else {
return i + "";
}
}
}
사용자 정의 속성
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Bitrise에서 배포 어플리케이션 설정 테스트하기이 글은 Bitrise 광고 달력의 23일째 글입니다. 자체 또는 당사 등에서 Bitrise 구축 서비스를 사용합니다. 그나저나 며칠 전 Bitrise User Group Meetup #3에서 아래 슬라이드를 발표했...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.