본문

[2018.01.01] 88. 서피스 뷰(Surface View) 개념과 실습

도입

이번 포스팅에서는 서피스 뷰(Surface View)의 개념을 학습한 뒤 실습을 할 예정이다.

안드로이드 머티리얼 디자인을 실습하며 안드로이드의 Window와 서피스 뷰 개념에 대해 궁금했고 개념을 알아볼 예정이다.



서피스 뷰(Surface View)개념

(출처 - https://developer.android.com/reference/android/view/SurfaceView.html)

서피스 뷰는 기존의 뷰를 상속받으며 그래픽 처리가 빠른 View이다.

추가적으로 하드웨어 가속이 가능하므로 그래픽 처리가 빠르다. 앱에서 3D 처리를 위해서 사용한다.


그렇다면 뷰(View)보다 서피스 뷰(Surface View)를 사용하는 것이 좋을까?

최신 버전에서는 하드웨어 가속을 기본적으로 제공하므로 예전만큼 서피스뷰와 뷰가 큰 차이를 보이지 않습니다. 따라서 일반적인 경우에는 View를 상속하여 그리기 작업을 수행하도록 해도 큰 문제가 없으며, 오히려 View 클래스의 onDraw()와 invalidate() 메소드에 익숙해질수록 View를 상속하는 것이 더 쉬워지므로 View를 상속하는 것이 더 나은 처리 방법이라 할 수도 있습니다.

Do it! 안드로이드 앱 프로그래밍 p523



서피스 뷰 구성

구분

설명

서피스 홀더(SurfaceHolder)

  서피스 뷰에 필요한 제어 기능 제공

콜백 인터페이스

  서피스 뷰의 변화 상태를 관리하는 인터페이스

잠금(Lock) 기능

  서피스 뷰에 1개의 어플리케이션 접근만 허용하기 위해 잠금 기능 제공



실습

SurfaceView 클래스

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
public class StageView extends SurfaceView implements SurfaceHolder.Callback {
    private final String TAG = getClass().getSimpleName();
    SurfaceHolder holder;
    Thread runThread;
 
    int width = 0;
    int height = 0;
 
    public StageView(Context context) {
        super(context);
        
        // 화면 크기     
        DisplayMetrics metrics = context.getResources().getDisplayMetrics();
        width = metrics.widthPixels;
        height = metrics.heightPixels;
 
        // View를 생성할 때 Surface를 관리하는 Holder를 함께 생성
        // Holder를 상속 했기 때문에 getHolder 메소드 호출 가능
        holder = getHolder();
 
        // Holder에 콜백 추가
        // Surface View의 변경사항이 있을 때 마다 아래 3개 메소드 호출
        holder.addCallback(this);
        runThread = new DrawThread();
 
        
    }
 
    // Surface View가 생성될 때 호출
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        Log.d(TAG, "surfaceCreated: " + "onCreate");
        runThread.start();
    }
 
    // View가 변경 사항이 있을 때 ex) 크기가 바뀔 때 호출
    @Override
    public void surfaceChanged(SurfaceHolder holder, int formatint width, int height) {
        Log.d(TAG, "surfaceChanged: " + "changed");
    }
 
    // View가 종료 될 때 호출
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        Log.d(TAG, "surfaceDestroyed: " + "destory");
        runThread = null;
    }
 
    class DrawThread extends Thread {
        float x=0, y=0, r=50;
        Paint paint;
        public void run() {
            paint = new Paint();
            paint.setColor(Color.RED);
            while(runThread != null) {
                // 그림판에 락을 걸어 잠근다.
                Canvas canvas = holder.lockCanvas();
 
                // Circle 이동
                x += 10; y += 10;
                canvas.drawColor(Color.WHITE);
                canvas.drawCircle(x, y, 50, paint);
                
                // 화면을 넘어가면 초기화
                if (x > width)      x = 0;
                if (y > height)     y = 0;
 
                // 그림판의 락을 푼다.
                holder.unlockCanvasAndPost(canvas);
            }
        }
    }
}
cs


MainActivity 클래스

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class MainActivity extends AppCompatActivity {
 
    private FrameLayout stage;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
 
        // 서피스 뷰 생성 및 
        SurfaceView view = new StageView(this);
        stage.addView(view);
    }
 
    private void initView() {
        stage = findViewById(R.id.stage);
    }
}
cs


activity_main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.heepie.day093_surfaceview.MainActivity">
 
    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Surface View"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 
    <FrameLayout
        android:id="@+id/stage"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView">
 
    </FrameLayout>
</android.support.constraint.ConstraintLayout>
cs



스크린 샷



#surface view #서피스 뷰

공유

댓글