Canvas的初识——模拟表盘数字绘制

看了题目,大家都该知道,我今天想说些什么了,是的,我今天想说说Canvas这个android中的让人摸不着头脑的元素,对于Canvas很多人都知道他就是用来画东西的,其他的也没啥用,是啊,说的没错,它就是用来画东西的,可能刚接触android的童鞋们不了解,但是有一定时间开发经验的小伙伴们都知道,Canvas是走进android高级开发道路上必不可少的,那么它究竟有什么地方让我们这么捉摸不透呢?下面让我们一点一点的了解——Canvas

为了让大家能够熟悉Canvas,我在接下来的文段落中会教大家绘制一个简单的表盘上的数字,当然,他和表盘一样,有12个数字,而且只画整点时间数,先给大家看一下效果图吧

效果图

其实很简单,就是一个背景,上面画了一圈数字,但是大家看好了,数字是正对着大家的,没有任何倾斜,看起来很容易,这需要丰富的想象力啊,否则还真想不出来是怎么实现的

好了,废话就不说了,先给大家说说这个Canvas吧,在Android中我们在写自定义View的时候,大家都知道,有三种方式,一种是继承自View,一种是继承制ViewGroup,还有一种是继承自现有控件,对现有空间进行改造,那么最为灵活的就是继承自View了,当然这也是难点,确实需要想想力啊,首先Canvas是一张画布,想要在画布上画一张图,就需要有笔Paint,有了笔我们这才能画,所以想要在Canvas上面画图,就需要有Paint,并且是一个带有样式的Paint

首先呢,我们需要有一个继承View的类,然后我们需要实现三个构造方法分别是:

public MyView(Context context) {
    super(context, null);
}
public MyView(Context context, AttributeSet attrs) {
    super(context, attrs);
    initData();
}
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);    
    initData();
}
  1. 第一个构造函数是在代码中实例化View的时候需要用的
  2. 第二个构造函数是在Xml文件文件中创建代码的时候用的所以比第一个多了一个自定义属性参数
  3. 第三个构造方法多了一个样式参数,是在Xml里面多一个自定义样式的时候调用的

所以在创建自定义View的时候需要同时实线这三个构造函数,关于怎样写自定义View,小编在这里就不多讲了,毕竟改文章主要是代大家熟悉Canvas的,小编会另写一篇文章教大家怎样去写自定义View,接下来我们先看一段代码

private void initData() {
    mPint = new Paint();
    mPint.setAntiAlias(true);
}

这是对Paint画笔的一个实例化,setAntiAlias方法主要是用来消除锯齿,是画出来的图像更加自然,圆滑,这里我们还要实现一个onSizeChanged方法,用来获取测量后的布局的宽和高

@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    mRidus = Math.min(w, h) / 2;
}

这里我们定义一个圆的半径,因为我们要花表盘上的数字,由于表盘是个圆形,所以要定义一个圆形的半径,这里的半径我们选择为宽的一半,min函数用于求出宽和高中较小的那一个,设置好这些东西后,我们就开始画了,我直接上代码

/**    
 * 画文字     
 * @param canvas    
 */    
private void paintText(Canvas canvas) {
        //将画布中心移动到屏幕中心
        canvas.translate(getWidth() / 2, getHeight() / 2);
        //设置画笔的颜色为红色
        mPint.setColor(Color.RED);
        //设置画笔的字体大小为30
        mPint.setTextSize(30);
        //由于表盘一圈是360度,总共有60个刻度,每个刻度是6度,所以我们这里循环60次
        for (int i = 0; i < 60 ; i++) {
            //当i除以5余数为0的时候,我们确定它为整点
            if ( i % 5 == 0) { 
                //获取要显示的数字,转换成字符型
                String text = (i / 5 == 0 ? 12 : i / 5) + "";
                //这里实例化一个Rect主要是用来获取,需要画出来的数字的宽和高
                Rect mRect = new Rect();
                mPint.getTextBounds(text, 0, text.length(), mRect); 
                //我们获取文字的高为,基于坐标的底部距离减去顶部距离
                int textHeight = mRect.bottom - mRect.top;
                //保存画布
                canvas.save();
                //这个时候我们使用Canvas的Save方法保存了刚才的状态,这个时候我们不移动X轴,只移动Y轴,将坐标向上移动-mRidus + textHeight距离,因为对于手机来说,向上为Y的负轴,所以为-mRidus + textHeight,下面我一会用图来说明
                canvas.translate(0, -mRidus + textHeight);
                //由于我们没旋转一次,会使用Canvas的rotate方法顺时针旋转6度,所以文字也会跟着旋转,但是我们要让文字不旋转的话,就需要逆时针旋转相应的度数
                canvas.rotate(-6 * i);
                //最后使用Canvas的drawText方法画出来就可以了,由于drawText方法画汉字是从左向右的,所以x坐标为-(mRect.right - mRect.left) / 2,y坐标为mRect.bottom
                canvas.drawText(text, -(mRect.right - mRect.left) / 2, mRect.bottom, mPint);
                //恢复到保存最初的状态
                canvas.restore();
            }            
            //旋转6度
            canvas.rotate(6);
        } 
        //恢复到保存最初的状态
        canvas.restore(); 
   }

上面的注释,比较多,但是说的应该很清楚了,不过我还是给大家详细讲一下坐标轴的移动,首先看第一句:

canvas.translate(getWidth() / 2, getHeight() / 2);

坐标轴移动示意图

这下应该很明白了,我们再看下一句

 canvas.translate(0, -mRidus + textHeight);

旋转文字坐标移动示意图

最后就是将旋转的图层恢复到原来的样子,效果图就出来了,最后运行一下,怎么样还不错吧
这里写图片描述

转载请注明出处http://blog.csdn.net/u010151514/article/details/52355213

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
光学衍射是指光线经过物体的边缘、孔或者其他不规则物体时,光线会发生弯曲、扩散、干涉等现象。在Canvas中,我们可以利用绘图函数模拟光学衍射的效果。 首先,我们需要了解一些基本的物理概念,例如光的波动性、光的衍射等。然后,我们可以根据这些概念来编写绘图代码。 以下是一个简单的光学衍射模拟的代码示例: ```javascript // 创建一个画布 const canvas = document.createElement('canvas'); canvas.width = 600; canvas.height = 400; // 获取画布的上下文对象 const ctx = canvas.getContext('2d'); // 定义一些参数 const wavelength = 10; // 光波长 const slitSize = 2; // 缝宽 const distance = 300; // 屏幕距离 const screenOffset = 200; // 屏幕偏移 // 绘制背景色 ctx.fillStyle = '#000'; ctx.fillRect(0, 0, canvas.width, canvas.height); // 绘制光源 ctx.fillStyle = '#fff'; ctx.beginPath(); ctx.arc(50, 200, 5, 0, Math.PI * 2); ctx.fill(); // 绘制缝隙 ctx.fillStyle = '#fff'; ctx.fillRect(100, 180, slitSize, 40); // 计算并绘制衍射图案 for (let x = 0; x < canvas.width; x++) { let intensity = 0; // 计算每个像素点的光强度 for (let s = 0; s < slitSize; s += wavelength / 2) { const distanceToSource = Math.sqrt((50 - x) ** 2 + (200 - screenOffset) ** 2); const distanceToScreen = Math.sqrt((x - 100 + s) ** 2 + (screenOffset - distance) ** 2); const pathLengthDifference = distanceToScreen - distanceToSource; const pathLengthDifferenceRatio = pathLengthDifference / wavelength; const pathLengthDifferencePhase = pathLengthDifferenceRatio * Math.PI * 2; intensity += Math.cos(pathLengthDifferencePhase); } // 绘制像素点 intensity = Math.abs(intensity) * 10; ctx.fillStyle = `rgb(${intensity}, ${intensity}, ${intensity})`; ctx.fillRect(x, 300 - intensity, 1, intensity); } // 将画布添加到页面中 document.body.appendChild(canvas); ``` 在这个示例中,我们首先创建了一个宽度为600,高度为400的画布,在画布上绘制了一个白色的点表示光源,以及一个白色的长方形表示缝隙。然后,我们通过循环遍历画布的每个像素点,计算该像素点的光强度,并根据光强度绘制相应的像素点。最终,我们将绘制好的画布添加到页面中。 需要注意的是,这个示例只是一个简单的光学衍射模拟,实际情况可能更加复杂。如果想要进行更加精确的模拟,需要对光学衍射的物理模型有更深入的了解,并且进行更复杂的计算。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值