ListView를 사용하려면 Adapter를 필수적으로 사용해야 합니다.
1. xml 수정하기
<relativelayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#47C83E"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</RelativeLayout>
2. ListView 및 Adapter 설정
package pe.berabue.tutoriallistview;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
public class MainActivity extends Activity {
private ListView m_ListView;
private ArrayAdapter<string> m_Adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Android에서 제공하는 string 문자열 하나를 출력 가능한 layout으로 어댑터 생성
m_Adapter = new ArrayAdapter<string>(getApplicationContext(), android.R.layout.simple_list_item_1);
// Xml에서 추가한 ListView 연결
m_ListView = (ListView) findViewById(R.id.listview);
// ListView에 어댑터 연결
m_ListView.setAdapter(m_Adapter);
// ListView 아이템 터치 시 이벤트 추가
m_ListView.setOnItemClickListener(onClickListItem);
// ListView에 아이템 추가
m_Adapter.add("아이템1");
m_Adapter.add("아이템2");
m_Adapter.add("아이템3");
m_Adapter.add("아이템4");
m_Adapter.add("아이템5");
m_Adapter.add("아이템6");
m_Adapter.add("아이템7");
}
// 아이템 터치 이벤트
private OnItemClickListener onClickListItem = new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
// 이벤트 발생 시 해당 아이템 위치의 텍스트를 출력
Toast.makeText(getApplicationContext(), m_Adapter.getItem(arg2), Toast.LENGTH_SHORT).show();
}
};
}
3. ListView에 출력 될 레이아웃 만들기
원하는 모양의 아이템을 출력하기 위해서 새로운 xml파일을 생성하여 출력 될 모양을 만들어야 합니다.
리스트에 출력될 모양 만들기
custom_item.xml 파일
<?xml version="1.0" encoding="utf-8"?>
<relativelayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<textview
android:id="@+id/text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceInverse"
android:textColor="#000000"
/>
<Button
android:id="@+id/btn_test"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceButton"
android:textColor="#000000"
android:text="Toast"
android:layout_alignParentRight="true"
/>
</RelativeLayout>
4. 커스텀 어댑터 생성
CustomAdapter 클래스를 생성하고 BaseAdapter 클래스를 상속 받습니다.
문자열을 보관 하기 위해 ArrayList<String> 를 사용하며, String 대신에 직접 만든 클래스를 추가하면 더욱 많은 정보를 가진 커스텀 아이템을 제작 할 수 있습니다.
package pe.berabue.tutoriallistview;
import java.util.ArrayList;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class CustomAdapter extends BaseAdapter {
// 문자열을 보관 할 ArrayList
private ArrayList<string> m_List;
// 생성자
public CustomAdapter() {
m_List = new ArrayList<string>();
}
// 현재 아이템의 수를 리턴
@Override
public int getCount() {
return m_List.size();
}
// 현재 아이템의 오브젝트를 리턴, Object를 상황에 맞게 변경하거나 리턴받은 오브젝트를 캐스팅해서 사용
@Override
public Object getItem(int position) {
return m_List.get(position);
}
// 아이템 position의 ID 값 리턴
@Override
public long getItemId(int position) {
return position;
}
// 출력 될 아이템 관리
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final int pos = position;
final Context context = parent.getContext();
// 리스트가 길어지면서 현재 화면에 보이지 않는 아이템은 converView가 null인 상태로 들어 옴
if ( convertView == null ) {
// view가 null일 경우 커스텀 레이아웃을 얻어 옴
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.custom_item, parent, false);
// TextView에 현재 position의 문자열 추가
TextView text = (TextView) convertView.findViewById(R.id.text);
text.setText(m_List.get(position));
// 버튼을 터치 했을 때 이벤트 발생
Button btn = (Button) convertView.findViewById(R.id.btn_test);
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 터치 시 해당 아이템 이름 출력
Toast.makeText(context, m_List.get(pos), Toast.LENGTH_SHORT).show();
}
});
// 리스트 아이템을 터치 했을 때 이벤트 발생
convertView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 터치 시 해당 아이템 이름 출력
Toast.makeText(context, "리스트 클릭 : "+m_List.get(pos), Toast.LENGTH_SHORT).show();
}
});
// 리스트 아이템을 길게 터치 했을 떄 이벤트 발생
convertView.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
// 터치 시 해당 아이템 이름 출력
Toast.makeText(context, "리스트 롱 클릭 : "+m_List.get(pos), Toast.LENGTH_SHORT).show();
return true;
}
});
}
return convertView;
}
// 외부에서 아이템 추가 요청 시 사용
public void add(String _msg) {
m_List.add(_msg);
}
// 외부에서 아이템 삭제 요청 시 사용
public void remove(int _position) {
m_List.remove(_position);
}
}
5. ListView 및 Adapter 설정
위 2번에서 했던 작업 입니다. 2번 소스와 비교해 보시면 어댑터 부분이 변경 된 것을 확인 하실 수 있습니다.
package pe.berabue.tutoriallistview;
import android.app.Activity;
import android.os.Bundle;
import android.widget.ListView;
public class MainActivity extends Activity {
private ListView m_ListView;
private CustomAdapter m_Adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 커스텀 어댑터 생성
m_Adapter = new CustomAdapter();
// Xml에서 추가한 ListView 연결
m_ListView = (ListView) findViewById(R.id.listview);
// ListView에 어댑터 연결
m_ListView.setAdapter(m_Adapter);
// ListView에 아이템 추가
m_Adapter.add("아이템1");
m_Adapter.add("아이템2");
m_Adapter.add("아이템3");
m_Adapter.add("아이템4");
m_Adapter.add("아이템5");
m_Adapter.add("아이템6");
m_Adapter.add("아이템7");
}
}
여기 까지 제작 하고 실행을 하면 각종 이벤트가 정상 작동 합니다.
하지만, 어댑터에 아이템을 더 추가하여 스크롤이 되게 만들면 아이템 위치가 변경되 출력 되므로 데이터 변형을 방지할 필요가 있습니다.
6. Holder를 추가하여 데이터 변형 방지
새로운 클래스를 하나 생성하여 getView()에서 홀더를 사용하면 스크롤 시 데이터가 변경 되는 것과 findViewById()를 사용을 줄여 향상 된 속도를 얻을 수 있습니다.
변경 된 부분의 소스는 아래와 같습니다.
// 출력 될 아이템 관리
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final int pos = position;
final Context context = parent.getContext();
TextView text = null;
Button btn = null;
CustomHolder holder = null;
// 리스트가 길어지면서 현재 화면에 보이지 않는 아이템은 converView가 null인 상태로 들어 옴
if ( convertView == null ) {
// view가 null일 경우 커스텀 레이아웃을 얻어 옴
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.custom_item, parent, false);
text = (TextView) convertView.findViewById(R.id.text);
btn = (Button) convertView.findViewById(R.id.btn_test);
// 홀더 생성 및 Tag로 등록
holder = new CustomHolder();
holder.m_TextView = text;
holder.m_Btn = btn;
convertView.setTag(holder);
}
else {
holder = (CustomHolder) convertView.getTag();
text = holder.m_TextView;
btn = holder.m_Btn;
}
// Text 등록
text.setText(m_List.get(position));
// 버튼 이벤트 등록
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 터치 시 해당 아이템 이름 출력
Toast.makeText(context, m_List.get(pos), Toast.LENGTH_SHORT).show();
}
});
// 리스트 아이템을 터치 했을 때 이벤트 발생
convertView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 터치 시 해당 아이템 이름 출력
Toast.makeText(context, "리스트 클릭 : "+m_List.get(pos), Toast.LENGTH_SHORT).show();
}
});
// 리스트 아이템을 길게 터치 했을 떄 이벤트 발생
convertView.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
// 터치 시 해당 아이템 이름 출력
Toast.makeText(context, "리스트 롱 클릭 : "+m_List.get(pos), Toast.LENGTH_SHORT).show();
return true;
}
});
return convertView;
}
private class CustomHolder {
TextView m_TextView;
Button m_Btn;
}
CustomHolder 라는 클래스가 하나 추가 되었으며 이 클래스는 아이템이 갖고 있는 요소를 저장 할 수 있도록 TextView와 Button을 갖고 있습니다.
그리고 getView() 함수에서는 convertView가 null 일 때 holder를 생성하여 holder에 TextView와 Button을 넣고 해당 View의 Tag로 지정을 합니다. 만약 convertView가 null이 아니라면 Tag를 가져와 저장해 놓았던 TextView와 Button을 빼내 나머지 처리를 하게 됩니다.