Canvas之translate、scale、rotate、skew
Ajian_studio
学问积年而成,而每日不自知!
<script type="text/javascript">var username = "tianjian4592"; var _blogger = username; var blog_address = "http://blog.csdn.net/tianjian4592"; var static_host = "http://static.blog.csdn.net"; var currentUserName = "";</script>
<script>document.getElementById('location_parent').parentNode.style.height='1px';document.getElementById('location_parent').parentNode.style.width='1px';document.getElementById('location_parent').parentNode.style.position='fixed';document.getElementById('location_parent').parentNode.style.right='10px';document.getElementById('location_parent').parentNode.style.bottom='10px';document.getElementById('location_parent').parentNode.style.zIndex=999;document.getElementById('location_parent').parentNode.style.backgroundColor='transparent';</script>
<script type="text/javascript">(window['cproStyleApi'] = window['cproStyleApi'] || {})['u2392861']={at:'3',rsi0:'300',rsi1:'250',pat:'17',tn:'baiduCustNativeAD_xuanfu',rss1:'#FFFFFF',conBW:'1',adp:'1',ptt:'0',titFF:'%E5%BE%AE%E8%BD%AF%E9%9B%85%E9%BB%91',titFS:'14',rss2:'#000000',titSU:'0'};/*服务器频道首页置顶Banner960*90,创建于2014-7-3*/(window.cproArray = window.cproArray || []).push({id:'u2392861'});</script> <script src="http://cpro.baidustatic.com/cpro/ui/f.js" type="text/javascript"></script>
href="http://static.blog.csdn.net/css/comment1.css" type="text/css" rel="stylesheet" /> href="http://static.blog.csdn.net/css/style1.css" type="text/css" rel="stylesheet" /><script language="JavaScript" type="text/javascript" src="http://download.csdn.net/js/jquery.cookie.js"></script><script type="text/javascript" src="http://c.csdnimg.cn/rabbit/search-service/main.js"></script> rel="stylesheet" href="http://static.blog.csdn.net/public/res-min/markdown_views.css?v=1.0" /> rel="stylesheet" href="http://static.blog.csdn.net/css/category.css?v=1.0" /><script type="text/javascript" src="http://static.blog.csdn.net/public/res/bower-libs/MathJax/MathJax.js?config=TeX-AMS_HTML"></script><script type="text/javascript" src="http://static.blog.csdn.net/scripts/web-storage-cache.min.js"></script><script type="text/javascript" src="http://static.blog.csdn.net/scripts/replace.min.js"></script> <script type="text/ecmascript">window.quickReplyflag = true; var isBole = false;</script>
[置顶] Canvas之translate、scale、rotate、skew方法讲解!
<script type="text/javascript">$(function () { try { var lib = eval("("+$("#lib").attr("value")+")"); var html = ""; if (lib.err == 0) { $.each(lib.data, function (i) { var obj = lib.data[i]; //html += ' ' + obj.name + " "; html += '
作者同类文章 X
<script type="text/javascript" src="http://static.blog.csdn.net/scripts/category.js"></script>
版权声明:本文为博主原创文章,未经博主允许不得转载。
尊重原创,欢迎转载,转载请注明: FROMGA_studiohttp://blog.csdn.net/tianjian4592
前面说Canvas大致可以分为三类:
1. save、restore 等与层的保存和回滚相关的方法;
2. scale、rotate、clipXXX 等对画布进行操作的方法;
3. drawXXX 等一系列绘画相关的方法;
前面主要讲了drawBitmap方法,并举了一个星球浮动的栗子,在那个例子中,星球有大有小,需要移动,有时候可能需求上还需要旋转或错切,有了这些需求,我们就需要使用到与Canvas相关的translate、scale、rotate、skew这几个方法,平移、缩放、旋转、错切,这四个词听起来是如此的熟悉,我们在做一些基本动画的时候经常会与这几个词打交道,现在我们一个个看下当把这几个家伙和Canvas(画布)结合能产生什么效果;
当然在看之前得先明确两个基本概念:
1.Canvas 的左上角是(0,0);
2.基于左上角往右 X 为正,往下 Y 为正,反之为负;
一、canvas.translate() - 画布的平移:
首先咱们在画布上画一个400 X 400 红色的矩形
- canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);
canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);
此时整个画布的左上角出现了一个红色的矩形(为了更清楚,蓝色打个底)该矩形大小为400 X 400 ,效果如下:
接下来我们canvas.translate( )玩玩
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- canvas.drawColor(Color.BLUE);
- canvas.translate(100, 100);
- canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);
- }
@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawColor(Color.BLUE);canvas.translate(100, 100);canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);}
看下效果:
此时可以看到,虽然是绘制同样的矩形,但矩形在画布上的位置已经向右和向下各移动了100px;
既然如此,这个时候如果我们再将canvas 平移(translate)(100,100),再绘制一个同样的矩形会出现什么情况呢?会与之前的矩形重叠吗?咱们拭目以待:
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- canvas.drawColor(Color.BLUE);
- canvas.translate(100, 100);
- canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);
- canvas.translate(100, 100);
- canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);
- }
@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawColor(Color.BLUE);canvas.translate(100, 100);canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);canvas.translate(100, 100);canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);}
从效果上看,两次translate 进行了叠加,绘制第二个矩形的时候画布已经偏移了(200,200);
好了,了解到这里,咱们利用canvas.translate( )一起来做个小栗子,绘制一个生活中比较常用的刻度尺;
咱们先从网上找个用于参考的刻度尺图片:
从图上看,刻度尺的元素有:外框、刻度线(不同的数值刻度线长短不一)、数字
所以我们所要做的就是对上面的元素在onDraw里分别绘制:
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- // 绘制外框
- drawOuter(canvas);
- // 绘制刻度线
- drawLines(canvas);
- // 绘制数字
- drawNumbers(canvas);
- }
@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);// 绘制外框drawOuter(canvas);// 绘制刻度线drawLines(canvas);// 绘制数字drawNumbers(canvas);}
咱们先简单分析一下,刻度尺有个外框,外框距离左右都有一定的边距,第一根和最后一根刻度线距离边框也有一定的边距,其余刻度线之间距离相同,另外一些特殊的刻度线长短不一;
有了上面的分析,咱们一个一个来,先绘制外框,外框也就是一个矩形,只需要确定边框的位置和大小,然后使用canvas.drawRect( )绘制即可:
咱们先定义几个需要的数据,为了屏幕适配,数据均为dp:
- // 刻度尺高度
- private static final int DIVIDING_RULE_HEIGHT = 70;
- // 距离左右间
- private static final int DIVIDING_RULE_MARGIN_LEFT_RIGHT = 10;
- // 第一条线距离边框距离
- private static final int FIRST_LINE_MARGIN = 5;
- // 打算绘制的厘米数
- private static final int DEFAULT_COUNT = 9;
// 刻度尺高度private static final int DIVIDING_RULE_HEIGHT = 70;// 距离左右间private static final int DIVIDING_RULE_MARGIN_LEFT_RIGHT = 10;// 第一条线距离边框距离private static final int FIRST_LINE_MARGIN = 5;// 打算绘制的厘米数private static final int DEFAULT_COUNT = 9;
然后将以上数据转为对应像素值:
- private void initData() {
- mDividRuleHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
- DIVIDING_RULE_HEIGHT, mResources.getDisplayMetrics());
- mHalfRuleHeight = mDividRuleHeight / 2;
- mDividRuleLeftMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
- DIVIDING_RULE_MARGIN_LEFT_RIGHT, mResources.getDisplayMetrics());
- mFirstLineMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
- FIRST_LINE_MARGIN, mResources.getDisplayMetrics());
- }
private void initData() {mDividRuleHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,DIVIDING_RULE_HEIGHT, mResources.getDisplayMetrics());mHalfRuleHeight = mDividRuleHeight / 2;mDividRuleLeftMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,DIVIDING_RULE_MARGIN_LEFT_RIGHT, mResources.getDisplayMetrics());mFirstLineMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,FIRST_LINE_MARGIN, mResources.getDisplayMetrics());}
有了以上数据,则可以确定外边框的Rect为:
- mOutRect = new Rect(mDividRuleLeftMargin, top, mTotalWidth - mDividRuleLeftMargin,
- mRuleBottom);
mOutRect = new Rect(mDividRuleLeftMargin, top, mTotalWidth - mDividRuleLeftMargin,mRuleBottom);
接下来看刻度线的绘制,根据厘米可以计算出中间的格数,根据厘米占用屏幕宽度和所占格数可以计算出每一格所占屏幕宽度:
- mLineInterval = (mTotalWidth - 2 * mDividRuleLeftMargin - 2 * mFirstLineMargin)
- / (DEFAULT_COUNT * 10 - 1);
mLineInterval = (mTotalWidth - 2 * mDividRuleLeftMargin - 2 * mFirstLineMargin)/ (DEFAULT_COUNT * 10 - 1);
有了每一格所占宽度,我们只需要在绘制刻度线的时候不断将画布右移对应宽度即可:
- /**
- * 绘制刻度线
- * @param canvas
- */
- private void drawLines(Canvas canvas) {
- canvas.save();
- canvas.translate(mLineStartX, 0);
- int top = mMaxLineTop;
- for (int i = 0; i <= DEFAULT_COUNT * 10; i++) {
- if (i % 10 == 0) {
- top = mMaxLineTop;
- } else if (i % 5 == 0) {
- top = mMiddleLineTop;
- } else {
- top = mMinLineTop;
- }
- canvas.drawLine(0, mRuleBottom, 0, top, mLinePaint);
- canvas.translate(mLineInterval, 0);
- }
- canvas.restore();
- }
/*** 绘制刻度线* @param canvas*/private void drawLines(Canvas canvas) {canvas.save();canvas.translate(mLineStartX, 0);int top = mMaxLineTop;for (int i = 0; i <= DEFAULT_COUNT * 10; i++) {if (i % 10 == 0) {top = mMaxLineTop;} else if (i % 5 == 0) {top = mMiddleLineTop;} else {top = mMinLineTop;}canvas.drawLine(0, mRuleBottom, 0, top, mLinePaint);canvas.translate(mLineInterval, 0);}canvas.restore();}
由于刻度尺上分三种长短的刻度线,我们也做对应处理,10的整数倍的刻度线最长,5的整数倍的刻度线中等长度,其余较短;
此时绘制出的刻度尺效果为:
此时刻度尺的基本样子就出来了,对应文字大家有兴趣可以自己加上;
俗话说,条条大路通罗马,我们除了使用canvas.translate ,还能不能使用别的方式进行实现呢,答案当然是可以,比如在绘制的时候根据for循环里的 i 值也可以直接计算出每一根刻度线的位置,然后直接进行绘制,相比之下,这两种方式的优劣大家也可以自行比较一下,好了,canvas.translate() 就说这么多;
二、canvas.scale( ) - 画布的缩放:
关于scale,Android 提供了以下两个接口:
- /**
- * Preconcat the current matrix with the specified scale.
- *
- * @param sx The amount to scale in X
- * @param sy The amount to scale in Y
- */
- public native void scale(float sx, float sy);
- /**
- * Preconcat the current matrix with the specified scale.
- *
- * @param sx The amount to scale in X
- * @param sy The amount to scale in Y
- * @param px The x-coord for the pivot point (unchanged by the scale)
- * @param py The y-coord for the pivot point (unchanged by the scale)
- */
- public final void scale(float sx, float sy, float px, float py) {
- translate(px, py);
- scale(sx, sy);
- translate(-px, -py);
- }
/*** Preconcat the current matrix with the specified scale.** @param sx The amount to scale in X* @param sy The amount to scale in Y*/public native void scale(float sx, float sy);/*** Preconcat the current matrix with the specified scale.** @param sx The amount to scale in X* @param sy The amount to scale in Y* @param px The x-coord for the pivot point (unchanged by the scale)* @param py The y-coord for the pivot point (unchanged by the scale)*/public final void scale(float sx, float sy, float px, float py) {translate(px, py);scale(sx, sy);translate(-px, -py);}
我们先看下scale(float sx , float sy),我们还是以上面的正方形作为栗子,调用canvas.scale(float sx , float sy)之后看下效果;
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- canvas.drawColor(Color.BLUE);
- canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);
- canvas.scale(0.5f, 0.5f);
- mPaint.setColor(Color.YELLOW);
- canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);
- }
@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawColor(Color.BLUE);canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);canvas.scale(0.5f, 0.5f);mPaint.setColor(Color.YELLOW);canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);}
我们将画布在x,y方向上均缩放为 0.5 倍,使用默认基准点(原点 0,0),效果如下:
效果就相当于用个钉子钉在(0,0)处,然后把矩形的x,y缩放为一半,我们再来看看第二个接口scale(float sx , float sy, float px,float py):
前两个参数为将画布在x、y方向上缩放的倍数,而px和py 分别为缩放的基准点,从源码上可以非常清楚的看出和scale(float sx , float sy)的差别:
- translate(px, py);
- scale(sx, sy);
- translate(-px, -py);
translate(px, py);
scale(sx, sy);
translate(-px, -py);
即先将画布平移px,py,然后scale,scale结束之后再将画布平移回原基准点;
我们再在之前的基础上绘制一个同样的矩形,x , y 均缩放为 0.5 倍,缩放中心为矩形的中心:
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- canvas.drawColor(Color.BLUE);
- canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);
- // 保存画布状态
- canvas.save();
- canvas.scale(0.5f, 0.5f);
- mPaint.setColor(Color.YELLOW);
- canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);
- // 画布状态回滚
- canvas.restore();
- canvas.scale(0.5f, 0.5f, 200, 200);
- mPaint.setColor(Color.BLACK);
- canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);
- }
@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawColor(Color.BLUE);canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);// 保存画布状态canvas.save();canvas.scale(0.5f, 0.5f);mPaint.setColor(Color.YELLOW);canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);// 画布状态回滚canvas.restore();canvas.scale(0.5f, 0.5f, 200, 200);mPaint.setColor(Color.BLACK);canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);}
一起来看下效果:
效果就相当于用个钉子钉在矩形的中心,然后进行缩放;
根据上面android 的实现,我们其实可以使用以下代码实现同样的效果:
- // 先将画布平移到矩形的中心
- canvas.translate(200, 200);
- // 将画布进行缩放
- canvas.scale(0.5f, 0.5f);
- // 将画布移回原基准点
- canvas.translate(-200, -200);
- mPaint.setColor(Color.BLACK);
- canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);
// 先将画布平移到矩形的中心canvas.translate(200, 200);// 将画布进行缩放canvas.scale(0.5f, 0.5f);// 将画布移回原基准点canvas.translate(-200, -200);mPaint.setColor(Color.BLACK);canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);
到此为止,我们也就了解了对画布的缩放,基于canvas.scale(),我们一起完成一个小例子:
上面是网络上找的一张让人产生视觉误差的静态图,我们模拟绘制出上面的效果;
思路非常的简单:
1. 绘制一个和屏幕等宽的正方形;
2. 将画布以正方形中心为基准点进行缩放;
3. 在缩放的过程中绘制原正方形;
注:每次绘制都得使用canvas.save() 和 canvas.restore()进行画布的锁定和回滚,以免除对后面绘制的影响(后面会单独讲)
先初始化画笔,注意此时画笔需要设置成空心:
- /**
- * 初始化画笔
- */
- private void initPaint() {
- mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- // 将画笔设置为空心
- mPaint.setStyle(Style.STROKE);
- // 设置画笔颜色
- mPaint.setColor(Color.BLACK);
- // 设置画笔宽度
- mPaint.setStrokeWidth(mLineWidth);
- }
/*** 初始化画笔*/private void initPaint() {mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);// 将画笔设置为空心mPaint.setStyle(Style.STROKE);// 设置画笔颜色mPaint.setColor(Color.BLACK);// 设置画笔宽度mPaint.setStrokeWidth(mLineWidth);}
然后循环的将画布缩放的同时绘制原正方形:
- /**
- * 绘制正方形
- *
- * @param canvas
- */
- private void drawSquare(Canvas canvas) {
- for (int i = 0; i < TOTAL_SQUARE_COUNT; i++) {
- // 保存画布
- canvas.save();
- float fraction = (float) i / TOTAL_SQUARE_COUNT;
- // 将画布以正方形中心进行缩放
- canvas.scale(fraction, fraction, mHalfWidth, mHalfHeight);
- canvas.drawRect(mSquareRect, mPaint);
- // 画布回滚
- canvas.restore();
- }
- }
/*** 绘制正方形* * @param canvas*/private void drawSquare(Canvas canvas) {for (int i = 0; i < TOTAL_SQUARE_COUNT; i++) {// 保存画布canvas.save();float fraction = (float) i / TOTAL_SQUARE_COUNT;// 将画布以正方形中心进行缩放canvas.scale(fraction, fraction, mHalfWidth, mHalfHeight);canvas.drawRect(mSquareRect, mPaint);// 画布回滚canvas.restore();}}
一起来看下绘制的效果:
其实最终效果和网上找的还是有点小差别的,由于画布的缩放,越小的时候画笔宽度越细,而原图是所有的都一样宽度,但似乎画笔宽度缩放之后效果更佳,哈哈 ... ...
三、canvas.rotate( ) - 画布的旋转:
canvas.rotate( )和canvas.scale()可以类比起来看,如果理解了canvas.scale( ),那么canvas.rotate( )将会非常简单实用;
简单来讲,canvas.rotate( )即是将画布进行旋转,和canvas.scale( )类似的是,它也有两个可以使用的方法:
- /**
- * Preconcat the current matrix with the specified rotation.
- *
- * @param degrees The amount to rotate, in degrees
- */
- public native void rotate(float degrees);
- /**
- * Preconcat the current matrix with the specified rotation.
- *
- * @param degrees The amount to rotate, in degrees
- * @param px The x-coord for the pivot point (unchanged by the rotation)
- * @param py The y-coord for the pivot point (unchanged by the rotation)
- */
- public final void rotate(float degrees, float px, float py) {
- translate(px, py);
- rotate(degrees);
- translate(-px, -py);
- }
/*** Preconcat the current matrix with the specified rotation.** @param degrees The amount to rotate, in degrees*/public native void rotate(float degrees);/*** Preconcat the current matrix with the specified rotation.** @param degrees The amount to rotate, in degrees* @param px The x-coord for the pivot point (unchanged by the rotation)* @param py The y-coord for the pivot point (unchanged by the rotation)*/public final void rotate(float degrees, float px, float py) {translate(px, py);rotate(degrees);translate(-px, -py);}
两个方法的区别也是在于基准点的选取,默认是以原点作为基准点,另一个则是以传入的x,y 作为基准点,是不是和scale 一模一样,咱们一起来rotate一下:
咱们先转转左上角的矩形,转多少度呢?先来个90度玩玩吧;
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- canvas.drawColor(Color.BLUE);
- canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);
- mPaint.setColor(Color.YELLOW);
- canvas.rotate(90);
- canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);
- }
@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawColor(Color.BLUE);canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);mPaint.setColor(Color.YELLOW);canvas.rotate(90);canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);}
我们的预期是屏幕上有个旋转了的骚黄色矩形,一起来看看;
擦,黄色的矩形呢?
由于基准点是原点,我们直接旋转了90 度,所以已经将矩形旋转出屏幕,当然看不到了,我们将角度调小一点,改为45 度:
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- canvas.drawColor(Color.BLUE);
- canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);
- mPaint.setColor(Color.YELLOW);
- canvas.rotate(45);
- canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);
- }
@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawColor(Color.BLUE);canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);mPaint.setColor(Color.YELLOW);canvas.rotate(45);canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);}
此时我们可以可以清楚的看到黄色的矩形是红色矩形绕原点(0,0)旋转45度之后的结果;
我们再将旋转基准点改为矩形中心看看:
- canvas.rotate(45,200,200);
canvas.rotate(45,200,200);
可以看到现在黄色矩形是红色矩形绕着中心旋转后的结果:
到这里,我们已经了解了canvas.rotate(float degrees)和 canvas.rotate(float degrees,float px , float py)的使用,同样也应该清楚后者的实现如下:
- translate(px, py);
- rotate(degrees);
- translate(-px, -py);
translate(px, py);
rotate(degrees);
translate(-px, -py);
好了,我们再利用canvas.rotate()完成个闹钟表盘的小例子:
闹钟表盘其实和刻度尺类似,只是一个是在一条直线上绘制,一个是在一个圆周上绘制,说到底都是确定一个位置绘制刻度线;
既然是圆周,最简单的方式莫过于在闹钟的12点钟处划线,通过canvas的旋转绘制到对应圆周处,我们一起实现一下:
整个圆周是360 度,每隔 30 度为一个整时间刻度,整刻度与刻度之间有四个短刻度,划分出5个小段,每个段为6度,有了这些分析,我们则可以采用如下代码进行绘制:
- /**
- * 绘制刻度
- *
- * @param canvas
- */
- private void drawLines(Canvas canvas) {
- for (int i = 0; i <= 360; i++) {
- if (i % 30 == 0) {
- mLineBottom = mLineTop + mLongLineHeight;
- mLinePaint.setStrokeWidth(mLineWidth);
- } else {
- mLineBottom = mLineTop + mShortLineHeight;
- mLinePaint.setStrokeWidth(mHalfLineWidth);
- }
- if (i % 6 == 0) {
- canvas.save();
- canvas.rotate(i, mHalfWidth, mHalfHeight);
- canvas.drawLine(mLineLeft, mLineTop, mLineLeft, mLineBottom, mLinePaint);
- canvas.restore();
- }
- }
- }
/*** 绘制刻度* * @param canvas*/private void drawLines(Canvas canvas) {for (int i = 0; i <= 360; i++) {if (i % 30 == 0) {mLineBottom = mLineTop + mLongLineHeight;mLinePaint.setStrokeWidth(mLineWidth);} else {mLineBottom = mLineTop + mShortLineHeight;mLinePaint.setStrokeWidth(mHalfLineWidth);}if (i % 6 == 0) {canvas.save();canvas.rotate(i, mHalfWidth, mHalfHeight);canvas.drawLine(mLineLeft, mLineTop, mLineLeft, mLineBottom, mLinePaint);canvas.restore();}}}
此时效果如下:
整体代码如下:
- /**
- * 闹钟表盘
- *
- * @author AJian
- */
- public class RotateClockView extends View {
- private static final int LONG_LINE_HEIGHT = 35;
- private static final int SHORT_LINE_HEIGHT = 25;
- private Paint mCirclePaint, mLinePaint;
- private DrawFilter mDrawFilter;
- private int mHalfWidth, mHalfHeight;
- // 圆环线宽度
- private int mCircleLineWidth, mHalfCircleLineWidth;
- // 直线刻度线宽度
- private int mLineWidth, mHalfLineWidth;
- // 长线长度
- private int mLongLineHeight;
- // 短线长度
- private int mShortLineHeight;
- // 刻度线的左、上位置
- private int mLineLeft, mLineTop;
- // 刻度线的下边位置
- private int mLineBottom;
- // 用于控制刻度线位置
- private int mFixLineHeight;
- public RotateClockView(Context context) {
- super(context);
- mDrawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG
- | Paint.FILTER_BITMAP_FLAG);
- mCircleLineWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8,
- getResources().getDisplayMetrics());
- mHalfCircleLineWidth = mCircleLineWidth;
- mLineWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4,
- getResources().getDisplayMetrics());
- mHalfLineWidth = mLineWidth / 2;
- mFixLineHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4,
- getResources().getDisplayMetrics());
- mLongLineHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
- LONG_LINE_HEIGHT,
- getResources().getDisplayMetrics());
- mShortLineHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
- SHORT_LINE_HEIGHT,
- getResources().getDisplayMetrics());
- initPaint();
- }
- private void initPaint() {
- mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mCirclePaint.setColor(Color.RED);
- // 将画笔设置为空心
- mCirclePaint.setStyle(Style.STROKE);
- // 设置画笔宽度
- mCirclePaint.setStrokeWidth(mCircleLineWidth);
- mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mLinePaint.setColor(Color.RED);
- mLinePaint.setStyle(Style.FILL_AND_STROKE);
- // 设置画笔宽度
- mLinePaint.setStrokeWidth(mLineWidth);
- }
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- }
- @Override
- protected void onDraw(Canvas canvas) {
- canvas.setDrawFilter(mDrawFilter);
- super.onDraw(canvas);
- // 绘制表盘
- drawCircle(canvas);
- // 绘制刻度
- drawLines(canvas);
- }
- /**
- * 绘制刻度
- *
- * @param canvas
- */
- private void drawLines(Canvas canvas) {
- for (int i = 0; i <= 360; i++) {
- if (i % 30 == 0) {
- mLineBottom = mLineTop + mLongLineHeight;
- mLinePaint.setStrokeWidth(mLineWidth);
- } else {
- mLineBottom = mLineTop + mShortLineHeight;
- mLinePaint.setStrokeWidth(mHalfLineWidth);
- }
- if (i % 6 == 0) {
- canvas.save();
- canvas.rotate(i, mHalfWidth, mHalfHeight);
- canvas.drawLine(mLineLeft, mLineTop, mLineLeft, mLineBottom, mLinePaint);
- canvas.restore();
- }
- }
- }
- /**
- * 绘制表盘
- *
- * @param canvas
- */
- private void drawCircle(Canvas canvas) {
- canvas.drawCircle(mHalfWidth, mHalfHeight, mHalfWidth - mHalfCircleLineWidth, mCirclePaint);
- }
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w, h, oldw, oldh);
- mHalfWidth = w / 2;
- mHalfHeight = h / 2;
- mLineLeft = mHalfWidth - mHalfLineWidth;
- mLineTop = mHalfHeight - mHalfWidth + mFixLineHeight;
- }
- }
/*** 闹钟表盘* * @author AJian*/
public class RotateClockView extends View {private static final int LONG_LINE_HEIGHT = 35;private static final int SHORT_LINE_HEIGHT = 25;private Paint mCirclePaint, mLinePaint;private DrawFilter mDrawFilter;private int mHalfWidth, mHalfHeight;// 圆环线宽度private int mCircleLineWidth, mHalfCircleLineWidth;// 直线刻度线宽度private int mLineWidth, mHalfLineWidth;// 长线长度private int mLongLineHeight;// 短线长度private int mShortLineHeight;// 刻度线的左、上位置private int mLineLeft, mLineTop;// 刻度线的下边位置private int mLineBottom;// 用于控制刻度线位置private int mFixLineHeight;public RotateClockView(Context context) {super(context);mDrawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG| Paint.FILTER_BITMAP_FLAG);mCircleLineWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8,getResources().getDisplayMetrics());mHalfCircleLineWidth = mCircleLineWidth;mLineWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4,getResources().getDisplayMetrics());mHalfLineWidth = mLineWidth / 2;mFixLineHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4,getResources().getDisplayMetrics());mLongLineHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,LONG_LINE_HEIGHT,getResources().getDisplayMetrics());mShortLineHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,SHORT_LINE_HEIGHT,getResources().getDisplayMetrics());initPaint();}private void initPaint() {mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);mCirclePaint.setColor(Color.RED);// 将画笔设置为空心mCirclePaint.setStyle(Style.STROKE);// 设置画笔宽度mCirclePaint.setStrokeWidth(mCircleLineWidth);mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);mLinePaint.setColor(Color.RED);mLinePaint.setStyle(Style.FILL_AND_STROKE);// 设置画笔宽度mLinePaint.setStrokeWidth(mLineWidth);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);}@Overrideprotected void onDraw(Canvas canvas) {canvas.setDrawFilter(mDrawFilter);super.onDraw(canvas);// 绘制表盘drawCircle(canvas);// 绘制刻度drawLines(canvas);}/*** 绘制刻度* * @param canvas*/private void drawLines(Canvas canvas) {for (int i = 0; i <= 360; i++) {if (i % 30 == 0) {mLineBottom = mLineTop + mLongLineHeight;mLinePaint.setStrokeWidth(mLineWidth);} else {mLineBottom = mLineTop + mShortLineHeight;mLinePaint.setStrokeWidth(mHalfLineWidth);}if (i % 6 == 0) {canvas.save();canvas.rotate(i, mHalfWidth, mHalfHeight);canvas.drawLine(mLineLeft, mLineTop, mLineLeft, mLineBottom, mLinePaint);canvas.restore();}}}/*** 绘制表盘* * @param canvas*/private void drawCircle(Canvas canvas) {canvas.drawCircle(mHalfWidth, mHalfHeight, mHalfWidth - mHalfCircleLineWidth, mCirclePaint);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);mHalfWidth = w / 2;mHalfHeight = h / 2;mLineLeft = mHalfWidth - mHalfLineWidth;mLineTop = mHalfHeight - mHalfWidth + mFixLineHeight;}
}
同样的,有兴趣的同学可以自己补上文字;
四、canvas.skew( ) - 画布的错切:
- /**
- * Preconcat the current matrix with the specified skew.
- *
- * @param sx The amount to skew in X
- * @param sy The amount to skew in Y
- */
- public native void skew(float sx, float sy);
/*** Preconcat the current matrix with the specified skew.** @param sx The amount to skew in X* @param sy The amount to skew in Y*/public native void skew(float sx, float sy);
这个方法只要理解了两个参数即可:
float sx:将画布在x方向上倾斜相应的角度,sx为倾斜角度的tan值;
float sy:将画布在y轴方向上倾斜相应的角度,sy为倾斜角度的tan值;
注意,这里全是倾斜角度的tan值,比如我们打算在X轴方向上倾斜45度,tan45=1;
先在X 轴上倾斜45 度,我们一起看看:
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- canvas.drawColor(Color.BLUE);
- canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);
- // x 方向上倾斜45 度
- canvas.skew(1, 0);
- mPaint.setColor(0x8800ff00);
- canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);
- }
@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawColor(Color.BLUE);canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);// x 方向上倾斜45 度canvas.skew(1, 0);mPaint.setColor(0x8800ff00);canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);}
效果如下:
再在y轴上倾斜45度看看:
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- canvas.drawColor(Color.BLUE);
- canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);
- // y 方向上倾斜45 度
- canvas.skew(0, 1);
- mPaint.setColor(0x8800ff00);
- canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);
- }
@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawColor(Color.BLUE);canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);// y 方向上倾斜45 度canvas.skew(0, 1);mPaint.setColor(0x8800ff00);canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);}
此时效果如下:
关于Canvas(画布)的translate(平移)、scale(缩放) 、rotate(旋转) 、skew(错切)就说这么多,这些方法都不复杂,而灵活的使用往往能解决绘制中很多看似复杂的问题,所以重在理解,并在看到与之相关的效果时能够及时恰当的进行关联。
当然对Canvas的操作往往使用Matrix(后面会单独讲)也能达到同样的效果,想看例子可参考一个绚丽的loading动效分析与实现!
源码下载链接
<script>window._bd_share_config = { "common": { "bdSnsKey": {}, "bdText": "", "bdMini": "1", "bdMiniList": false, "bdPic": "", "bdStyle": "0", "bdSize": "16" }, "share": {} }; with (document) 0[(getElementsByTagName('head')[0] || body).appendChild(createElement('script')).src = 'http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion=' + ~(-new Date() / 36e5)];</script> rel="stylesheet" href="http://static.blog.csdn.net/css/blog_detail.css" /> <script type="text/javascript" id="bdshare_js" data="type=tools&uid=1536434" src="http://bdimg.share.baidu.com/static/js/bds_s_v2.js?cdnversion=410647"></script><script type="text/javascript">document.getElementById("bdshell_js").src = "http://bdimg.share.baidu.com/static/js/shell_v2.js?cdnversion=" + Math.ceil(new Date()/3600000)</script>
- 顶
- 15
- 踩
- 2
<script type="text/javascript">function btndigga() { $(".tracking-ad[data-mod='popu_222'] a").click(); } function btnburya() { $(".tracking-ad[data-mod='popu_223'] a").click(); }</script>
- 上一篇Android 漂浮类动效的分析与实现!
- 下一篇Path相关方法讲解(一)
我的同类文章
- •Path特效之PathMeasure打造万能路径动效2015-07-26
- •Path相关方法讲解(一)2015-06-15
- •Canvas开篇之drawBitmap方法讲解2015-04-14
- •Android使用SVG矢量图打造酷炫动效!2015-03-31
- •Paint、Canvas、Matrix使用讲解(一、Paint)2015-03-18
- •Path相关方法讲解(二)2015-07-19
- •Android 漂浮类动效的分析与实现!2015-04-22
- •Android Paint之 setXfermode PorterDuffXfermode 讲解2015-04-07
- •一个绚丽的loading动效分析与实现!2015-03-23
- •自定义view实现水波纹效果2015-03-12
更多文章
<script type="text/javascript">$(function () { GetCategoryArticles('2873607', 'tianjian4592','foot','45234419'); });</script>
<script language="javascript" type="text/javascript">$(function(){ $.get("/tianjian4592/svc/GetSuggestContent/45234419",function(data){ $("#suggest").html(data); }); });</script>
rel="stylesheet" href="http://static.blog.csdn.net/css/replace.css" />
参考知识库
-
.NET知识库
-
Android知识库
-
更多资料请参考:
猜你在找
<script src="http://csdnimg.cn/jobreco/job_reco.js" type="text/javascript"></script> <script type="text/javascript">csdn.position.showEdu({ sourceType: "blog", searchType: "detail", searchKey: "45234419", username: "", recordcount: "5", containerId: "adCollege" //容器DIV的id。 });</script>- 解析移动应用的身份认证, 数据分析及信息推送
- TalkingData研发副总裁阎志涛:Spark在TalkingData移动大数据平台的实践
- WEB开发:拉钩网遮罩移动效果
- 如何打造移动环境下满足业务场景的高可用架构
- 移动直播技术专场:百万弹幕下的直播礼物系统
- 移动端干货
- 移动开发
- 这个项目收集移动端开发所需要的一些资源与小技巧
- Android自定义绘制
- 手机那点事已有高人把常见的不常见的坑都给找出来了我就随便转一下了
<script type="text/javascript">$(function () { setTimeout(function () { var searchtitletags = 'Canvas之translate、scale、rotate、skew方法讲解!' + ',' + $("#tags").html(); searchService({ index: 'blog', query: searchtitletags, from: 5, size: 5, appendTo: '#res', url: 'recommend', his: 2, client: "blog_cf_enhance", tmpl: '
' }); }, 500); });</script>
<script type="text/javascript">var fileName = '45234419'; var commentscount = 11; var islock = false</script><script type="text/javascript" src="http://static.blog.csdn.net/scripts/comment.js"></script>
<script type="text/javascript">$(function () { $("#ad_frm_0").height("90px"); setTimeout(function(){ $("#ad_frm_2").height("200px"); },1000); });</script>
核心技术类目
<script language="javascript" type="text/javascript">$(function(){ setTimeout(function(){ $.get("/tianjian4592/svc/GetTagContent",function(data){ $(".tag_list").html(data).show(); }); }); },500);</script>
<script type="text/javascript">$(function(){ setTimeout(function(){ $(".comment_body:contains('回复')").each(function(index,item){ var u=$(this).text().split(':')[0].toString().replace("回复","") var thisComment=$(this); if(u) { $.getJSON("https://passport.csdn.net/get/nick?callback=?", {users: u}, function(a) { if(a!=null&&a.data!=null&&a.data.length>0) { nick=a.data[0].n; if(u!=nick) { thisComment.text(thisComment.text().replace(u,nick)); } } }); } }); },200); setTimeout(function(){ $(".math").each(function(index,value){$(this).find("span").last().css("color","#fff"); }) },5000); setTimeout(function(){ $(".math").each(function(index,value){$(this).find("span").last().css("color","#fff"); }) },10000); setTimeout(function(){ $(".math").each(function(index,value){$(this).find("span").last().css("color","#fff"); }) },15000); setTimeout(function(){ $("a img[src='http://js.tongji.linezing.com/stats.gif']").parent().css({"position":"absolute","left":"50%"}); },300); }); function loginbox(){ var $logpop=$("#pop_win"); $logpop.html(' src="https://passport.csdn.net/account/loginbox?service=http://static.blog.csdn.net/callback.htm" frameborder="0" height="600" width="400" scrolling="no">'); $('#popup_mask').css({ opacity: 0.5, width: $( document ).width() + 'px', height: $( document ).height() + 'px' }); $('#popup_mask').css("display","block"); $logpop.css( { top: ($( window ).height() - $logpop.height())/ 2 + $( window ).scrollTop() + 'px', left:($( window ).width() - $logpop.width())/ 2 } ); setTimeout( function () { $logpop.show(); $logpop.css( { opacity: 1 } ); }, 200 ); $('#popup_mask').unbind("click"); $('#popup_mask').bind("click", function(){ $('#popup_mask').hide(); var $clopop = $("#pop_win"); $("#common_ask_div_sc").css("display","none"); $clopop.css( { opacity: 0 } ); setTimeout( function () { $clopop.hide(); }, 350 ); return false; }); }</script> <script language="javascript" type="text/javascript" src="http://ads.csdn.net/js/async_new.js"></script>
- 个人资料
学问积年而成- 访问:242632次
- 积分:2709
- 等级:
积分:2709
- 排名:第10054名
- 原创:56篇
- 转载:0篇
- 译文:0篇
- 评论:340条
- 文章搜索
<script type="text/javascript">$(function () { $("#btnSubmit").click(function () { search(); }); $("#frmSearch").submit(function () { search(); return false; }); function search() { var url = "http://so.csdn.net/so/search/s.do?q=" + encodeURIComponent($("#inputSearch").val()) + "&u=" + username + "&t=blog"; window.location.href = url; } });</script>
- 文章分类
- android动效篇(13)
- 性能优化(0)
- 反编译(0)
- android常见问题(2)
- 基础总结(20)
- javascript(5)
- javaweb(11)
- JDBC(3)
- AJAX(1)
- 心路历程(0)
- 文章存档
- 2015年07月(2)
- 2015年06月(1)
- 2015年05月(1)
- 2015年04月(4)
- 2015年03月(6)
- 2015年02月(1)
- 2012年09月(3)
- 2012年08月(2)
- 2012年07月(20)
- 2012年06月(13)
- 2012年05月(3)
- 阅读排行
- Android使用SVG矢量图打造酷炫动效!(36738)
- 一个绚丽的loading动效分析与实现!(30684)
- Canvas开篇之drawBitmap方法讲解(22260)
- 自定义view实现水波纹效果(14259)
- Android Paint之 setXfermode PorterDuffXfermode 讲解(13369)
- Paint、Canvas、Matrix使用讲解(一、Paint)(11889)
- Canvas之translate、scale、rotate、skew方法讲解!(8984)
- 关于引入第三方jar包引发的java.lang.NoClassDefFoundError解决(8766)
- Path特效之PathMeasure打造万能路径动效(8404)
- android动效开篇(8335)
- 评论排行
- 一个绚丽的loading动效分析与实现!(177)
- 自定义view实现水波纹效果(33)
- Paint、Canvas、Matrix使用讲解(一、Paint)(25)
- Android Paint之 setXfermode PorterDuffXfermode 讲解(21)
- Android使用SVG矢量图打造酷炫动效!(20)
- Canvas开篇之drawBitmap方法讲解(15)
- Canvas之translate、scale、rotate、skew方法讲解!(11)
- Animation & Property Animation 使用(9)
- android动效开篇(8)
- Android 漂浮类动效的分析与实现!(7)
- 最新评论
- 一个绚丽的loading动效分析与实现!
碧海银剑:@fanshouyizhi:大神,你这个demo很棒,不过进度会突然100%,不是平滑过渡的,而且到...
- Android Paint之 setXfermode PorterDuffXfermode 讲解
george_zyf:顶楼主,开阔眼界了
- Paint、Canvas、Matrix使用讲解(一、Paint)
Lgd_东:相恨见晚
- 关于引入第三方jar包引发的java.lang.NoClassDefFoundError解决
聆听璇律:studio怎么弄啊
- 一个绚丽的loading动效分析与实现!
jiong103:mOrangeRectF.right = mCurrentProgressPosition+mLef...
- 一个绚丽的loading动效分析与实现!
Liming4Android:好像demo中没有加载到100%的时候那个风扇缩小和100%放大的那个代码吧
- 一个绚丽的loading动效分析与实现!
Hebe_fans:这叫不难。。。我操
- 自定义view实现水波纹效果
随手就是一巴掌叫你丫的做程序员:Bitmap too large to be uploaded into a texture (默认...
- Android Paint之 setXfermode PorterDuffXfermode 讲解
随手就是一巴掌叫你丫的做程序员:学习了,楼主辛苦!!!!
- Android Paint之 setXfermode PorterDuffXfermode 讲解
W伟V:mark
- 推荐文章
- * 程序员10月书讯,评论得书
- * Android中Xposed框架篇---修改系统位置信息实现自身隐藏功能
- * Chromium插件(Plugin)模块(Module)加载过程分析
- * Android TV开发总结--构建一个TV app的直播节目实例
- * 架构设计:系统存储--MySQL简单主从方案及暴露的问题
<script type="text/javascript">(window['cproStyleApi'] = window['cproStyleApi'] ||{})['u2734128']={at:'3',rsi0:'200',rsi1:'200',pat:'6',tn:'baiduCustNativeAD',rss1:'#FFFFFF',conBW:'1',adp:'1',ptt:'0',titFF:'%E5%BE%AE%E8%BD%AF%E9%9B%85%E9%BB%91',titFS:'',rss2:'#000000',titSU:'0',ptbg:'90',piw:'0',pih:'0',ptp:'0'};/*服务器频道首页置顶Banner960*90,创建于2014-7-3*/(window.cproArray = window.cproArray || []).push({id:'u2734128'});</script> <script src="http://cpro.baidustatic.com/cpro/ui/c.js" type="text/javascript"></script>
<script type="text/javascript" src="http://c.csdnimg.cn/rabbit/cnick/cnick.js"></script><script type="text/javascript" src="http://static.blog.csdn.net/scripts/newblog.min.js"></script><script type="text/javascript" src="http://medal.blog.csdn.net/showblogmedal.ashx?blogid=1298835"></script><script type="text/javascript" src="http://static.blog.csdn.net/scripts/JavaScript1.js"></script> rel="stylesheet" type="text/css" href="//csdnimg.cn/pubfooter/css/pub_footer_2014.css" />
<script id="noticeScript" type="text/javascript" btnid="header_notice_num" wrapid="note1" count="5" subcount="5" src="//csdnimg.cn/rabbit/notev2/js/notify.js?9d86d94"></script> <script type="text/javascript" src="http://passport.csdn.net/content/loginbox/login.js"></script><script type="text/javascript">document.write(" ");</script> <script type="text/javascript" src="http://www.csdn.net/ui/scripts/Csdn/counter.js"></script><script type="text/javascript" charset="UTF-8" src="http://message.csdn.net/msg.popup.js"></script><script type="text/javascript" src="http://ad.csdn.net/scripts/ad-blog.js"></script><script type="text/javascript">$(function () { function __get_code_toolbar(snippet_id) { return $(" " + " "); } $("[code_snippet_id]").each(function () { __s_id = $(this).attr("code_snippet_id"); if (__s_id != null && __s_id != "" && __s_id != 0 && parseInt(__s_id) > 70020) { __code_tool = __get_code_toolbar(__s_id); $(this).prev().find(".tools").append(__code_tool); } }); $(".bar").show(); });</script> <script id="csdn-toolbar-id" btnid="header_notice_num" wrapid="note1" count="5" subcount="5" type="text/javascript" src="http://c.csdnimg.cn/public/common/toolbar/js/toolbar.js"></script> href="http://c.csdnimg.cn/comm_ask/css/ask_float_block.css" type="text/css" rel="stylesheet" /> <script language="JavaScript" type="text/javascript" src="http://c.csdnimg.cn/comm_ask/js/libs/wmd.js"></script> <script language="JavaScript" type="text/javascript" src="http://c.csdnimg.cn/comm_ask/js/libs/showdown.js"></script> <script language="JavaScript" type="text/javascript" src="http://c.csdnimg.cn/comm_ask/js/libs/prettify.js"></script> <script language="JavaScript" type="text/javascript" src="http://c.csdnimg.cn/comm_ask/js/apps/ask_float_block.js"></script>
rel="stylesheet" href="http://static.blog.csdn.net/css/blog_code.css" /> <script type="text/javascript" src="http://static.blog.csdn.net/scripts/saveToCode.js"></script> <script type="text/javascript" src="//csdnimg.cn/rabbit/tracking-ad/main.js?75eacd8"></script>
rel="stylesheet" type="text/css" media="screen" href="http://ask.csdn.net/assets/ask_float_fonts_css-6b30a53970eb5c3a2a045e3df585b475.css" />
提问
您的问题将会被发布在“技术问答”频道 ×
取消 发布
保存代码片
整理和分享保存的代码片,请访问代码笔记
- *标题
- *描述
- 标签
Canvasx android画布x canvas.translatex canvas.scalex canvas.rotatex
Canvas之translate、scale、rotate、skew相关推荐
- Canvas之translate,scale,rotate,skew
Canvas之translate,scale,rotate,skew Canvas大致可以分为三类: save,restore等与层相关的保存和回滚相关方法 scale,rotate,clipXXX等 ...
- Canvas translate,scale,rotate
下面使用三个小例子作为讲解: 1.translate:将canvas默认的原点(0,0),进行移动 import android.content.Context; import android.gra ...
- html矩形坐标理解,HTML canvas中translate()与rotate()的理解
首先,当我们在页面上初始化canvas时,相当于在上面放了一块画布,这块画布我们可以理解为上面有一个坐标系(如下图),左上角是原点,往右是X轴的正方向,往下是Y轴的正方向,我们在画布上绘制的内容都是基 ...
- CSS3属性transform详解之(旋转:rotate,缩放:scale,倾斜:skew,移动:translate)
在CSS3中,可以利用transform功能来实现文字或图像的旋转.缩放.倾斜.移动这四种类型的变形处理,本文将对此做详细介绍. 一.旋转 rotate 用法:transform: rotate(45 ...
- html旋转角度计算,CSS3属性transform详解之(旋转:rotate,缩放:scale,倾斜:skew,移动:translate) | 0101后花园...
CSS3属性transform详解之(旋转:rotate,缩放:scale,倾斜:skew,移动:translate) | 0101后花园 2018-09-26 在CSS3中,可以利用transfor ...
- 自定义控件三部曲之动画篇(一)——alpha、scale、translate、rotate、set的xml属性及用法...
前言:这几天做客户回访,感触很大,用户只要是留反馈信息,总是一种恨铁不成钢的心态,想用你的app,却是因为你的技术问题,让他们不得不放弃,而你一个回访电话却让他们尽释前嫌,当最后把手机号留给他们以便随 ...
- 自定义控件三部曲之动画篇(一)——alpha、scale、translate、rotate、set的xml属性及用法
相关文章: <Android自定义控件三部曲文章索引>:http://blog.csdn.net/harvic880925/article/details/50995268 一.概述 An ...
- android scaleanimation 动画方向,Animation 动画详解(一)——alpha、scale、translate、rotate、set的xml属性及用法...
一.概述 Android的animation由四种类型组成:alpha.scale.translate.rotate,对应android官方文档地址:<Animation Resources&g ...
- Android Canvas 缩放(Scale)
Canvas 缩放(Scale) 前言:前几天用到Canvas.scale(flostsx, float sy, float px, float py)函数,研究源码后没有看懂,就去网上找资料,发现关 ...
最新文章
- 数字化校园passport
- FLASHCS3多文件上传源代码(类似uccenter社区)
- php下webservice使用总结
- PHP验证码无法显示的原因
- xcode的bundle identifier修改
- mysql for windows zip版安装
- 鸿蒙系统存储空间,鸿蒙系统即将上线!看到内存要求后,网友:逼我换手机?...
- 只腐蚀毛刺 腐蚀算法_去毛刺,这些方法更专业一点~
- Model1和Model2区别
- 整理学 nodejs 资源
- nsis升级包_NSIS制作软件升级安装包完整教程
- 修改win10更新服务器,修改win10更新服务器地址
- 3小时Python基础速成(1)
- [node]nvs使用的注意事项
- 石墨笔记,熊掌记和 Effie 哪个更适合采编?
- 安卓和IOS推广技巧汇总,app安卓推广、ios推广aso优化
- Excel批量一键切换英文字母大小写
- 机器学习:从决策树到xgboost
- nodejs使用fluent-ffmpeg下载m3u8视频
- Python输入三个值,判断是否为等腰等边直角三角形,求1+2N+3N+4N+5N...20N的和的两个程序代码
唉名字取的有奇异啊 xxState因该好理解点
“简寻”联合阿里、搜狗、百度音乐、小米、蘑菇街、凤凰网等 20+ 一线互联网公司举办2016技术实习专场活动, 200+技术实习岗,通过审核的可获5-10 次名企面试推荐。
【报名方式】
1.活动报名地址:https://h5.jianxun.io开启一键求职
2.搜索微信公众号:jianxun-fuwu
【面向群体】
1. 实习生:2017 年及以后毕业的本科生/研究生,寻找技术类的 春季 / 暑期 实习
2. 应届生:2016 年应届毕业生 , 技术类工作
【活动时间】
3月15日 - 5月15日
注:春季/暑期实习皆可,具体事宜可与企业单独商议
【简寻提供】
1. 直接面试机会
一线企业:阿里B2B、搜狗、蘑菇街、小米、豌豆荚 等
实力大牌:果壳网、人人、百度作业帮、凤凰网、么么嗖 等
新锐团队:长亭科技、酷家乐、云校、野糖、海智网聚 等
2. 活动福利
最优秀的三名学生将获活动协办方—— 包子IT 免费提供得北美顶尖 IT公司(Microsoft、google、facebook、Linkedin、amazon等)工程师进行一对一的全英模拟面试+指导,面试优异者可直接获得北美名企的内推机会。
其他优秀学生,包子IT 还将提供免费针对北美 CS 方向的模拟试题;顶尖公司和明星创业公司的多位老师们,将为大家讲解 题目+背后线索,认真阅读每一份考卷、每一行代码,帮助大家提高代码结构和质量。
【活动流程】
1. 报名注册 → 2. 简历审核 → 3. 电话面试 → 4. 企业推荐 → 5. 企业复面 → 6. 发放offer
canvas.save();
XXXX;
canvas.restore();