티스토리 뷰



이 자료들은 팁스소프트에서 제공하는 [ 알짜배기 ] 프로그램을 이용하면 더 편리하게 볼수 있습니다.
* 알짜배기 프로그램 받기 - http://www.tipssoft.com/bulletin/tb.php/QnA/8406
* 안드로이드 강좌 목록 - http://www.tipssoft.com/bulletin/tb.php/old_bbs/501
이번 강좌에서는 리스트뷰(ListView) 가 만들어지는 원리와 방법 그리고 리스트뷰를 사용하는 간단한
예제에 대해서 소개하도록 하겠습니다.
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_width="fill_parent"
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_width="fill_parent"
android:layout_height="fill_parent"
>
<ListView
android:id="@+id/id_list"
android:layout_width="fill_parent"
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_width="fill_parent"
android:layout_height="fill_parent"
>
<ListView
android:id="@+id/id_list"
android:layout_width="fill_parent"
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_width="fill_parent"
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"};
/** Called when the activity is first created. */
@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"};
/** Called when the activity is first created. */
@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(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"};
/** Called when the activity is first created. */
@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());
}
}
< 실행 화면 : 항목을 클릭했을 때 >

 

'프로그램 > 안드로이드 강좌' 카테고리의 다른 글

쓰레드-1  (0) 2012.08.15
리스트뷰 사용하기2  (0) 2012.08.15
Edittext 사용하기  (0) 2012.08.15
버튼 사용하기  (0) 2012.08.15
안드로이드 프로그래밍 시작하기  (0) 2012.08.15
댓글