Android Programming Complete Guide 1 Sound Edit Edit

  • Slides: 40
Download presentation
커스텀 위젯 안드로이드 프로그래밍 정복(Android Programming Complete Guide)

커스텀 위젯 안드로이드 프로그래밍 정복(Android Programming Complete Guide)

1. 기존 위젯 변형 § Sound. Edit 예제 • 기존 컨트롤 수정 방법이며, Edit.

1. 기존 위젯 변형 § Sound. Edit 예제 • 기존 컨트롤 수정 방법이며, Edit. Text 클 래스를 확장하여 키 입력시마다 소리를 내는 입력 위젯을 만든다. • 커스텀 위젯 클래스는 별도의 소스 파일 에 따로 작성는 것이 관리에 편리하다. • Edit. Text 클래스를 확장하여 Sound. Edit. Widget 클래스를 파생 시켰으 며, 생성자는 세 벌을 모두 정의하였다. - XML에서 전개 시 2개의 인수를 취하는 생 성자가 호출 - new 연산자로 생성 시 context 인수만 취하는 첫 번째 생성자가 호출된다. • 범용성을 높이기 위해서는 모든 생성자 를 다 구비하는 것이 바람직하다. - 예제에는 두 번째 생성자만 사용됨. Widget/Sound. Edit. java public class Sound. Edit extends Activity { public void on. Create(Bundle saved. Instance. State) { super. on. Create(saved. Instance. State); set. Content. View(R. layout. soundedit); } } class Sound. Edit. Widget extends Edit. Text { Sound. Pool m. Pool = null; int m. Click; public Sound. Edit. Widget(Context context) { super(context); init(context); } public Sound. Edit. Widget(Context context, Attribute. Set attrs) { super(context, attrs); init(context); } public Sound. Edit. Widget(Context context, Attribute. Set attrs, int def. Style) { super(context, attrs, def. Style); init(context); } void init(Context context) { m. Pool = new Sound. Pool(1, Audio. Manager. STREAM_MUSIC, 0); m. Click = m. Pool. load(context, R. raw. click, 1); } protected void on. Text. Changed(Char. Sequence text, int start, int before, int after) { if (m. Pool != null) { m. Pool. play(m. Click, 1, 1, 0, 0, 1); } } } 4/40

1. 기존 위젯 변형 § Sound. Edit 예제 • 리니어 안에 안내 텍스트 뷰

1. 기존 위젯 변형 § Sound. Edit 예제 • 리니어 안에 안내 텍스트 뷰 하나와 커스텀 사운드 에디트를 배치한다. • XML 파일에 커스텀 위젯을 배치 시 엘리먼트 이름에 위젯의 클래스 명을 적되 커스텀 위젯은 풀 패키지 명을 다 적어야 한다. • Sound. Edit. Widget도 Edit. Text의 파생 클래스이며 View의 파생 클래스이므로 상위 클래스가 제공 하는 모든 속성 사용이 가능하다. - on. Key. Down : 16진수 입력 조절 가능 - on. Draw : 배경 이미지 삽입 가능 Widget/soundedit. xml <? xml version="1. 0" encoding="utf-8"? > <Linear. Layout xmlns: android="http: //schemas. android. com/apk/res/android" android: orientation="vertical" android: layout_width="fill_parent" android: layout_height="fill_parent“ > <Text. View android: layout_width="fill_parent" android: layout_height="wrap_content" android: text=“문자를 입력하시면 소리가 납니다. ” /> <exam. Widget. Sound. Edit. Widget android: layout_width="fill_parent" android: layout_height="wrap_content" android: text. Size=“ 12 pt” /> </Linear. Layout> [ Sound. Edit 예제 실행 결과 ] 7/40

1. 기존 위젯 변형 • Num. Edit. Widget 클래스는 Linear. Layout을 상속 받아 차일드를

1. 기존 위젯 변형 • Num. Edit. Widget 클래스는 Linear. Layout을 상속 받아 차일드를 일 렬로 배치 가능하다. • 클래스의 멤버로 m. Edit, m. Text를 선언 하고 init에서 두 객체를 생성하여 리니 어에 추가한다. • 두 위젯의 상호 동작을 정의한다. - 에디트 내용 변경 시 문자열의 길이를 텍스 트 뷰에 출력. - 위젯 자신이 Text. Watcher 리스너 구현, m. Edit 텍스트의 변경 리스너를 this로 지정. - 리스너의 on. Text. Changed 메서드에서 문자 열 변경 시 길이를 새로 조사하여 텍스트 뷰에 출력. • 문자열 변경 시점을 구한다는 점에서 이전 예제와 비슷. - Sound. Edit 예제 : Text. View의 메서드 - Num. Edit 예제 : Text. Watcher 인터페이스의 메서드 • Edit. Text를 멤버로 포함할 뿐이므로 on. Text. Changed 메서드를 재정의할 수 없다. • 와처를 등록, 이를 통해 문자열 변경 시 점을 알아내야 한다. Widget/Num. Edit. java public class Num. Edit extends Activity { public void on. Create(Bundle saved. Instance. State) { super. on. Create(saved. Instance. State); set. Content. View(R. layout. numedit); } } class Num. Edit. Widget extends Linear. Layout implements Text. Watcher { Edit. Text m. Edit; Text. View m. Text; public Num. Edit. Widget(Context context) { super(context); init(); } public Num. Edit. Widget(Context context, Attribute. Set attrs) { super(context, attrs); init(); } void init() { set. Orientation(Linear. Layout. VERTICAL); m. Edit = new Edit. Text(get. Context()); m. Text = new Text. View(get. Context()); m. Text. set. Text("Now Length : 0 Characters"); Linear. Layout. Params param = new Linear. Layout. Params( Layout. Params. FILL_PARENT, Layout. Params. WRAP_CONTENT); add. View(m. Edit, param); add. View(m. Text, param); m. Edit. add. Text. Changed. Listener(this); } public void after. Text. Changed(Editable s) { } public void before. Text. Changed(Char. Sequence s, int start, int count, int after) { } public void on. Text. Changed(Char. Sequence s, int start, int before, int count) { m. Text. set. Text("Now Length : " + s. length() + " Characters") } } 9/40

1. 기존 위젯 변형 § 세 개 이상의 위젯을 묶어 복잡한 기능 수행이 가능하며,

1. 기존 위젯 변형 § 세 개 이상의 위젯을 묶어 복잡한 기능 수행이 가능하며, Relative. Layout, Table. Layout을 확장하여원하는 모양으로 배치할 수 있다. § 합쳐진 그룹 위젯에 대해 여백이나 마진, 배경색 등 조정 가능하며, 커스텀 속성을 통해 내부 위젯의 속성 역시 조정 가능하다. § 포함되는 위젯의 개수가 많고 배치가 복잡하면 코드에서 생성, 배치가 번거로우므로 XML 문서로 뷰 그룹을 디자인하여 배치와 속성을 지정해 놓고 코드에서 레이아웃을 전 개하여 배치하면 된다. § numeditwidget 예제 Widget/numeditwidget. xml <? xml version="1. 0" encoding="utf-8"? > <Linear. Layout xmlns: android="http: //schemas. android. com/apk/res/android" android: orientation="vertical" android: layout_width="fill_parent" android: layout_height="fill_parent” > <Edit. Text android: id="@+id/limedit_edit" android: layout_width="fill_parent" android: layout_height="wrap_content” /> <Text. View android: id="@+id/limedit_text" android: layout_width="fill_parent" android: layout_height="wrap_content" android: text="Now Length : 0 Characters” /> </Linear. Layout> void init() { Layout. Inflater inflater = (Layout. Inflater)get. Context(). get. System. Service( Context. LAYOUT_INFLATER_SERVICE); inflater. inflate(R. layout. numeditwidget, this, true); m. Edit = (Edit. Text)find. View. By. Id(R. id. limedit_edit); m. Text = (Text. View)find. View. By. Id(R. id. limedit_text); . . 10/40

1. 기존 위젯 변형 § attribute 예제 • 리니어 안에 버튼 위젯을 배치, 각

1. 기존 위젯 변형 § attribute 예제 • 리니어 안에 버튼 위젯을 배치, 각 속성을 적용하고 Text 속성은 string. xml에 정의한 후 참조로 지 정한다. • 각 속성들은 aapt에 의해 컴파일되며 전개자가 Button 객체를 생성할 때 생성자로 전달한다. • attr. Button은 Button에서 파생, 생성자에서 attrs 인수를 확인할 뿐 표준 버튼과 동작이 동일. • 전개자에 의해 생성되므로 두 번째 생성자만 정의. Widget/attribute. xml Widget/Attribute. java <? xml version="1. 0" encoding="utf-8"? > <Linear. Layout xmlns: android="http: //schemas. android. com/apk/res/android" android: orientation="vertical" android: layout_width="fill_parent" android: layout_height="fill_parent"> <exam. Widget. Attr. Button android: id="@+id/attrbtn" android: layout_width="wrap_content" android: layout_height="wrap_content" android: text="@string/attrbtn" android: text. Size="15 pt" android: text. Color="#ff 0000"/> <Edit. Text android: id="@+id/attredit" android: layout_width="fill_parent" android: layout_height="wrap_content"/> </Linear. Layout> public class Attribute extends Activity { public void on. Create(Bundle saved. Instance. State) { super. on. Create(saved. Instance. State); set. Content. View(R. layout. attribute); Attr. Button btn = (Attr. Button)find. View. By. Id(R. id. attrbtn); Edit. Text edit = (Edit. Text)find. View. By. Id(R. id. attredit); edit. set. Text(btn. m. Text); } } class Attr. Button extends Button { String m. Text = ""; public Attr. Button(Context context, Attribute. Set attrs) { super(context, attrs); int i; String Name; String Value; for (i=0; i<attrs. get. Attribute. Count(); i++) { Name = attrs. get. Attribute. Name(i); Value = attrs. get. Attribute. Value(i); m. Text += (Name + " = " + Value + "n"); } } } 12/40

1. 기존 위젯 변형 v 사운드 속성 § 커스텀 위젯도 자신만의 속성을 정의하여 사용

1. 기존 위젯 변형 v 사운드 속성 § 커스텀 위젯도 자신만의 속성을 정의하여 사용 가능하다. § Sound. Edit 2 예제 • Sound. Edit 예제를 확장, 소리의 종류, 볼륨, 재생 속도 등을 속성으로 제공한다. • 커스텀 위젯의 속성은 attrs. xml에 정의하고, res/values 폴더 안에 파일을 작성한다. (파일명은 사용자가 원하는 대로 지정 가능하다. ) Widget/values/attrs. xml <? xml version="1. 0" encoding="utf-8"? > <resources> <declare-styleable name="Sound. Edit. Widget 2"> <attr name="sound" format="integer" /> <attr name="volume" format="float" /> <attr name="speed" format="float" /> </declare-styleable> </resources> public static final class styleable { public static final int[] Sound. Edit. Widget 2 = { 0 x 7 f 010000, 0 x 7 f 010001, 0 x 7 f 010002 }; public static final int Sound. Edit. Widget 2_sound = 0; public static final int Sound. Edit. Widget 2_speed = 2; public static final int Sound. Edit. Widget 2_volume = 1; }; • declare-styleable 엘리먼트의 name 속성에 위젯의 이름 작성. • attr 엘리먼트의 name에 속성의 이름, format에 속성의 타입 지정. - ingeger, float, string, dimension, color 등의 타입 지정 - enum 열거형으로 속성값에 개별 이름 설정 가능. • 문서에 속성을 정의해 놓으면 R. java에 styleable 클래스가 자동으로 생성된다. • 클래스 명과 같은 이름으로 속성의 배열이 작성되며 각 속성의 첨자가 0부터 순서대로 부여된다. • 생성자에서는 이 값들을 참조하여 XML 문서의 속성을 읽는다. 14/40

1. 기존 위젯 변형 • 커스텀 속성에 대한 네임 스페이스는 표준과 유사하되 마지막 부분을

1. 기존 위젯 변형 • 커스텀 속성에 대한 네임 스페이스는 표준과 유사하되 마지막 부분을 프로젝트의 패키지명으로 수정하여 사용한다. • 세 개의 커스텀 위젯을 배치하되 하나는 sound를 2로 지정했고, 하나는 속도와 볼륨을 절반으로 줄였다. Widget/soundedit 2. xml <? xml version="1. 0" encoding="utf-8"? > <Linear. Layout xmlns: android="http: //schemas. android. com/apk/res/android" xmlns: custom="http: //schemas. android. com/apk/res/exam. Widget" android: orientation="vertical" android: layout_width="fill_parent" android: layout_height="fill_parent" > <exam. Widget. Sound. Edit. Widget 2 android: layout_width="fill_parent" android: layout_height="wrap_content" /> <exam. Widget. Sound. Edit. Widget 2 android: layout_width="fill_parent" android: layout_height="wrap_content" custom: sound="2" custom: speed="0. 5" custom: volume="0. 5" /> </Linear. Layout> [ Sound. Edidt 2 예제 실행 결과 ] 15/40

1. 기존 위젯 변형 • 생성자는 attrs 배열을 init 메서드로 전달하되 new 연산자로 직접

1. 기존 위젯 변형 • 생성자는 attrs 배열을 init 메서드로 전달하되 new 연산자로 직접 생성 시 null이 전달되며, init 메 서드는 전개자로부터 호출 시 attrs에 저장된 속성값을 읽어 위젯에 적용한다. • obtain. Styled. Attributes 메서드로 R. java에 정의된 속성의 배열 전달 시 Typed. Array 객체로 리턴된 다. Widget/soundedit 2. java - 1 Widget/soundedit 2. java - 2 public class Sound. Edit 2 extends Activity { public void on. Create(Bundle saved. Instance. State) { super. on. Create(saved. Instance. State); set. Content. View(R. layout. soundedit 2); } } void init(Context context, Attribute. Set attrs) { m. Pool = new Sound. Pool(1, Audio. Manager. STREAM_MUSIC, 0); m. Click 1 = m. Pool. load(context, R. raw. click, 1); m. Click 2 = m. Pool. load(context, R. raw. click 2, 1); m. Sound = m. Click 1; if (attrs != null) { Typed. Array ar = context. obtain. Styled. Attributes(attrs, R. styleable. Sound. Edit. Widget 2); m. Volume = ar. get. Float(R. styleable. Sound. Edit. Widget 2_volume, 1. 0 f); m. Speed = ar. get. Float(R. styleable. Sound. Edit. Widget 2_speed, 1. 0 f); m. Sound = ar. get. Int(R. styleable. Sound. Edit. Widget 2_sound, m. Click 1); ar. recycle(); } } class Sound. Edit. Widget 2 extends Edit. Text { Sound. Pool m. Pool = null; int m. Click 1, m. Click 2; int m. Sound; float m. Volume = 1. 0 f; float m. Speed = 1. 0 f; public Sound. Edit. Widget 2(Context context) { super(context); init(context, null); } protected void on. Text. Changed(Char. Sequence text, int start, int before, int after) { if (m. Pool != null) { m. Pool. play(m. Sound, m. Volume, 0, 0, m. Speed); } } public Sound. Edit. Widget 2(Context context, Attribute. Set attrs) { super(context, attrs); init(context, attrs); } public Sound. Edit. Widget 2(Context context, Attribute. Set attrs, int def. Style) { super(context, attrs, def. Style); init(context, attrs); } } 16/40

2. 새로운 위젯 § Measuring 예제 소스 코드 Widget/Measuring. java - 1 public class

2. 새로운 위젯 § Measuring 예제 소스 코드 Widget/Measuring. java - 1 public class Measuring extends Activity { public void on. Create(Bundle saved. Instance. State) { super. on. Create(saved. Instance. State); set. Content. View(R. layout. measuring); final Meas. View meas = (Meas. View)find. View. By. Id(R. id. meas); final Edit. Text text = (Edit. Text)find. View. By. Id(R. id. text); text. post. Delayed(new Runnable() { public void run() { text. set. Text(meas. m. Result); } }, 1000); } } class Meas. View extends View { String m. Result = ""; public Meas. View(Context context, Attribute. Set attrs, int def. Style) { super(context, attrs, def. Style); } public Meas. View(Context context, Attribute. Set attrs) { super(context, attrs); } public Meas. View(Context context) { super(context); } protected void on. Draw(Canvas canvas) { canvas. draw. Color(Color. RED); } Widget/Measuring. java - 2 protected void on. Measure(int width. Measure. Spec, int height. Measure. Spec) { int w. Mode, h. Mode; int w. Spec, h. Spec; int Width, Height; Width = 150; Height = 80; w. Mode = Measure. Spec. get. Mode(width. Measure. Spec); w. Spec = Measure. Spec. get. Size(width. Measure. Spec); h. Mode = Measure. Spec. get. Mode(height. Measure. Spec); h. Spec = Measure. Spec. get. Size(height. Measure. Spec); switch (w. Mode) { case Measure. Spec. AT_MOST: Width = Math. min(w. Spec, Width); break; case Measure. Spec. EXACTLY: Width = w. Spec; break; case Measure. Spec. UNSPECIFIED: break; } switch (h. Mode) { case Measure. Spec. AT_MOST: Height = Math. min(h. Spec, Height); break; case Measure. Spec. EXACTLY: Height = h. Spec; ; break; case Measure. Spec. UNSPECIFIED: break; } 20/40

2. 새로운 위젯 • 수직 리니어 안에 수평 리니어와 에디트 배치하였으며, 에디트는 배치 결과를

2. 새로운 위젯 • 수직 리니어 안에 수평 리니어와 에디트 배치하였으며, 에디트는 배치 결과를 문자열로 확인하기 위한 장치이다. • 수평 리니어는 높이 100 픽셀의 노란색 배경이 지정되어 있으며, 이 안에 폭 100 픽셀의 버튼을 양쪽에 배치, 중간에 Meas. View를 끼워넣었다. Widget/measuring. xml <? xml version="1. 0" encoding="utf-8"? > <Linear. Layout xmlns: android="http: //schemas. android. com/apk/res/android" android: orientation="vertical" android: layout_width="fill_parent" android: layout_height="fill_parent"> <Linear. Layout android: orientation="horizontal" android: layout_width="fill_parent" android: layout_height="100 px" android: background="#ffff 00"> <Button android: layout_width="100 px" android: layout_height="wrap_content" android: text="Left"/> <exam. Widget. Meas. View android: id="@+id/meas" android: layout_width="wrap_content" android: layout_height="wrap_content"/> <Button android: layout_width="100 px" android: layout_height="wrap_content" android: text="Right"/> </Linear. Layout> <Edit. Text android: id="@+id/text" android: layout_width="fill_parent" android: layout_height="wrap_content" android: text. Size="7 pt"/> </Linear. Layout> [ Measuring 예제 실행 결과 ] 22/40

2. 새로운 위젯 § measuring 2 예제 • Meas. View의 폭과 높이를 wrap_content에서 100

2. 새로운 위젯 § measuring 2 예제 • Meas. View의 폭과 높이를 wrap_content에서 100 px, 50 px로 강제 지정한다. § measuring 3 예제 • 양쪽 버튼 2개를 없애고 Meas. View만 남겨두되 폭과 높이를 fill_parent로 지정한다. § measuring 4 예제 • 버튼을 남겨두고 Meas. View의 폭과 높이를 fill_parent로 지정한다. Widget/measuring 3. xml Widget/measuring 2. xml <exam. Widget. Meas. View android: id="@+id/meas" android: layout_width="100 px" android: layout_height="50 px”/> [ Measuring 2 예제 실행 결과 ] <Linear. Layout android: orientation="horizontal" android: layout_width="fill_parent" android: layout_height="100 px" android: background="#ffff 00"> <exam. Widget. Meas. View android: id="@+id/meas" android: layout_width="fill_parent" android: layout_height="fill_parent"/> [ Measuring 3 예제 실행 결과 ] [ Measuring 4 예제 실행 결과 ] 23/40

2. 새로운 위젯 § 차일드가 부모의 제안을 거부할 수 있듯 부모도 차일드의 요청을 다

2. 새로운 위젯 § 차일드가 부모의 제안을 거부할 수 있듯 부모도 차일드의 요청을 다 들어주지 못하는 경 우가 있다. § 레이아웃이 복잡하고 차일드 수가 많아져 한번의 대화로 완벽한 배치를 만들어 내기 어 려우면 여러 차일드에게 반복적으로 질문을 날려 모두가 OK할 때까지 조정을 반복. § measuring 5 예제 • 세 위젯 모두 layout_weight 속성을 지정하여 폭을 나누어 가지도록 하였다. Widget/measuring 5. xml <Linear. Layout android: orientation="horizontal" android: layout_width="fill_parent" android: layout_height="100 px" android: background="#ffff 00"> <Button android: layout_width="wrap_content" android: layout_height="wrap_content" android: text="Left" android: layout_weight="1"/> <exam. Widget. Meas. View android: id="@+id/meas" android: layout_width="wrap_content" android: layout_height="wrap_content" android: layout_weight="1"/> <Button android: layout_width="wrap_content" android: layout_height="wrap_content" android: text="Right" android: layout_weight="1"/> [ Measuring 5 예제 실행 결과 ] 25/40

2. 새로운 위젯 v 무지개 프로그래스 § 무지개색으로 작업의 진행 경과를 보여주는 수직 프로그래스

2. 새로운 위젯 v 무지개 프로그래스 § 무지개색으로 작업의 진행 경과를 보여주는 수직 프로그래스 바 위젯이다. § 기존 클래스를 상속받거나 조합해서는 만들 수 없으며 최상위의 View를 상속받아 처음 부터 다시 만들어야 한다. § 표준 프로그래스 바는 수평만 가능하므로 상속받아도 수직으로는 불가능하다. § Rainbow. Test 예제 Widget/Rainbow. Test. java - 2 m. Handler = new Handler() { public void handle. Message(Message msg) { int Pos; Pos = m. Progress. get. Pos(); if (Pos < m. Progress. get. Max()) { m. Progress. set. Pos(Pos+1); m. Handler. send. Empty. Message. Delayed(0, 100); } else { Toast. make. Text(Rainbow. Test. this, "Completed", 0). show(); m. Progress. set. Pos(0); } } }; Widget/Rainbow. Test. java - 1 public class Rainbow. Test extends Activity { Rainbow. Progress m. Progress; Handler m. Handler; public void on. Create(Bundle saved. Instance. State) { super. on. Create(saved. Instance. State); set. Content. View(R. layout. rainbowtest); m. Progress = (Rainbow. Progress)find. View. By. Id(R. id. progress); Button btn = (Button)find. View. By. Id(R. id. start); btn. set. On. Click. Listener(new Button. On. Click. Listener() { public void on. Click(View v) { if (m. Progress. get. Pos() == 0) { m. Progress. set. Pos(0); m. Handler. send. Empty. Message(0); } } }); } } class Rainbow. Progress extends View { int m. Max; int m. Pos; int m. Prog. Height; Linear. Gradient m. Shader; 26/40

2. 새로운 위젯 § Rainbow. Test 예제 Widget/Rainbow. Test. java - 3 public Rainbow.

2. 새로운 위젯 § Rainbow. Test 예제 Widget/Rainbow. Test. java - 3 public Rainbow. Progress(Context context, Attribute. Set attrs, int def. Style) { super(context, attrs, def. Style); init(); } public Rainbow. Progress(Context context, Attribute. Set attrs) { super(context, attrs); init(); } public Rainbow. Progress(Context context) { super(context); init(); } Widget/Rainbow. Test. java – 4 int get. Pos() { return m. Pos; } protected void on. Draw(Canvas canvas) { if (m. Shader == null) { m. Prog. Height = get. Height() - get. Padding. Top() – get. Padding. Bottom(); int[] colors = { Color. RED, Color. YELLOW, Color. GREEN, Color. BLUE }; m. Shader = new Linear. Gradient(0, 0, 0, m. Prog. Height, colors, null, Tile. Mode. CLAMP); } void init() { m. Max = 100; m. Pos = 0; } Rect. F rt = new Rect. F(); rt. left = get. Padding. Left(); rt. right = get. Width() - get. Padding. Right(); rt. bottom = get. Padding. Top() + m. Prog. Height; rt. top = rt. bottom - m. Prog. Height * m. Pos / m. Max; void set. Max(int a. Max) { if (a. Max > 0) { m. Max = a. Max; invalidate(); } } Paint fillpnt = new Paint(); fillpnt. set. Shader(m. Shader); canvas. draw. Rect(rt, fillpnt); rt. top = get. Padding. Top(); Paint outpnt = new Paint(); outpnt. set. Color(Color. WHITE); outpnt. set. Style(Paint. Style. STROKE); canvas. draw. Rect(rt, outpnt); int get. Max() { return m. Max; } void set. Pos(int a. Pos) { if (a. Pos < 0 || a. Pos > m. Max) { return; } m. Pos = a. Pos; invalidate(); } } 27/40

2. 새로운 위젯 § Rainbow. Test 예제 Widget/Rainbow. Test. java – 5 protected void

2. 새로운 위젯 § Rainbow. Test 예제 Widget/Rainbow. Test. java – 5 protected void on. Measure(int width. Measure. Spec, int height. Measure. Spec) { int Width = 26, Height = 100; • 일정 범위에서 현재 위치값을 표시하는 것 이 위젯의 주요 임무이므로 범위와 현재 위치인 m. Max, m. Pos를 멤버로 가진다. switch (Measure. Spec. get. Mode(width. Measure. Spec)) { case Measure. Spec. AT_MOST: Width = Math. min(Measure. Spec. get. Size(width. Measure. Spec), Width); break; case Measure. Spec. EXACTLY: Width = Measure. Spec. get. Size(width. Measure. Spec); break; } • 범위의 최소값은 무조건 0으로 고정한다. • 두 멤버는 init에서 각각 100, 0으로 초기 화되며 외부에서 set. Max, set. Pos 메서드로 변경 가능하다. • set* 메서드는 규칙에 맞지 않는 값은 거부 하여 스스로를 방어한다. switch (Measure. Spec. get. Mode(height. Measure. Spec)) { case Measure. Spec. AT_MOST: Height = Math. min(Measure. Spec. get. Size(height. Measure. Spec), Height); break; case Measure. Spec. EXACTLY: Height = Measure. Spec. get. Size(height. Measure. Spec); break; } - set. Max : 1이상. - set. Pos : 0 ~ m. Max 범위 내. • 프로그래스 막대를 그리는 코드는 모드 on. Draw에 작성되어 있다. • 최초 호출 시 패딩을 고려하여 높이를 계 산해 놓고 이 높이를 가득 채우는 그러데 이션 셰이더를 생성해 놓는다. set. Measured. Dimension(Width, Height); } } • 나머지는 단순 좌표 계산과 그리기 코드이 다. 28/40

2. 새로운 위젯 • 메인 레이아웃에 프로그래스와 버튼을 배치해 놓고 타이머로 작업을 진행시킨다. -

2. 새로운 위젯 • 메인 레이아웃에 프로그래스와 버튼을 배치해 놓고 타이머로 작업을 진행시킨다. - 프로그래스 위젯에 패딩 속성을 지정했는데, 코드에서는 패딩만큼 안쪽 여백을 둬야 한다. - on. Draw에서 셰이더와 외곽선 좌표를 구하는데 패딩을 고려하고 있다. - 마진의 경우 위젯 바깥쪽의 여백이므로 고려하지 않아도 좋다. - 액티비티는 버튼을 누를 때 핸드러를 호출하여 0. 01초에 한번씩 프로그래스를 진행, Max에 도달하면 작업을 중지한다. Widget/rainbowtest. xml <? xml version="1. 0" encoding="utf-8"? > <Linear. Layout xmlns: android="http: //schemas. android. com/apk/res/android" android: orientation="vertical" android: layout_width="fill_parent" android: layout_height="fill_parent" > <exam. Widget. Rainbow. Progress android: id="@+id/progress" android: layout_width="wrap_content" android: layout_height="wrap_content" android: padding. Left="5 px" android: padding. Top="10 px" android: padding. Right="5 px" android: padding. Bottom="10 px" /> <Button android: id="@+id/start" android: layout_width="wrap_content" android: layout_height="wrap_content" android: text="Start" /> </Linear. Layout> [ Rainbow. Test 예제 실행 결과 ] 29/40

3. 여러 가지 뷰 § Scroll. View. Test 예제 • 수직으로 긴 커스텀 뷰를

3. 여러 가지 뷰 § Scroll. View. Test 예제 • 수직으로 긴 커스텀 뷰를 스크롤한다. • 메인 레이아웃에는 스크롤 뷰 하나만 배치 , 커스텀 뷰는 실행중에 생성하여 스크롤 뷰의 차일드로 추가한다. • Color. View는 특별한 기능 없이 점점 진해 지는 그러데이션을 보여준다. • 뷰의 크기는 on. Measure에서 폭 500, 높이 1024로 강제 지정했다. [ Scroll. View. Test 예제 실행 결과 ] Widget/scrollviewtest. xml <? xml version="1. 0" encoding="utf-8"? > <Scroll. View xmlns: android="http: //schemas. android. com/apk/res/android" android: id="@+id/scr" android: layout_width="fill_parent" android: layout_height="wrap_content“ > </Scroll. View> Widget/Scroll. View. Test. java public class Scroll. View. Test extends Activity { public void on. Create(Bundle saved. Instance. State) { super. on. Create(saved. Instance. State); set. Content. View(R. layout. scrollviewtest); Scroll. View svw = (Scroll. View)find. View. By. Id(R. id. scr); //svw. set. Scroll. Bar. Style(View. SCROLLBARS_INSIDE_INSET); //svw. set. Vertical. Fading. Edge. Enabled(false); //svw. set. Vertical. Scroll. Bar. Enabled(false); svw. add. View(new Color. View(this)); } } class Color. View extends View { public Color. View(Context context) { super(context); } public void on. Draw(Canvas canvas) { Paint Pnt = new Paint(); for (int y=0; y<1024; y+=4) { Pnt. set. ARGB(255, 255 -y/4, 255); canvas. draw. Rect(0, y, 500, y+4, Pnt); } } protected void on. Measure (int width. Measure. Spec, int height. Measure. Spec) { set. Measured. Dimension(500, 1024); } } 31/40

3. 여러 가지 뷰 § 1. 5버전부터 수평 스크롤 가능한 클래스가 추가되었으며 클래스 이름

3. 여러 가지 뷰 § 1. 5버전부터 수평 스크롤 가능한 클래스가 추가되었으며 클래스 이름 앞에 Horizontal이 추가되었다. § HScroll. View. Test 예제 • 레이아웃에는 Scroll. View 대신 Horizontal. Scroll. View를 배치, 수직으로 그러데이션하는 대신 수평 으로 그러데이션한다. Widget/HScroll. View. Test. java public class HScroll. View. Test extends Activity { public void on. Create(Bundle saved. Instance. State) { super. on. Create(saved. Instance. State); set. Content. View(R. layout. hscrollviewtest); Horizontal. Scroll. View svw = (Horizontal. Scroll. View)find. View. By. Id(R. id. scr); svw. add. View(new HColor. View(this)); } } class HColor. View extends View { public HColor. View(Context context) { super(context); } public void on. Draw(Canvas canvas) { Paint Pnt = new Paint(); for (int x=0; x<1024; x+=4) { Pnt. set. ARGB(255, 255 -x/4, 255); canvas. draw. Rect(x, 0, x+4, 500, Pnt); } } protected void on. Measure (int width. Measure. Spec, int height. Measure. Spec) { set. Measured. Dimension(1024, 500); } } [ HScroll. View. Test 예제 실행 결과 ] 34/40

3. 여러 가지 뷰 § 웹뷰를 사용하면 간단한 웹 브라우저는 만들 수 있으며, 액티비티의

3. 여러 가지 뷰 § 웹뷰를 사용하면 간단한 웹 브라우저는 만들 수 있으며, 액티비티의 일부에 웹 페이지를 표시할 수 있다. Widget/Web. View. Test. java - 2 § Web. View. Test 예제 Button. On. Click. Listener m. Click. Listener = new View. On. Click. Listener() { public void on. Click(View v) { switch (v. get. Id()) { case R. id. btngo: String url; Edit. Text addr = (Edit. Text)find. View. By. Id(R. id. address); url = addr. get. Text(). to. String(); m. Web. load. Url(url); break; case R. id. btnback: if (m. Web. can. Go. Back()) { m. Web. go. Back(); } break; case R. id. btnforward: if (m. Web. can. Go. Forward()) { m. Web. go. Forward(); } break; case R. id. btnlocal: m. Web. load. Url("file: ///android_asset/test. html"); break; } } }; • 레이아웃에 에디트와 버튼들을 상단에 배 치, 나머지 영역을 웹 뷰로 가득 채우고 코 드에서는 각 버튼이 클릭될 때 웹 뷰에게 명령을 내린다. Widget/Web. View. Test. java - 1 public class Web. View. Test extends Activity { Web. View m. Web; public void on. Create(Bundle saved. Instance. State) { super. on. Create(saved. Instance. State); set. Content. View(R. layout. webviewtest); m. Web = (Web. View)find. View. By. Id(R. id. web); m. Web. set. Web. View. Client(new My. Web. Client()); Web. Settings set = m. Web. get. Settings(); set. Java. Script. Enabled(true); set. Built. In. Zoom. Controls(true); m. Web. load. Url("http: //www. google. com"); find. View. By. Id(R. id. btngo). set. On. Click. Listener(m. Click. Listener); find. View. By. Id(R. id. btnback). set. On. Click. Listener(m. Click. Listener); find. View. By. Id(R. id. btnforward). set. On. Click. Listener(m. Click. Listener); find. View. By. Id(R. id. btnlocal). set. On. Click. Listener(m. Click. Listener); } class My. Web. Client extends Web. View. Client { public boolean should. Override. Url. Loading(Web. View view, String url) { view. load. Url(url); return true; } } } 36/40

안드로이드 프로그래밍 정복(Android Programming Complete Guide)

안드로이드 프로그래밍 정복(Android Programming Complete Guide)