谷歌已经为我们提供了非常丰富的控件,一般任务均可完成,但是有时候一些特别任务还是需要我们自定义控件来完成。

本文尝试完成一个自定义钟表控件。

</pre><pre name="code" class="java">package com.shusheng007.customviews;import com.shusheng007.mp3plaryer.R;import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.text.format.Time;
import android.util.AttributeSet;
import android.view.View;public class CustomClockView extends View
{private Time mCalendar;// 表盘上的各指针图private Drawable mHourHand;private Drawable mMinuteHand;//表盘图片private Drawable mDial;// 定义表盘的宽和高private int mDialWidth;private int mDialHeight;private boolean mAttached;private final Handler mHandler = new Handler();private float mMinutes;private float mHour;//用于判断,view是否需要重新绘制private boolean mChanged;public CustomClockView(Context context){this(context,null);}public CustomClockView(Context context, AttributeSet attrs){this(context, attrs,0);}public CustomClockView(Context context, AttributeSet attrs, int defStyleAttr){super(context, attrs, defStyleAttr);Resources r = context.getResources();/** 通过资源加载各图片,用于绘制时钟*/mDial = r.getDrawable(R.drawable.clock_dial);mHourHand = r.getDrawable(R.drawable.clock_hour);mMinuteHand = r.getDrawable(R.drawable.clock_minute);mCalendar = new Time();mDialWidth = mDial.getIntrinsicWidth();mDialHeight = mDial.getIntrinsicHeight();}/** 要计算该组件的宽和高时调用该方法*/@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){//获得模式和尺寸int widthMode = MeasureSpec.getMode(widthMeasureSpec);int widthSize = MeasureSpec.getSize(widthMeasureSpec);int heightMode = MeasureSpec.getMode(heightMeasureSpec);int heightSize = MeasureSpec.getSize(heightMeasureSpec);float hScale = 1.0f;float vScale = 1.0f;//判断尺寸模式是否为Unspecified,如果不是就需要判断表盘大小是否超出容器尺寸if (widthMode != MeasureSpec.UNSPECIFIED && widthSize < mDialWidth) {hScale = (float) widthSize / (float) mDialWidth;}if (heightMode != MeasureSpec.UNSPECIFIED && heightSize < mDialHeight) {vScale = (float) heightSize / (float) mDialHeight;}//如果表盘图像尺寸超出其组件的尺寸,则需要缩放float scale = Math.min(hScale, vScale);//此函数必须调用,用于设置空间尺寸setMeasuredDimension(resolveSize((int) (mDialWidth * scale), widthMeasureSpec),resolveSize((int) (mDialHeight * scale), heightMeasureSpec));}@Overrideprotected void onDraw(Canvas canvas){// TODO Auto-generated method stubsuper.onDraw(canvas);// 用一个标识来判断是否要重新绘boolean changed = mChanged;if (changed) {mChanged = false;}// 获取在其父容器中的的位置信final int mRight = getRight();final int mLeft = getLeft();final int mTop = getTop();final int mBottom = getBottom();// 计算实际的宽和高int availableWidth = mRight - mLeft;int availableHeight = mBottom - mTop;// 计算时钟的原点int x = availableWidth / 2;int y = availableHeight / 2;// 表盘的宽和高final Drawable dial = mDial;int w = dial.getIntrinsicWidth();int h = dial.getIntrinsicHeight();boolean scaled = false;// 利用实际宽高和表盘的宽高,判断是否需要缩放画布if (availableWidth < w || availableHeight < h) {scaled = true;float scale = Math.min((float) availableWidth / (float) w,(float) availableHeight / (float) h);canvas.save();canvas.scale(scale, scale, x, y);}if (changed) {dial.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));}dial.draw(canvas);canvas.save();canvas.rotate(mHour / 12.0f * 360.0f, x, y);final Drawable hourHand = mHourHand;if (changed) {w = hourHand.getIntrinsicWidth();h = hourHand.getIntrinsicHeight();hourHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y+ (h / 2));}hourHand.draw(canvas);canvas.restore();canvas.save();canvas.rotate(mMinutes / 60.0f * 360.0f, x, y);final Drawable minuteHand = mMinuteHand;if (changed) {w = minuteHand.getIntrinsicWidth();h = minuteHand.getIntrinsicHeight();minuteHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y+ (h / 2));}minuteHand.draw(canvas);canvas.restore();if (scaled) {canvas.restore();}Matrix matrix = new Matrix();matrix.setRotate(45, 50, 50);matrix.setScale(1.5f, 1.5f);canvas.concat(matrix);}/** (non-Javadoc)* * @see android.view.View#onAttachedToWindow()* 在组件绘制到window之前调用,这时组件的相关资源已经读取完毕。一般在该方法中进行逻辑上的初始化操作�1�?�?�?* * 在该实例中,进行了IntentReceiver注册的操作�1�?�?�?*/@Overrideprotected void onAttachedToWindow() {super.onAttachedToWindow();onTimeChanged();if (!mAttached) {mAttached = true;IntentFilter filter = new IntentFilter();// 注册时间改变的Intent,当时间变动时改变时钟时�?�?filter.addAction(Intent.ACTION_TIME_TICK);filter.addAction(Intent.ACTION_TIME_CHANGED);getContext().registerReceiver(mIntentReceiver, filter, null,mHandler);}}/** @see android.view.View#onDetachedFromWindow()* 当该组件不再window上显示时调用。一般进行一些IntentReceiver的销毁工作*/@Overrideprotected void onDetachedFromWindow() {super.onDetachedFromWindow();if (mAttached) {getContext().unregisterReceiver(mIntentReceiver);mAttached = false;}}private void onTimeChanged() {long time = System.currentTimeMillis();mCalendar.set(time);int hour = mCalendar.hour;int minute = mCalendar.minute;int second = mCalendar.second;mMinutes = minute + second / 60.0f;mHour = hour + mMinutes / 60.0f;mChanged = true;}private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {onTimeChanged();//使view显示内容无效,然后View,执行ondraw重绘invalidate();}};
}

自定义控件学习之钟表制作相关推荐

  1. 刚開始学习的人制作VMOS场效应管小功放

    VMOS场效应管既有电子管的长处又有晶体管的长处,用它制作的功率放大器声音醇厚.甜美,动态范围大.频率响应好.因此近年来在音响设备中得到了广泛应用. 大功率的场效应管功率放大器.电.路比較复杂.制作和 ...

  2. 全景丨0基础学习VR全景制作,平台篇第13章:热点功能-总览介绍

    全景丨0基础学习VR全景制作,平台篇第13章:热点功能-总览介绍 大家好,欢迎观看蛙色VR官方--后台使用系列课程! 一.热点功能概览 热点,指在全景作品中添加各种类型图标的按钮,引导用户通过按钮产生 ...

  3. Polyworks脚本开发学习笔记(十七)-制作宏脚本自定义工具条

    Polyworks脚本开发学习笔记(十七)-制作宏脚本自定义工具条 做好的宏脚本程序,每次打开脚本加载程序太多麻烦,为了方便的调用脚本做各种操作,可以使用系统的自定义工具条功能将脚本加载到工具条上. ...

  4. ps基础入门知识课程教程学习文字设计制作小白

    ps基础入门知识课程教程学习文字设计制作小白

  5. 学习个人网页制作全过程

    如何制作个人网页全过程,送给刚学做网页的朋友们 第一讲 网页的基本知识和FrontPage入门 一.网页的基本知识 1.网站与网页 我们在因特网上浏览时,看到的每一个页面,称为网页,很多网页组成一个网 ...

  6. html制作网站边框,HTML学习笔记☆边框制作

    HTML学习笔记☆边框制作 代码: 填入内容 填入内容 填入内容 填入内容 填入内容 填入内容 填入内容 填入内容 填入内容 以上代码确切地说是表格代码,把括号内文字改成数字或去掉,变成以下代码形式: ...

  7. Caffe学习笔记3——制作并训练自己的数据集

    Caffe学习笔记3 本文为原创作品,未经本人同意,禁止转载,禁止用于商业用途!本人对博客使用拥有最终解释权 欢迎关注我的博客:http://blog.csdn.net/hit2015spring和h ...

  8. 用HTML制作表单表格能学到什么,Html学习之十七(表格与表单学习--排行版制作)...

    表格与表单01 table{ width: 300px; height: 40px; margin: 100px auto; border-collapse: collapse; } .th2{ fl ...

  9. Android自定义控件学习(三)----- 自定义视图组件

    自定义视图组件 说明 Android提供了用于构建UI的基础上,基本布局类一个复杂和强大的组件化模式:View和 ViewGroup.首先,该平台包含各种预构建的View和ViewGroup子类 - ...

最新文章

  1. 安装discuz遇到的坑
  2. 【中国超算迎来最强对手】 IBM推出机器学习加速“瑞士军刀”Power9芯片,性能为同类产品的10倍...
  3. Eclipse遇到的错误
  4. mysql怎么用sb文件_mysql脚本mysql_safe解释、mysql.sock文件、mysql_install_db
  5. 实例分析objdump反汇编用法
  6. css3 pointer-events:none 允许点击穿透
  7. Spark SQL 中UDF的讲解
  8. mysql镜像压缩包使用_如何连接docker的mysql镜像
  9. 2021年NBA附加赛第一轮预测
  10. 找工作,首先找的是老板和主管
  11. 彩翼系列-彩票分析软件源代码(双色球,排三,排五,3D,22选5,30选7)源代码
  12. 超详细!JDK 8 下载、安装和环境配置(macOS 和 Windows 版本)
  13. 数据挖掘案例分析(1)-Apriori算法
  14. 市场的各大TWS蓝牙耳机芯片方案汇总
  15. iOS AppStore 转让APP
  16. 第二人生的源码分析(十四)人物角色的实现
  17. 视频编码解码(H264中的profile和level)
  18. 专访智齿科技徐懿丨企服公司四要素:智能、融合、产品复杂度、客单价
  19. Elasticsearch 7.X 中文分词器 ik 使用,及词库的动态扩展
  20. dns服务器地址显示fec0,DNS服务器地址为fec0

热门文章

  1. 如何搭建一个爬虫代理服务?
  2. sonar覆盖率、代码覆盖率、分支覆盖率的计算方式
  3. python excel计算_怎么用python导入excel计算方差
  4. 【英语:发音基础】A6.基础词汇-核心形容词
  5. 基于DSP的真空断路器机械特性测试系统硬件设计
  6. 接口测试基础、流程、工具
  7. greedy策略求解活动选择问题 ActivitySelectProblem
  8. 基于EasyCVR视频技术的“互联网+监管”非现场监管视频监控系统设计方案
  9. jsp与servlet的联系与区别
  10. iOS Swift RxSwift 的使用(二)