ListView를 사용하려면 Adapter를 필수적으로 사용해야 합니다.
<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>
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();
}
};
}
원하는 모양의 아이템을 출력하기 위해서 새로운 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>
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);
}
}
위 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");
}
}
여기 까지 제작 하고 실행을 하면 각종 이벤트가 정상 작동 합니다.
하지만, 어댑터에 아이템을 더 추가하여 스크롤이 되게 만들면 아이템 위치가 변경되 출력 되므로 데이터 변형을 방지할 필요가 있습니다.
새로운 클래스를 하나 생성하여 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을 빼내 나머지 처리를 하게 됩니다.
"어떤 것을 완전히 알려거든 그것을 다른 이에게 가르쳐라."
- Tryon Edwards -