最后
最后这里放上我这段时间复习的资料,这个资料也是偶然一位朋友分享给我的,里面包含了腾讯、字节跳动、阿里、百度2020-2021面试真题解析,并且把每个技术点整理成了视频和PDF(知识脉络 + 诸多细节)。
还有 高级架构技术进阶脑图、高级进阶架构资料 帮助大家学习提升进阶,这里我也免费分享给大家也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。
一起互勉~
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
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 红色的矩形
[html] view plain copy
- canvas.drawRect(new Rect(0, 0, 400, 400), mPaint);
此时整个画布的左上角出现了一个红色的矩形(为了更清楚,蓝色打个底)该矩形大小为400 X 400 ,效果如下:
接下来我们canvas.translate( )玩玩
[html] view plain copy
-
@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);
-
}
看下效果:
此时可以看到,虽然是绘制同样的矩形,但矩形在画布上的位置已经向右和向下各移动了100px;
既然如此,这个时候如果我们再将canvas 平移(translate)(100,100),再绘制一个同样的矩形会出现什么情况呢?会与之前的矩形重叠吗?咱们拭目以待:
[html] view plain copy
-
@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);
-
}
从效果上看,两次translate 进行了叠加,绘制第二个矩形的时候画布已经偏移了(200,200);
好了,了解到这里,咱们利用canvas.translate( )一起来做个小栗子,绘制一个生活中比较常用的刻度尺;
咱们先从网上找个用于参考的刻度尺图片:
从图上看,刻度尺的元素有:外框、刻度线(不同的数值刻度线长短不一)、数字
所以我们所要做的就是对上面的元素在onDraw里分别绘制:
[html] view plain copy
-
@Override
-
protected void onDraw(Canvas canvas) {
-
super.onDraw(canvas);
-
// 绘制外框
-
drawOuter(canvas);
-
// 绘制刻度线
-
drawLines(canvas);
-
// 绘制数字
-
drawNumbers(canvas);
-
}
咱们先简单分析一下,刻度尺有个外框,外框距离左右都有一定的边距,第一根和最后一根刻度线距离边框也有一定的边距,其余刻度线之间距离相同,另外一些特殊的刻度线长短不一;
有了上面的分析,咱们一个一个来,先绘制外框,外框也就是一个矩形,只需要确定边框的位置和大小,然后使用canvas.drawRect( )绘制即可:
咱们先定义几个需要的数据,为了屏幕适配,数据均为dp:
[html] view plain copy
-
// 刻度尺高度
-
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;
然后将以上数据转为对应像素值:
[html] view plain copy
-
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为:
[html] view plain copy
-
mOutRect = new Rect(mDividRuleLeftMargin, top, mTotalWidth - mDividRuleLeftMargin,
-
mRuleBottom);
接下来看刻度线的绘制,根据厘米可以计算出中间的格数,根据厘米占用屏幕宽度和所占格数可以计算出每一格所占屏幕宽度:
[html] view plain copy
-
mLineInterval = (mTotalWidth - 2 * mDividRuleLeftMargin - 2 * mFirstLineMargin)
-
/ (DEFAULT_COUNT * 10 - 1);
有了每一格所占宽度,我们只需要在绘制刻度线的时候不断将画布右移对应宽度即可:
[html] view plain copy
-
/**
-
* 绘制刻度线
-
* @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 提供了以下两个接口:
[html] view plain copy
-
/**
-
* 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)之后看下效果;
[html] view plain copy
-
@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);
-
}
我们将画布在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)的差别:
[html] view plain copy
-
translate(px, py);
-
scale(sx, sy);
-
translate(-px, -py);
即先将画布平移px,py,然后scale,scale结束之后再将画布平移回原基准点;
我们再在之前的基础上绘制一个同样的矩形,x , y 均缩放为 0.5 倍,缩放中心为矩形的中心:
[html] view plain copy
-
@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);
-
}
一起来看下效果:
效果就相当于用个钉子钉在矩形的中心,然后进行缩放;
根据上面android 的实现,我们其实可以使用以下代码实现同样的效果:
[html] view plain copy
-
// 先将画布平移到矩形的中心
-
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()进行画布的锁定和回滚,以免除对后面绘制的影响(后面会单独讲)
先初始化画笔,注意此时画笔需要设置成空心:
[html] view plain copy
-
/**
-
* 初始化画笔
-
*/
-
private void initPaint() {
-
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-
// 将画笔设置为空心
-
mPaint.setStyle(Style.STROKE);
-
// 设置画笔颜色
-
mPaint.setColor(Color.BLACK);
-
// 设置画笔宽度
-
mPaint.setStrokeWidth(mLineWidth);
-
}
然后循环的将画布缩放的同时绘制原正方形:
[html] view plain copy
-
/**
-
* 绘制正方形
-
*
-
* @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( )类似的是,它也有两个可以使用的方法:
[html] view plain copy
-
/**
-
* 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度玩玩吧;
[html] view plain copy
-
@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);
-
}
我们的预期是屏幕上有个旋转了的骚黄色矩形,一起来看看;
擦,黄色的矩形呢?
由于基准点是原点,我们直接旋转了90 度,所以已经将矩形旋转出屏幕,当然看不到了,我们将角度调小一点,改为45 度:
[html] view plain copy
-
@Override
-
protected void onDraw(Canvas canvas) {
文末
当你打算跳槽的时候,应该把“跳槽成功后,我能学到什么东西?对我的未来发展有什么好处”放在第一位。这些东西才是真正引导你的关键。在跳槽之前尽量“物尽其用”,把手头上的工作做好,最好是完成了某个项目或是得到提升之后再走。跳槽不是目的,而是为了达到最终职业目标的手段
最后祝大家工作升职加薪,面试拿到心仪Offer
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
色的矩形呢?
由于基准点是原点,我们直接旋转了90 度,所以已经将矩形旋转出屏幕,当然看不到了,我们将角度调小一点,改为45 度:
[html] view plain copy
[外链图片转存中…(img-eZLARZeE-1715815055594)] [外链图片转存中…(img-Si36J0ap-1715815055595)]
-
@Override
-
protected void onDraw(Canvas canvas) {
文末
当你打算跳槽的时候,应该把“跳槽成功后,我能学到什么东西?对我的未来发展有什么好处”放在第一位。这些东西才是真正引导你的关键。在跳槽之前尽量“物尽其用”,把手头上的工作做好,最好是完成了某个项目或是得到提升之后再走。跳槽不是目的,而是为了达到最终职业目标的手段
最后祝大家工作升职加薪,面试拿到心仪Offer
[外链图片转存中…(img-P5FKESug-1715815055595)]
[外链图片转存中…(img-LYnBn2wK-1715815055595)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!