Android 의 ListView 사용

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을 빼내 나머지 처리를 하게 됩니다.

 

 

Tags: 
youngdeok's picture

Language

Get in touch with us

"If you would thoroughly know anything, teach it to other."
- Tryon Edwards -