SW 배움터/안드로이드

안드로이드 5: SurfaceView의 사용법

kusson 2017. 5. 18. 13:25
반응형
728x170

 게임과 같이 복잡하고 빠른 그래픽이 요구되는 애플리케이션에서는 캔버스에 직접 이미지를 그리는 것은 무리가 있기 때문에 그리기 전용의 화면을 제공하는 SurfaceView를 사용해야 한다. SurfaceView에는 다음 장의 화면을 미리 그려두고 그리기가 끝나면 바로 전환하는 더블 버퍼링이란 기능이 있어 처리속도를 빠르게 할 수 있다. 또한 직접적인 그리기 처리는 다른 스레드에서 수행한다. 스레드란 프로그램의 처리 흐름을 말하는데 다른 스레드를 추가함으로써 마치 2개 이상의 처리를 동시에 하는 것과 같은 효과를 줄 수 있다.

 

1. SurfaceView의 사용법에 대해서 알아본다.

 1)SurfaceView를 상속받아서 새로운 클래스를 정의한다.

 2)액티비티의 화면으로 SurfaceView를 설정한 후에 새로운 스레드에서 이SurfaceView에 그림을 그린다.

 3)SurfaceHolder.Callback을 구현해서 Surface가 생성되고 소멸되는 시점을 알려준다.

 

    cf) class SurfaceViewMyView extends SurfaceView implements SurfaceHolder.Callback{

          public void SurfaceCreated(SurfaceHolder holder){

            //Surface가 준비되었으므로 스레드를 시작한다.

            .

            .

            .

         }

 

        public void SurfaceDestroyed(SurfaceHolder holder){

            //Surface가 소멸되었으므로 스레드를 종료한다.

            .

            .

            .

         }

 

        public void SurfaceChanged(SurfaceHolder holder, int format, int width, int height) {

             //Surface가 변경됨.

             .

             .

             .

         }

       }

 

 

  4)SurfaceView 객체는 우리가 직접 처리할 수 없고 반드시 SurfaceHolder를 통하여 처리해야 한다.

    SurfaceView 객체가 초기화될 때 getholder()를 호출해서 SurfaceHolder를 얻으면 된다.

    cf) SurfaceHolder holder = getHolder();

 

  5)만약 SurfaceHolder의 콜백메서드를 받고 싶다면 addCallback()을 호출한다.

    cf) holder.addCallback(this);

 

  6)SurfaceView와 SurfaceHolder의 관계

 

 

 SurfaceView의 상태제어는 SurfaceHolder의 상태제어를 콜백 메서드로 호출해서 사용하고

 SurfaceView의 락제어는 SurfaceHolder의 락제어를 호출해서 사용한다.

 

 

 

7) onDraw()       -->    draw()

   inValidate      -->     redraw()

SurfaceView는 안드로이드의 기본뷰 계층에 포함되지 않기때문에 onDraw()inValidate()을 사용할 수

  없고 draw()redraw()로 대체해야 한다.

 

2. 애니메이션 프로그램 작성

 이제 문자를 오른쪽에서 왼쪽으로 고속으로 스크롤하는 프로그램을 작성해 본다. 물론 위에서 설명한 SurfaceView를 이용한다.

 

ex)

private class SurfaceViewMyView extends SurfaceView 

                                         implements SurfaceHolder.Callback, Runnable{

 

  private SurfaceHolder holder;

  private Thread thread;

  private int positionX = 0;

  private Paint paint = new Paint();

 

     public SurfaceViewMyView (Context context) {

super(context);

holder = getHolder();          // 위의 설명 4)를 참고한다.

holder.addCallback(this);      // 5) 참고

}

 

public void surfaceCreated(Surface holder) {        //서피스가 생성될 때 호출되는 메서드.

thread = new Thread(this); 

thread.start();                                        //스레드를 시작한다.

}

 

public void surfaceDestroyed(SurfaceHolder holder) { //서피스가 소멸될 때 호출되는 메서드.

thread = null;

}

 

public void surfaceChanged(SurfaceHolder holder,    //서피스가 갱신될 때 호출되는 메서드.

                                     int format, int w, int h) {

}

 

public void run() {                                       // 다른 스레드에서 실행되는 메서드이다.

paint.setTexSize(30);

while(thread != null) {                            // 루프의 조건을 준다. null이 될때까지 돈다.

    Canvas canvas = holder.lockCanvas();     // 뒤 화면 그리기를 시작한다.

   if (canvas == null)

      break;

   canvas.drawColor(Color.WHITE);

   canvas.drawText("testTextAnimation", positionX, 100, paint); // 화면에 글자를 출력한다.

   holder.unlockCanvasAndPost(canvas);         // 뒤 화면 그리기를 종료하고 holder에 반영한다.

 

   positionX -= 20;                                   // 화면의 글자가 20픽셀씩 왼쪽으로 이동하여

   if (positionX < 0)                                  // 왼쪽 끝까지 오면

       positionX = getwidth();                      //  오른쪽 끝으로 돌아간다.

   try{                                                   //  예외처리를 둔다.

      Thread.sleep(100);                              //  100밀리초(0.1초) 지연시간을 준다.

   }catch (Exception e){ }

 }

   }

}

 

 

반응형
그리드형