Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
/*
* The MIT License
* Copyright 2018 Una Thompson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import java.util.Calendar;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Paint.Join;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.util.DisplayMetrics;
public class ClockDrawable extends Drawable {
private static final float TAU = (float)(Math.PI*2);
private Context ctx;
private int color;
private int sizeDp;
private int alpha = 255;
private ColorFilter colorFilter;
private Handler handler = new Handler();
private Path path = new Path();
private Paint paint = new Paint();
private Calendar calendar = Calendar.getInstance();
private boolean fixed = false;
private boolean drawSecondsHand = false;
private boolean smoothSeconds = false;
public ClockDrawable(Context ctx, int color, int sizeDp, int alpha) {
this.ctx = ctx;
this.color = color;
this.sizeDp = sizeDp;
this.alpha = alpha;
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
this.colorFilter = colorFilter;
invalidateSelf();
}
@Override
public void setAlpha(int alpha) {
this.alpha = alpha;
invalidateSelf();
}
@Override
public int getOpacity() {
return alpha;
}
public void setFixedTime(Calendar calendar) {
if (calendar == null) {
this.calendar = Calendar.getInstance();
this.fixed = false;
} else {
this.calendar = calendar;
this.fixed = true;
}
invalidateSelf();
}
public void setDrawSecondsHand(boolean drawSecondsHand) {
this.drawSecondsHand = drawSecondsHand;
}
public void setSmoothSeconds(boolean smoothSeconds) {
this.smoothSeconds = smoothSeconds;
}
@Override
public void draw(Canvas canvas) {
DisplayMetrics dm = ctx.getResources().getDisplayMetrics();
float dp = dm.density;
if (!fixed) {
calendar.setTimeInMillis(System.currentTimeMillis());
}
int hour = calendar.get(Calendar.HOUR);
int minute = calendar.get(Calendar.MINUTE);
int second = calendar.get(Calendar.SECOND);
int millis = calendar.get(Calendar.MILLISECOND);
float secondExact = smoothSeconds ? second+(millis/1000f) : second;
float minuteExact = minute+(secondExact/60f);
float hourExact = hour+(minuteExact/60f);
float hourAngle = (hourExact/12f)*TAU;
float minuteAngle = (minuteExact/60f)*TAU;
float secondAngle = (secondExact/60f)*TAU;
float hourX = (float)Math.sin(hourAngle);
float hourY = (float)-Math.cos(hourAngle);
float minuteX = (float)Math.sin(minuteAngle);
float minuteY = (float)-Math.cos(minuteAngle);
float secondX = drawSecondsHand ? (float)Math.sin(secondAngle) : 0;
float secondY = drawSecondsHand ? (float)-Math.cos(secondAngle) : 0;
float size = sizeDp*dp;
float half = size/2;
float hourOffset = 4*dp;
float minuteOffset = 6*dp;
float secondOffset = 7*dp;
paint.setStrokeWidth(1.5f*dp);
paint.setAntiAlias(true);
paint.setColorFilter(colorFilter);
paint.setStrokeJoin(Join.BEVEL);
paint.setColor(color);
paint.setAlpha(alpha);
paint.setStyle(Style.STROKE);
path.reset();
path.moveTo(half, half);
path.lineTo(half+(hourX*hourOffset), half+(hourY*hourOffset));
path.moveTo(half, half);
path.lineTo(half+(minuteX*minuteOffset), half+(minuteY*minuteOffset));
canvas.drawPath(path, paint);
if (drawSecondsHand) {
paint.setStrokeWidth(1*dp);
path.reset();
path.moveTo(half, half);
path.lineTo(half+(secondX*secondOffset), half+(secondY*secondOffset));
canvas.drawPath(path, paint);
}
paint.setStrokeWidth(2*dp);
canvas.drawOval(3*dp, 3*dp, size-(3*dp), size-(3*dp), paint);
handler.removeCallbacksAndMessages(null);
if (!fixed) {
if (drawSecondsHand) {
if (smoothSeconds) {
invalidateSelf();
} else {
handler.postDelayed(this::invalidateSelf, 1000);
}
} else {
handler.postDelayed(this::invalidateSelf, 5000);
}
}
}
@Override
public int getIntrinsicHeight() {
return (int)(sizeDp*ctx.getResources().getDisplayMetrics().density);
}
@Override
public int getIntrinsicWidth() {
return (int)(sizeDp*ctx.getResources().getDisplayMetrics().density);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment