美文网首页
Android自定义控件探索之旅一5(笔记)

Android自定义控件探索之旅一5(笔记)

作者: 骑小猪看流星 | 来源:发表于2018-11-30 00:13 被阅读61次

    本篇文章是Android自定义控件探索之旅一4的续篇,主要学习的是Canvas绘制图片的第二种实现方式。

    绘制图片之Canvas.drawBitmap(Bitmap bitmap,......)

    既然关于Canvas绘制方式的第二种实现方式涉及到了Bitmap,那么关于Bitmap,我个人想说的是:很不喜欢一些开发者将Bitmap的概念直接等同于图片,这种概念完全就是混淆视听、让人误解。关于Bitmap很权威的解释如下:Bitmap:也称 位图,又称栅格图(英语:Raster graphics)或点阵图,它是使用像素阵列(Pixel-array/Dot-matrix点阵)来表示的图像。实际上一张图片是由很多个像素点组建而成的。简而言之,Bitmap可以简单理解为一个画架,开发者可以在具体的应用场景,把图片放到Bitmap上接着对图片做一些处理。值得一提的是Bitmap文件的图像显示效果很好,但是非压缩格式,因此会需要占用较大的存储空间,所以在使用Bitmap时,经常会遇到内存溢出等情况,这是因为图片太大或者android系统对单个应用施加的内存限制等原因造成的。

    简单说完了Bitmap的基本概念,下面介绍一下Bitmap是如何使用的。

    关于Bitmap官方介绍Creates Bitmap objects from various sources, including files, streams, and byte-arrays 这句话翻译过来可以说是非常的简单明了。另外,Bitmap的加载和使用离不开BitmapFactory,BitmapFactory这个类提供了四种方法用来加载和获取Bitmap:

    • 方法一:decodeFile 从文件系统加载
      a.通过Intent打开本地图片或照片
      b.在onActivityResult中获取图片uri
      c.根据uri获取图片的路径
      d.根据路径解析bitmap: Bitmap bm = BitmapFactory.decodeFile(sd_path)

    • 方法二:decodeResource 以R.drawable.xxx的形式从本地资源中加载
      Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.aaa);

    • 方法三:decodeStream 从输入流加载
      a.开启异步线程去获取网络图片
      b.网络返回InputStream
      c.解析:Bitmap bm = BitmapFactory.decodeStream(stream),这是一个耗时操作,要在子线程中执行

    • 方法四:decodeByteArray 从字节数组中加载
      a.开启异步线程去获取网络图片
      b.网络返回InputStream
      c.把InputStream转换成byte[]
      d.解析:Bitmap bm = BitmapFactory.decodeByteArray(myByte,0,myByte.length);
      注意:decodeFile和decodeResource间接调用decodeStream方法。

    在使用Bitmap时,经常会遇到内存溢出等情况,内存溢出的原因可能是因为图片太大或者Android系统对单个应用施加的内存限制等原因造成的,所以,高效的使用Bitmap就显得尤为重要,因此Bitmap的效率优化重要性就不言而喻。至于Bitmap内存优化的内容这里就不提及了。那么关于Bitmap的概念就简单介绍到这里。

    通常来说,绘制Bitmap都是读取已有的图片,然后将其转换为Bitmap紧接着绘制到Canvas上。那么,Canvas绘制Bitmap的API有以下几种:

    // 第一种
    public void drawBitmap (Bitmap bitmap, Matrix matrix, Paint paint)
    
    // 第二种
    public void drawBitmap (Bitmap bitmap, float left, float top, Paint paint)
    
    // 第三种
    public void drawBitmap (Bitmap bitmap, Rect src, Rect dst, Paint paint)
    public void drawBitmap (Bitmap bitmap, Rect src, RectF dst, Paint paint)
    
    

    而且点开Canvas的源码,里面的 drawBitmap()方法,实际上全部是调用父类的BaseCanvas里面的drawBitmap()方法:

       /**
         * Draw the specified bitmap, with its top/left corner at (x,y), using the specified paint,
         * transformed by the current matrix.
         * <p>
         * Note: if the paint contains a maskfilter that generates a mask which extends beyond the
         * bitmap's original width/height (e.g. BlurMaskFilter), then the bitmap will be drawn as if it
         * were in a Shader with CLAMP mode. Thus the color outside of the original width/height will be
         * the edge color replicated.
         * <p>
         * If the bitmap and canvas have different densities, this function will take care of
         * automatically scaling the bitmap to draw at the same density as the canvas.
         *
         * @param bitmap The bitmap to be drawn
         * @param left The position of the left side of the bitmap being drawn
         * @param top The position of the top side of the bitmap being drawn
         * @param paint The paint used to draw the bitmap (may be null)
         */
        public void drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint) {
            super.drawBitmap(bitmap, left, top, paint);
        }
    
    

    针对Canvas绘制Bitmap的三种方法,下面做详细的叙述:

    • 第一种方法中后两个参数(matrix, paint),是在绘制的时候对图片进行一些改变。因此,如果只是需要将图片内容绘制出来只需要如下操作就可以了:
     mCanvas.drawBitmap(bitmap,new Matrix(),new Paint());
    

    注意:图片左上角位置默认为坐标原点。

    • 第二种方法是在绘制时,指定了图片左上角的坐标(距离坐标原点的距离),系统源码如下:
       /**
         * Draw the specified bitmap, with its top/left corner at (x,y), using the specified paint,
         * transformed by the current matrix.
         * <p>
         * Note: if the paint contains a maskfilter that generates a mask which extends beyond the
         * bitmap's original width/height (e.g. BlurMaskFilter), then the bitmap will be drawn as if it
         * were in a Shader with CLAMP mode. Thus the color outside of the original width/height will be
         * the edge color replicated.
         * <p>
         * If the bitmap and canvas have different densities, this function will take care of
         * automatically scaling the bitmap to draw at the same density as the canvas.
         *
         * @param bitmap The bitmap to be drawn
         * @param left The position of the left side of the bitmap being drawn
         * @param top The position of the top side of the bitmap being drawn
         * @param paint The paint used to draw the bitmap (may be null)
         */
        public void drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint) {
            super.drawBitmap(bitmap, left, top, paint);
        }
    
    
    • 第三种方法较之前的方法多了新参数,分别是 Rect和RectF,这两个参数是用来做什么的?
    名称 作用
    Rect 指定 绘制 图片的区域
    Rect dst 或RectF dst 指定图片在屏幕上 显示 的区域

    举个例子,帧动画是Android中的一种动画,所谓的 ,就是影像动画中最小单位的单幅影像画面,相当于电影胶片上的每一格镜头。 一帧就是一副静止的画面,连续的帧就形成动画,如电视图象等。简单点说就是类似幻灯片播放的那种效果,因此帧动画的本质就是将一张张的图片,通过代码对这些图片进行连续的活动(这样就形成了动画)。好了,现在也可以使用drawBitmap搭配Rect和RectF,首先指定 绘制 图片的区域,接着按照开发需求,指定图片在屏幕上 显示 的区域,这样做的好处是把同一个动画效果的所有资源图片整理到一张图片上,会大大的减少资源文件数量,方便管理。因此针对帧动画这种实现方式又提供了一种新的解决思路。

    关于Canvas绘制图片的第二种实现方式,Canvas.drawBitmap(...)大概内容就介绍到这里,下一篇文章主要介绍的Canvas如何绘制文字

    如果这篇文章对您有开发or学习上的些许帮助,希望各位看官留下宝贵的star,谢谢。

    Ps:著作权归作者所有,转载请注明作者, 商业转载请联系作者获得授权,非商业转载请注明出处(开头或结尾请添加转载出处,添加原文url地址),文章请勿滥用,也希望大家尊重笔者的劳动成果,谢谢。

    相关文章

      网友评论

          本文标题:Android自定义控件探索之旅一5(笔记)

          本文链接:https://www.haomeiwen.com/subject/glvbqqtx.html