안드로이드에서 일련의 데이터를 표시할 때에는 대부분 리스트를 사용합니다. 사실, 안드로이드 뿐만 아니라 모든 곳에서 데이터를 표시할 때에는 리스트를 사용하죠.:)
안드로이드에서 리스트를 사용하는 예
데이터를 리스트 형태로 표시해 주기 위해서는 아래와 같은 세 가지 요소가 필요합니다.
앞의 AutoCompleteTextView에서와 마찬가지로, ListView에서도 원본 데이터와 그 데이터를 표시해주는 ListView 사이에 어댑터가 필요합니다. 여기에서도 마찬가지로 어댑터는 원본 데이터를 ListView와 연결시켜줌과 동시에, 리스트에 원본 데이터를 어떻게 표시할 지 정의해줍니다.
탭을 사용할 때와 마찬가지로, ListView를 조금 더 편하게 사용하기 위해 액티비티를 구현할 때 List
안드로이드에서 ListView를 표시할 때 그냥 Activity를 상속하는 클래스를 사용할 수도 있지만, List에 관련된 여러 메소드들이 추가되어있는 ListActivity를 주로 사용합니다.
ListActivity를 상속하는 액티비티를 작성할 경우 ListView의 어댑터를 설정할 때 ListView를 참조하는 객체를 만들지 않아도 어댑터를 지정할 수 있지만, ListView의 id를 필히 @android:id/list로 설정하셔야 합니다. 그렇지 않으면 아래와 같이 런타임 오류가 발생하게 됩니다.
ListView의 ID를 제데로 설정해주지 않으면 발생하는 런타임 오류
ListActivity를 상속하게 되면 리스트에 표시할 항목이 없을 때 사용자에게 보여줄 화면을 설정하는 것도 비교적 쉽게 할 수 있습니다. 일반적으로 아래와 같은 화면이 되겠죠.
리스트에 표시할 내용이 없을 때 사용자에게 보여주는 문구
이처럼 리스트에 표시할 내용이 없을 때, 빈 화면을 보여주는 대신 사용자에게 항목을 추가하는 방법에 대한 안내를 해주거나, 최소한 "항목이 없습니다" 정도는 표시해 주는 것이 예의(?) 입니다. :)
위와 같이 표시할 항목이 없을 때 대체로 표시할 화면을 설정하려면, 해당 화면 (레이아웃, 뷰)의 id를 @android:id/empty로 설정해주면 됩니다. 정말 매우 간단하죠? 예제에서는 표시할 항목이 없을 경우 아래와 같이 간단한 문구를 표시해주도록 구현하였습니다.
한번 예제의 레이아웃 코드 중 일부를 보도록 하겠습니다.
[main.xml]
01.
<
ListView
android:layout_height
=
"wrap_content"
02.
android:id
=
"@android:id/list"
03.
android:layout_width
=
"fill_parent"
/>
04.
05.
<
TextView
android:layout_width
=
"wrap_content"
06.
android:id
=
"@android:id/empty"
07.
android:text
=
"표시할 내용이 없습니다."
08.
android:layout_height
=
"wrap_content"
09.
android:layout_gravity
=
"center_horizontal"
/>
10.
ListActivity를 상속하므로 ListView의 id는 @android:id/list 로, 리스트에 표시할 항목이 없을 경우 표시할 TextView의 id는 @android:id/empty로 설정한 모습을 확인할 수 있습니다.
그리고, 이 예제의 윗부분에 EditText와 Button의 레이아웃을 보면 두 위젯이 각각 일정한 비율의 가로 크기를 가지고 있는 것을 볼 수 있습니다. 이는 LinearLayout 내의 요소에 적용되는 속성인 weight 속성을 적용했기 때문입니다.
01.
<
EditText
android:layout_height
=
"wrap_content"
02.
android:id
=
"@+id/inputText"
03.
android:layout_width
=
"0dp"
04.
android:layout_weight
=
"5"
05.
android:hint
=
"추가할 단어를 입력하세요."
/>
06.
07.
<
Button
android:layout_height
=
"wrap_content"
08.
android:layout_width
=
"0dp"
09.
android:layout_weight
=
"1"
10.
android:id
=
"@+id/inputButton"
11.
android:text
=
"Add"
/>
위와 같이 각각의 너비 (layout_width)를 0으로 하고, layout_weight 속성을 지정해 주면, weight 의 크기에 따라 레이아웃 내에서 해당 요소의 너비가 정해지게 됩니다. 위의 경우 전체 너비에서 EditText와 Button이 5:1 비율로 화면을 차지하게 구성된 모습입니다.
그럼 이제 본격적으로 예제 어플리케이션의 코드를 보도록 하겠습니다. 예제 어플리케이션은 위의 EditText에 텍스트를 입력하고, 버튼을 누르면 입력한 항목이 List에 추가되도록 하였습니다.
[ListViewExample.java]
01.
package
com.androidhuman.example.ListViewExample;
02.
03.
import
java.util.ArrayList;
04.
05.
import
android.app.ListActivity;
06.
07.
import
android.os.Bundle;
08.
import
android.view.View;
09.
import
android.view.View.OnClickListener;
10.
import
android.widget.ArrayAdapter;
11.
import
android.widget.Button;
12.
import
android.widget.EditText;
13.
14.
public
class
ListViewExample
extends
ListActivity {
15.
private
ArrayList<String> list;
16.
private
ArrayAdapter<String> adapter;
17.
private
EditText inputText;
18.
private
Button inputButton;
19.
20.
@Override
21.
public
void
onCreate(Bundle savedInstanceState) {
22.
super
.onCreate(savedInstanceState);
23.
setContentView(R.layout.main);
24.
25.
inputText = (EditText)findViewById(R.id.inputText);
26.
inputButton = (Button)findViewById(R.id.inputButton);
27.
list =
new
ArrayList<String>();
28.
29.
inputButton.setOnClickListener(
new
OnClickListener(){
30.
31.
@Override
32.
public
void
onClick(View v) {
33.
list.add(inputText.getText().toString());
34.
inputText.setText(
""
);
35.
adapter.notifyDataSetChanged();
36.
}
37.
38.
});
39.
40.
adapter =
new
ArrayAdapter<String>(
this
,
41.
android.R.layout.simple_list_item_1, list);
42.
43.
setListAdapter(adapter);
44.
}
45.
}
주요 부분에 대해 한번 다시 살펴보도록 하겠습니다. 어댑터를 생성하는 과정은 기존에 AutoCompleteTextView에서 봤던 과정과 동일합니다. 표시할 데이터 및 표시될 레이아웃을 설정해주고 있습니다.
그리고, 해당 어댑터를 ListView의 어댑터로 지정하기 위해 setListAdapter()메소드에 우리가 만든 어댑터를 인자로 넘겨주고 있습니다. 이렇게 해서야 비로소 우리가 표시하고 싶은 데이터와 데이터를 표시해줄 ListView가 연결이 된 셈입니다.
그리고, 버튼의 리스너 부분을 한번 보도록 하죠.
1.
@Override
2.
public
void
onClick(View v) {
3.
list.add(inputText.getText().toString());
4.
inputText.setText(
""
);
5.
adapter.notifyDataSetChanged();
6.
}
버튼을 클릭하면 EditText에 입력된 내용을 데이터가 담긴 ArrayList인 list에 추가해주고, EditText 필드를 초기화시켜주는 것을 확인할 수 있습니다. 여기에서 무엇보다 주요한 것은 바로 notifyDataSetChanged() 메소드입니다.
우리가 표시할 데이터를 담고 있는 리스트인 list 객체에 데이터를 추가함으로써 데이터에 변화가 생기게 되었고, 이러한 변화는 어댑터가 자동으로 감지하지 못하므로 어댑터에게 이 사실을 알려야 합니다. notifyDataSetChanged() 메소드를 호출하게 되면 어댑터가 다시 리스트로부터 최신의 데이터를 받아오고, 업데이트된 내용이 다시 ListView에 표시될 수 있게 해줍니다.
따라서, 표시할 데이터를 수정하였다면 이 메소드를 호출해야만 ListView에 수정된 내용이 정상적으로 표시되므로 데이터를 변경하였을 때에는 이 메소드를 호출해주는 것을 잊지 말아야 합니다.
예제의 실행 모습은 아래와 같습니다.
ListViewExample 예제의 실행 모습
ListView 선택 이벤트 처리
ListView에 표시된 항목을 클릭했을 때 어떤 동작을 구현하고 싶다면 어떻게 해야할까요? 어렵게 생각하실지도 모르겠지만, 정말 간단합니다. ListActivity 내의 메소드인 onListItemClick() 메소드를 오버라이드한 후 구현하면 됩니다. 아래에서는 위의 예제에 이어 항목을 선택하면 선택한 항목의 문자열을 토스트(Toast)를 통해 표시해주도록 하고 있습니다.
1.
@Override
2.
protected
void
onListItemClick (ListView l, View v,
int
position,
long
id){
3.
super
.onListItemClick(l, v, position, id);
4.
Toast.makeText(
this
, list.get(position), Toast.LENGTH_SHORT).show();
5.
}
onListItemClick() 메소드는 총 4개의 인자를 받으며, 각각은 아래와 같은 값을 가집니다.
- ListView : 리스트 항목 선택 이벤트가 발생한 ListView
- View : 선택한 "항목"의 뷰 인스턴스 (리스트의 한 항목)
- position : 선택한 항목의 인덱스 값
- id : 데이터베이스 등을 표시하는 ListView일 경우 선택한 항목의 id값
위의 메소드를 추가한 후 예제를 실행시켜 보면 아래와 같은 결과를 볼 수 있습니다.
두 번째 항목을 클릭했을 때의 화면
어때요? 생각보다 쉽지 않나요? 어댑터라는 개념 때문에 처음에는 생소하고 어려워 보일지 몰라도 알고보면 그리 어렵지 않은녀석(?)이랍니다. :)