1. 리스트뷰의구조 리스트뷰는어떤데이터그룹에대한각각의정보들을항목별로출력시키고사용자에게원하는항목을검색하거나선택할수있도록해주는컨트롤객체입니다. 그래서다른컨트롤처럼정해진형태의정보를저장하는것이아니기때문에리스트뷰가데이터를직접관리하기는힘들었을것입니다. 그래서효과적인데이터관리를위해 "ArrayAdapter" 라는클래스가추가되었고리스트뷰는이클래스를이용해서사용자가지정한데이터에접근하도록구현되어있습니다. 간단한데이터를다룰때는 ArrayAdapter 클래스를그대로사용할수도있지만, 사용자가원하는다양한형태를효과적으로표현하기위해서는 ArrayAdapter 클래스를그대로사용하지않고 ArrayAdapter 클래스에서상속받아새로운클래스를만드는경우도많을것입니다. 이렇게다양한형태로 ArrayAdapter 클래스가변한다면리스트뷰가데이터관리객체에접근하기가힘들어질것입니다. 그래서데이터접근을표준화할수있도록 "Adapter" 라는인터페이스가추가적으로제공됩니다. ArrayAdapter 클래스는 Adapter 라는인터페이스를기준으로구현되고리스트뷰는데이터접근시에실제클래스와는상관없이 Adapter 라는인터페이스를통해서만접근함으로써두객체가독립성을유지할수있는형태로설계되어있습니다. 이구성을그림으로표현하면아래와같습니다. 결국, 클래스상속을사용해서 ArrayAdapter 클래스를다양화시키더라도리스트뷰객체는 Adapter 인터페이스를통해서만접근하기때문에데이터접근에문제가생기지않습니다. 위그림을좀더구체적으로살펴보면실질적으로데이터를관리하는최상위클래스는 BaseAdapter 이며그자식클래스로서데이터타입을직접정하여관리할수있는 ArrayAdapter 가있습니다. ( CursorAdapter, SimpleAdapter,... 등다른클래스도있지만리스트뷰와직접적인연관성이없어서다른클래스들은생략했습니다. ) BaseAdapter 클래스가구현시에 ListAdapter 와 SpinnerAdapter 인터페이스를기준으로만들어졌기때문에 ListAdapter 인터페이스를사용해서도얼마든지 BaseAdapter 클래스로만들어진객체에접근이가능합니다. 그리고 ArrayAdapter 클래스도 BaseAdapter 클래스에서상속받아만들어졌기때문에동일하게 ListAdapter 인터페이스를사용해서접근이가능합니다. 결과적으로 ArrayAdapter 에서상속받아만들어질모든클래스에게도동일하게적용될것입니다.
이것은리스트뷰의 setadapter 메소드에잘표현되어있습니다. setadapter 는리스트뷰에사용할데이터객체를넘겨주는메소드입니다. 일반적으로생각한다면 ArrayAdapter 객체를생성하여사용할데이터를저장할것이고데이터가저장된 ArrayAdapter 객체를 setadapter 메소드에전달할것입니다. 하지만리스트뷰클래스의 setadapter 메소드의원형은다음과같습니다. void setadapter(listadapter adapter); 내부적으로는 ArrayAdapter 객체든 ArrayAdapter 에서상속받은객체든상관없이모두사용할수있는 ListAdapter 인터페이스로받아서처리하겠다는뜻입니다. 즉, 리스트뷰내부적으로는 ListAdapter 를통해서만데이터에접근하겠다는뜻입니다. 2. 리스트뷰의작업순서 리스트뷰를사용하려면리스트뷰의각항목이어떤데이터를가질것인지결정해야합니다. 이것이결정되면이데이터를어떻게출력할것인지를정해야합니다. 그런다음데이터를관리할객체를생성하여사용할데이터와출력형식을저장하고리스트뷰에해당객체를넘겨주면됩니다. 작업하는순서를나열해보면다음과같습니다. 2.1 각항목에출력할데이터형식을 XML 리소스에정의한다. ( 3.1 항참조 ) 2.2 ArrayAdapter 객체를생성하면서 XML 리소스정보와실제사용할데이터를전달한다. 2.3 리스트뷰객체의 setadapter 메소드에생성된 ArrayAdapter 객체를넘긴다. 이것을그림으로표현해보면아래와같습니다. 3. 단순한리스트뷰구성하기 리스트뷰는항목의출력형식을정의해놓은 XML 리소스와리스트뷰에출력할데이터객체의배열을연결해주어야사용할수있으며아래와같은순서로따라하시면됩니다.
3.1 항목의출력형식을정의한 XML 리소스파일생성 리스트뷰의각항목은기본적으로 TextView 컨트롤의레이아웃형태를가지며, XML 코드는아래의코드처럼구성할수있습니다. XML 코드는 main.xml 파일이존재하는위치에 "list.xml" 처럼별개의이름을가진파일로생성하여아래와같은내용을저장하면됩니다. <?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_height="fill_parent" <!-- 항목의내부여백을준다.--> android:padding="10dp" <!-- 출력될글자의크기를설정한다.--> android:textsize="16sp" 안드로이드개발툴에서이미정의해놓은출력형식이있으므로 XML 리소스를연결할때정의된리소스값을적절하게사용하면됩니다. 3.2 리소스코드에리스트뷰의레이아웃구성 응용프로그램의레이아웃을정의하는 main.xml 리소스파일에리스트뷰의출력형태를정의하는레이아웃을구성합니다. <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_height="fill_parent" > <ListView android:id="@+id/id_list" android:layout_height="wrap_content" </LinearLayout> 레이아웃에서정의된리스트뷰는 id_list 라는 ID 값을사용하며상위요소에정의된너비값을자신의너비값으로가지며, 자신이소유한데이터를포함할만큼의높이값을가집니다. 3.3 출력될데이터객체생성 리스트뷰에연결된데이터객체는여러가지형태의객체가올수있으며기본적으로 String 을기반으로하는데이터타입이어야합니다. 리스트뷰에데이터가추가되는경우에는리스트구조로데이터를관리하는 ArrayList 클래스를사용해야하지만이번강좌에서는데이터의추가 / 삭제가없는기초적인형태를설명할것이기때문에정적인형태의 String 배열을사용하여데이터객체를생성하도록하겠습니다. static final String[] m_item_string = new String[] "Tipssoft", "Tipsware", "StagePia", "StageDMX", "HandyPHP";
리스트뷰를사용하는클래스에위의코드처럼멤버변수로배열을선언합니다. 3.4 리스트뷰에항목출력형식을지정한 XML 리소스와데이터연결 리스트뷰에 ArrayAdapter 클래스의생성자를이용하여항목출력형식을지정한 XML 리소스와데이터객체를다음과같이연결시킵니다. // 항목출력형식지정한 XML 리소스와데이터를설정한 ArrayAdapter 객체를생성한다. // 사용할 ArrayAdapter 클래스의기본데이터는 String 타입으로사용한다. ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.list, m_item_string); // 레이아웃리소스파일에정의된 id_list 라는 ID 의리스트뷰를얻어온다. ListView list = (ListView) findviewbyid(r.id.id_list); // 리소스값과데이터값이저장된 ArrayAdapter 객체를리소스뷰에설정하여연결한다. list.setadapter(adapter); 만약정의해놓은항목출력형식지정한 XML 리소스가없다면 R 클래스의 layout 클래스내부에미리정의되어있는아래와같은리소스들을 ArrayAdapter 객체의생성자에서사용할수있으며사용방법은아래와같습니다. - 예약된리소스값 simple_list_item_1 simple_list_item_2 simple_list_item_activated_1 simple_list_item_activated_2 simple_list_item_checked simple_list_item_multiple_choice simple_list_item_single_choice simple_selectable_list_item - 리소스사용방법 adapter = new ArrayAdapter<String>(this, R.layout.simple_list_item_1, m_item_string); 4. 리스트뷰사용하기 이제리스트뷰를이용한간단한예제를리스너의사용법별로살펴보도록하겠습니다. 이예제는정적인문자열그룹정보를가지고있는하나의리스트뷰와문자열초기값이없는텍스트뷰가있으며리스트뷰의항목을클릭하면해당항목의문자열이텍스트뷰에출력됩니다. 이때리스트뷰는사용자가리스트뷰의항목을선택하는것을알수있도록 OnItemClickListener 라는이벤트리스너를사용합니다. 모든예제는리소스코드를동일하게사용하기때문에아래의 XML 코드들로통일하도록하겠습니다. <!-- main.xml : 메인레이아웃리소스파일 --> <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_height="fill_parent"
> <ListView android:id="@+id/id_list" android:layout_height="wrap_content" <TextView android:id="@+id/id_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="20dp" android:textsize="20sp" android:layout_gravity="center_horizontal" </LinearLayout> <!-- listview_item.xml : 항목별출력형식을정의한리소스파일 --> <?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_height="fill_parent" android:padding="10dp" android:textsize="16sp" 4.1 리스너변수를멤버변수로연결하여사용하기 소스코드의메인클래스에리스너인터페이스를멤버변수로선언및할당하고, 인터페이스의메소드를정의한후컨트롤에는해당인터페이스의멤버변수를연결합니다. 정의된인터페이스가멤버변수의형태로존재하기때문에여러컨트롤에동일한이벤트처리를해야하는경우효과적인방법입니다. package com.example.examlistview; import android.app.activity; import android.os.bundle; import android.widget.listview; // 리스트뷰클래스를사용하기위해추가 import android.widget.adapterview.onitemclicklistener; // 리스너이벤트를사용하기위해추가 // 이벤트리스너의 onitemclick 메소드에서넘어오는 AdapterView 를사용하기위해추가 import android.widget.adapterview; import android.widget.textview; // 텍스트뷰클래스를사용하기위해추가 import android.widget.arrayadapter; // 어댑터클래스를사용하기위해추가 // 이벤트리스너의 onitemclick 메소드에서넘어오는 View 를사용하기위해추가 import android.view.view; public class ExamListViewAppActivity extends Activity // 이벤트리스너인터페이스멤버변수를선언및정의한다. private OnItemClickListener m_item_listener = new OnItemClickListener() public void onitemclick(adapterview<?> parent, View view, int position, long id) // 매개변수로넘어온선택된항목 View 를 TextView 로캐스팅한다.
; TextView select_item = (TextView)view; // 리소스파일에정의된 id_tv 라는 ID 의텍스트뷰를얻어온다. TextView tv = (TextView) findviewbyid(r.id.id_tv); // TextView 로캐스팅된선택항목의문자열을얻어서텍스트뷰에출력시킨다. tv.settext(select_item.gettext()); // 리스트뷰에서사용할문자열선언 static final String[] m_item_string = new String[] "Tipssoft", "Tipsware", "StagePia", "StageDMX", "HandyPHP"; ; @Override public void oncreate(bundle savedinstancestate) super.oncreate(savedinstancestate); setcontentview(r.layout.main); // listview_item 리소스와문자열정보를저장한 ArrayAdapter 객체를생성한다. ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.listview_item, m_item_string) // 리소스파일에정의된 id_list 라는 ID 의리스트뷰를얻는다. ListView list = (ListView) findviewbyid(r.id.id_list); // 리스트뷰에 ArrayAdapter 객체를설정하여리스트뷰에데이터와출력형태를지정한다. list.setadapter(adapter); // 리스너를설정한다. list.setonitemclicklistener(m_item_listener); 4.2 리스터인터페이스를단순할당하여연결하기 리스너를연결할때사용하는 setonitemclicklistener() 메소드의매개변수에 new 예약어를이용하여인터페이스를즉시할당하고메소드정의를하여연결하는것입니다. 이방법은 1 회성으로이벤트를처리할때사용하는것이좋습니다. package com.example.examlistview; import android.app.activity; import android.os.bundle; import android.widget.listview; import android.widget.adapterview.onitemclicklistener; import android.widget.adapterview; import android.widget.textview; import android.widget.arrayadapter; import android.view.view; public class ExamListViewAppActivity extends Activity static final String[] m_item_string = new String[] "Tipssoft", "Tipsware", "StagePia", "StageDMX", "HandyPHP"; @Override
g); public void oncreate(bundle savedinstancestate) super.oncreate(savedinstancestate); setcontentview(r.layout.main); ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.listview_item, m_item_strin ListView list = (ListView) findviewbyid(r.id.id_list); list.setadapter(adapter); // 리스트뷰에리스너인터페이스를할당및정의하여설정한다. list.setonitemclicklistener(new OnItemClickListener() public void onitemclick(adapterview<?> parent, View view, int position, long id) TextView select_item = (TextView)view; TextView tv = (TextView) findviewbyid(r.id.id_tv); tv.settext(select_item.gettext()); ); 4.3 메인클래스에서리스너인터페이스구현 (implements) 하기 소스코드가작성된메인클래스에 implement 예약어를사용하여리스너인터페이스를구현하는방법입니다. package com.example.examlistview; import android.app.activity; import android.os.bundle; import android.widget.listview; import android.widget.adapterview.onitemclicklistener; import android.widget.adapterview; import android.widget.textview; import android.widget.arrayadapter; import android.view.view; // ExamListViewAppActivity 클래스에 OnItemClickListener 인터페이스를구현한다. public class ExamListViewAppActivity extends Activity implements OnItemClickListener static final String[] m_item_string = new String[] "Tipssoft", "Tipsware", "StagePia", "StageDMX", "HandyPHP"; @Override public void oncreate(bundle savedinstancestate) super.oncreate(savedinstancestate); setcontentview(r.layout.main); ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.listview_item, m_item_string); ListView list = (ListView) findviewbyid(r.id.id_list); list.setadapter(adapter);
// 리스트뷰에리스너인터페이스를구현한이클래스를넘겨주어리스너를설정한다. list.setonitemclicklistener(this); // OnItemClickListener 인터페이스의 onitemclick 메소드를정의한다. public void onitemclick(adapterview<?> parent, View view, int position, long id) TextView select_item = (TextView)view; TextView tv = (TextView) findviewbyid(r.id.id_tv); tv.settext(select_item.gettext()); < 실행화면 : 항목을클릭했을때 >