SurfaceView实现模拟时钟

SurfaceView打造自定义时钟ClockView 从事Android开发也一段时间了,一直有做云笔记的习惯,但是博客不怎么写。最近给自己定了个计划,坚持每周至少写三个自定义控件,所谓熟能生巧呀。作为第一篇写的博客,给大家带来用SurfaceView打造的自定义时钟。PS:最近看见洋神的一篇推送,有人写了这个,自己看着效果图就写了哈哈,至少效果感觉还阔以O(∩_∩)O 先看下这炫酷的效果哈哈(时钟上的很线是录制的原因,效果是没有那根线的, 阅读详情
package com.example.compassdemo;


import java.util.Calendar;
import java.util.Timer;
import java.util.TimerTask;

import android.os.Bundle;
import android.app.Activity;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.WindowManager;

public class MainActivity extends Activity {
	SurfaceView view;
	SurfaceHolder s_hold; 
	
	//圆盘半径
	int radius=200;
	//屏幕的宽高
	int screenWidth;
	int screenHeight;
	//圆盘原点
	int cx;
	int cy;
	//画笔
	Paint paint;
	//文字
	String TEXT="http://app.ewolian.com/pages/count.jsp";
	
	//计数
	int COUNT=60;
	
	//计时器  
    Timer timer=new Timer();  
    TimerTask task=null;  
    
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        WindowManager windowManager=getWindowManager();  
        Display display=windowManager.getDefaultDisplay();  
        DisplayMetrics metrics=new DisplayMetrics();  
        display.getMetrics(metrics);  
        //获取屏幕的宽高
        screenHeight=metrics.heightPixels;//获取屏幕的高度  
        screenWidth=metrics.widthPixels;
        //设置圆盘的圆心
        cx=screenWidth/2;
        cy=screenHeight/2-40;
        
        view=(SurfaceView) findViewById(R.id.sView);
        s_hold=view.getHolder();
        s_hold.addCallback(new Callback() {

			@Override
			public void surfaceChanged(SurfaceHolder holder, int arg1, int arg2,
					int arg3) {
				// TODO Auto-generated method stub
			}

			@Override
			public void surfaceCreated(SurfaceHolder holder) {
				// TODO Auto-generated method stub
				//创建时绘制背景
				drawBack(holder);
			}

			@Override
			public void surfaceDestroyed(SurfaceHolder arg0) {
				// TODO Auto-generated method stub
				//销毁计时器
				if(timer!=null){
					timer.cancel();
				}
			}		
		});  
        
        task=new TimerTask() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				//获取系统当前的时间
				Calendar c = Calendar.getInstance(); 
				int minutes=c.getTime().getMinutes();
				int seconds=c.getTime().getSeconds();
				int hours=c.getTime().getHours();
				
				Canvas canvas=s_hold.lockCanvas(new Rect(cx-radius+90,cy-radius+90,cx+radius-90,cy+radius-90));
				canvas.drawColor(Color.BLUE);
				drawMinutes(canvas,minutes);
				drawSeconds(canvas,seconds);
				drawHours(canvas,hours);
				s_hold.unlockCanvasAndPost(canvas);
				
			}

			private void drawHours(Canvas canvas, int hours) {
				// TODO Auto-generated method stub
				canvas.save();
				Paint p6=new Paint();
				p6.setColor(Color.RED);
				p6.setStyle(Paint.Style.FILL);
				p6.setStrokeWidth(5);
				canvas.rotate(360/12*hours,cx,cy);
				canvas.drawLine(cx,cy,cx,cy-90, p6);
				canvas.restore();
			}

			private void drawSeconds(Canvas canvas, int seconds) {
				// TODO Auto-generated method stub
				canvas.save();
				Paint p4=new Paint();
				p4.setColor(Color.GREEN);
				p4.setStyle(Paint.Style.FILL);
				p4.setStrokeWidth(2);
				canvas.rotate(360/COUNT*seconds,cx,cy);
				canvas.drawLine(cx,cy,cx,cy-130, p4);
				canvas.restore();
			}

			private void drawMinutes(Canvas canvas, int minutes) {
				// TODO Auto-generated method stub
				Paint p5=new Paint();
				p5.setColor(Color.YELLOW);
				p5.setStyle(Paint.Style.FILL);
				p5.setStrokeWidth(3);
				canvas.save();
				canvas.rotate(360/COUNT*minutes,cx,cy);
				canvas.drawLine(cx, cy, cx,cy-110, p5);
				canvas.restore();
			}
		};
		timer.schedule(task,1000,1000);
    }

    //绘制背景
    private void drawBack(SurfaceHolder holder){
    	//锁定SurfaceView画布
 	   Canvas canvas=holder.lockCanvas();
 	   //设置画布颜色
 	   canvas.drawColor(Color.BLUE);
 	   //画圆盘
 	   drawCircle(canvas,radius);
 	   //绘制文字
 	   drawText(canvas,radius,TEXT);
 	   //画刻度线
 	   drawDividing(canvas,radius);
 	   //解锁提交绘制
 	   holder.unlockCanvasAndPost(canvas);
 	   //holder.lockCanvas(new Rect(0,0,0,0));  
 	   //holder.unlockCanvasAndPost(canvas);  
    }

	private void  drawDividing(Canvas canvas, int radius) {
		// TODO Auto-generated method stub
		Paint p2=new Paint(paint);
		p2.setTextSize(20);
		for(int i=0;i<COUNT;i++){
			if(i%5==0){
				p2.setStrokeWidth(5);
				canvas.drawLine(cx,cy-radius,cx,cy-radius-20, p2);
				p2.setStrokeWidth(2);
				if(i==0){
					canvas.drawText(String.valueOf(12),cx-5,cy-radius-20-4, p2);
				}else{
					canvas.drawText(String.valueOf(i/5),cx-5,cy-radius-20-4, p2);
				}
			}else{
				p2.setStrokeWidth(3);
				canvas.drawLine(cx,cy-radius,cx,cy-radius-10, p2);
			}
			canvas.rotate(360/COUNT,cx,cy);
		}
	}

	private void drawText(Canvas canvas, int radius, String text) {
		// TODO Auto-generated method stub
		canvas.save();
		RectF rectf=new RectF(cx-radius+20,cy-radius+20,cx+radius-20,cy+radius-20);
		Path path=new Path();
		path.addArc(rectf,-180,359);
		Paint p1=new Paint(paint);
		p1.setStyle(Paint.Style.FILL);
		p1.setTextSize(20);
		p1.setStrokeWidth(1);
		canvas.drawTextOnPath(text, path,0,0, p1);
		canvas.restore();
	}

	private void drawCircle(Canvas canvas,int radius) {
		// TODO Auto-generated method stub
		paint=new Paint();
		paint.setAntiAlias(true);
		paint.setStyle(Paint.Style.STROKE);
		paint.setStrokeWidth(8);
		paint.setColor(Color.RED);
		canvas.drawCircle(cx,cy,radius, paint);	
	}
   

	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
		if(timer!=null){
			timer.cancel();
		}
	}
}
</pre><pre name="code" class="java"><pre name="code" class="html"><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/LinearLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    >

    <SurfaceView
        android:id="@+id/sView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>




自定义View实现米老鼠时钟 先看效果图,米老鼠的两个手分别指向时钟和分钟,然后米老鼠的脚在一秒执行一次动画操作。 分析完之后就先实现gif的播放, 如果实现gif的播放,就想着使用SurfaceView实现每格一秒循环一次贞动画。于是就需要8张贞图片,然后在surfaceView的125ms时间内播放一个贞,最后1000ms也就是1s播放了一次米老鼠跺脚的行为。代码如下: private int coun 阅读详情

相关推荐

Android平台C++媒体播放器开发:从FFmpeg解码到音视频同步实战

在移动应用开发中,高性能音视频处理是核心技术领域之一,其底层实现通常依赖于C/C++语言以保证执行效率。其核心原理涉及媒体数据的解封装、解码、渲染与同步流程,通过FFmpeg等开源库实现跨格式编解码,结合多线程架构管理数据流。这项技术的工程价值在于能够为短视频、直播、游戏等场景提供稳定高效的播放能力,解决音画同步、低延迟等关键问题。本文以Android平台为例,详细解析如何利用NDK、OpenGL ES和OpenSL ES构建本地播放器,涵盖FFmpeg集成、线程模型设计及音视频同步策略,帮助开发者深入理解

weixin_30918633的博客 416

Android自定义View实现时钟效果ClockView

目录目录 废话不多说先上图 分析 SurfaceView注意事项 废话啰嗦完了 咱们开始实战 总结 Tips1.废话不多说先上图 录制的可能略卡,三次时间图片是因为我分别点了下面三个按钮的效果,并非bug2.分析 观看上图咱们需要绘制的有:时针 分针 秒针 时刻度 秒刻度 仪表盘上的数字 上下午区分标识(AM/PM) View与Surface的取舍:View一般用于绘制静态页面或者界面元素跟随用户的

chuwe1的博客 2776

手把手教你用BMD101芯片DIY一个便携心电监护仪(附手机APP开发指南)

本文详细介绍了如何利用BMD101芯片DIY便携式心电监护仪,包括硬件搭建、信号处理、蓝牙数据传输及手机APP开发全流程。通过ESP32主控和BMD101芯片的高精度生物电信号采集,结合移动端实时波形绘制技术,打造可定制的心电监测系统,适合健康科技爱好者和创客实践。

weixin_30706691的博客 334

s时钟画布 android,Android UI编程进阶——使用SurfaceViewt和Canvas实现动态时钟

概述:很多时候我们想要自己写一些类似时钟、罗盘的控件,却又找不到合适的Demo。我想这时你可能索性就直接上图片了。在Android有Canvas和Paint这么好的画师的情况下,还是选择使用图片,的确是有一些尴尬了。下面我就利用一步一步实现自定义时钟来对这个问题做一个讲解。(注明:本人不太会制作GIF图片,以下图片均不能动态展示,想要查看动态效果,请转到博客末尾处下载源码进行查看)错误示例:这里我...

weixin_39844549的博客 278

用SurfaceView自定义时钟

用SurfaceView自定义绘制时钟效果,attr自定义属性效果,时钟秒针每秒绘制一次,分针没分绘制一次

在surfaceview上放置控件

在surfaceview上放置控件如按钮等,采用framelayout

Android实时取景:用SurfaceView实现 -- Camera

对于基于摄像头的Android应用,实时取景是一个基本前提,通过前置或后置摄像头持续获取捕获到的内容,可以进一步做处理(人脸检测、美颜、滤镜等)。 所谓实时取景,简单说就是调用android的摄像头,把摄像头捕获的内容显示在apk的界面上。只要应用不关闭,相机就持续捕获,apk上看到的就是实时的取景了。 采用SurfaceView和Camera来做这件事。 是SDK自带的SurfaceVie

JKjiang123的博客 2016

在SurfaceView中添加组件

在SurfaceView中添加组件,一个界面中既有surfaceview又有button、textview等组件,http://blog.youkuaiyun.com/xiaominghimi/archive/2010/12/26/6099194.aspx

Android实时取景:用SurfaceView实现

update: 这篇blog没有处理android sdk api>=23时的动态权限问题。建议直接使用这一篇:Android SurfaceView Tutorial With Example 对于基于摄像头的Android应用,实时取景是一个基本前提,通过前置或后置摄像头持续获取捕获到的内容,可以进一步做处理(人脸检测、美颜、滤镜等)。 所谓实时取景,简单说就是调用android的摄像...

weixin_30852419的博客 90

Cocos Creator 3.x 实战:用脚本动态加载Spine动画,告别resources硬编码

本文详细介绍了Cocos Creator 3.x中Spine动画的动态加载与挂点系统实战技巧。通过Asset Bundle替代传统resources硬编码方式,实现资源的高效管理和热更新支持,同时结合TypeScript强类型和单例模式优化加载流程。文章还深入探讨了跨平台适配、挂点编程方案及性能优化策略,帮助开发者提升游戏开发效率与灵活性。

weixin_42526353的博客 267

精益六西格玛Python数字化应用开发-Day18 应用场景:家电企业生产效率优化

本文将重点介绍专门针对精益六西格玛黑带使用场景的 Python 库,这些库功能侧重于数据分析和流程优化,特别适用于 DMAIC 方法论和看板管理。考虑到读者具备中高级Python 使用经验,我们将深入探讨各库的高级功能和实际应用应用场景。 某家电企业生产线自动化程度高,数据量巨大,希望通过精益管理提升生产效率。企业借助 Python 脚本,打通各类数据源(MES、ERP、设备日志),自动归集生产数据,分析各工序的生产节拍、设备停机、效率损失,快速定位瓶颈环节

m0_56592100的博客 906

Android应用优化(4)浅谈动画和帧率

前几天帮同事看了一个问题,就是做了一个时间助手的应用,包括了一个模拟时钟一个计时器,单独动画看着还ok,但是在ViewPager中滑动就出现了滑不动和卡顿的情况。 首先,建议他把view换成surfaceview来实现,发现这样不仅没有解决问题,反而把其他fragment的界面变得滑动卡顿了。 然后,仔细分析了一下代码,发现主要原因是他在实现时钟的旋转时不停的创建图片和旋转图片,这才是问题的关

hehui1860的专栏 4275

虚幻UE 增强输入-触发器

输入触发器(UInputTrigger): 使用经过修饰器修改的输入值,或者使用其他输入动作的输出值,来确定是否激活输入动作。

UE成长之路,欢迎大家的关注! 5465

Camera驱动开发:从V4L2框架到MIPI-CSI实战

Camera驱动作为连接硬件与上层应用的核心组件,在嵌入式系统和移动设备开发中扮演关键角色。其技术实现主要基于Linux V4L2框架和Android HAL层架构,涉及设备状态管理、视频缓冲处理以及控制接口实现等核心功能。在硬件交互层面,MIPI-CSI接口的时钟同步与信号完整性直接影响成像质量,而UVC协议则决定了USB摄像头的兼容性表现。通过合理配置设备树参数和优化DMA缓冲区管理,开发者可以显著提升驱动性能。典型应用场景包括RK3568等嵌入式平台的摄像头适配,以及实现HDR模式、3A算法等高级成像

435

win10解决IE浏览器安装不上的问题(卸载依然显示不能安装)

目前win10 系统不支持外部ie安装程序,所以必须用win10自带的应用来安装 一、错误的卸载的方式 在控制面板的当前安装的程序界面是看不到ie的,需要选择控制面板左上角的启用或关闭windows功能 将ie11前面的勾勾去掉 这种方法是很多网站上的误区,其实这并没有卸载成功ie只是把ie的功能关闭了,但是他还在你的电脑上。你可以理解为我们说的对文件夹执行的隐藏文件夹功能。那个隐藏的文件夹依...

清平乐的技术专栏 3万+

Android系统解决-授予管理所有文件的权限问题

Android版本一直在加,Android9/Android10/Android11/Android12/Android13/Android14/Android15 , 客户app 也在不断适配,但是存在特别是定制产品中,客户不愿意适配,啥问题都让系统解决,绕过一定机制、实现。这里说的就是一个常见的常见需求:Android13 上面,客户要求默认授予管理所有文件的权限,如下:问题是机器重启后这个权限仍需要重新打开才行,那就是每次开机使用某些功能前都需要授权一次。是的ADB对应命令。

十年饮冰,难凉热血 2541

Android系统真实体感:硬件约束、软件博弈与用户幻觉的动态平衡

Android并非抽象的操作系统概念,而是根植于物理世界的技术综合体。其运行本质由芯片寄存器、PCB信号完整性、传感器时钟同步和电池电化学特性等硬件铁律所限定;同时在AOSP开放框架、Vendor闭源Blob与OEM深度定制之间持续博弈;最终通过16ms渲染周期、触控预测插值与后台唤醒契约,构建出符合人眼与神经响应的‘流畅幻觉’。理解Android整体印象,关键在于穿透Framework层,直抵SoC启动序列、HAL时序偏差、Thermal HAL物理判决等实测细节——这正是Android系统工程师每日调试

diaoqi6581的博客 430

【项目实战】主流车载操作系统,QNX实时操作系统入门介绍

QNX是一种实时操作系统,自1980年代初期由Quantum Software Systems成立以来,已被广泛应用于各种行业和领域。QNX具有实时响应、高可靠性和分布式等特点,为各种设备提供了强大的底层操作系统平台。随着科技的不断发展和进步,QNX系统的应用范围和潜力也在不断扩大。本文将全面介绍QNX系统,包括其引言、背景、系统特性、应用领域和生态系统等方面。QNX作为一种实时操作系统,具有高效的实时性能、高可靠性、分布式、可剪裁性和可扩展性等特点。它在各个领域都有广泛的应用,并拥有一个庞大的生态系统。

奶爸的编程之路,也就一周冷个三天 3071

别再傻傻用GPIO了!手把手教你用SPI给FPGA烧录比特文件(基于SAMA5D27和Linux)

本文详细介绍了如何利用SPI接口替代传统的GPIO方式,为FPGA烧录比特文件,实现高达600倍的加载速度提升。通过SAMA5D27处理器和Linux系统的实战配置,包括设备树设置、驱动优化和硬件连接调整,帮助开发者显著提高FPGA开发效率。

weixin_30876945的博客 580

虚拟网络的“隐形盾”:C#如何用代码把DDoS踢出门?

本文分享了如何用C#防御DDoS攻击的实战经验。通过三种核心防御策略:1)基于IP的速率限制中间件,使用滑动时间窗口算法控制请求流量;2)自动IP封禁服务,通过特征检测识别恶意IP并加入黑名单;3)优化数据库连接池和HTTP客户端连接池,合理配置资源参数。文中提供了详细的C#代码实现,包括限流中间件、IP封禁服务和连接池优化方案,并分享了生产环境中的调优经验,如配合Redis实现分布式限流、使用fail2ban自动封禁等技巧,帮助开发者构建更健壮的防御体系。

墨夶的博客 329

大数据在电力行业的应用案例解析 -【电力技术】(十)电力数字化运营与大数据精准服务体系建设

电力数字化运营,是大数据在电力行业从技术场景走向业务价值的最终落点。它以数据为纽带,将用户、设备、服务、收益、风险全部纳入统一闭环,实现从 “管好电” 向 “运营好能源资产” 升级。在新型电力系统与市场化改革双重驱动下,谁能用好数据、建好闭环、做好运营,谁就能在服务、成本、效益、安全上建立长期优势。

getusushu的博客 70

STM32+Android蓝牙示波器实战:从电路设计到App开发的避坑指南

本文详细介绍了基于STM32和Android平台的便携式数字示波器开发全流程,涵盖硬件电路设计、STM32嵌入式编程、蓝牙数据传输优化及Android端波形显示性能提升等关键环节。针对开发中常见的信号调理、ADC采样、蓝牙稳定性等痛点问题,提供了实用的解决方案和优化技巧,帮助开发者高效完成从电路设计到App开发的全栈实现。

weixin_42524226的博客 139

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

多媒体技术基础:数据类型、压缩与流媒体应用

多媒体技术是数字化时代处理文字、图像、音频和视频等多样化数据的核心技术。其核心原理包括数据压缩(如Huffman编码、JPEG/MPEG标准)、媒体同步(时间戳管理)和流媒体传输(HLS/DASH协议)。这些技术显著降低了存储与带宽需求,支撑了从视频会议到在线教育的广泛应用场景。当前AI驱动的神经网络编解码器和自适应码率技术(ABR)进一步优化了多媒体处理效率,而VR/AR等沉浸式体验则拓展了技术边界。理解多媒体数据类型特性(如RGB/YUV色彩空间、采样率与帧率)及处理流程,是开发高性能音视频系统的基础。

weixin_30570101的博客 455

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

音画不同步的本质:时间基准与缓冲区协同控制

音画不同步并非简单卡顿,而是音视频时间轴错位引发的系统性故障。其核心在于时间基准源选择、解码渲染流水线异步性、网络抖动影响及帧率匹配失准四大原理。消费级场景下,CLOCK_MONOTONIC作为单调高精度时钟是可靠基准;而缓冲区水位动态调控可主动抑制音画偏移放大效应。该问题广泛存在于直播、点播、WebRTC等音视频开发场景,直接影响4K/HDR/杜比全景声等高阶体验。本文聚焦音视频开发中真实产线级解决方案,涵盖PTS校准、Jitter Buffer自适应、帧率锁定等关键技术路径。

weixin_33816946的博客 340

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

上一篇: Android TTS使用实例
下一篇: 拦截来电(来电挂断)
android_xc
博客等级 码龄12年 15粉丝 23原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值