1. xml 수정하기
ListView가 보여질 레이아웃의 xml에 ListView 위젯을 추가 합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <relativelayout xmlns:android= "http://schemas.android.com/apk/res/android" 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 설정
어댑터를 생성하고 xml에 추가한 Listview에 어댑터를 연결하여 ListView가 동작 되도록 해보겠습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | 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( "하스스톤" ); m_Adapter.add( "몬스터 헌터" ); m_Adapter.add( "디아블로" ); m_Adapter.add( "와우" ); m_Adapter.add( "리니지" ); m_Adapter.add( "안드로이드" ); m_Adapter.add( "아이폰" ); } // 아이템 터치 이벤트 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 파일
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <?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 대신에 직접 만든 클래스를 추가하면 더욱 많은 정보를 가진 커스텀 아이템을 제작 할 수 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | 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번 소스와 비교해 보시면 어댑터 부분이 변경 된 것을 확인 하실 수 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | 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( "하스스톤" ); m_Adapter.add( "몬스터 헌터" ); m_Adapter.add( "디아블로" ); m_Adapter.add( "와우" ); m_Adapter.add( "리니지" ); m_Adapter.add( "안드로이드" ); m_Adapter.add( "아이폰" ); } } |
여기 까지 제작 하고 실행을 하면 각종 이벤트가 정상 작동 하는 것을 확인 하실 수 있습니다.
하지만, 어댑터에 아이템을 더 추가하여 스크롤이 되게 만들면 아이템 위치가 변경되 출력 되는게 보이실 겁니다.
6. Holder를 추가하여 데이터 변형 방지
새로운 클래스를 하나 생성하여 getView()에서 홀더를 사용하면 스크롤 시 데이터가 변경 되는 것과 findViewById()를 사용을 줄여 향상 된 속도를 얻을 수 있습니다.
변경 된 부분의 소스는 아래와 같습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | // 출력 될 아이템 관리 @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을 빼내 나머지 처리를 하게 됩니다.
이상으로 ListView 사용 방법과 커스텀에 대한 튜토리얼을 마치도록 하겠습니다.