Android – [SelfView] 自定义圆盘指针时钟
ps:简约圆盘指针时钟,颜色可调、自由搭配;支持阿拉伯数字、罗马数字刻度显示;
效果图
使用:
< com.nepalese.harinetest.player.VirgoCircleClockandroid: id= " @+id/circleclock" android: layout_width= " 300dp" android: layout_height= " 300dp" app: paddingFrame= " 10dp" app: strokeSize= " 5dp" app: offsetMark= " -1dp" app: offsetText= " -1dp" app: rSmall= " 5px" app: rBig= " 8px" app: needBg= " true" app: frameColor= " @color/colorBlack30" app: bgColor= " @color/colorEye" app: markColor1= " @color/black" app: markColor2= " @color/colorWhite" app: textColor= " @color/black" app: txtSize= " 18sp" app: displayType= " type_num" />
private VirgoCircleClock circleClock;
circleClock = findViewById ( R . id. circleclock) ;
circleClock. startPlay ( ) ;
if ( circleClock != null ) { circleClock. releaseView ( ) ;
}
码源:
1. attrs.xml
<?xml version="1.0" encoding="utf-8"?>
< resources> < declare-styleable name = " VirgoCircleClock" > < attr name = " needBg" format = " boolean" /> < attr name = " bgColor" format = " color|reference" /> < attr name = " frameColor" format = " color|reference" /> < attr name = " markColor1" format = " color|reference" /> < attr name = " markColor2" format = " color|reference" /> < attr name = " textColor" format = " color|reference" /> < attr name = " secondColor" format = " color|reference" /> < attr name = " rBig" format = " dimension|reference" /> < attr name = " rSmall" format = " dimension|reference" /> < attr name = " offsetMark" format = " dimension|reference" /> < attr name = " offsetText" format = " dimension|reference" /> < attr name = " displayType" format = " integer" > < enum name = " type_num" value = " 1" /> < enum name = " type_roma" value = " 2" /> </ attr> < attr name = " paddingFrame" format = " dimension|reference" /> < attr name = " txtSize" format = " dimension|reference" /> < attr name = " strokeSize" format = " dimension|reference" /> </ declare-styleable>
</ resources>
2. VirgoCircleClock.java
package com. nepalese. harinetest. player ; import android. content. Context ;
import android. content. res. TypedArray ;
import android. graphics. Canvas ;
import android. graphics. Color ;
import android. graphics. Paint ;
import android. graphics. Rect ;
import android. os. Handler ;
import android. os. Message ;
import android. util. AttributeSet ;
import android. util. Log ;
import android. view. View ; import androidx. annotation. Nullable ; import com. nepalese. harinetest. R ; import java. util. Calendar ; public class VirgoCircleClock extends View { private static final String TAG = "VirgoCircleClock" ; private static final int DEF_RADIUS_BIG = 3 ; private static final int DEF_RADIUS_SMALL = 2 ; private static final int DEF_OFF_MARK = 2 ; private static final int DEF_OFF_TEXT = 3 ; private static final int TYPE_NUM = 1 ; private static final int TYPE_ROMA = 2 ; private static final int DEF_PADDING = 15 ; private static final float DEF_SIZE_TEXT = 18f ; private static final float DEF_FRAME_STROKE = 5f ; private static final float RATE_HOUR = 0.5f ; private static final float RATE_HOUR_TAIL = 0.05f ; private static final float RATE_HOUR_WIDTH = 70f ; private static final float RATE_MINUTE = 0.6f ; private static final float RATE_MINUTE_TAIL = 0.08f ; private static final float RATE_MINUTE_WIDTH = 120f ; private static final float RATE_SECOND = 0.7f ; private static final float RATE_SECOND_TAIL = 0.1f ; private static final float RATE_SECOND_WIDTH = 240f ; private Paint paintMain; private Paint paintFrame; private Calendar calendar; private boolean needBg; private int bgColor; private int frameColor; private int markColor1; private int markColor2; private int textColor; private int secondColor; private int radiusBig, radiusSmall; private int offMark, offText; private int markY, txtY; private int displayStyle; private int padding; private int radius; private int hours, minutes, seconds; private int centerX, centerY; private float textSize; private float strokeSize; public VirgoCircleClock ( Context context) { this ( context, null ) ; } public VirgoCircleClock ( Context context, @Nullable AttributeSet attrs) { this ( context, attrs, 0 ) ; } public VirgoCircleClock ( Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super ( context, attrs, defStyleAttr) ; init ( context, attrs) ; } private void init ( Context context, AttributeSet attrs) { TypedArray typedArray = context. obtainStyledAttributes ( attrs, R . styleable. VirgoCircleClock) ; needBg = typedArray. getBoolean ( R . styleable. VirgoCircleClock_needBg, false ) ; bgColor = typedArray. getColor ( R . styleable. VirgoCircleClock_bgColor, Color . WHITE) ; frameColor = typedArray. getColor ( R . styleable. VirgoCircleClock_frameColor, Color . BLACK) ; markColor1 = typedArray. getColor ( R . styleable. VirgoCircleClock_markColor1, Color . BLACK) ; markColor2 = typedArray. getColor ( R . styleable. VirgoCircleClock_markColor2, Color . DKGRAY) ; textColor = typedArray. getColor ( R . styleable. VirgoCircleClock_textColor, Color . BLACK) ; secondColor = typedArray. getColor ( R . styleable. VirgoCircleClock_secondColor, Color . RED) ; radiusBig = typedArray. getDimensionPixelSize ( R . styleable. VirgoCircleClock_rBig, DEF_RADIUS_BIG) ; radiusSmall = typedArray. getDimensionPixelSize ( R . styleable. VirgoCircleClock_rSmall, DEF_RADIUS_SMALL) ; offMark = typedArray. getDimensionPixelSize ( R . styleable. VirgoCircleClock_offsetMark, DEF_OFF_MARK) ; offText = typedArray. getDimensionPixelSize ( R . styleable. VirgoCircleClock_offsetText, DEF_OFF_TEXT) ; displayStyle = typedArray. getInteger ( R . styleable. VirgoCircleClock_displayType, TYPE_NUM) ; textSize = typedArray. getDimension ( R . styleable. VirgoCircleClock_txtSize, DEF_SIZE_TEXT) ; strokeSize = typedArray. getDimension ( R . styleable. VirgoCircleClock_strokeSize, DEF_FRAME_STROKE) ; padding = typedArray. getDimensionPixelSize ( R . styleable. VirgoCircleClock_paddingFrame, DEF_PADDING) ; initData ( ) ; } public void initLayout ( int width, int height) { Log . d ( TAG, "initLayout: " + width + " - " + height) ; int diameter = Math . min ( width, height) ; radius = ( int ) ( ( diameter - padding - strokeSize) / 2 ) ; centerX = diameter / 2 ; centerY = diameter / 2 ; markY = ( int ) ( padding + strokeSize + offMark) ; txtY = markY + radiusBig * 2 + offText; } private void initData ( ) { paintMain = new Paint ( ) ; paintMain. setAntiAlias ( true ) ; paintMain. setStyle ( Paint. Style . FILL) ; paintFrame = new Paint ( ) ; paintFrame. setAntiAlias ( true ) ; paintFrame. setStyle ( Paint. Style . STROKE) ; paintFrame. setStrokeWidth ( strokeSize) ; calendar = Calendar . getInstance ( ) ; } @Override protected void onSizeChanged ( int w, int h, int oldw, int oldh) { super . onSizeChanged ( w, h, oldw, oldh) ; if ( w > 0 && h > 0 ) { initLayout ( w, h) ; } } @Override protected void onDraw ( Canvas canvas) { super . onDraw ( canvas) ; if ( radius < 1 ) { return ; } getTimes ( ) ; drawPlate ( canvas) ; drawPointHour ( canvas) ; drawPointMinutes ( canvas) ; drawPointSeconds ( canvas) ; } private void getTimes ( ) { calendar. setTimeInMillis ( System . currentTimeMillis ( ) ) ; hours = calendar. get ( Calendar . HOUR_OF_DAY) ; minutes = calendar. get ( Calendar . MINUTE) ; seconds = calendar. get ( Calendar . SECOND) ; } private void drawPlate ( Canvas canvas) { if ( needBg) { paintMain. setColor ( bgColor) ; canvas. drawCircle ( centerX, centerY, radius, paintMain) ; } paintFrame. setColor ( frameColor) ; canvas. drawCircle ( centerX, centerY, radius, paintFrame) ; canvas. save ( ) ; for ( int i = 0 ; i < 60 ; i++ ) { if ( i % 5 == 0 ) { paintMain. setColor ( markColor1) ; canvas. drawCircle ( centerX - radiusBig / 2f , markY, radiusBig, paintMain) ; } else { paintMain. setColor ( markColor2) ; canvas. drawCircle ( centerX - radiusSmall / 2f , markY, radiusSmall, paintMain) ; } canvas. rotate ( 6 , centerX, centerY) ; } canvas. restore ( ) ; paintMain. setColor ( textColor) ; paintMain. setTextSize ( textSize) ; for ( int i = 1 ; i <= 12 ; i++ ) { double radians = Math . toRadians ( 30 * i) ; String hourText; if ( displayStyle == TYPE_ROMA) { hourText = getHoursGreece ( i) ; } else { hourText = String . valueOf ( i) ; } Rect rect = new Rect ( ) ; paintMain. getTextBounds ( hourText, 0 , hourText. length ( ) , rect) ; int textWidth = rect. width ( ) ; int textHeight = rect. height ( ) ; canvas. drawText ( hourText, ( float ) ( centerX + ( radius - txtY) * Math . sin ( radians) - textWidth / 2 ) , ( float ) ( centerY - ( radius - txtY) * Math . cos ( radians) + textHeight / 2 ) , paintMain) ; } } private void drawPointHour ( Canvas canvas) { drawPoint ( canvas, 360 / 12 * hours + ( 30 * minutes / 60 ) , RATE_HOUR, RATE_HOUR_TAIL, RATE_HOUR_WIDTH) ; } private void drawPointMinutes ( Canvas canvas) { drawPoint ( canvas, 360 / 60 * minutes + ( 6 * seconds / 60 ) , RATE_MINUTE, RATE_MINUTE_TAIL, RATE_MINUTE_WIDTH) ; } private void drawPointSeconds ( Canvas canvas) { paintMain. setColor ( secondColor) ; drawPoint ( canvas, 360 / 60 * seconds, RATE_SECOND, RATE_SECOND_TAIL, RATE_SECOND_WIDTH) ; } private void drawPoint ( Canvas canvas, int degree, float rateLen, float rateTail, float rateWidth) { double radians = Math . toRadians ( degree) ; int endX = ( int ) ( centerX + radius * Math . cos ( radians) * rateLen) ; int endY = ( int ) ( centerY + radius * Math . sin ( radians) * rateLen) ; canvas. save ( ) ; paintMain. setStrokeWidth ( radius / rateWidth) ; canvas. rotate ( ( - 90 ) , centerX, centerY) ; canvas. drawLine ( centerX, centerY, endX, endY, paintMain) ; radians = Math . toRadians ( degree - 180 ) ; endX = ( int ) ( centerX + radius * Math . cos ( radians) * rateTail) ; endY = ( int ) ( centerY + radius * Math . sin ( radians) * rateTail) ; canvas. drawLine ( centerX, centerY, endX, endY, paintMain) ; canvas. restore ( ) ; } private String getHoursGreece ( int i) { switch ( i) { case 1 : return "I" ; case 2 : return "II" ; case 3 : return "III" ; case 4 : return "IV" ; case 5 : return "V" ; case 6 : return "VI" ; case 7 : return "VII" ; case 8 : return "VIII" ; case 9 : return "IX" ; case 10 : return "X" ; case 11 : return "XI" ; case 12 : default : return "XII" ; } } private final int MSG_UPDATE_TIME = 1 ; private final Handler handler = new Handler ( new Handler. Callback ( ) { @Override public boolean handleMessage ( Message msg) { if ( msg. what == MSG_UPDATE_TIME) { invalidate ( ) ; startTask ( ) ; } return false ; } } ) ; private void startTask ( ) { handler. removeMessages ( MSG_UPDATE_TIME) ; handler. sendEmptyMessageDelayed ( MSG_UPDATE_TIME, 1000L ) ; } private void pauseTask ( ) { removeMsg ( ) ; } private void stopTask ( ) { removeMsg ( ) ; } private void removeMsg ( ) { handler. removeMessages ( MSG_UPDATE_TIME) ; } public void startPlay ( ) { startTask ( ) ; } public void pausePlay ( ) { pauseTask ( ) ; } public void continuePlay ( ) { startTask ( ) ; } public void releaseView ( ) { stopTask ( ) ; }
}