當前位置:首頁 » 安卓系統 » android的surfaceview

android的surfaceview

發布時間: 2023-07-25 03:31:25

㈠ 如何獲得Surfaceview android的普通相機的看法

SurfaceView是View的子類,它內嵌了一個專門用於繪制的Surface,你可以控制這個Surface的格式和尺寸,Surfaceview控制這個Surface的繪制位置。surface是縱深排序(Z-ordered)的,說明它總在自己所在窗口的後面。SurfaceView提供了一個可見區域,只有在這個可見區域內的surface內容才可見。surface的排版顯示受到視圖層級關系的影響,它的兄弟視圖結點會在頂端顯示。這意味者 surface的內容會被它的兄弟視圖遮擋,這一特性可以用來放置遮蓋物(overlays)(例如,文本和按鈕等控制項)。注意,如果surface上面有透明控制項,那麼每次surface變化都會引起框架重新計算它和頂層控制項的透明效果,這會影響性能。SurfaceView默認使用雙緩沖技術的,它支持在子線程中繪制圖像,這樣就不會阻塞主線程了,所以它更適合於游戲的開發。 SurfaceView的使用首先繼承SurfaceView,並實現SurfaceHolder.Callback介面,實現它的三個方法:surfaceCreated,surfaceChanged,surfaceDestroyed。surfaceCreated(SurfaceHolder holder):surface創建的時候調用,一般在該方法中啟動繪圖的線程。surfaceChanged(SurfaceHolder holder, int format, int width,int height):surface尺寸發生改變的時候調用,如橫豎屏切換。surfaceDestroyed(SurfaceHolder holder) :surface被銷毀的時候調用,如退出遊戲畫面,一般在該方法中停止繪圖線程。還需要獲得SurfaceHolder,並添加回調函數,這樣這三個方法才會執行。SurfaceView實戰下面通過一個小demo來學習SurfaceView在實際項目中的使用,繪制一個精靈,該精靈有四個方向的行走動畫,讓精靈沿著屏幕四周不停的行走。

㈡ android獲取surfaceview裡面的每一幀

屏幕的顯示機制和幀動畫類似,也是一幀一幀的連環畫,只不過刷新頻率很高,感覺像連續的。為了顯示一幀,需要經歷計算和渲染兩個過程,CPU 先計算出這一幀的圖像數據並寫入內存,然後調用 OpenGL 命令將內存中數據渲染成圖像存放在 GPU Buffer 中,顯示設備每隔一定時間從 Buffer 中獲取圖像並顯示。
上述過程中的計算,對於View來說,就好比在主線程遍歷 View樹 以決定視圖畫多大(measure),畫在哪(layout),畫些啥(draw),計算結果存放在內存中,SurfaceFlinger 會調用 OpenGL 命令將內存中的數據渲染成圖像存放在 GPU Buffer 中。每隔16.6ms,顯示器從 Buffer 中取出幀並顯示。所以自定義 View 可以通過重載onMeasure()、onLayout()、onDraw()來定義幀內容,但不能定義幀刷新頻率。
SurfaceView可以突破這個限制。而且它可以將計算幀數據放到獨立的線程中進行。下面是自定義SurfaceView的模版代碼:
public abstract class BaseSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
public static final int DEFAULT_FRAME_DURATION_MILLISECOND = 50;
//用於計算幀數據的線程
private HandlerThread handlerThread;
private Handler handler;
//幀刷新頻率
private int frameDuration = DEFAULT_FRAME_DURATION_MILLISECOND;
//用於繪制幀的畫布
private Canvas canvas;
private boolean isAlive;
public BaseSurfaceView(Context context) {
super(context);
init();
}
protected void init() {
getHolder().addCallback(this);
//設置透明背景,否則SurfaceView背景是黑的
setBackgroundTransparent();
}
private void setBackgroundTransparent() {
getHolder().setFormat(PixelFormat.TRANSLUCENT);
setZOrderOnTop(true);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
isAlive = true;
startDrawThread();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
stopDrawThread();
isAlive = false;
}
//停止幀繪制線程
private void stopDrawThread() {
handlerThread.quit();
handler = null;
}
//啟動幀繪制線程
private void startDrawThread() {
handlerThread = new HandlerThread(「SurfaceViewThread」);
handlerThread.start();
handler = new Handler(handlerThread.getLooper());
handler.post(new DrawRunnable());
}
private class DrawRunnable implements Runnable {
@Override
public void run() {
if (!isAlive) {
return;
}
try {
//1.獲取畫布
canvas = getHolder().lockCanvas();
//2.繪制一幀
onFrameDraw(canvas);
} catch (Exception e) {
e.printStackTrace();
} finally {
//3.將幀數據提交
getHolder().unlockCanvasAndPost(canvas);
//4.一幀繪制結束
onFrameDrawFinish();
}
//不停的將自己推送到繪制線程的消息隊列以實現幀刷新
handler.postDelayed(this, frameDuration);
}
}
protected abstract void onFrameDrawFinish();
protected abstract void onFrameDraw(Canvas canvas);
}
用HandlerThread作為獨立幀繪制線程,好處是可以通過與其綁定的Handler方便地實現「每隔一段時間刷新」,而且在Surface被銷毀的時候可以方便的調用HandlerThread.quit()來結束線程執行的邏輯。
DrawRunnable.run()運用模版方法模式定義了繪制演算法框架,其中幀繪制邏輯的具體實現被定義成兩個抽象方法,推遲到子類中實現,因為繪制的東西是多樣的,對於本文來說,繪制的就是一張張圖片,所以新建BaseSurfaceView的子類FrameSurfaceView:
逐幀解析 & 及時回收
public class FrameSurfaceView extends BaseSurfaceView {
public static final int INVALID_BITMAP_INDEX = Integer.MAX_VALUE;
private List bitmaps = new ArrayList<>();
//幀圖片
private Bitmap frameBitmap;
//幀索引
private int bitmapIndex = INVALID_BITMAP_INDEX;
private Paint paint = new Paint();
private BitmapFactory.Options options = new BitmapFactory.Options();
//幀圖片原始大小
private Rect srcRect;
//幀圖片目標大小
private Rect dstRect = new Rect();
private int defaultWidth;
private int defaultHeight;
public void setDuration(int ration) {
int frameDuration = ration / bitmaps.size();
setFrameDuration(frameDuration);
}
public void setBitmaps(List bitmaps) {
if (bitmaps == null || bitmaps.size() == 0) {
return;
}
this.bitmaps = bitmaps;
//默認情況下,計算第一幀圖片的原始大小
getBitmapDimension(bitmaps.get(0));
}
private void getBitmapDimension(Integer integer) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(this.getResources(), integer, options);
defaultWidth = options.outWidth;
defaultHeight = options.outHeight;
srcRect = new Rec

熱點內容
死鎖避免的演算法 發布:2025-02-05 04:43:07 瀏覽:579
python查文檔 發布:2025-02-05 04:27:49 瀏覽:496
javaxmldom 發布:2025-02-05 04:27:40 瀏覽:9
linux修改內存大小 發布:2025-02-05 04:26:05 瀏覽:997
ftp命令復制文件 發布:2025-02-05 04:26:00 瀏覽:303
python好用的ide 發布:2025-02-05 04:14:18 瀏覽:516
id密碼開頭是多少 發布:2025-02-05 04:11:51 瀏覽:101
數據結構c語言ppt 發布:2025-02-05 04:11:45 瀏覽:43
如何用學習機配置的筆寫字 發布:2025-02-05 04:09:15 瀏覽:395
5歲編程 發布:2025-02-05 04:06:21 瀏覽:653