Android绘图基础--Canvas和Drawable

Android绘图基础--Canvas和Drawable,第1张

Github链接

画2D图形有两种方法

Canvas实际上是封装了各种draw方法的类,调用draw方法把图形绘制到底层的Surface上,即绘制在Window上。

这个例子中构造了两个Canvas和一个Bitmap,分别调用其draw方法,先是mCanvas往Bitmap里绘制一个方块,再在onDraw方法内调用canvasdrawBitmap绘制这个方块。

思考一个问题,为什么mCanvas需要设置Bitmap?

很简单,因为它没有持有一块内存地址,自然没法绘制。来看一下draw的起点ViewRootImpl(软件绘制,不开启硬件加速下)。

这个通过mSurfacelockCanvas返回的Canvas是Viewdraw的canvas变量,所以当1,2情况时,Canvas都持有一个Bitmap,指向共享内存里的某一小块,当调用Canvasdraw方法时就能绘制出东西。但对于自定义Canvas来说并不是,即使设置一个Bitmap和绘制了Bitmap,但不往共享内存上写,屏幕上是不会显示的,SurfaceView同理,通过SurfacelockCanvas获取持有共享内存的Canvas,绘制完毕后调用SurfaceunlockCanvasAndPost把绘制内容显示到surface上并release掉Canvas。

顺带一提Canvassave和Canvasrestore方法,如下Demo

效果图如

画的是三个颜色和旋转角度都不同的小方形。

步骤1把默认坐标系旋转20°,画出第一个蓝色的方形,步骤2保存当前的matrix(旋转了20°),继续旋转20°,此时坐标系已经旋转了40°,画出第二个**的方块,步骤3,恢复上一步保存的matrix(旋转了20°),此时坐标系还是旋转了20°,步骤4,再旋转40°,此时坐标系旋转了60°,画出第三个黑色方块。

Canvassave用于保存当前matrix和clip,Canvasrestore用于恢复上次保存的matrix和clip。

Drawable是一个能画出来的物体的抽象,使用前需要调用setBounds确定位置和大小,通过getIntrinsicHeight和getIntrinsicWidth取到实际大小。Drawable可以有几种形式存在:Bitmap、Nine Patch、Vector、Shape、Layers等。

从ResourcegetDrawable会判断是否xml结尾,不是的话走6,7步,如果从xml中读取,需要getResourcegetDrawable -> ResourceImplloadDrawableForCookie -> drawablecreateFromXml -> DrawableInflaterinflateFromXmlForDensity -> drawableinflateFromTag

看一下Shape实现类GradientDrawable的inflate实现,读取各项属性并赋值,到draw方法。

调用canvasdrawRect把mRect画出来,而mRect的赋值在ensureValidRect。[上传失败(image-a25af0-1515826613001)]

bounds在哪里设置的?答案是ImageViewupdateDrawable内,会调用DrawablegetIntrinsicHeight赋值(从xml中size属性读取),再调用configureBounds -> setBounds,如果使用的不是ImageView,一定要在draw之前 调用setBounds ,否则size就会出错。

回到loadDrawableForCookie,再看一下6,7步加载的过程,通过AssetManager读取流数据,通过DrawablecreateFromResourceStream这个我们经常使用的方法获取到Drawable。

取到屏幕密度之后调用BitmapFactorydecodeResourcesStream,计算密度后调用native创建Bitmap,感兴趣的同学可以看下更具体的分析文章(如 理解Bitmap )。

本文探究了两点

Android 711 源码

Android 官方文档, Canvas and Drawable , Drawable 等

<canvas> 元素负责在页面中设定一个区域,然后就可以通过 JavaScript 动态地在这个区域中绘制图形。

要使用 <canvas> 元素,必须先设置其 width 和 height 属性,指定可以绘图的区域大小。出现在开始和结束标签中的内容是后备信息,如果浏览器不支持 <canvas> 元素,就会显示这些信息。

如果不添加任何样式或者不绘制任何图形,在页面中是看不到该元素的。

要在这块画布(canvas)上绘图,需要取得绘图上下文。而取得绘图上下文对象的引用,需要调用getContext() 方法并传入上下文的名字。传入 "2d" ,就可以取得 2D 上下文对象。

使用 toDataURL() 方法,可以导出在 <canvas> 元素上绘制的图像。这个方法接受一个参数,即图像的 MIME 类型格式,而且适合用于创建图像的任何上下文。

取得画布中的一幅 PNG 格式的图像:

如果绘制到画布上的图像源自不同的域, toDataURL() 方法会抛出错误。

使用 2D 绘图上下文提供的方法,可以绘制简单的 2D 图形,比如矩形、弧线和路径。2D 上下文的坐标开始于 <canvas> 元素的左上角,原点坐标是(0,0)。

2D 上下文的两种基本绘图 *** 作是填充和描边。填充,就是用指定的样式(颜色、渐变或图像)填充图形;描边,就是只在图形的边缘画线。大多数 2D 上下文 *** 作都会细分为填充和描边两个 *** 作,而 *** 作的结果取决于两个属性: fillStyle 和 strokeStyle 。

这两个属性的值可以是字符串、渐变对象或模式对象,而且它们的默认值都是 "#000000" 。如果为它们指定表示颜色的字符串值,可以使用 CSS 中指定颜色值的任何格式,包括颜色名、十六进制码、rgb 、 rgba 、 hsl 或 hsla 。

与矩形有关的方法包括 fillRect() 、strokeRect() 和 clearRect() 。这三个方法都能接收 4 个参数:矩形的 x 坐标、矩形的 y 坐标、矩形宽度和矩形高度。这些参数的单位都是像素。

fillRect() 方法在画布上绘制的矩形会填充指定的颜色。填充的颜色通过 fillStyle 属性指定:

strokeRect() 方法在画布上绘制的矩形会使用指定的颜色描边。描边颜色通过 strokeStyle 属性指定。

描边线条的宽度由 lineWidth 属性控制,该属性的值可以是任意整数。另外,通过 lineCap 属性可以控制线条末端的形状是平头、圆头还是方头( "butt" 、"round" 或 "square" ),通过 lineJoin 属性可以控制线条相交的方式是圆交、斜交还是斜接( "round" 、 "bevel" 或 "miter" )。

clearRect() 方法用于清除画布上的矩形区域。本质上,这个方法可以把绘制上下文中的某一矩形区域变透明。

通过路径可以创造出复杂的形状和线条。要绘制路径,首先必须调用 beginPath() 方法,表示要开始绘制新路径。然后,再通过调用下列方法来实际地绘制路径。

如果想绘制一条连接到路径起点的线条,可以调用closePath() 。如果路径已经完成,你想用 fillStyle 填充它,可以调用 fill() 方法。另外,还可以调用 stroke() 方法对路径描边,描边使用的是 strokeStyle 。最后还可以调用 clip() ,这个方法可以在路径上创建一个剪切区域。

绘制一个不带数字的时钟表盘:

isPointInPath() 方法接收 x 和 y 坐标作为参数,用于在路径被关闭之前确定画布上的某一点是否位于路径上。

绘制文本主要有两个方法: fillText() 和 strokeText() 。这两个方法都可以接收 4 个参数:要绘制的文本字符串、x 坐标、y 坐标和可选的最大像素宽度。

两个方法都以下列 3 个属性为基础:

fillText() 方法使用fillStyle 属性绘制文本, strokeText() 方法使用 strokeStyle 属性为文本描边。

通过上下文的变换,可以把处理后的图像绘制到画布上。2D 绘制上下文支持各种基本的绘制变换。创建绘制上下文时,会以默认值初始化变换矩阵,在默认的变换矩阵下,所有处理都按描述直接绘制。为绘制上下文应用变换,会导致使用不同的变换矩阵应用处理,从而产生不同的结果。

把原点变换到表盘的中心:

使用 rotate() 方法旋转时钟的表针:

可以调用 save() 方法,调用这个方法后,当时的所有设置都会进入一个栈结构,得以妥善保管。调用 restore() 方法,在保存设置的栈结构中向前返回一级,恢复之前的状态。

save() 方法保存的只是对绘图上下文的设置和变换,不会保存绘图上下文的内容。

可以使用 drawImage()方法把一幅图像绘制到画布上。

以使用三种不同的参数组合。最简单的调用方式是传入一个 HTML <img> 元素,以及绘制该图像的起点的 x 和 y 坐标。

如果想改变绘制后图像的大小,可以再多传入两个参数,分别表示目标

宽度和目标高度。通过这种方式来缩放图像并不影响上下文的变换矩阵。

绘制出来的图像大小会变成 20×30 像素。

可以选择把图像中的某个区域绘制到上下文中。 drawImage() 方法的这种调用方式总共需要传入 9 个参数:要绘制的图像、源图像的 x 坐标、源图像的 y 坐标、源图像的宽度、源图像的高度、目标图像的 x 坐标、目标图像的 y 坐标、目标图像的宽度、目标图像的高度。这样调用drawImage() 方法可以获得最多的控制。

2D 上下文会根据以下几个属性的值,自动为形状或路径绘制出阴影。

要创建一个新的线性渐变,可以调用 createLinearGradient() 方法。这个方法接收 4 个参数:起点的 x 坐标、起点的 y 坐标、终点的 x 坐标、终点的 y 坐标。调用这个方法后,它就会创建一个指定大小的渐变,并返回

CanvasGradient 对象的实例。

创建了渐变对象后,下一步就是使用 addColorStop() 方法来指定色标。这个方法接收两个参数:色标位置和 CSS 颜色值。色标位置是一个 0(开始的颜色)到 1(结束的颜色)之间的数字。

为了让渐变覆盖整个矩形,而不是仅应用到矩形的一部分,矩形和渐变对

象的坐标必须匹配才行。

要创建径向渐变(或放射渐变),可以使用 createRadialGradient() 方法。这个方法接收 6 个参数,对应着两个圆的圆心和半径。前三个参数指定的是起点圆的原心(x 和 y)及半径,后三个参数指定的是终点圆的原心(x 和 y)及半径。

模式其实就是重复的图像,可以用来填充或描边图形。要创建一个新模式,可以调用createPattern() 方法并传入两个参数:一个 HTML <img> 元素和一个表示如何重复图像的字符串。其中,第二个参数的值与 CSS 的 background-repeat 属性值相同,包括 "repeat" 、 "repeat-x" 、"repeat-y" 和 "no-repeat" 。

createPattern() 方法的第一个参数也可以是一个 <video> 元素,或者另一个 <canvas> 元素。

2D 上下文的一个明显的长处就是,可以通过 getImageData() 取得原始图像数据。这个方法接收4 个参数:要取得其数据的画面区域的 x 和 y 坐标以及该区域的像素宽度和高度。

取得左上角坐标为(10,5)、大小为 50×50 像素的区域的图像数据:

返回的对象是 ImageData 的实例。每个 ImageData 对象都有三个属性: width 、 height 和data 。其中 data 属性是一个数组,保存着图像中每一个像素的数据。

在 data 数组中,每一个像素用4 个元素来保存,分别表示红、绿、蓝和透明度值。

数组中每个元素的值都介于 0 到 255 之间(包括 0 和 255)。

还有两个会应用到 2D 上下文中所有绘制 *** 作的属性: globalAlpha 和 globalCompositionOperation 。其中, globalAlpha 是一个介于 0 和 1 之间的值(包括 0和 1),用于指定所有绘制的透明度。默认值为 0。如果所有后续 *** 作都要基于相同的透明度,就可以先把 globalAlpha 设置为适当

值,然后绘制,最后再把它设置回默认值 0。

第二个属性 globalCompositionOperation 表示后绘制的图形怎样与先绘制的图形结合。

WebGL 是针对 Canvas 的 3D 上下文。

WebGL是从 OpenGL ES 20 移植到浏览器中的,而 OpenGL ES 20 是游戏开发人员在创建计算机图形图像时经常使用的一种语言。WebGL 支持比 2D 上下文更丰富和更强大的图形图像处理能力。

WebGL 涉及的复杂计算需要提前知道数值的精度,而标准的 JavaScript 数值无法满足需要。为此,WebGL 引入了一个概念,叫类型化数组(typed arrays)。类型化数组也是数组,只不过其元素被设置为特定类型的值。

类型化数组的核心就是一个名为 ArrayBuffer 的类型。每个 ArrayBuffer 对象表示的只是内存中指定的字节数,但不会指定这些字节用于保存什么类型的数据。通过 ArrayBuffer 所能做的,就是为了将来使用而分配一定数量的字节。

创建了 ArrayBuffer 对象后,能够通过该对象获得的信息只有它包含的字节数,方法是访问其byteLength 属性:

使用 ArrayBuffer (数组缓冲器类型)的一种特别的方式就是用它来创建数组缓冲器视图。其中,最常见的视图是 DataView ,通过它可以选择 ArrayBuffer 中一小段字节。为此,可以在创建 DataView实例的时候传入一个 ArrayBuffer 、一个可选的字节偏移量(从该字节开始选择)和一个可选的要选择的字节数。

实例化之后, DataView 对象会把字节偏移量以及字节长度信息分别保存在 byteOffset 和byteLength 属性中。

类型化视图一般也被称为类型化数组,因为它们除了元素必须是某种特定的数据类型外,与常规的数组无异。

类型化数组是 WebGL 项目中执行各种 *** 作的重要基础。

目前,主流浏览器的较新版本大都已经支持 <canvas> 标签。同样地,这些版本的浏览器基本上也都支持 2D 上下文。但对于 WebGL 而言,目前还只有 Firefox 4+和 Chrome 支持它。

这还不简单吗?直接加个动画就行了!

现在我做下补充:

package comqiulongtextscrolldemo;

import androidcontentContext;

import androidgraphicsCanvas;

import androidgraphicsColor;

import androidgraphicsPaint;

import androidutilAttributeSet;

import androidviewView;

public class CustomScrollText extends View {

//背景画笔

private Paint backPaint;

//背景颜色

private int backColor = ColorGRAY;

//文本画笔

private Paint textPaint;

//字体颜色

private int textColor = ColorBLACK;

//字体大小

private int textSize = 20;

//文字内容

private String textContent = "textView";

//X轴偏移量

private float OffsetX = 0;

//刷新线程

private RefreshRunnable mRefreshRunnable;

public CustomScrollText(Context context) {

super(context);

init();

}

public CustomScrollText(Context context, AttributeSet attrs) {

super(context, attrs);

init();

}

public CustomScrollText(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

init();

}

/

  初始化画笔

 /

private void init(){

backPaint = new Paint();

backPaintsetAntiAlias(true);

backPaintsetColor(backColor);

backPaintsetStyle(PaintStyleFILL);

textPaint = new Paint();

     textPaintsetAntiAlias(true);

     textPaintsetColor(textColor);

     textPaintsetStyle(PaintStyleFILL);

     textPaintsetTextSize(textSize);

}

    @Override

    protected void onAttachedToWindow() {

        superonAttachedToWindow();

        //启动刷新

        mRefreshRunnable = new RefreshRunnable();

        post(mRefreshRunnable);

    }

    @Override

    protected void onDetachedFromWindow() {

        superonDetachedFromWindow();

        //关闭刷新

        removeCallbacks(mRefreshRunnable);

    }

@Override

protected void onDraw(Canvas canvas) {

superonDraw(canvas);

//绘制背景

canvasdrawRect(0, 0, getWidth(), textSize+10, backPaint);// 长方形

       //绘制文本内容

       canvasdrawText(textContent, OffsetX, textSize, textPaint);

}

/

  测量控件宽高 

 /

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

int width = measure(widthMeasureSpec);

int height = measure(heightMeasureSpec);

setMeasuredDimension(width, height);

}

private int measure(int measureSpec) {

int specMode = MeasureSpecgetMode(measureSpec);

int specSize = MeasureSpecgetSize(measureSpec);

int result = 70;

if (specMode == MeasureSpecAT_MOST) {//最大可获空间

result = specSize;

} else if (specMode == MeasureSpecEXACTLY) {//精确尺寸

result = specSize;

}

return result;

}

/

  刷新线程

  @author qiulong

 

 /

    private class RefreshRunnable implements Runnable {

        public void run() {

            synchronized (CustomScrollTextthis) {

             OffsetX--;

             //获取字体宽度

             float txtWidth = textPaintmeasureText(textContent, 0, textContentlength());

             if((0 - OffsetX) >= txtWidth){

             OffsetX = getWidth();

             }

                invalidate();

                postDelayed(this, 5);

            }

        }

    }

    

/

  设置文本内容

  @param value

 /

public void setTextContent(String value){

thistextContent = value;

}

/

  获取文本内容

  @return

 /

public String getTextContent(){

return textContent;

}

/

  设置文本颜色

  @param color

 /

public void setTextColor(int color){

thistextColor = color;

textPaintsetColor(textColor);

}

/

  获取文本颜色

  @return

 /

public int getTextColor(){

return textColor;

}

/

  设置文本大小

  @param size

 /

public void setTextSize(int size){

thistextSize = size;

     textPaintsetTextSize(textSize);

}

/

  获取文本大小

  @return

 /

public int getTextSize(){

return textSize;

}

/

  设置背景颜色

 /

public void setBackgroundColor(int color){

thisbackColor = color;

backPaintsetColor(backColor);

}

/

  获取背景颜色

  @return

 /

public int getBackgroundColor(){

return backColor;

}

}

下面是MainActivityclass :

package comqiulongtextscrolldemo;

import androidosBundle;

import androidappActivity;

import androidgraphicsColor;

public class MainActivity extends Activity {

private CustomScrollText mtext;

@Override

protected void onCreate(Bundle savedInstanceState) {

superonCreate(savedInstanceState);

setContentView(Rlayoutactivity_main);

mtext = (CustomScrollText)findViewById(Ridmtext);

mtextsetTextContent("你加个我看看,说谁都会说,你怎么不干脆说让他直接滚动起来就好了,回答问题也要有点诚意好不");

mtextsetTextSize(30);

mtextsetTextColor(ColorBLUE);

mtextsetBackgroundColor(ColorGREEN);

}

}

然后至于你说的速度控制方面,也很简单!你可以尝试修改下,我就不一五一十的全帮你写了!另外还有一个你说的信息间距我没搞懂是什么意思!

canvas,是一个H5的新标签,通过js来实现绘图的神奇功能。

<canvas> 标签只是图形容器,您必须使用脚本来绘制图形。

那么我们怎么来使用canvas标签呢?

注意,在这里我直接在行间设置了宽高,是因为若不设定宽高,浏览器会默认设置canvas大小为宽300、高100像素,而且不能使用css来设置(会被拉伸),建议直接写于canvas标签内部,或者是直接用js脚本中来设置。如下:

首先,获取canvas的绘图环境,这是一个封装了很多绘图功能的对象。

来举个栗子

我们使用了几个绘图方法:

1moveTo(x坐标 , y坐标) 可以理解为定位画笔在画布上的位置

2lineTo(x坐标 , y坐标) 顾名思义,就是画一条直线到某个点,此方法只做路径运动,并没有视觉上的效果。

3stroke() 描边方法 让运动路径从视觉上显现 用 画笔描出来

4strokeStyle 设定颜色的方法 可以直接用颜色名称,例如"red" "green",或者用十六进制颜色"#fff",还有rgb(0-255,0-255,0-255), rgba(0-255,0-255,0-255,透明度)。

栗子2 用canvas写出两个不一样颜色的线 :

关于路径beginPath和closePath

1、系统默认在绘制第一个路径的开始点为beginPath

2、如果画完前面的路径没有重新指定beginPath,那么画第其他路径的时候会将前面最近指定的beginPath后的全部路径重新绘制

ps:记住每次画路径都在前后加gd beginPath() 和gd closePath()

当然canvas也可以绘制出各种图形

栗子3 绘制矩形

绘制矩形有两个小方法:

1 contextfillRect(x,y,width,height) 所谓的满矩形就是填充一个矩形

2 strokeRect(x,y,width,height) 绘制矩形(不填色)。笔触的默认颜色是黑色。

相反 清除矩形区域即为

canvas更多有趣的东西,我们下次再讲~~~

重要view大小(属性值决定最终上屏时的缩放比例) 画布bufffer大小 glviewPort视口大小(映射画布坐标到NDC坐标 -1到1 GL世界的坐标)

所有view单位 和 buffer单位不一致的,都要 渲染引擎提供处理的。

renderer = new THREEWebGLRenderer({ antialias: true });

renderersetPixelRatio(windowdevicePixelRatio);

renderersetSize(screenCanvasclientWidth, screenCanvasclientHeight);

json文件内为view单位,创建buffer用的物理像素,绘制通过render 给定dstR 做映射,实现了view单位到物理像素单位的映射。

void Animation::render(SkCanvas canvas, const SkRect dstR) {

const SkRect srcR = SkRect::MakeSize(this->size());

if (dstR) {

canvas->concat(SkMatrix::MakeRectToRect(srcR, dstR, SkMatrix::kCenter_ScaleToFit));

}

}

要自己手动调整和映射。canvasscale

如何解决画布模糊问题 >

canvaswidth获取的是写在标签属性中的宽度值,eg :<canvas width="800" height="600"></canvas>

这时我们获取的canvas的宽度值是800px;但是如果canvas标签没有设置宽高属性,而是写在css样式表,或者style标签中,canvaswidth获取的是canvas的默认宽(canvas默认宽是300px,默认高是150px)

简短的说就像text框要输入文字一样,你必须先让text取得焦点,获得光标才能进行输入

bitmap就像画布,canvas就像画笔。要画画就要知道画在哪里,所以必须要画布。

view的onDraw的canvas是花在view的背景上,也是类似bitmap上。

缓冲是在另一个后台bitmap上画好在进行展示

以上代表个人通俗理解只做参考理解,不是标准

在上一篇 《Python reportlab库之hello world》 中我们演示了简单Demo,在Demo中使用Canvas对象。

本篇文章将简单介绍一下Canvas对象,首先我先来看看Canvas的构造函数

filename 参数控制最终PDF文件的名称

pagesize 参数有width和height两个参数,canvas默认的大小是A4纸(美国标志信件采用的就是A4),具体demo如下

运行效果

bottomup 参数用于切换坐标系。一些系统把(0,0)坐标设置在底部左侧。 bottomup 未来可能会被移除。

pageCompression 选择是否压缩每个页面。默认的页面是不被压缩的,因为压缩会影响文件处理速度。如果 pageCompression =1,那么文件将被压缩到最小,但生成时间也会被延长。注意,总是会被压缩。如果您有大量的文章和矢量图像会造成文件过大,使用 pageCompression 参数将有效减少文件体积。

encoding 参数在20版本上已经省略了,大家基本上可以忽略这个参数。

verbosity 参数参数确定打印多少日志信息。默认情况下, verbosity 为0。如果值为1,您将得到生成文档是的日志信息。数值越高可能会在未来产生更多的日志输出。

encrypt 参数决定文档是否加密。默认情况下,文档是不加密的。

以上就是关于Android绘图基础--Canvas和Drawable全部的内容,包括:Android绘图基础--Canvas和Drawable、JS之使用Canvas绘图、android文字横向滚动的自定义view等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/9728500.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-01
下一篇 2023-05-01

发表评论

登录后才能评论

评论列表(0条)

保存