Android 에서 흔히 볼 수 있 는 그래 픽 그리 기 방식 요약
Android 플랫폼 은 풍부 한 공식 컨트롤 을 제공 하여 개발 자 에 게 인터페이스 UI 개발 을 실현 하지만 실제 업무 에서 다양한 맞 춤 형 수 요 를 만 날 수 있 습 니 다.이 는 개발 자가 직접 컨트롤 을 그 리 는 방식 으로 이 루어 져 야 합 니 다.일반적으로 Android 는 Canvas 와 OpenGL ES 두 가지 방식 으로 이 루어 집 니 다.그 중에서 Canvas 는 Android 바 텀 의 Skia 2D 벡터 그래 픽 처리 함수 라 이브 러 리 를 통 해 이 루어 집 니 다.구체 적 으로 Canvas 와 OpenGL 을 통 해 도형 을 그 리 는 방법 은 무엇 입 니까?이것 은 Android 가 제공 하 는 View 류 에 의존 하여 구체 적 으로 실현 해 야 합 니 다.다음 과 같은 몇 가지 흔 한 응용 방식 을 조합 해 야 합 니 다.
Canvas
이것 은 보통 사용 하 는 자체 그리 기 컨트롤 방식 으로 View 류 의 onDraw(Canvas canvas)를 다시 쓰 는 방법 으로 이 루어 집 니 다.그림 을 새로 고 쳐 야 할 때 invalidate()방법 을 사용 하여 View 대상 자체 가 새로 고 쳐 집 니 다.이 방안 은 사용자 정의 논리 와 관련 된 것 이 비교적 간단 하고 UI 스 레 드 에서 논 리 를 그 리 는 것 이 단점 입 니 다.새로 고침 효율 이 높 지 않 고 3D 렌 더 링 이 지원 되 지 않 습 니 다.
public class CustomView extends View {
public CustomView(Context context) {
super(context);
}
public CustomView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onDraw(Canvas canvas) {
// draw whatever.
}
}
SurfaceView + Canvas이 방식 은 View+Canvas 방식 에 비해 SurfaceView 를 사용 하기 때문에 Android WMS 시스템 에 자신의 Surface 를 만들어 렌 더 링 을 합 니 다.그 그리 기 논 리 는 독립 된 스 레 드 에서 진행 할 수 있 기 때문에 View+Canvas 방식 보다 성능 이 효율 적 입 니 다.그러나 일반적인 상황 에서 그 리 는 라인 을 만 들 고 Surface Holder.Callback 인 터 페 이 스 를 실현 하여 Surface View 의 생명 주 기 를 관리 해 야 하 는데 그 실현 논 리 는 View+Canvas 보다 약간 복잡 하 다.또한 3D 렌 더 링 은 지원 되 지 않 으 며 Surface 는 View hierachy 에 있 지 않 기 때문에 View 의 속성 에 의 해 제어 되 지 않 기 때문에 이동,크기 조정 등 변환 을 할 수 없고 다른 View Group 에 넣 을 수 없 으 며 Surface View 는 끼 워 넣 을 수 없습니다.
public class CustomSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable {
private boolean mRunning = false;
private SurfaceHolder mSurfaceHolder;
public CustomSurfaceView(Context context) {
super(context);
initView();
}
public CustomSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public CustomSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
private void initView() {
getHolder().addCallback(this);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
mSurfaceHolder = holder;
new Thread(this).start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
mSurfaceHolder = holder;
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mRunning = false;
}
@Override
public void run() {
mRunning = true;
while (mRunning) {
SystemClock.sleep(333);
Canvas canvas = mSurfaceHolder.lockCanvas();
if (canvas != null) {
try {
synchronized (mSurfaceHolder) {
onRender(canvas);
}
} finally {
mSurfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
private void onRender(Canvas canvas) {
// draw whatever.
}
}
TextureView + Canvas이 방식 은 SurfaceView+Canvas 방식 과 유사 하지만 TextureView 를 통 해 이 루어 지기 때문에 Surface 가 View hierachy 에 없 는 결함 을 제거 할 수 있 습 니 다.TextureView 는 WMS 에서 창 을 따로 만 들 지 않 고 View hierachy 의 일반 View 로 서 다른 일반 View 와 마찬가지 로 이동,회전,크기 조정,애니메이션 등 변 화 를 할 수 있 습 니 다.이러한 방식 도 단점 이 있 습 니 다.하드웨어 가 가속 화 된 창 에서 만 사용 할 수 있 습 니 다.메모리 사용량 은 Surface View 보다 높 고 5.0 이전에 메 인 UI 스 레 드 에 렌 더 링 되 었 으 며 5.0 이후 에는 단독 렌 더 링 스 레 드 가 있 습 니 다.
public class CustomTextureView extends TextureView implements TextureView.SurfaceTextureListener, Runnable {
private boolean mRunning = false;
private SurfaceTexture mSurfaceTexture;
private Surface mSurface;
private Rect mRect;
public CustomTextureView(Context context) {
super(context);
initView();
}
public CustomTextureView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public CustomTextureView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
private void initView() {
setSurfaceTextureListener(this);
}
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
mSurfaceTexture = surface;
mRect = new Rect(0, 0, width, height);
mSurface = new Surface(mSurfaceTexture);
new Thread(this).start();
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
mSurfaceTexture = surface;
mRect = new Rect(0, 0, width, height);
mSurface = new Surface(mSurfaceTexture);
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
mRunning = false;
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
@Override
public void run() {
mRunning = true;
while (mRunning) {
SystemClock.sleep(333);
Canvas canvas = mSurface.lockCanvas(mRect);
if (canvas != null) {
try {
synchronized (mSurface) {
onRender(canvas);
}
} finally {
mSurface.unlockCanvasAndPost(canvas);
}
}
}
}
private void onRender(Canvas canvas) {
canvas.drawColor(Color.RED);
// draw whatever.
}
}
이상 은 2D 그래 픽 렌 더 링 에서 흔히 볼 수 있 는 방식 으로 3D 그래 픽 렌 더 링 이나 고급 이미지 처리(예 를 들 어 필터,AR 등 효과)를 하려 면 OpenGL ES 를 도입 해 야 한다.OpenGL ES(OpenGL for Embedded Systems)는 OpenGL 3 차원 그래 픽 API 의 부분 집합 으로 휴대 전화,PDA,게임 호스트 등 내장 형 장 치 를 대상 으로 디자인 된 그래 픽 렌 더 링 API 의 디자인 기준 으로 서로 다른 소프트 하드웨어 개발 업 체 가 OpenGL API 내부 에서 서로 다른 실제 방식 을 가 질 수 있다.다음은 Android 플랫폼 에서 OpenGL ES 렌 더 링 을 어떻게 하 는 지 소개 합 니 다.보통 다음 과 같은 세 가지 방식 이 있 습 니 다.
SurfaceView + OpenGL ES
EGL 은 OpenGL API 와 네 이 티 브 창 시스템 간 인터페이스 로 OpenGL ES 의 플랫폼 무관 성 은 바로 EGL 을 통 해 이 루어 진 것 으로 EGL 은 서로 다른 플랫폼 의 차 이 를 차단 했다.OpenGL API 를 사용 하여 그래 픽 을 그 리 려 면 먼저 EGL 환경 을 구축 해 야 합 니 다.
보통 EGL 렌 더 링 을 사용 하 는 일반적인 절차:
-EGLDisplay 대상 을 가 져 오고 로 컬 창 시스템 과 의 연결 을 구축 하여 eglGetDisplay 방법 으로 EGLDisplay 를 가 져 옵 니 다.
-EGL 방법 을 초기 화하 고 연결 을 연 후 egl Initialize 방법 으로 초기 화 합 니 다.
-EGLConfig 대상 을 가 져 오고 표면 을 렌 더 링 하 는 설정 정 보 를 egl Choose Config 방법 으로 EGLConfig 를 얻 을 수 있 는 지 확인 합 니 다.
-렌 더 링 표면 EGLSurface 를 만 듭 니 다.EGLDisplay 와 EGLConfig 를 통 해 eglCreate WindowSurface 나 eglCreate PbufferSurface 방법 으로 렌 더 링 표면 을 만 들 고 EGLSurface 를 얻 습 니 다.
-렌 더 링 컨 텍스트 EGLContext 를 만 들 고 EGLDisplay 와 EGLConfig 를 통 해 eglCreate Context 방법 으로 렌 더 링 컨 텍스트 를 만 들 고 EGLContext 를 얻 을 수 있 습 니 다.
-바 인 딩 컨 텍스트 는 egl MakeCurrent 방법 을 통 해 EGLSurface,EGLContext,EGLDisplay 세 가 지 를 바 인 딩 합 니 다.바 인 딩 에 성공 하면 OpenGLES 환경 이 만들어 지고 그 다음 에 렌 더 링 을 할 수 있 습 니 다.
-교환 버퍼 OpenGLES 그리 기 가 끝 난 후 eglSwapBuffers 방법 으로 앞 뒤 버퍼 를 교환 하여 화면 에 내용 을 표시 합 니 다.화면 밖의 렌 더 링 은 이 방법 을 사용 하지 않 아 도 됩 니 다.
-EGL 환경 그리 기 종료 후 EGL 을 사용 하지 않 아 도 되 는 경우 eglMakeCurrent 의 바 인 딩 을 취소 하고 EGLDisplay,EGLSurface,EGLContext 세 대상 을 폐기 해 야 합 니 다.
상기 EGL 환경 구축 이 비교적 복잡 합 니 다.여 기 는 설명 을 많이 하지 않 고 코드 를 통 해 구체 적 인 실현 을 참고 할 수 있 습 니 다.
public class OpenGLSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable {
private boolean mRunning = false;
private SurfaceHolder mSurfaceHolder;
public OpenGLSurfaceView(Context context) {
super(context);
initView();
}
public OpenGLSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public OpenGLSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
private void initView() {
getHolder().addCallback(this);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
mSurfaceHolder = holder;
new Thread(this).start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
mSurfaceHolder = holder;
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mRunning = false;
}
@Override
public void run() {
// EGL
EGL10 egl = (EGL10) EGLContext.getEGL();
//
EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
// EGLDisplay
int[] version = new int[2];
egl.eglInitialize(dpy, version);
int[] configSpec = {
EGL10.EGL_RED_SIZE, 5,
EGL10.EGL_GREEN_SIZE, 6,
EGL10.EGL_BLUE_SIZE, 5,
EGL10.EGL_DEPTH_SIZE, 16,
EGL10.EGL_NONE
};
EGLConfig[] configs = new EGLConfig[1];
int[] num_config = new int[1];
// config opengl
egl.eglChooseConfig(dpy, configSpec, configs, 1, num_config);
EGLConfig config = configs[0];
EGLContext context = egl.eglCreateContext(dpy, config,
EGL10.EGL_NO_CONTEXT, null);
// surface
EGLSurface surface = egl.eglCreateWindowSurface(dpy, config, mSurfaceHolder, null);
// opengles
egl.eglMakeCurrent(dpy, surface, surface, context);
// opengles
GL10 gl = (GL10)context.getGL();
mRunning = true;
while (mRunning) {
SystemClock.sleep(333);
synchronized (mSurfaceHolder) {
onRender(gl);
//
egl.eglSwapBuffers(dpy, surface);
}
}
egl.eglMakeCurrent(dpy, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
egl.eglDestroySurface(dpy, surface);
egl.eglDestroyContext(dpy, context);
egl.eglTerminate(dpy);
}
private void onRender(GL10 gl) {
gl.glClearColor(1.0F, 0.0F, 0.0F, 1.0F);
// Clears the screen and depth buffer.
gl.glClear(GL10.GL_COLOR_BUFFER_BIT
| GL10.GL_DEPTH_BUFFER_BIT);
}
}
위의 코드 를 보면 SurfaceView+Canvas 의 그리 기 방식 에 비해 다음 과 같은 두 가지 변화 가 있 습 니 다.while(true)순환 전후 EGL 환경 구조의 코드 가 추가 되 었 습 니 다
EGL 환경 을 구축 하 는 것 이 번 거 롭 고 스 레 드 를 튼튼 하 게 유지 해 야 하기 때문에 Surface View 를 직접 사용 하여 OpenGL 을 그리 기 가 불편 합 니 다.다행히 안 드 로 이 드 플랫폼 은 GLSurfaceView 류 를 제공 하여 개발 자 들 이 OpenGL 의 렌 더 링 개발 을 신속하게 진행 할 수 있 도록 이러한 논 리 를 잘 밀봉 했다.GLSurfaceView 클래스 를 사용 하여 그래 픽 렌 더 링 을 하려 면 GLSurfaceView.Renderer 인 터 페 이 스 를 실현 해 야 합 니 다.이 인 터 페 이 스 는 onDrawFrame(GL 10 gl)방법 을 제공 하여 이 방법 에서 구체 적 인 렌 더 링 논 리 를 실현 합 니 다.
public class OpenGLGLSurfaceView extends GLSurfaceView implements GLSurfaceView.Renderer {
public OpenGLGLSurfaceView(Context context) {
super(context);
setRenderer(this);
}
public OpenGLGLSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
setRenderer(this);
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// pass through
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
gl.glViewport(0, 0, width, height);
}
@Override
public void onDrawFrame(GL10 gl) {
gl.glClearColor(1.0F, 0.0F, 0.0F, 1.0F);
// Clears the screen and depth buffer.
gl.glClear(GL10.GL_COLOR_BUFFER_BIT
| GL10.GL_DEPTH_BUFFER_BIT);
}
}
TextureView + OpenGL ES이 방식 은 SurfaceView+OpenGL ES 사용 방법 과 유사 합 니 다.이 방법 을 사용 하면 TextureView 를 통 해 이 루어 진 다 는 장점 이 있 기 때문에 Surface 가 View hierachy 에 없 는 결함 을 제거 할 수 있 습 니 다.TextureView 는 WMS 에서 창 을 따로 만 들 지 않 고 View hierachy 의 일반 View 로 서 다른 일반 View 와 마찬가지 로 이동,회전 할 수 있 습 니 다.크기 조정,애니메이션 등 변화.여기 서 TextureView 류 를 사용 하여 EGL 환경 을 구축 할 때 주의해 야 합 니 다.eglCreate Window Surface()에 들 어 오 는 매개 변 수 는 SurfaceTexture 인 스 턴 스 입 니 다.
public class OpenGLTextureView extends TextureView implements TextureView.SurfaceTextureListener, Runnable {
private boolean mRunning = false;
private SurfaceTexture mSurfaceTexture;
public OpenGLTextureView(Context context) {
super(context);
initView();
}
public OpenGLTextureView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public OpenGLTextureView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
private void initView() {
setSurfaceTextureListener(this);
}
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
mSurfaceTexture = surface;
new Thread(this).start();
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
mSurfaceTexture = surface;
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
mRunning = false;
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
@Override
public void run() {
// EGL
EGL10 egl = (EGL10) EGLContext.getEGL();
//
EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
// EGLDisplay
int[] version = new int[2];
egl.eglInitialize(dpy, version);
int[] configSpec = {
EGL10.EGL_RED_SIZE, 5,
EGL10.EGL_GREEN_SIZE, 6,
EGL10.EGL_BLUE_SIZE, 5,
EGL10.EGL_DEPTH_SIZE, 16,
EGL10.EGL_NONE
};
EGLConfig[] configs = new EGLConfig[1];
int[] num_config = new int[1];
// config opengl
egl.eglChooseConfig(dpy, configSpec, configs, 1, num_config);
EGLConfig config = configs[0];
EGLContext context = egl.eglCreateContext(dpy, config,
EGL10.EGL_NO_CONTEXT, null);
// surface
EGLSurface surface = egl.eglCreateWindowSurface(dpy, config, mSurfaceTexture, null);
// opengles
egl.eglMakeCurrent(dpy, surface, surface, context);
// opengles
GL10 gl = (GL10)context.getGL();
mRunning = true;
while (mRunning) {
SystemClock.sleep(333);
synchronized (mSurfaceTexture) {
onRender(gl);
//
egl.eglSwapBuffers(dpy, surface);
}
}
egl.eglMakeCurrent(dpy, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
egl.eglDestroySurface(dpy, surface);
egl.eglDestroyContext(dpy, context);
egl.eglTerminate(dpy);
}
private void onRender(GL10 gl) {
gl.glClearColor(1.0F, 0.0F, 1.0F, 1.0F);
// Clears the screen and depth buffer.
gl.glClear(GL10.GL_COLOR_BUFFER_BIT
| GL10.GL_DEPTH_BUFFER_BIT);
}
}
코드 예시 참조github.com/sunjinbo/hi …
총결산
안 드 로 이 드 에서 흔히 볼 수 있 는 그래 픽 그리 기 방식 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 안 드 로 이 드 그래 픽 그리 기 방식 에 관 한 내용 은 예전 의 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 많은 응원 부탁드립니다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.