Android(安卓)自定义控件,模仿小米秒表样式的时钟,完整代码注解
16lz
2021-01-24
一个模仿小米手机秒表样式的安卓小应用程序,利用自定义控件实现。
超详细的代码注释
开发工具为:Android Studio
看图
代码:
大表盘自定义控件:【xiaomiClock 】
public class xiaomiClock extends View { private Paint textPaint,paint; private Path mTriangle; private Timer mTimer; private float agree = 1; private Shader mshader; private PathEffect mEffect; public xiaomiClock(Context context) { super(context); } public xiaomiClock(Context context, AttributeSet attrs) { super(context, attrs); //mEffect = new DashPathEffect(new float[]{1,2,5,10,50,20}, 0); // float[]{ 虚线的厚度, 虚线的间距,虚线的厚度, 虚线的间距 ......} mEffect = new DashPathEffect(new float[]{5,0}, 0); // float[]{ 虚线的厚度, 虚线的间距,虚线的厚度, 虚线的间距 ......} mshader = new SweepGradient(500, 500, Color.parseColor("#3b3b3b"), Color.parseColor("#ffffff")); //渐变遮罩样式 textPaint = new Paint(); textPaint.setStrokeWidth(16); textPaint.setColor(Color.WHITE); textPaint.setStrokeCap(Paint.Cap.ROUND); textPaint.setAntiAlias(true); paint = new Paint(); paint.setAntiAlias(true); mTriangle = new Path(); mTriangle.moveTo(960, 500);// 此点为多边形的顶点【三角形(指针)】 //下面两个x 相等,表示底边的位置 mTriangle.lineTo(1000, 525); // y:底边宽的其中一个顶点 mTriangle.lineTo(1000, 475); //y:底边宽的其中一个顶点 mTriangle.close(); setmTimer(); System.out.println("度数" + ((float) 6.0 / 10)); } @Override protected void onDraw(Canvas canvas) { //绘画手表盘 drawbeauty(canvas); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //设置宽高 setMeasuredDimension(1000,1000); //画布大小 } public void drawbeauty(Canvas canvas) { int canvasWidth = canvas.getWidth(); int canvasHeight = canvas.getHeight(); //设置缓存层,因为下面要实用xfermode,使用xfemode必须使用缓存层,否则会出现黑色背景 int layerId = canvas.saveLayer(0, 0, canvasWidth, canvasHeight, null, Canvas.ALL_SAVE_FLAG); //初始化画笔,因为上下两层做画需要的画笔属性不一样,所以只能每次重新设置一次 paint.setStyle(Paint.Style.STROKE); //设置画笔为不填充模式 paint.setPathEffect(mEffect); //设置笔画样式,这里设置的是虚线样式 paint.setStrokeWidth(50); //设置笔画宽度 canvas.drawCircle(500, 500, 420, paint); //画一个纯色表盘,虚线,空心圆形 【表盘位置和大小】 //设置画笔属性,SRC_IN属性,让第二个图案只能花在第一个图案上面,也就是只能画在上面所说那个纯色表盘里面 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); //把画笔虚线属性去掉,因为我要的是一个实心圆形,然后让这个实心但是颜色不一样圆形画在上面所说表盘上面,因为设置了xfermode,所以显示的一样会是虚线圆形表盘,但是颜色会变成你现在的颜色 paint.setPathEffect(null); //设置画笔shader属性,这里设置的是SweepGradient模式,可以让颜色过渡泾渭分明,以圆形为中心开始变化 paint.setShader(mshader); paint.setStyle(Paint.Style.FILL); canvas.save(); //保存画布 //旋转画布,然后你就会发现时钟表盘开始动了 canvas.rotate(agree, 500, 500); //画布旋转的中心点 canvas.drawRect(10, 10, 1000, 1100, paint); //渐变矩形绘制 canvas.drawPath(mTriangle, textPaint); //绘制小三角形 canvas.restore(); //最后将画笔去除Xfermode paint.setXfermode(null); canvas.restoreToCount(layerId); } private void setmTimer() { mTimer = new Timer(); mTimer.schedule(new TimerTask() { @Override public void run() { agree = agree + 0.022f;//数值越大,旋转速度越快 if (agree > 360) agree = 1; postInvalidate(); } }, 1000, 3); //延时/周期 }}
小码表表盘自定义控件:【xiaomiClock 02】
public class xiaomiClock02 extends View { private Paint textPaint,paint; private Path mTriangle; private Timer mTimer; private float agree = 1; private Shader mshader; private PathEffect mEffect; public xiaomiClock02(Context context) { super(context); } public xiaomiClock02(Context context, AttributeSet attrs) { super(context, attrs); //mEffect = new DashPathEffect(new float[]{1,2,5,10,50,20}, 0); // float[]{ 虚线的厚度, 虚线的间距,虚线的厚度, 虚线的间距 ......} mEffect = new DashPathEffect(new float[]{5,0}, 0); // float[]{ 虚线的厚度, 虚线的间距,虚线的厚度, 虚线的间距 ......} mshader = new SweepGradient(110, 110, Color.parseColor("#3b3b3b"), Color.parseColor("#ffffff")); //渐变遮罩样式【渐变色的渐变中心点以及颜色】 textPaint = new Paint(); textPaint.setStrokeWidth(16); textPaint.setColor(Color.WHITE); textPaint.setStrokeCap(Paint.Cap.ROUND); textPaint.setAntiAlias(true); paint = new Paint(); paint.setAntiAlias(true); mTriangle = new Path(); mTriangle.moveTo(190, 110);// 此点为多边形的顶点【三角形(指针)】 //下面两个x 相等,表示底边的位置 mTriangle.lineTo(110, 112); // y:底边宽的其中一个顶点 mTriangle.lineTo(110, 108); //y:底边宽的其中一个顶点 mTriangle.close(); setmTimer(); System.out.println("度数" + ((float) 6.0 / 10)); } @Override protected void onDraw(Canvas canvas) { //绘画手表盘 drawbeauty(canvas); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //设置宽高 setMeasuredDimension(220,220); //画布大小 } public void drawbeauty(Canvas canvas) { int canvasWidth = canvas.getWidth(); int canvasHeight = canvas.getHeight(); //设置缓存层,因为下面要实用xfermode,使用xfemode必须使用缓存层,否则会出现黑色背景 int layerId = canvas.saveLayer(0, 0, canvasWidth, canvasHeight, null, Canvas.ALL_SAVE_FLAG); //初始化画笔,因为上下两层做画需要的画笔属性不一样,所以只能每次重新设置一次 paint.setStyle(Paint.Style.STROKE); //设置画笔为不填充模式 paint.setPathEffect(mEffect); //设置笔画样式,这里设置的是虚线样式 paint.setStrokeWidth(2); //设置笔画宽度 canvas.drawCircle(110, 110, 100, paint); //画一个纯色表盘,虚线,空心圆形 【表盘位置和大小】 //设置画笔属性,SRC_IN属性,让第二个图案只能花在第一个图案上面,也就是只能画在上面所说那个纯色表盘里面 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); //把画笔虚线属性去掉,因为我要的是一个实心圆形,然后让这个实心但是颜色不一样圆形画在上面所说表盘上面,因为设置了xfermode,所以显示的一样会是虚线圆形表盘,但是颜色会变成你现在的颜色 paint.setPathEffect(null); //设置画笔shader属性,这里设置的是SweepGradient模式,可以让颜色过渡泾渭分明,以圆形为中心开始变化 paint.setShader(mshader); paint.setStyle(Paint.Style.FILL); canvas.save(); //保存画布 //旋转画布,然后你就会发现时钟表盘开始动了 canvas.rotate(agree, 110, 110); //画布旋转的中心点 canvas.drawRect(1, 1, 220, 220, paint); //渐变矩形绘制 canvas.drawPath(mTriangle, textPaint); //绘制小三角形 canvas.restore(); //最后将画笔去除Xfermode paint.setXfermode(null); canvas.restoreToCount(layerId); } private void setmTimer() { mTimer = new Timer(); mTimer.schedule(new TimerTask() { @Override public void run() { agree = agree + 0.2f + 1f;//数值越大,旋转速度越快 if (agree > 360) agree = 1; postInvalidate(); } }, 1000, 3); //延时/周期 }}
BaseActivity设置主题为黑色
public class BaseActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //主题设置 setTheme(R.style.AppTheme01); }}
主题Styles样式
MainActivity 设置时间代码
public class MainActivity extends BaseActivity{ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); new DataThread().start(); //时间控制线程 } //设定显示系统时间 private String getData() { long sysTime = System.currentTimeMillis(); CharSequence sysTimeStr = DateFormat.format("" + "yyyy/MM/dd", sysTime); return (String) sysTimeStr; } @SuppressLint("HandlerLeak") private Handler mHandlerData = new Handler() { public void handleMessage(android.os.Message msg) { TextView textView = findViewById(R.id.Time_TextView01); //确定系统时间变化的控件 textView.setText((String) msg.obj); } }; //设定显示系统时间 private String getTime() { long sysTime = System.currentTimeMillis(); CharSequence sysTimeStr = DateFormat.format("" + "HH:mm:ss", sysTime); return (String) sysTimeStr; } @SuppressLint("HandlerLeak") private Handler mHandlerTime = new Handler() { public void handleMessage(android.os.Message msg) { TextView textView = findViewById(R.id.Time_TextView02); //确定系统时间变化的控件 textView.setText((String) msg.obj); } }; private class DataThread extends Thread { @Override public void run() { for (int i = 0; i < 999999999; i++) { //一共变化多少次次 try { Thread.sleep(10); //每一毫秒变化一次 } catch (InterruptedException e) { e.printStackTrace(); } final String sysTime = getTime(); final String sysData = getData(); // 只能在主线程中修改ui控件 mHandlerData.sendMessage(mHandlerData.obtainMessage(0, sysData)); //系统日期 mHandlerTime.sendMessage(mHandlerTime.obtainMessage(0, sysTime)); //系统时间 } } }}
.
App下载:https://aifabu.com/iUfi
源码下载:https://download.csdn.net/download/erp_lxkun_jak/11240191
【注意:使用开发工具是 Android Studio 哦!】
.
.
感谢你的查阅,希望可以帮到你,祝你学习愉快!
我是和你一起学习的 易君
更多相关文章
- Android画图demo
- android 简单的画图操作
- android 圆形进度条的简单实现
- android 绘图--简单手写绘图后保存为图片(demo)
- Android(安卓)自己画View设置画笔的颜色
- Android绘图篇(一)——Canvans基本操作
- 【Android应用实例之二】跟随手指的小球——自定义View应用
- Android本地验证码的生成
- Android(安卓)Canvas绘制直方图