ref) http://tigerwoods.tistory.com/13
이번에는 ListView, Spinner, Grid와 같이
사용자가 키보드나 가상키보드 타이핑으로 정보를 입력 하지 않고,
미리 정의된 data set 중 원하는 데이터 고를 수 있게 도와주는 selection 위젯에 대해 알아본다.
1. Adapter
먼저 selection위젯에 data를 공급하고 모양도 결정하는 Adapter객체에 대해 알아보자
Adapter의 역할
안드로이드에서 adapter는 다음과 같은 역할을 한다.
- selection 위젯(List, combo, spinner등)에 일관된 interface로 data 공급.
- adapter가 공급한 data가 어떤 형식의view를 통해 selection 위젯에 표현 될지를 결정.
Adapter 종류
안드로이드에서 제공하는 adapter는 여러 종류가 있다. 다음은 자주 쓰이는 adapter이다.
- CursorAdapter: Cursor(DB Query 결과에 랜덤하게 읽고 쓸 수 있게 해주는 interface)로부터 데이터를 selection 위젯에 공급하는 adapter. Content Provider (뒷 chapter에 자세히 다룸)가 제공하는 data를 selection위젯에 연결할 때 도 사용함.
- SimpleAdapter: data를 XML Layout 파일에 지정된 View형태로 표하는데 사용 함.
- ActivityAdapter, ActivityIconAdapter: 특정 Intent 발생 시 실행될 activity의 이름이나 아이콘 목록을 위한 adapter.
- ArrayAdapter: array나 java.util.List에 저장된 data를 위한 adapter.
ArrayAdapter사용법
Adapter중 가장 사용이 간편한 ArrayAdapter는 array 또는 java.util.List에 저장된 data를 selection 위젯에 공급한다. 다음은 ArrayAdapter의 상속 구조이다.
다음은 사용법이다.
String items[] = { "How", "to", "use", "ArrayAdapter?" };
ArrayAdapter <String> aa = new ArrayAdapter <String> (this,
android.R.layout.simple_list_item_1,
items);
ListView 인스턴스.setAdapter(aa);
첫 번째로, ArrayAdapter객체를 생성하여야 한다. 위의 생성자 호출에 사용된 인자들은 다음과 같다.
- this – 사용할 Context (일반적으로 아답터를 포함하는activity의 instance)
- android.R.layout.simple_list_item_1 – Selection 위젯의 각 아이템을 채울 view의 resource ID. TextView가 포함된 layout파일을 전달하며, 여기에 어떤 형식의 TextView 리소스를 지정하느냐에 따라 selection 위젯을 구성하는 각 아이템의 text 형태(글씨의 크기, 색깔, 배경, 스타일 등)가 바뀜.
- items – Selection 위젯에 나열될 array나 java.util.List형식의 data. ArrayAdapter는 공급된 data의 모든 요소를 toString() 메소드로 String화 하고, 위의 리소스ID 파라미터에 정의된 형태의 view 형태로 표현한다. 이 예제의 경우 android.R.layout.simple_list_item_1은 기본 TextView임으로 배열의 각 요소는 일반적인 text로 표현됨.
두 번째로, ListView의 setAdapter 메소드를 이용하여 ListView와 adapter를 연결 한다.
위ArrayAdapter 생성자의 2번째 인자, android.R.layout.simple_list_item_1은 안드로이드 Library가 기본으로 제공하는 selection 위젯 를 위한 많은 아이템 layout파일 중 하나이며, 다음과 같이 기본 TextView의 형태로 ListView 아이템을 표현한다.
하지만, ListView에 표시되는 text의 모양을 커스터마이징 하고 싶다면, \res\layout\ 밑에 원하는 스타일의 element가 선언 되어 있는 XML layout file을 추가하고
ArrayAdapter 생성시 2번째 인자로 새로운 layout 리소스 파일(R.layout.새로운layout파일이름)을 지정하면 된다. 다음은 예에서는 text에 50px크키, 빨간색, bold|italic을 적용한 예이다.
listview_item_layout_01.xml (파일이름에 대문자 사용 못함)
1 |
<? xml version = "1.0" encoding = "utf-8" ?> |
4 |
android:layout_width = "fill_parent" |
5 |
android:layout_height = "wrap_content" |
6 |
android:textSize = "50px" |
7 |
android:textColor = "#FF0000" |
8 |
android:textStyle = "bold|italic" /> |
위와 같은 XML layout file을 java코드 내부에서 다음과 같이 적용.
String items[] = { "How", "to", "use", "ArrayAdapter?" };
ArrayAdapter <String> aa = new ArrayAdapter <String> (this,
R.layout.listview_item_layout_01,
items);
ListView 인스턴스.setAdapter(aa);
다음과 같이 ListView 아이템 text의 스타일이 변한다.
Selection 위젯의 아이템 view를 좀더 복잡한 형태의 view로 대체 하고 싶다면 ArrayAdapter를 상속해서 새로운 ArrayAdapter 클래스를 만들고 getView() 메소드를 오버라이딩 하면된다. 자세한 방법은 이곳으로 (013: ListView 꾸미기 & 최적화하기 2/2)
2. ListView 사용법
ListView의 상속 구조는 다음과 같다.
ListView의 구현은 Activity를 상속하는 방법과 ListActivity를 상속하는 방법 두 가지가 있다.
Activity를 상속하여 구현
Activity 기반 ListView (main.xml)
01 |
<? xml version = "1.0" encoding = "utf-8" ?> |
03 |
android:orientation = "vertical" |
04 |
android:layout_width = "fill_parent" |
05 |
android:layout_height = "fill_parent" > |
09 |
android:id = "@+id/textview" |
10 |
android:layout_width = "wrap_content" |
11 |
android:layout_height = "wrap_content" |
12 |
android:text = "No Selection" /> |
16 |
android:id = "@+id/listview" |
17 |
android:layout_width = "fill_parent" |
18 |
android:layout_height = "fill_parent" /> |
XML Layout 파일인 main.xml에서는 ListView element를 등록하고 listview 라고 identify했다.
또, ListView의 요소 중 선택된 아이템이 List 맨 위 아이템으로 옮겨오는 여부를 결정하는android:drawSelectorOnTop 속성을 false로 지정했다.
Activity 기반 ListView (MyListView_Activity.java)
01 |
package com.holim.test; |
02 |
import android.app.Activity; |
03 |
import android.os.Bundle; |
04 |
import android.view.View; |
05 |
import android.widget.AdapterView; |
06 |
import android.widget.ArrayAdapter; |
07 |
import android.widget.ListView; |
08 |
import android.widget.TextView; |
11 |
public class MyListView_Activity extends Activity |
12 |
implements AdapterView.OnItemClickListener { |
15 |
String items[] = { "111" , "222" , "333" }; |
23 |
/** Called when the activity is first created. */ |
25 |
public void onCreate(Bundle savedInstanceState) { |
26 |
super .onCreate(savedInstanceState); |
27 |
setContentView(R.layout.main); |
33 |
ArrayAdapter<String> aa = new ArrayAdapter<String>( this , |
34 |
android.R.layout.simple_list_item_1, |
38 |
lv = (ListView)findViewById(R.id.listview); |
44 |
lv.setOnItemClickListener( this ); |
47 |
tv = (TextView)findViewById(R.id.textview); |
52 |
public void onItemClick(AdapterView<?> parent, View view, int position, long id) { |
54 |
tv.setText(items[position]); |
실행 화면은 다음과 같다.
ListActivity를 상속하여 구현
구현하려는 Activity의 view가 한 개의 ListView로 이루어져 있다면 이 방법이 훨씬 편하다.
ListActivity 기반 ListView (main.xml)
01 |
<? xml version = "1.0" encoding = "utf-8" ?> |
03 |
android:orientation = "vertical" |
04 |
android:layout_width = "fill_parent" |
05 |
android:layout_height = "fill_parent" > |
09 |
android:id = "@+id/textview" |
10 |
android:layout_width = "fill_parent" |
11 |
android:layout_height = "wrap_content" |
12 |
android:text = "No Selection" /> |
17 |
android:id = "@id/android:list" |
18 |
android:layout_width = "fill_parent" |
19 |
android:layout_height = "fill_parent" /> |
24 |
android:id = "@id/android:empty" |
25 |
android:layout_width = "wrap_content" |
26 |
android:layout_height = "wrap_content" |
27 |
android:text = "No Item" /> |
ListActivity 기반 ListView (MyListView_ListActivity.java)
01 |
package com.holim.test; |
02 |
import android.app.ListActivity; |
03 |
import android.os.Bundle; |
04 |
import android.view.View; |
05 |
import android.widget.ArrayAdapter; |
06 |
import android.widget.ListView; |
07 |
import android.widget.TextView; |
09 |
public class MyListView_ListActivity extends ListActivity { |
12 |
String items[] = { "111" , "222" , "333" }; |
17 |
/** Called when the activity is first created. */ |
19 |
public void onCreate(Bundle savedInstanceState) { |
20 |
super .onCreate(savedInstanceState); |
21 |
setContentView(R.layout.main); |
27 |
ArrayAdapter <String> aa = new ArrayAdapter<String>( this , |
28 |
android.R.layout.simple_list_item_1, |
34 |
tv = (TextView)findViewById(R.id.textview); |
39 |
public void onListItemClick(ListView l, View v, int position, long id) { |
40 |
tv.setText(items[position]); |
실행 화면과 기능은 Activity를 상속하여 구현했을 때 와 완전히 동일하다.
3. Spinner
Spinner의 상속 관계는 다음과 같다.
Spinner는 다른 비쥬얼 툴킷의 Combo box와 같은 기능을 한다.
Spinner는 ListView와 같이 화면을 모두 차지하지 않으면서, ListView처럼 특정 data set내에서 입력이 필요할 때 사용된다.
Spinner 예제 (main.xml)
01 |
<? xml version = "1.0" encoding = "utf-8" ?> |
03 |
android:orientation = "vertical" |
04 |
android:layout_width = "fill_parent" |
05 |
android:layout_height = "fill_parent" > |
09 |
android:id = "@+id/textview" |
10 |
android:layout_width = "fill_parent" |
11 |
android:layout_height = "wrap_content" |
12 |
android:text = "No Selection" /> |
16 |
android:id = "@+id/spinner" |
17 |
android:layout_width = "fill_parent" |
18 |
android:layout_height = "wrap_content" /> |
Spinner 예제 (MySpinner.java)
01 |
package com.holim.test; |
02 |
import android.app.Activity; |
03 |
import android.os.Bundle; |
04 |
import android.view.View; |
05 |
import android.widget.AdapterView; |
06 |
import android.widget.ArrayAdapter; |
07 |
import android.widget.Spinner; |
08 |
import android.widget.TextView; |
12 |
public class MySpinner extends Activity |
13 |
implements AdapterView.OnItemSelectedListener { |
15 |
String items[] = { "111" , "222" , "333" , "444" , "555" , "666" , "777" , "888" }; |
20 |
/** Called when the activity is first created. */ |
22 |
public void onCreate(Bundle savedInstanceState) { |
23 |
super .onCreate(savedInstanceState); |
24 |
setContentView(R.layout.main); |
30 |
ArrayAdapter<String> aa = new ArrayAdapter<String> ( this , |
31 |
android.R.layout.simple_spinner_item, |
34 |
Spinner sp = (Spinner)findViewById(R.id.spinner); |
40 |
sp.setOnItemSelectedListener( this ); |
42 |
tv = (TextView)findViewById(R.id.textview); |
47 |
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { |
48 |
tv.setText(items[position]); |
53 |
public void onNothingSelected(AdapterView<?> parent) { |
실행화면은 다음과 같다.
4. GridView 사용
GridView는 2차원 테이블형식을 이용하여 data를 화면에 표시한다.
다음은 상속 구조이다.
GridView에서 행(Row)/열(Column)간의 간격을 조정하는 GridView의 속성은 다음과 같다.
- android:numColumns: Grid 한 Row에 나열될 Column의 개수를 지정(1~n개). "auto_fit"으로 설정하면 사용 가능한 공간에 따라 자동으로 column의 개수 정해짐.
- android:verticalSpacing(horizontalSpacing): Grid의 셀 간 간격. verticalSpacing은 상하 간, horizontalSpacing은 좌우 간의 간격을 pixel로 지정. (ex. "5px")
- android:columnWidth: Column의 너비를 pixel로 지정.
- android:stretchMode: android:numColumns이 "auto_fit"으로 설정되었을때만 적용. auto_fit을 하고 남은 좌우 공간을 어떻게 분배할지를 결정함. columnWidth로 설정되면 남은 공간이 column들에게 골고루 할당되며, spacingWidth로 설정되면 column간 여백이 남은 공간을 골고루 나눠 할당 받음.
GridView Test 예제 (main.xml)
01 |
<? xml version = "1.0" encoding = "utf-8" ?> |
03 |
android:orientation = "vertical" |
04 |
android:layout_width = "fill_parent" |
05 |
android:layout_height = "fill_parent" > |
09 |
android:id = "@+id/textview" |
10 |
android:layout_width = "wrap_content" |
11 |
android:layout_height = "wrap_content" |
12 |
android:text = "No Selection" /> |
16 |
android:id = "@+id/gridview" |
17 |
android:layout_width = "fill_parent" |
18 |
android:layout_height = "fill_parent" |
19 |
android:numColumns = "auto_fit" |
20 |
android:horizontalSpacing = "20px" |
21 |
android:verticalSpacing = "20px" |
22 |
android:columnWidth = "40px" |
23 |
android:stretchMode = "columnWidth" |
24 |
android:gravity = "center" /> |
GridView Test 예제 (gridview_item_layout_01.xml)
01 |
<? xml version = "1.0" encoding = "utf-8" ?> |
04 |
android:layout_width = "wrap_content" |
05 |
android:layout_height = "wrap_content" |
06 |
android:textSize = "20px" |
07 |
android:textColor = "#FF0000" |
08 |
android:background = "#FFFFFF" |
09 |
android:typeface = "serif" |
10 |
android:gravity = "center" /> |
GridView Test 예제 (MyGridView.java)
01 |
package com.holim.com; |
02 |
import android.app.Activity; |
03 |
import android.os.Bundle; |
04 |
import android.view.View; |
05 |
import android.widget.AdapterView; |
06 |
import android.widget.ArrayAdapter; |
07 |
import android.widget.GridView; |
08 |
import android.widget.TextView; |
12 |
public class MyGridView extends Activity |
13 |
implements AdapterView.OnItemClickListener { |
15 |
String items[] = { "111" , "222" , "333" , "444" , "555" , |
16 |
"666" , "777" , "888" , "999" , "000" , "222" , "333" , |
17 |
"444" , "555" , "666" , "777" , "888" , "999" , "000" }; |
21 |
/** Called when the activity is first created. */ |
23 |
public void onCreate(Bundle savedInstanceState) { |
24 |
super .onCreate(savedInstanceState); |
25 |
setContentView(R.layout.main); |
31 |
ArrayAdapter<String> aa = new ArrayAdapter<String>( this , |
32 |
R.layout.gridview_item_layout_01, |
36 |
GridView gv = (GridView)findViewById(R.id.gridview); |
42 |
gv.setOnItemClickListener( this ); |
44 |
tv = (TextView)findViewById(R.id.textview); |
49 |
public void onItemClick(AdapterView<?> parent, View view, int position, long id) { |
50 |
tv.setText(items[position]); |
실행 결과는 다음과 같다.
5. Text자동 완성: AutoCompleteTextView
인터넷 브라우져 같은 프로그램에서 제공하는 자동 완성 기능이 첨부된 TextView이다.
사용자가 특정 시점(android:completionThreshold 속성으로 조종)까지 입력한 data를 data set의 각 아이템 첫머리와 비교하여 일치하는 모든 data set의 item을 사용자에게 제시하여 사용자 입력을 최소화 할 수 있도록 한다.
다음은 클래스 상속 구조이다.
앞에서도 언급한 android:completionThreshold 속성은 사용자가 몇 글자를 입력했을 때부터 data set과 비교를 시작할 지를 정하며, 1~n의 정수를 속성값으로 입력 받는다.
AutoCompletTextView에서 중요한 것은 selection listener interface를 적용할 수 없다는 것이다.
이유는 사용자가 data set중의 한 item을 선택할 수도 있지만, 사용자가 의도한 data가 data set 내부에 없을 경우 data를 끝까지 직접 입력 하는 경우도 있기 때문이다.
그렇기 때문에 android.text.TextWatcher interface를 사용하여 입력data의 변화에 대해 반응하여야 한다.
AutoCompleteTextView 예제 (main.xml)
01 |
<? xml version = "1.0" encoding = "utf-8" ?> |
03 |
android:orientation = "vertical" |
04 |
android:layout_width = "fill_parent" |
05 |
android:layout_height = "fill_parent" > |
09 |
android:id = "@+id/textview" |
10 |
android:layout_width = "fill_parent" |
11 |
android:layout_height = "wrap_content" |
12 |
android:text = "No input yet" /> |
16 |
android:id = "@+id/auto" |
17 |
android:layout_width = "fill_parent" |
18 |
android:layout_height = "wrap_content" |
19 |
android:completionThreshold = "1" /> |
AutoCompleteTextView 예제 (MyAutoCompleteTextView.java)
01 |
package com.holim.test; |
02 |
import android.app.Activity; |
03 |
import android.os.Bundle; |
04 |
import android.text.AutoText; |
05 |
import android.text.Editable; |
06 |
import android.text.TextWatcher; |
07 |
import android.widget.ArrayAdapter; |
08 |
import android.widget.AutoCompleteTextView; |
09 |
import android.widget.TextView; |
12 |
public class MyAutoCompleteTextView extends Activity |
13 |
implements TextWatcher { |
16 |
String items[] = { "USA" , "China" , "Japan" , "Korea" , "Korean" }; |
19 |
AutoCompleteTextView autotext; |
21 |
/** Called when the activity is first created. */ |
23 |
public void onCreate(Bundle savedInstanceState) { |
24 |
super .onCreate(savedInstanceState); |
25 |
setContentView(R.layout.main); |
28 |
tv = (TextView)findViewById(R.id.textview); |
29 |
autotext = (AutoCompleteTextView)findViewById(R.id.auto); |
35 |
ArrayAdapter <String> aa; |
36 |
aa = new ArrayAdapter <String> ( this , |
37 |
android.R.layout.simple_dropdown_item_1line, |
40 |
autotext.setAdapter(aa); |
43 |
autotext.addTextChangedListener( this ); |
47 |
public void afterTextChanged(Editable s){ |
48 |
tv.setText(autotext.getText()); |
52 |
public void beforeTextChanged(CharSequence s, int start, int count, int after){ |
57 |
public void onTextChanged(CharSequence s, int start, int before, int count){ |
다음은 실행 화면이다.
Korea, Korean, USA, China, Japan가 data set으로 등록되어 있어 해당 단어의 첫 글자를 입력하면 그 그자로 시작하는 단어가 입력 창 밑에 나타나며, 원하는 item을 클릭하거나 계속 키보드로 입력을 진행 할 수 있다.