音视频开发指南:图片的绘制

栏目: Android · 发布时间: 5年前

内容简介:在 Android 音视频开发学习思路 里面,我们写到了,想要逐步入门音视频开发,就需要一步步的去学习整理,并积累。本文是音视频开发指南的第一篇。 对应的要学习的内容是:在 Android 平台绘制一张图片,使用3 种不同的 API,ImageView、SurfaceView、自定义 View。这个想必做过Android开发的都知道如何去绘制了:很轻松,在界面上清晰的看到养眼的美女:

在 Android 音视频开发学习思路 里面,我们写到了,想要逐步入门音视频开发,就需要一步步的去学习整理,并积累。本文是音视频开发指南的第一篇。 对应的要学习的内容是:在 Android 平台绘制一张图片,使用3 种不同的 API,ImageView、SurfaceView、自定义 View。

ImageView 绘制图片

这个想必做过Android开发的都知道如何去绘制了:

//  ImageView 加载几种来源 
//(1) drawable/mipmap 中通过 R.drawabe.xxx 加载图片资源
//(2) assests或者sdcard的路径的资源
// 这里我以 assests 代表来加载资源
ImageView customImageView = findViewById(R.id.img_middle);
customImageView.setImageBitmap(Util.getImageFromAssetsFile(this, "prettygirl.png"));
// Util.getImageFromAssetsFile(this, "prettygirl.png")
public static Bitmap getImageFromAssetsFile(Context context, String fileName) {
    Bitmap image = null;
    AssetManager am = context.getResources().getAssets();
    try {
        InputStream is = am.open(fileName);
        image = BitmapFactory.decodeStream(is);
        is.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return image;
}
复制代码

很轻松,在界面上清晰的看到养眼的美女:

音视频开发指南:图片的绘制

自定义 View 绘制图片

有些时候我们需要加载图片需要自定义View来加载图片,通过上边加载图片的方式加上我自己自定义View 经验,我们很快能写出下边通过自定义View的代码来加载图片。

/**
 * 自定义View 显示图片
 */
public class CustomImageView extends View {
    private Bitmap mBitmap;
    private Paint mPaint = new Paint();

    ···

    private void init() {
        initPaint();
    }

    private void initPaint() {
        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
        //设置抗锯齿
        mPaint.setAntiAlias(true);
    }

    public void setBitmap(Bitmap bitmap) {
        mBitmap = bitmap;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mBitmap == null) {
            return;
        }
        canvas.drawBitmap(mBitmap, 0, 0, mPaint);
    }
}
复制代码

SurfaceView 绘制图片

这个比 ImageView 绘制图片稍微复杂一点点,接下来呢,说说自己对它的理解

定义

SurfaceView是View的一个特殊子类,它的目的是 另外提供一个线程 进行绘制操作。

它的特性是:可以在主线程之外的线程中向屏幕绘图上。这样可以避免画图任务繁重的时候造成主线程阻塞,从而提高了程序的反应速度。

实现

首先继承SurfaceView并实现SurfaceHolder.Callback接口,使用接口的原因:因为使用SurfaceView 有一个原则,所有的绘图工作必须得在Surface 被创建之后才能开始(Surface—表面,这个概念在 图形编程中常常被提到。基本上我们可以把它当作显存的一个映射,写入到Surface 的内容。

可以被直接复制到显存从而显示出来,这使得显示速度会非常快),而在Surface 被销毁之前必须结束。所以Callback 中的surfaceCreated 和surfaceDestroyed 就成了绘图处理代码的边界。

需要重写的方法如下:

//在surface的大小发生改变时激发、
public void surfaceChanged(SurfaceHolder holder,int format,int width,int height){}
//在创建时激发,一般在这里调用画图的线程。
public void surfaceCreated(SurfaceHolder holder){}
//销毁时激发,一般在这里将画图的线程停止、释放。
public void surfaceDestroyed(SurfaceHolder holder) {}
复制代码

使用SurfaceView大概流程:

  1. 继承SurfaceView并实现SurfaceHolder.Callback接口
  2. SurfaceView.getHolder()获得SurfaceHolder对象
  3. SurfaceHolder.addCallback(callback)添加回调函数
  4. SurfaceHolder.lockCanvas()获得Canvas对象并锁定画布
  5. Canvas绘画
  6. SurfaceHolder.unlockCanvasAndPost(Canvas canvas)结束锁定画图,并提交改变,将图形显示。

这里用到了一个类SurfaceHolder,可以把它当成surface的控制器,就好比我们常用的MVC 设计模式,用来操纵Surface。处理它的Canvas上画的效果和动画,控制表面、大小、像素等。下面我说几个需要注意的方法:

// 给SurfaceView当前的持有者一个回调对象。
abstract void addCallback(SurfaceHolder.Callback callback);
// 锁定画布,一般在锁定后就可以通过其返回的画布对象Canvas,在其上面画图等操作了。
abstract Canvas lockCanvas();
// 锁定画布的某个区域进行画图等..因为画完图后,会调用下面的unlockCanvasAndPost来改变显示内容。
// 相对部分内存要求比较高的游戏来说,可以不用重画dirty外的其它区域的像素,可以提高速度。
abstract Canvas lockCanvas(Rect dirty);
// 结束锁定画图,并提交改变。
abstract void unlockCanvasAndPost(Canvas canvas);
复制代码

注意:每次利用SurfaceHolder获得画布时,前一次的内容将会保留。

我这里贴一下重要部分的代码:

/**
 * 自定义SurfaceView 绘制图片
 */
public class CustomSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable {

   ····

    private void init() {
        mHolder = getHolder();
        mHolder.addCallback(this);
        mPaint = new Paint();
        //获取焦点
        setFocusable(true);
        setFocusableInTouchMode(true);
        //设置常量
        setKeepScreenOn(true);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        isRunning = true;
        mThread = new Thread(this);
        mThread.start();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        isRunning = false;
    }

    @Override
    public void run() {
        //循环绘制
        while (isRunning) {
            draw();
        }
    }

    private void draw() {
        try {
            mCanvas = mHolder.lockCanvas();
            if (mCanvas != null) {
                mCanvas.drawBitmap(Util.getImageFromAssetsFile(mContext, PICTURE_NAME), 0, 0, mPaint);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (mCanvas != null) {
                //释放canvas
                mHolder.unlockCanvasAndPost(mCanvas);
            }
        }

    }
}
复制代码

源码地址(image包名下):https://github.com/StudyLifeTime/basicvideotutorial

总结

最后总结一下学习这三种加载方式,自定义View 和 ImageView 加载方式大同小异,就是自定义View注意画笔的抗锯齿操作,然后绘制图片如果很浪费资源的情况下推荐使用 SurfaceView ,毕竟是在工作线程里绘制不会影响到主线程的阻塞问题。

编程·思维·职场

音视频开发指南:图片的绘制


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

算法心得:高效算法的奥秘(原书第2版)

算法心得:高效算法的奥秘(原书第2版)

(美)Henry S. Warren, Jr. / 爱飞翔 / 机械工业出版社 / 2014-3 / 89.00

【编辑推荐】 由在IBM工作50余年的资深计算机专家撰写,Amazon全五星评价,算法领域最有影响力的著作之一 Google公司首席架构师、Jolt大奖得主Hoshua Bloch和Emacs合作创始人、C语言畅销书作者Guy Steele倾情推荐 算法的艺术和数学的智慧在本书中得到了完美体现,书中总结了大量高效、优雅和奇妙的算法,并从数学角度剖析了其背后的原理 【读者评价......一起来看看 《算法心得:高效算法的奥秘(原书第2版)》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

MD5 加密
MD5 加密

MD5 加密工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具