* 내용 보시고 좋으면 게시물 추천해 주세요 (게시물 아래에 "이 게시물을~" 부분을 눌러 주시면 되죠)

PAAD 11장 고급 안드로이드 개발  - 발표: 2010년 03월 10일(수) - 오후 07시 30분


11장 목차

  1. 편집증 환자, 안드로이드

    1. 리눅스 커널 보안
    2. 권한 소개 (Permission)
    3. 권한 선언과 적용하기
    4. 인텐트 방송에 권한 적용하기
  2. AIDL을 이용해 서비스를 위한 IPC 지원하기

    1. AIDL 인터페이스 구현하기

      1. 커스텀 클래스 객체 전달하기
      2. AIDL 정의 만들기
      3. IPC 인터페이스 구현하고 노출하기
  3. 인터넷 서비스 이용하기
  4. 리치 유저 인터페이스 구축하기

    1. 애니메이션으로 작업하기 (tweend animation, frame by frame)

      1. 트윈드애니메이션 (소개, 만들기, 적용하기, 리스너)
      2. 레이아웃 뷰 그룹 애니메이션 (만들기, 이용하기)
      3. 프레임 바이 프레임 만들고 이용하기
    2. 애플리케이션에 테마로 스킨 입히기
    3. 고급 캔버스 그리기

      1. 캔버스 
      2. 페인트 활용
      3. 투명 이용하기
      4. 셰이더 소개
      5. 그레이디언드 셰이더 정의하기
      6. 셰이더 타일 모드 이용하기
      7. MaskFilter 이용하기
      8. ColorFilter 이용하기
      9. PathEffect 이용하기
      10. Xfermode 바꾸기
      11. 앤티앨리어싱으로 페인트 품질 높이기
      12. 2D 그래픽스를 위한 하드웨어 가속
      13. 캔버스 드로잉 베스트 프랙티스
    4. 오버레이에 생명력 불어 넣기
    5. SurfaceView소개

      1. 언제 SurfaceView을 이용해야 하나?
      2. 새로운 SurfaceView 컨트롤 만들기
      3. SurfaceView로 3D 컨트롤 만들기
  5. 인터랙티브한 컨트롤 만들기

    1. 터치 스크린 이용하기

      1. 터치 이벤트 처리
      2. 움직임 추적하기
    2. 장치 키와 버튼 이용하기 (D패드 포함)
    3. 트랙볼 이용하기


주요 용어: Permission, AIDL, tween Animation, layoutview group animation, thema, Canvas, SurfaceView, touch event, overlay

1. 편집증환자 안드로이드 / 권한 - Permission


1) 리눅스 커널 보안

샌드박스내의 리소스

01_sandbox.PNG

안드로이드의 보안 

 - 리눅스 커널에 기반한 보안 수준

 - 패키지 설치시 User ID부여. 이것으로 자기 영역을 부여 받고 보호 받는다. 

 - 상호 프로세스, 리소스에 대한 사용 제한이 따르게 된다. 


어플리케이션간 통신

 - 안드로이드 샌드박스로 격리된 프로세스간에 통신 기능을 제공한다.

 - 

BroadCast Intent, Service, Content Provider, AIDL이 이런 역할을 수행한다.


안드로이드 권한(Permission)

 - 통신 기능의 내용을 제어하기 위해서 시작과 끝점에서 

Permission

을 점검하는 기능이 부여 되어 있다.

Permission이 점검 당하는 시점

- 시스템 내부로의 호출 시점

- 액티비티 시작 시점

- 브로드캐스트 보내는 시점

- 켄텐츠프로바이더 접근 시점

- 서비스 바인딩 시점 또는 시작 시점

 - 점검결과로 퍼미션에 적합하면 동작되고, 부적합하면 실행되지 않고, 알림도 없다 단지 log로는 남는다.

   부적합시에 일부 Exception이 발생될 수 있다.


2) 권한 - Permissions


2-1) 권한의 소개 

01_1permision.png

데이터를 손상시키는 악의적인 애플리케이션, 민감한 정보에 대한 접근, 외부 통신 채널 또는 하드웨어 리소스 남용을 예방하는데 사용됨

- Native Component는 권한 요구사항을 갖는다.

  > android.m

anifest.permission 에서 네이티브 권한 문자열을 확인할 수있다. (앱에 별도로 지정된 것은 확인 안됨)

  > 이런 권한이 정의된 네이티브 컨포너트는 <uses-permission>을 사용해서 접근할 수 있다.

04__uses_permission.PNG

- androidmanifest.xml에 기술된 권하은 애플리케이션 설치 시점에 분석 표시 되며 설치 승인 및 거부를 할 수 있다.  

- 설치 시점에 권한 확인을 하고 나면 이후로는 해당 권한은 재평가 되지는 않는다.

03__install.PNG


2-2) 

권한의 선언, 적용

다른 패키지들이 내 패키지내의 콤포넌트를 접근 제어하고자 할때 권한을 선언해서 사용할 수 있다.

권한 선언:

permission 태그를 사용해서 선언

  05__permission.PNG 


   <permission

android:name=”com.paad.DETONATE_DEVICE”

android:protectionLevel=”dangerous”

android:label=”Self Destruct”

android:description=”@string/detonate_description”>

   </permission>


protectionLevel속성: 

 이 레벨을 설정에 따라서 사용자가 퍼미션을 요구하는 애플리케이션 알수 있거나,

 해당 퍼미션이 누가 사용하는지 알수 있게 해 준다.

 허가할 권한의 접근 수준: normal, dangerous, signature, signatureOrSystme


permissionGroup속성:

 선택 사항으로 단지 시스템이 사용자에게 퍼미션 표시를 돕기 위해서 사용된다.

 표준 시스템 그룹에서 정의한 사항을 표기하는 것이 좋다. 

 직접 정의도 가능하다. 그렇지만 사용자에게 퍼미션UI를 단순화 하기 위해서 표준것을 사용하는 것이 

좋다.


Lavel속성, Description속성:

 퍼미션 정의에 필수 사항이다.

 Lavel: 퍼미션 리스트에 나타나고, 퍼미션이 보호하는 기능의 핵심부분을 몇개의 단어로 기술할 것

 Desc..: 퍼미션 상세보기에 나타나고, 두문장으로 기술하는데 

           첫번째문장은 퍼미션의 설명, 

           두번째는 퍼

미션 부여시 발생될 수 있는 나쁜 것이 무엇인지를 사용자에게 경고해 주는 내용을 기술한다.


아래 adb명령을 통해서 시스템의 퍼미션 정보를 볼 수 있다.


adb shell pm list permissions

 이 명령을 통해서 시스템에 현재 정의된 퍼미션들을 볼 수 있다.


adb shell pm list permissions -s

 -s 옵션은 사용자가 보는 방식과 같은 방식으로 볼 수 있다.


권한 적용:

권한 적용은 AndroidManifest.xml의 각 컴포넌트 태그내에 android:permission속성을 기술하면된다. 

- Activity: 권한을 추가해 액티비티를 띄우는 다른 애플리케이션의 능력을 제어한다.

- BroadCast Receiver: 여러분의 수신자로 어떤 애플리케이션이 브로드캐스트 인텐트를 전송할 수 있는지 제어한다.

  > sendBroadcast(myIntnet, REQUIRED_PERMISSION);

- Contents Provider :  콘텐츠 공급자의 읽기 접근과 쓰기 작업을 제어한다.

   > android:readPermission, android:writePermission

   > URI퍼미션: 

액티비티에게 그 인텐트 내의 특정 

데이터 URI에 대한 접근 퍼미션을 부여한다.

- Service : 서비스 시작하거나 바인드하는 다른 애플리케이션의 능력을 제어한다.

   <activity 

android:name=”.MyActivity”

android:label=”@string/app_name”

android:permission=”com.paad.DETONATE_DEVICE”>  //<== 나의 컴포넌트에 permission 속성과 권한 문자열 지정

   </activity>



 

그밖에 퍼미션 관련 기능 

(해당 퍼미션이 부여되어 있는지를 정수 값으로 리턴해 준다.)

그밖에 퍼미션 관련 기능 

(해당 퍼미션이 부여되어 있는지를 정수 값으로 리턴해 준다.)

- Context.checkCallingPermission()

   서비스를 호출할때 요구되는 퍼미션 문자열을 사용해서 호출한다.

- Context.checkPermission(String, int, int)

    이것은 다른 프로세스에 대해서 PID를 사용해서 그 프로세스의 퍼미션을 점검할 수 있다.

- PackageManager.checkPermission(String, String)

   앱의 패키지명을 알고 있을 때 사용한다.



2. AIDL을 이용해 서비스를 위한 IPC 지원하기


AIDL : Android Interface Definition Language

  •  서비스와 애플리케이션 콤포넌트간에 프로세스 간의 통신(IPC)을 지원하기 위한 안드로이드 인터페이스 정의 언어이다.
  •  이것은 Remote Call Procedure(RPC)로 COM이나 Corba와 비슷하다. 
  •  Client와 Server사이의 값을 전달하기 위해 proxy클래스를 사용한다.
  •  두개의 프로세스간 통신 할 수 있도록 코드를 생성할 때 사용되는 IDL언어로 Java에도 IDL이 있고

       JDK의  jdk/bin/idl.exe을 통해서 인터페이스를 해석해 준다.

       이것을 Android에서는 AIDL로 정의하고 AIDL Tool을 제공한다.  


원리:

- IPC를 통해서 객체를 전달하려면 OS 수준의 기본요소(Primitive)로 해체할 필요가 있다. 

  이렇게 해야지 하부 운영체제(OS)가 

이를 애플리케이션의 경계 너머로 전달 할 수 있다.

- AIDL은 프로세스가 객체를 주고 받을 수 있도록 하는 코드를 단순화하는데 이용된다. 

- 이 것은 프로세스간에 객체 매개변수를 받아 들이고 리턴하며,  

   값을 리턴할 수 있는 Public 메소드를 나의 서비스 내에 만들 수 있도록 해 준다.

- 서비스와 Client간은 싱크로 동작한다.

AIDL 문법

- AIDL이 지원하는 Data Type

  • Primitive Java Data Type(import 불필요)
  • String, List, Map, CharSequence (import 불필요)
  • 다른 AIDL-generated interface (반드시 import 필요)
  • Parcelable protocol 을 구현한 클래스 (반드시 import필요)

- method : 매개변수가 0개 이상 / return 값: void or value

- 매개변수: primitive 값 또는 다른 AIDL로 정의된 parameter

- 매개변수 direction : 매개변수가 값 타입인지, 레퍼런스 타입인지 나타내기 위해 방향 태그가 필요함

                                  in / out / inout  (primitive를 제외하고는 반드시 표기 필요 primitive default는 in임)

- 같은 패키지내 인터페이스라 하더라도 반드시 import를 해 줘야 한다.


커스텀 클래스 객체 전달하기

Parcelable인터페이스를 통해서 내 애플리케이션 클래스를 AIDL과 호환되도록 만든다.

- 객체를 프로세스간 경계를 넘어 마셜링될 수 있는 parcel내에 저장되는 기본 타임으로 분해 할 수 있도록 해준다.


작성 방법

 1) Parcelable객체를 상속받는 내 클래서를 만든다.

 2) writeToParcel메소드를 구현한다. : 클래스를 분해를 위해서 필요

 3) Parcelable.Creator객체 생성 : 들어오는 Parcel에 기반한 새로운 객체를 생성할 Public static필드 

 4) describeContents()

 5) AIDL 정의 : 내 서비스에 대한 AIDL인터페이스 정의할 때 이용하도록 하기 위함

    (parcelable Quke; )


AIDL 정의 만들기

- aidl파일: 프로세스를 넘나들 수 있는 서비스를 위해서 정의하며, 서비스가 구현할 인터페이스에 포함될 메서드와 필드를 정의한다.

- AIDL문법에 준수해서 내용을 작성한다.

- 주의 사항으로는 매개변수 마샬링에는 비용이 많이들기에 각 매개변수의 방향을 제한해야 한다.

파일: IEarthquakeService.aidl

package com.paad.earthquake;

import com.paad.earthquake.Quake;

interface IEarthquakeService {

List<Quake> getEarthquakes();

void refreshEarthquakes();

}


서비스에서 IPC 인터페이스 구현하고 노출하기

- ADT플러그인은 .aidl파일이 저장되면 "자바 interface파일 코드"가 자동 생성되어진다.

- 이 인터페이스는 내부클래스인 stub을 포함하는데 추상클래스로 우리가 만드는 서비스에서 확장애서 실젱 작업할 내용을 넣어 놓는다.

- 구현된 기능과 인터페이스는 클라이언트에 정보를 노출해야 한다. 

   이 방법은 해당 인터페이스의 인스턴스를 리턴하도록 onBind메서드에 재정의함으로 가능하다.


액티비티에서 IPC 서비스 이용하기

- IPC서비스를 바인드한다.

- ServiceConnection 클래스를 포함해서 onServiceConnected 메소드를 재정해서 사용한다.


AIDL 프로젝트의 클래스 구성도

06__AIDL_2.PNG

AIDLServiceProject 생성

    (1) IMyService.aidl정의

    (2) AIDL툴에 의해 코드 생성 확인

    (3) IMyService.Stub클래스에서 Remote Service메소드 정의

    (4) MyService생성

         AndroidManifest.xml에 MyService를 등록

         AIDLClientProject 생성

    (5) IMyService.aidl정의

    (6) AIDL툴에 의해서 코드 생성 확인

    (7) ServiceConnection클래스 정의

    (8) Service Client 정의의

   

실행순서

    1) AIDLService 실행

    2) AIDLClient 실행


3. 인터넷 서비스 이용하기



  • 구글의 g데이터 서비스
  • 야휴! 파이프
  • 구글 앱 엔진
  • 아마존 웹 서비스



4. 리치 인터페이스 구축하기


4.1.1 트윈드에니메이션

소개:

 - 최소의 리소스 비용으로 깊이나 움직임 또는 피드백을 제공하기 위한 간단한 방법을 제공한다. 

  (직접 캔버스에 다시 그리는 것에 비해 훨씬 쉽고 다소 리소스가 적게든다.)

 - 단일 리소스에 대해서 복수개의 인스턴스를 취급할때 여러 상태를 가질 수 있다.

  (Drawable을 사용할때는 한쪽의 인스턴스에 리소스의 상태 변형하면 다른쪽 인스턴스로 영향을 받음)


제공 가능한 효과:

 - 일련의 방향

 - 크기의 변화

 - 위치 이동

 - 불투명 변화


사용예:

 - 액티비티 간 전환

 - 액티비티 내에 있는 레이아웃 간 전화

 - 같은 뷰 내에 표시된 서로 다른 콘텐트 간 전환

 - 진행 상태를 표시하기 위한 모래시계 뷰 회전

 - 부정확하거나 유효하지 않은 데이터 입력을 표시하기 위한 입력 박스 흔들기

 

트윈드 애니메이션 만들기

 - 코드 방식

2_tweend_code.png


애니메이션시퀀스 (애니메이션, 애니메이션셋 모두 사용가능)

 - .setRepeatMode(): 값으로 RESTART(반복), REVERSE(앞뒤로 왔다 갔다)

 - .setRepeatCount(): 반복하고자 하는 숫자, 또는 INFINITE

 * 이 메소드를 사용하지 않을 경우 기본값으로 한 번 실행됨


 - 외부 리소스 방식

3_tweend_outresource.png

 * xml 파일 위치: res\anim\


 코드

 

 코드 방식 외부 리소스 방식
 

   // ---- Tweened animations

    // Create the AnimationSet

    animationSet = new AnimationSet(true);


    // Create a rotate animation.

    RotateAnimation rotate = new RotateAnimation(

           0, 360,                                                       RotateAnimation.RELATIVE_TO_SELF,0.5f, 

           RotateAnimation.RELATIVE_TO_SELF,0.5f);

    rotate.setFillAfter(true);

    rotate.setDuration(1000);


    // Create a scale animation

    ScaleAnimation scale = new ScaleAnimation(

            1, 0,                                                          1, 0,                                                         ScaleAnimation.RELATIVE_TO_SELF, 0.5f,                        ScaleAnimation.RELATIVE_TO_SELF, 0.5f);

    scale.setFillAfter(true);

    scale.setDuration(500);

    scale.setStartOffset(500);


    // Create an alpha animation

    AlphaAnimation alpha = new AlphaAnimation(1, 0);

    scale.setFillAfter(true);

    scale.setDuration(500);

    scale.setStartOffset(500);


    // Add each animation to the set

    animationSet.addAnimation(rotate);

    animationSet.addAnimation(scale);

    animationSet.addAnimation(alpha);

    

    animationSet.setRepeatMode(Animation.RESTART);

    animationSet.setRepeatCount(Animation.INFINITE); 

    myView.startAnimation(animationSet);  

 

 <?xml version="1.0" encoding="utf-8"?>

<set xmlns:android="http://schemas.android.com/apk/res/android" 

  android:shareInterpolator="true">

  <rotate

    android:fromDegrees="0"

    android:toDegrees="360"

    android:pivotX="50%" 

    android:pivotY="50%"

    android:startOffset="0"

    android:duration="1000" 

  />

  <scale

    android:fromXScale="1.0" 

    android:toXScale="0.0"

    android:fromYScale="1.0"

    android:toYScale="0.0" 

    android:pivotX="50%" 

    android:pivotY="50%" 

    android:startOffset="500"

    android:duration="500" 

  />

  <alpha

    android:fromAlpha="1.0"

    android:toAlpha="0.0"

    android:startOffset="500"

    android:duration="500"

  />

</set>


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ImageView myView;
= (ImageView) findViewById(R.id.myViewId);
Animation myAnimation
= AnimationUtils.loadAnimation(this, R.anim.myXML);
myView.startAnimation(myAnimation);


애니메이션 리스너 이용하기 (애니메이션, 애니메이션셋 모두 사용가능)

 - 애니메이션이 시작하거나 끝날 때 호출 되는 이벤트 핸들러를 만들도록 해준다.

 - .setAnimationListener(new AnimationListener(){}

   > onAnimationEnd()    : 완료한 후 

   > onAnimationRepeat() : 반복 시작 때

   > onAnimationStart()  : 새로 시작할 때



4.1.2 Layout과 View Animation만들기

소개

LayoutAnimation

 - View Group을 애니메니션하고 미리 결정된 순서에 따라서 각 자식 View 애니메이션(애니메이션셋)을 적용에 이용됨

LayoutAnimationController클래스: View Group에 있는 자식 View에 적용된 애니메이션을 지정한다. 

 - LayoutAnimationController: 각 View의 시작 Offset값과 자식 View의 애니메이션 순서을 선택할 수 있다.

   (순서: Animation효과가 적용될 자식View순서 값: forward, reverse, random)

 - GridLayoutAnimationController: 격자 행과 열 레퍼런스를 이용해 자신 뷰의 애니메니션 순서를 지정


LayoutAnimation만들기

- 외부 리소스 방식

4__layoutanimaction_xml.png

- 코드 방식

5__layoutanimaction_code.png

* .scheduleLayoutAnimation(): 강제적으로 ViewGroup을 다시 실행한다. (단 layoutAnimation이 설정되어 있어야 효과가있다.)

  ?? 이 애니메이션은 ViewGroup이 다음 번 배치될 때 실행 될 것이다. ?? 뭔소리??


LayoutAnimationListener

 - ViewGroup에 객체에 리스너를 부착할 수 있다. (콜백함수는 Animation리스너와 동일하다.)


코드

<!-- popin.xml-->

<set xmlns:android="http://schemas.android.com/apk/res/android"

  android:interpolator="@android:anim/accelerate_interpolator">

  <scale

    android:fromXScale="0.0" android:toXScale="1.0"

    android:fromYScale="0.0" android:toYScale="1.0"

    android:pivotX="50%"    

    android:pivotY="50%"

    android:duration="400" 

  />

</set> 

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

<!-- popinlayout.xml-->

<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"

  android:delay="0.5"

  android:animationOrder="reverse"

  android:animation="@anim/popin" 

 />

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

<!-- main.xml-->

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout 

  xmlns:android="http://schemas.android.com/apk/res/android"

  android:id="@+id/layout"

  android:orientation="vertical"

  android:layout_width="fill_parent"

  android:layout_height="fill_parent"

  android:layoutAnimation="@anim/popinlayout"

  >

 ...

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

ViewGroup을 사용한 코드 방식

 LayoutAnimationController layoutAni;

 layoutAni = AnimationUtils.loadLayoutAnimation(MyActivity.this, R.anim.popinlayout);

 viewGroup.setLayoutAnimation(layoutAni);




4.1.3 프레임 바이 프레임 애니메이션 만들고 이용하기

소개

- 프레임마다 이미지가 선택된 전통적인 셀기반 만화영화 기법과 가깝다.

- 프레임마다 백그라운드으로 사용되는 일련의 Drawable객체를 지정하고, 이것을 애니메이션 처리한다.


만들기

- XML draw 파일 만들기 

  Item 태그를 사용해서 애니메이션될 실제 이미지와 표시될 시간을 정의한다. 

  <item android:drawble="@drawable/rocekt1" android:duration="500"/>

  이것을 그룹화 animation-list 태그를 갖이 사용한다.

- .setBackgroudResource()를 사용해서 ImageView객체와 애니메이션(XML)을 배경으로 설정한다.

- .setBackgroudDrawable()을 사용해서 리소스 레퍼런스 대신 드로어블 인스턴스를 사용한다.

- 애니메이션의 start()메소드를 사용해서 애니메이션을 실행한다.


코드

<!-- animated_rocket.xml-->

<animation-list xmlns:android=”http://schemas.android.com/apk/res/android”

android:oneshot=”false”>

<item android:drawable=”@drawable/rocket1” android:duration=”500” />

<item android:drawable=”@drawable/rocket2” android:duration=”500” />

<item android:drawable=”@drawable/rocket3” android:duration=”500” />

</animation-list

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


ImageView image = (ImageView)findViewById(R.id.my_animation_frame);

image.setBackgroundResource(R.drawable.animated_rocket);

AnimationDrawable animation = (AnimationDrawable)image.getBackground(); animation.start();





4.2 애플리케이션 테마로 스킨 입히기

소개

테마는 애플리케이션이 일관된 LookAndFeel을 나타내도록 보장하는 방법


적용방법

 - manifest.xml에 application, activity 태트내에 다음 내용을 기록한다.

   android:theme="@android:style/Theme.Light" 


 - Theme.Black : 검은 배경에 하얀 전경 컨트롤 및 텍스트 사용한다.

 - Theme.Light : 하얀 배경에 어두운 테두리 및 텍스트를 사용한다.

 - Theme.Translucent : 부분적으로 투명한 폼을 사용한다.



4.3 고급 캔버스 그리기

캔버스?

 비티맵Bitmap이나 서피스Surface 오브젝트에 대한 실질적인 비트bit 컴포지션compositing을 처리하는 그리기를 하는 표면surface.

 canvas는 비트맵을 래핑하고 draw메서드를 노출한다.


그리기 기본 구성요소

 - Canvas: 하부에 있는 비트맵에 그리기 기본요소를 칠하는 그리기 메서드 제공

 - Paint : "브러시"라고도 불리며 Paint는 기본요소가 비트맵 위에 어떻게 그려지는지 지정할 수 있도록 함

 - Bitmap : 그리기가 수행되는 표면

6__canvas.PNG



안드로이드 그리기 API

 - 비트맵, 원, 선, 사각형, 텍스트 

 - 둥근 모서리 사각형

 - 투명도

 - gradient fill

 - anti-aliasing

 * 백터 그래픽스는 지원하지 않음

 * 전통적인 래스터 스타일의 다시 그리기 이동


Canvas와 Paint의 관계


7_canvasPaint.png





canvas.drawXXX(): 이것을 사용하여서 화면에 실제 그린다.

 drawARGB캔버스를 한가지 색으로 칠한다
 drawRGB캔버스를 한가지 색으로 칠한다. 
 drawArc

사각형 경계 영역 내에서 두 각 사이의 호를 그린다.

 drawBitmap캔버스에 비트맵을 그린다. 대상 크기를 지정하거나 변형을 위한 매트릭스를 이용하면 겉모습을 변경할 수 있다. 
 drawBitmapMesh매시를 이용해 비트맵을 그린다. 매시는 매시 안에 있는 점을 이동함으로써 대상의 겉모습을 조작할 수 있다 
 drawCircle주어진 점을 중심으로 지정된 반지름 크기의 원을 그린다. 
 drawLine두 점 사이에 선(혹은 일련의 선)을 그린다. 
 drawOval지정된 사각형을 경계로 하는 타원을 그린다. 
 drawPaint캔버스 전체를 지정된 페인트로 칠한다. 
 drawPath지정된 패스를 그린다. Path객체는 종종 그리기 기본요소 집합을 하나의 객체안에 담는데 이용한다. 
 drawPicture지정된 사각형 안에 Picture객체를 그린다. 
 drawPosText각 문자의 오프셋을 지정하는 텍스트 문자열을 그린다. 
 drawRect사각형을 그린다. 
 drawRoundRect둥근 모서리를 가진 사각형을 그린다. 
 drawText캔버스 위에 텍스트 문자열을 그린다. 텍스트 폰트, 크기, 색상, 랜더링 속성은 모두 Paint객체에서 설정한다. 
 drawTextOnPath지정된 패스를 따라 텍스트를 그린다. 
 drawVertices일련의 정점들로 지정된 여러 삼각 패치를 그린다. 
 drawColor캔버스를 한가지 색으로 칠한다. 



Paint 활용하기

paint클래스는 페인트브러쉬와 팔레트를 표현한다.

Paint객체를 수정해서 그릴때 이용되는 색상, 스타일, 폰트, 특수효과(투명,세이더,필터 등)를 제어할 수 있다.


.setColor() : 페인트 색상선택

.setStyle() : 객체의 윤곽, 일부을 채우고 등의 작업

.parseColor(): 해당 색상을 투명하게 처리

.setAlpha() : 불투명 처리

.setShader() : 솔리드 색상으로 칠해준다. 세이더의 가장 흔한 것으로 그레디언트로 채움은 것

 참고: ComposeShader, BitmapShader, GradientShader

.setMaskFilter(): 모서리에 알파채널변화로 효과주기. (BlueMaskFilter, EmbossMaskFilter)

.setColorfilter(): RGB채널 변화로 효과 주기(이것은 알파채널을 무시한다.)

 참고: ColorMatrixColorFilter, LightColorFilter, PorterDuffColorFilter

.setPathEffect(): 그리는 방법을 제어한다. 도형의 모서리 모양을 바꾸거나, 윤곽선을 제어한다.

 참고: CornerPathEffect, DashPathEffect, DiscretePathEffect, PathDashPathEffect, SumPathEffect, ComposePathEffect

.setXfermode(): 캔버스에 이미 그려진 것 위에 새로 칠하는 방법

 참고: AvoidXfermode, PixelXorfermode, PorterDuffXfermode

.setSubpixelText() : 그려지는 사선을 부드럽게 하기 위해 안티앨리어싱을 적용해 준다. (성능이 떨어뜨릴 수 있음)

.setAntiAlias() : 그려지는 사선을 부드럽게 하기 위해 안티앨리어싱을 적용해 준다. (성능이 떨어뜨릴 수 있음)


2D 그래피스를 위한 하드웨어 가속

- HW설정하기 : 2D 그래픽랜더링을 위해서 HW가속기를 사용하자. 

  myActivity.requestWindowFeature(Window.FATURE_OPENGL);

- 이 효과에 해당되지 않는 요소 존재한다. 특히 Path가 해당하지 않는다.

- invalidate()는 캔버스 랜더링을 새로 하도록 한다.00


캔버스 드로잉 베스트 프랙티스

- 하드웨어 가속을 고려해라 : 추천한다.

- 크기와 방향을 고려해라 : 뷰와 오버레이 만들때 해상도와 크기에 대한 고려를 해야 한다.

- 객체는 정적으로 한 번만 만들자 : 객체 생성 비용이 매우 비싸다. 페인트, 패스, 세이더는 한번 만들어서 계속 사용

- onDraw는 비싸다는 사실을 기억해라 : 캔버스를 다시 그리는 일을 최소화 한다. 아래 3가지가 팀이다.

- 캔버스 변환을 이용해라 :캔버스내의 엘리먼트를 수정하지 말고 캔버스를 변환하도록 하라.

- 애니메이션을 이용해라 : 뷰를 직접 그리기 보다는 미리 정의된 애니메이션을 이용해라

- 비트맵과 나인패치를 이용해라: 이미지 정적이용시 직접 그리기보다는 이것을 사용하라.


맵 오버레이에 생명력 불어넣기

- Skip합니다.


4.5 SurfaceView 소개

SurfaceView 소개

 - SurfaceView는 뷰 계층 구조 내에서 드로잉 전용 공간을 제공하는 뷰에 대한 특수한 서브클래스 이다.

 - 그 목적은 시스템의 뷰 계층 구조가 그릴 준비가 될 때까지 애플리케이션이 기다리지 않도록 하기 위해

   애플리케이션의 보조 쓰레드에게 이러한 드로잉 공간을 제공하는데 있다. 

 - 이 것은 View파생 클래스와 정확히 동일한 방식으로 이동한다. (애니메니션, 레이아웃 등 사용 가능)

 - Canvas 메소드를 이용한 대부분의 지원하며, OpenGL ES 라이브러리를 완벽히 지원한다.


용도:

 - 이것은 리소스가 많이 들거나 빠른 업데이트, 높은 프레임 속도를 요구할 때 특히 유용하다.

 - 단, 메모리의 소비가 발생될 수 있기에 사용시 신중을 기해야 한다. 


사용예:

 - 구글 어쓰

 - 인터렉티브 게임에 탑재된 3D 이미지 표시

 - 실시간 카메라 미리보기


SurfaceView 컨트롤 만들기

주요 코드 설명

 SurfaceHolder.callback

 - 상속받은 나의 클래스에는 실제 SurfaceView가 있지 않다 이 SurfaceHolder를 통해서 연결되지고 

 - 기반이 되는 서피스의 생성, 변경, 종료에 대한 이벤트를 알려 주는 인터페이스 

 - 이것은 서피스의 이벤트를 Callback형태로 제공해서 내가 언제 drawing할지 알게해준다.

 getHolder(): surfaceHolder 얻어 온다. 

 holder.addCallBack(this) : 내가 만든 객체가 SurfaceHolder 콜백을 수신하고자 한다는 것을 SurfaceHolder에게 알림

 surfaceHolder.lockCanvas(): 서피스를 잠그고 그리기 위한 캔버스를 리턴 받는다. 이제 우린 그릴 캔버스를 확보한 것이며, 

 이 캔버스는 이전 상태를 갖고 있기에 drawColor()로 초기색으로 변경하거나, drawBitmap()로 배경을 재설정해야할 것이다.

 sufaceHolder.unlockCanvasAndPost(): 캔버스 락을 풀고 현재 이미지를 랜더링한다.  


CallBack 메소드

 init() : 새로운 SurfaceHolder를 만들고 이 클래스를 SurfaceHolder의 콜백으로 지정한다.

 resume() : 그래픽 업데이트 스레드를 만들기 시작한다.

 pause() : 그래픽스 업데이트 스레드를 종료한다.

 surfaceCreated() : 인너 클래스의 child Thread를 실행한다. 

 surfaceDestroyed(): 서피스를 종료을 위해서 pause()를 호출한다. 

 surfaceChanged() : 서피스의 크기변경에 대응하는 메소드


MySurfaceViewThread 

  - 인너클래스로  실제 작업을 수행하는 Child Thread와 Canvas Draw를 처리하는 메소드를 포함한 클래스

  run(): 오버라이드해서 스레드가 정지될 때까지 드로잉 루프를 반복한다. 

  requestExitAndWait() : 스레드를 완료 상태로 표시하고 join()를 통해서 메인 스레드에 결합한다. (실제 화면에 그려진다.)

  onWindowResize() : 서피스 크기 변화를 준다.

 aa_1.surface.png

 * OpenGL ES를 사용한 SurfaceView 3D 컨트롤은 APIDemo의 GLSurfaceView를 참조할 것.



public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback {

  private SurfaceHolder holder;
  private MySurfaceViewThread mySurfaceViewThread;
  private boolean hasSurface;

  MySurfaceView(Context context) {
    super(context);
    init();
  }
 
  private void
init() {
    // Create a new SurfaceHolder and assign this class as its callback.
    holder =
getHolder();
    holder.
addCallback(this);
    hasSurface = false;
  }

  public void resume() {
    // Create and start the graphics update thread.
    if (mySurfaceViewThread == null) {
     
mySurfaceViewThread = new MySurfaceViewThread();

      if (hasSurface == true)
       
mySurfaceViewThread.start();
    }
  }

  public void pause() {
    // Kill the graphics update thread
    if (mySurfaceViewThread != null) {
      mySurfaceViewThread.
requestExitAndWait();
      mySurfaceViewThread = null;
    }
  }

  public void surfaceCreated(SurfaceHolder holder) {
    hasSurface = true;
    if (mySurfaceViewThread != null)
     
mySurfaceViewThread.start();
  }

  public void surfaceDestroyed(SurfaceHolder holder) {
    hasSurface = false;
   
pause();
  }

  public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    if (mySurfaceViewThread != null)
      mySurfaceViewThread.
onWindowResize(w, h);
  }

  //--------------------------------------------------------------------------

  class MySurfaceViewThread extends Thread {
    private boolean done;

    MySurfaceViewThread() {
      super();
      done = false;
    }

    @Override
    public void
run() {
      SurfaceHolder surfaceHolder = holder;
     
      // Repeat the drawing loop until the thread is stopped.
     
while (!done) {
        // Lock the surface and return the canvas to draw onto.
        Canvas
canvas = surfaceHolder.lockCanvas();

        // TODO: Draw on the canvas!

        // Unlock the canvas and render the current image.
       
surfaceHolder.unlockCanvasAndPost(canvas);
      }
    }

    public void requestExitAndWait() {
      // Mark this thread as complete and combine into
      // the main application thread.
     
done = true;
      try {
       
join();
      } catch (InterruptedException ex) { }
    }

    public void onWindowResize(int w, int h) {
      // Deal with a change in the available surface size.
    }
  }
}

 

 

 

 

5. 인터랙티브한 컨트롤 만들기



interactive.PNG

 


Touch Key Event

 - onTouchEvent()

 - Start, Move, End

 - RawX, RawY  X, Y

 - getPressure() 터치의 정도의 정보도 확보 가능함 (0:압력 없음, 1:보통압력)

 - getSize() 접촉면의 정규화 크기를 측정할 수 있다. (0: 매우 정밀 1:굵은 터치)

 - getHistory() 움직임을 추적을 도와 준다. 과거의 값과 현재 발생된 모든 이벤트 저장

 - getHistorical*() 위치 인덱스를 주면 각각의 시간, 압력, 면적, 위치를 얻을 수 있다.

 - Sample 예제: FingerPaint

Key Event

 - onKeyup(), onKeyDown()

 - Down, Up, Repeat(?)

 - 포함되는 키: 키보드, D패드, 볼륨, 뒤로가기, 전화걸기, 전화끊기

 - 미포함 키: 홈 (하나의 앱에 묶이지 않게 하기 위해 용도를 예약한 것 때문임)

 - keyCode메개변수: 눌려진 키 값

 - keyEvent매개변수: 특정키의 수행을 돕기 위해서 기능, 시프트, 심벌메타키를 감지하는 메서드 제공 

   또한 KeyDown,KeyUp도 감지한다.

TrackBall Event

 - onTrackballEvent()

 - MotionEvent매개변수 : 마지막 트랙볼의 움직임에 대한 상대적인 움직임 값을 x, y로 제공

 - D패드를 사용해도 동일한 움직임을 나타낸다.(??)


리스너 부착해서 이용하기

 - 해당 뷰에 .set*Listener를 사용하면 서브클래싱하지 않아도 된다.