TextureView的介绍
SurfaceView的工作方式是创建一个置于应用窗口之后的新窗口。这种方式的效率非常高,因为SurfaceView窗口刷新的时候不需要重绘应用程序的窗口(android普通窗口的视图绘制机制是一层一层的,任何一个子元素或者是局部的刷新都会导致整个视图结构全部重绘一次,因此效率非常低下,不过满足普通应用界面的需求还是绰绰有余),但是SurfaceView也有一些非常不便的限制。
但是SurfaceView也存在自己的缺陷,因为SurfaceView的内容不在应用窗口上,所以不能使用变换(平移、缩放、旋转等),也难以放在ListView或者ScrollView中,不能使用UI控件的一些特性比如View.setAlpha()。而TextureView的出现就是为了解决这方面的问题。
TestureView并没有创建单独的Surface用来绘制,这样使得可以和应用窗口一样做各种操作,需要注意的是,Textureview必须在硬件加速开启的窗口中。
原理分析
不开辟新的Surface,怎么就能做到和SurfaceView一样的事情呢?
核心类:
- TextureView
- SurfaceTexture
- SurfaceTextureListener
TextureView
public final void draw(Canvas canvas) {
// NOTE: Maintain this carefully (see View#draw)
mPrivateFlags = (mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
/* Simplify drawing to guarantee the layer is the only thing drawn - so e.g. no background,
scrolling, or fading edges. This guarantees all drawing is in the layer, so drawing
properties (alpha, layer paint) affect all of the content of a TextureView. */
if (canvas.isHardwareAccelerated()) {
DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas;
HardwareLayer layer = getHardwareLayer();
if (layer != null) {
applyUpdate();
applyTransformMatrix();
mLayer.setLayerPaint(mLayerPaint); // ensure layer paint is up to date
displayListCanvas.drawHardwareLayer(layer);
}
}
}
可以看出,TextureView是在硬件层进行绘制的。
SurfaceTexture可以理解成是Surface和GLES纹理的组合。这块具体看下面后篇文件的介绍。
使用示例
通过TextureView来完成sin曲线的绘制,包括了做setAlpha()和setRotation()操作。
package com.google.android.cameraview.demo;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.SurfaceTexture;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.view.SurfaceHolder;
import android.view.TextureView;
/**
* Created by panda on 2018/8/1
**/
@RequiresApi(api = Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public class Test2 extends AppCompatActivity implements TextureView.SurfaceTextureListener, Runnable {
private TextureView myTexture;
//用于绘图的canvas
private Canvas mCanvas;
//子线程标志位
private boolean mIsDrawing;
int x = 0;
int y = 400;
private Path mPath = new Path();
private Paint mPaint = new Paint();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test2);
myTexture = (TextureView) findViewById(R.id.one);
myTexture.setSurfaceTextureListener(this);
mPath.moveTo(x, y);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(10);
}
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
mIsDrawing = true;
new Thread(this).start();
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
float alpha = 1.0f;
@Override
public void run() {
while (mIsDrawing) {
try {
mCanvas = myTexture.lockCanvas();
mCanvas.drawColor(Color.WHITE);
x += 1;
y = (int) (100 * Math.sin(x * 2 * Math.PI / 180) + 400);
mPath.lineTo(x, y);
mCanvas.drawPath(mPath, mPaint);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != mCanvas) {
myTexture.unlockCanvasAndPost(mCanvas);
}
}
myTexture.setRotation(x);
if (alpha == 1.0f) {
alpha = 0.5f;
myTexture.setAlpha(alpha);
} else {
alpha = 1.0f;
myTexture.setAlpha(alpha);
}
}
}
}