Android – [SelfView] 炫酷文字圆盘时钟
ps: 感觉效果满帅的,就自己弄了个!
效果图
使用:
<com.nepalese.virgocomponent.view.VirgoTextClockViewandroid:layout_centerInParent="true"android:layout_width="match_parent"android:layout_height="match_parent"app:vtcTextColorMain="@color/colorRed" app:vtcTextColorSec="@color/colorGray"app:vtcTextSizeMain="14sp"app:vtcTextSizeClock="18sp"app:vtcOffset="10dp"app:vtcRadiusH="60dp"app:vtcRadiusM="125dp"app:vtcRadiusS="190dp"/>
码源:
1. attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources><declare-styleable name="VirgoTextClockView"><attr name="vtcTextColorMain" format="color|reference" /><attr name="vtcTextColorSec" format="color|reference" /><attr name="vtcColorBg" format="color|reference" /><attr name="vtcTextSizeMain" format="dimension|reference" /><attr name="vtcTextSizeClock" format="dimension|reference" /><attr name="vtcRadiusH" format="dimension|reference" /><attr name="vtcRadiusM" format="dimension|reference" /><attr name="vtcRadiusS" format="dimension|reference" /><attr name="vtcOffset" format="dimension|reference" /></declare-styleable>
</resources>
2. VirgoTextClockView.java
package com.nepalese.virgocomponent.view;import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.LinearInterpolator;import com.nepalese.virgocomponent.R;
import com.nepalese.virgocomponent.component.bean.ClockBean;import java.util.Calendar;
import java.util.Date;import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class VirgoTextClockView extends View {private static final int MIN_WIDTH = 200;private static final long INTERVAL_UPDATE = 1000L;private static final String[] HOURS = {"一点", "二点", "三点", "四点", "五点", "六点", "七点", "八点", "九点", "十点", "十一点", "十二点"};private static final String[] MINUTES = {"一分", "二分", "三分", "四分", "五分", "六分", "七分", "八分", "九分", "十分","十一分", "十二分", "十三分", "十四分", "十五分", "十六分", "十七分", "十八分", "十九分", "二十分","二十一分", "二十二分", "二十三分", "二十四分", "二十五分", "二十六分", "二十七分", "二十八分", "二十九分", "三十分","三十一分", "三十二分", "三十三分", "三十四分", "三十五分", "三十六分", "三十七分", "三十八分", "三十九分", "四十分","四十一分", "四十二分", "四十三分", "四十四分", "四十五分", "四十六分", "四十七分", "四十八分", "四十九分", "五十分","五十一分", "五十二分", "五十三分", "五十四分", "五十五分", "五十六分", "五十七分", "五十八分", "五十九分", ""};private static final String[] SECONDS = {"一秒", "二秒", "三秒", "四秒", "五秒", "六秒", "七秒", "八秒", "九秒", "十秒","十一秒", "十二秒", "十三秒", "十四秒", "十五秒", "十六秒", "十七秒", "十八秒", "十九秒", "二十秒","二十一秒", "二十二秒", "二十三秒", "二十四秒", "二十五秒", "二十六秒", "二十七秒", "二十八秒", "二十九秒", "三十秒","三十一秒", "三十二秒", "三十三秒", "三十四秒", "三十五秒", "三十六秒", "三十七秒", "三十八秒", "三十九秒", "四十秒","四十一秒", "四十二秒", "四十三秒", "四十四秒", "四十五秒", "四十六秒", "四十七秒", "四十八秒", "四十九秒", "五十秒","五十一秒", "五十二秒", "五十三秒", "五十四秒", "五十五秒", "五十六秒", "五十七秒", "五十八秒", "五十九秒", ""};private Paint mPaintMain;private Paint mPaintSecond;private Paint mPaintClock;private ValueAnimator mAnimator;private int mColorMain;private int mColorSecond;private int mColorBg;private int mWidth, mHeight;private int mH, mM, mS;private int mH24;private int mRadiusH, mRadiusM, mRadiusS;private String mWeek, mDate;private float mDegreeH, mDegreeM, mDegreeS;private float mTextSizeMain;private float mTextSizeClock;private float mOffset;private float mCenterHeight;public VirgoTextClockView(Context context) {this(context, null);}public VirgoTextClockView(Context context, @Nullable AttributeSet attrs) {this(context, attrs, 0);}public VirgoTextClockView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init(attrs);}private void init(AttributeSet attrs) {TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.VirgoTextClockView);mColorMain = typedArray.getColor(R.styleable.VirgoTextClockView_vtcTextColorMain, Color.WHITE);mColorSecond = typedArray.getColor(R.styleable.VirgoTextClockView_vtcTextColorSec, Color.GRAY);mColorBg = typedArray.getColor(R.styleable.VirgoTextClockView_vtcColorBg, Color.BLACK);mTextSizeMain = typedArray.getDimension(R.styleable.VirgoTextClockView_vtcTextSizeMain, 25f);mTextSizeClock = typedArray.getDimension(R.styleable.VirgoTextClockView_vtcTextSizeClock, 35f);mRadiusH = typedArray.getDimensionPixelSize(R.styleable.VirgoTextClockView_vtcRadiusH, 140);mRadiusM = typedArray.getDimensionPixelSize(R.styleable.VirgoTextClockView_vtcRadiusM, 220);mRadiusS = typedArray.getDimensionPixelSize(R.styleable.VirgoTextClockView_vtcRadiusS, 320);mOffset = typedArray.getDimensionPixelSize(R.styleable.VirgoTextClockView_vtcOffset, 8);typedArray.recycle();mPaintMain = new Paint();mPaintMain.setAntiAlias(true);mPaintMain.setColor(mColorMain);mPaintMain.setTextSize(mTextSizeMain);mPaintMain.setStyle(Paint.Style.FILL);mPaintSecond = new Paint();mPaintSecond.setAntiAlias(true);mPaintSecond.setColor(mColorSecond);mPaintSecond.setTextSize(mTextSizeMain);mPaintSecond.setStyle(Paint.Style.FILL);mPaintClock = new Paint();mPaintClock.setAntiAlias(true);mPaintClock.setColor(mColorMain);mPaintClock.setTextSize(mTextSizeClock);mPaintClock.setStyle(Paint.Style.FILL);initAnimator();getCurTime();}private void initAnimator() {mAnimator = ValueAnimator.ofFloat(6f, 0f);mAnimator.setDuration(150);mAnimator.setInterpolator(new LinearInterpolator());}private void getCurTime() {Calendar calendar = Calendar.getInstance();calendar.setTime(new Date());mH24 = calendar.get(Calendar.HOUR_OF_DAY);mH = calendar.get(Calendar.HOUR);mM = calendar.get(Calendar.MINUTE);mS = calendar.get(Calendar.SECOND);parseWeek(calendar.get(Calendar.DAY_OF_WEEK));parseDate(calendar.get(Calendar.MONTH) + 1, calendar.get(Calendar.DAY_OF_MONTH));calculateDegree();}private void calculateDegree() {mDegreeH = -360 / 12f * (mH - 1);mDegreeM = -360 / 60f * (mM - 1);mDegreeS = -360 / 60f * (mS - 1);}private void parseWeek(int week) {switch (week) {case 1:mWeek = "星期日";break;case 2:mWeek = "星期一";break;case 3:mWeek = "星期二";break;case 4:mWeek = "星期三";break;case 5:mWeek = "星期四";break;case 6:mWeek = "星期五";break;case 7:mWeek = "星期六";break;}}private void parseDate(int month, int day) {mDate = foramtTime(month, day, "/");}private String foramtTime(int h, int m, String tap) {String sH, sM;if (h < 10) {sH = "0" + h;} else {sH = String.valueOf(h);}if (m < 10) {sM = "0" + m;} else {sM = String.valueOf(m);}return sH + tap + sM;}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);mWidth = getRealSize(widthMeasureSpec);mHeight = getRealSize(heightMeasureSpec);mHeight = mWidth = Math.min(mWidth, mHeight);mCenterHeight = (mHeight + getFontHeight(mTextSizeMain)) / 2f;setMeasuredDimension(mWidth, mHeight);}private int getRealSize(int measureSpec) {int result;int mode = MeasureSpec.getMode(measureSpec);int size = MeasureSpec.getSize(measureSpec);if (mode == MeasureSpec.AT_MOST || mode == MeasureSpec.UNSPECIFIED) {result = MIN_WIDTH;} else {result = size;}return result;}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawColor(mColorBg);drawTimeInfo(canvas);drawHour(canvas);drawMinute(canvas);drawSecond(canvas);}private void drawTimeInfo(Canvas canvas) {String time = foramtTime(mH24, mM, "\t:\t");canvas.drawText(time, (mWidth - mPaintClock.measureText(time)) / 2f,(mHeight - getFontHeight(mTextSizeClock)) / 2f + mOffset, mPaintClock);String date = mDate + "\t" + mWeek;canvas.drawText(date, (mWidth - mPaintMain.measureText(date)) / 2f,(mHeight + getFontHeight(mTextSizeMain)) / 2f + mOffset, mPaintMain);}private void drawHour(Canvas canvas) {canvas.save();canvas.rotate(mDegreeH, mWidth / 2f, mHeight / 2f);for (int i = 0; i < HOURS.length; i++) {canvas.save();canvas.rotate(30 * i, mWidth / 2f, mHeight / 2f);if (i + 1 == mH || (i == 11 && mH == 0)) {canvas.drawText(HOURS[i], mRadiusH + mWidth / 2f, mCenterHeight, mPaintMain);} else {canvas.drawText(HOURS[i], mRadiusH + mWidth / 2f, mCenterHeight, mPaintSecond);}canvas.restore();}canvas.restore();}private void drawMinute(Canvas canvas) {canvas.save();canvas.rotate(mDegreeM, mWidth / 2f, mHeight / 2f);for (int i = 0; i < MINUTES.length; i++) {canvas.save();canvas.rotate(6 * i, mWidth / 2f, mHeight / 2f);if (i + 1 == mM) {canvas.drawText(MINUTES[i], mRadiusM + mWidth / 2f, mCenterHeight, mPaintMain);} else {canvas.drawText(MINUTES[i], mRadiusM + mWidth / 2f, mCenterHeight, mPaintSecond);}canvas.restore();}canvas.restore();}private void drawSecond(Canvas canvas) {canvas.save();canvas.rotate(mDegreeS, mWidth / 2f, mHeight / 2f);for (int i = 0; i < SECONDS.length; i++) {canvas.save();canvas.rotate(6 * i, mWidth / 2f, mHeight / 2f);if (i + 1 == mS) {canvas.drawText(SECONDS[i], mRadiusS + mWidth / 2f, mCenterHeight, mPaintMain);} else {canvas.drawText(SECONDS[i], mRadiusS + mWidth / 2f, mCenterHeight, mPaintSecond);}canvas.restore();}canvas.restore();}private float getFontHeight(float textSize) {Paint paint = new Paint();paint.setTextSize(textSize);Paint.FontMetrics fm = paint.getFontMetrics();return fm.descent - fm.ascent;}private final Runnable clockTask = new Runnable() {@Overridepublic void run() {updateClock();handler.postDelayed(clockTask, INTERVAL_UPDATE);}};private void updateClock() {getCurTime();float hd = mDegreeH;float md = mDegreeM;float sd = mDegreeS;mAnimator.removeAllUpdateListeners();mAnimator.addUpdateListener(animation -> {float av = (float) animation.getAnimatedValue();if (mM == 0 && mS == 0) {mDegreeH = hd + av * 5;}if (mS == 0) {mDegreeM = md + av;}mDegreeS = sd + av;invalidate();});mAnimator.start();}private final Handler handler = new Handler(Looper.myLooper()) {@Overridepublic void handleMessage(@NonNull Message msg) {super.handleMessage(msg);}};@Overrideprotected void onDetachedFromWindow() {super.onDetachedFromWindow();mAnimator.removeAllUpdateListeners();stopClock();}@Overrideprotected void onVisibilityChanged(@NonNull View changedView, int visibility) {super.onVisibilityChanged(changedView, visibility);if (visibility != VISIBLE) {stopClock();} else {startClock();}}public void startClock() {stopClock();handler.post(clockTask);}public void stopClock() {handler.removeCallbacks(clockTask);}public void setmColorMain(@ColorInt int mColorMain) {this.mColorMain = mColorMain;mPaintMain.setColor(mColorMain);mPaintClock.setColor(mColorMain);}public void setmColorSecond(@ColorInt int mColorSecond) {this.mColorSecond = mColorSecond;mPaintSecond.setColor(mColorSecond);}public void setmColorBg(@ColorInt int mColorBg) {this.mColorBg = mColorBg;}public void setmRadiusH(int mRadiusH) {this.mRadiusH = mRadiusH;}public void setmRadiusM(int mRadiusM) {this.mRadiusM = mRadiusM;}public void setmRadiusS(int mRadiusS) {this.mRadiusS = mRadiusS;}public void setmTextSizeMain(float mTextSizeMain) {this.mTextSizeMain = mTextSizeMain;mPaintMain.setTextSize(mTextSizeMain);mPaintSecond.setTextSize(mTextSizeMain);}public void setmTextSizeClock(float mTextSizeClock) {this.mTextSizeClock = mTextSizeClock;mPaintClock.setTextSize(mTextSizeClock);}public void setmOffset(float mOffset) {this.mOffset = mOffset;}public void setConfig(ClockBean bean) {this.setmColorMain(Color.parseColor(bean.getColorSelect()));this.setmColorSecond(Color.parseColor(bean.getColorDefault()));this.setmTextSizeMain(bean.getSizeClock());this.setmTextSizeClock(bean.getSizeCenter());this.setmOffset(bean.getOffset());this.setmRadiusH(bean.getrHour());this.setmRadiusM(bean.getrMinute());this.setmRadiusS(bean.getrSecond());}
}