ListView '리스트뷰'
- 데이터 목록(List)를 세로 방향의 리스트 형태로 나열하여 화면에 보여주는 ViewGroup 중 하나
- ViewGroup는 스크롤 기본지원
ListView 사용법
- ListView는 3가지의 구성요소로 존재
- 1) View - 화면에 보여줄 레이아웃 내에 View 객체
- 2) Item - 화면에 표시할 실질적인 item리스트 (데이터)
- 3) Adapter - Item리스트(데이터)를 View와 연결해서 뷰(View) 생성 및 관리하는 객체
Item -> Adapter, 아이템(리스트)와 Adapter를 연결하면 Adapter가 View를 생성
Adapter -> ListView, 어답터(Adapter)가 View를 생성해서 ListView에 배치
ListView 구현
1) 보여줄 레이아웃 XML 정의
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
<!-- Activity 타이틀 -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:layout_marginBottom="30dp"
android:text="SeekBar Activity"
android:textSize="25sp" />
<!-- 리스트뷰, ListView -->
<ListView
android:id="@+id/listview_list"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
2) ListView Item, 아이템 레이아웃 XML 정의
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_margin="10dp"
android:orientation="horizontal">
<!-- 리스트뷰 순서 표시할 TextView -->
<TextView
android:id="@+id/listitem_number"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="번호" />
<!-- 리스트뷰 아이템 내용 'Title' -->
<TextView
android:id="@+id/listitem_title"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:gravity="center_vertical"
android:text="title"
android:textSize="20sp" />
<!-- 리스트뷰 아이템 이미지 'image' -->
<ImageView
android:id="@+id/listitem_image"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:src="@drawable/ic_message" />
</LinearLayout>
3) item 데이터 객체, 클래스 생성
private class ListView_Item {
// 아이템 각각 내용, 'Title'
private String title;
// 아이템 각각 이미지 리소스 ID, 'Image'
private int image;
// 생성자 함수
public ListView_Item(String title, int image) {
this.title = title;
this.image = image;
}
public String getTitle() {
return title;
}
public int getImage() {
return image;
}
}
4) ListView 표현할 Adapter 구현, BaseAdapter 상속
-> getView()에서 item 레이아웃 inflation하는 방법은 2가지
// 첫번째 방법 1
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = layoutInflater.inflate(R.layout.listview_item, parent, false);
// 두번째 방법 2
View view = LayoutInflater.from(context).inflate(R.layout.listview_item, parent, false);
int getCount() : Adapter에 연결된 아이템 총 개수 반환
아이템타입 getItem(int position) : 아이템리스트 중 해당 위치(position) 아이템 반환
long getItemId(int position) : 해당 위치 position 반환
View getView() : 해당 위치 View 반환
private class ListView_Adapter extends BaseAdapter {
// 보여줄 Item 목록을 저장할 List
List<ListView_Item> items = null;
Context context;
// Adapter 생성자 함수
public ListView_Adapter(Context context, List<ListView_Item> items) {
this.items = items;
this.context = context;
}
// Adapter.getCount(), 아이템 개수 반환 함수
@Override
public int getCount() {
return items.size();
}
// Adapter.getItem(int position), 해당 위치 아이템 반환 함수
@Override
public ListView_Item getItem(int position) {
return items.get(position);
}
// Adapter.getItemId(int position), 해당 위치 반환 함수
@Override
public long getItemId(int position) {
return position;
}
// Adapter.getView() 해당위치 뷰 반환 함수
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// Infalter 구현 방법 1
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = layoutInflater.inflate(R.layout.listview_item, parent, false);
// ListView의 Item을 구성하는 뷰 연결
TextView number = view.findViewById(R.id.listitem_number);
TextView title = view.findViewById(R.id.listitem_title);
ImageView image = view.findViewById(R.id.listitem_image);
// ListView의 Item을 구성하는 뷰 세팅
ListView_Item item = items.get(position);
number.setText(String.valueOf(position+1)); // 해당위치 +1 설정, 배열순으로 0부터 시작
title.setText(item.getTitle()); // item 객체 내용을 가져와 세팅
image.setImageResource(item.getImage()); // item 객체 내용을 가져와 세팅
// 설정한 view를 반환해줘야 함
return view;
}
}
5) Adapter 생성 - ListView 연결
-> Item 리스트를 먼저 생성한 다음, Item리스트로 Adapter를 생성
-> 생성한 Adapter를 ListView에 추가.
-> 클릭 이벤트 처리
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_listview);
// ListView 생성
ListView listView = findViewById(R.id.listview_list);
// Item 리스트 선언 함수 init_ArrayList(20), 20은 추가할 아이템 개수
init_ArrayList(20);
// 만들어진 item 리스트로 Aapter 생성
ListView_Adapter mAdapter = new ListView_Adapter(this, items);
// ListView에 Adapter 연결
listView.setAdapter(mAdapter);
// ListView Item 클릭이벤트 처리
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
// AdapterView - 리스트뷰에 연결한 Adapter, getItemAtPosition(),
// Adapter의 메소드 getItem()과 동일한 메소드
ListView_Item item = (ListView_Item) adapterView.getItemAtPosition(position);
// 클릭한 위치의 Item의 title 문자열 반환
String title = item.getTitle();
// 클릭한 위치의 Item Title 문자열 토스트로 보여주기
Toast.makeText(context, title, Toast.LENGTH_SHORT).show();
}
});
}
Item List에 item을 추가하는 함수, 사용자 입력 아이템 개수만큼
// Item 리스트를 생성하는 함수
private void init_ArrayList(int count) {
// item을 저장할 List 생성
items = new ArrayList<>();
// Drawable 이미지 리소스 ID 값을 가져오기 위해 Resource객체 생성
Resources res = getResources();
// 함수의 인자로 넘겨준 count 아이템 개수만큼 반복, 아이템 추가
for (int i = 0; i < count; i++) {
// 이미지리소스 id값을 가져옴, res.getIdentifier("이미지 이름", "리소스 폴더 이름", 현재패키지 이름)
int img_ID = res.getIdentifier("listview_item" + (i % 4), "drawable", getPackageName());
// item 객체 생성하여 리스트에 추가
items.add(new ListView_Item((i + 1) + "번째 아이템", img_ID));
}
}
ViewHolder '뷰홀더' 필요성
- ListView는 스크롤 시 안보이던 아이템은 매번 getView로 재호출
- 아이템 내 View들을 매번 findViewById()로 로 재연결 (자원 낭비)
- 해결을 위해 ViewHolder로 한번 생성된 View는 findViewById 재호출 막음
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
// 아이템 내 View들을 저장할 Holder 생성
ViewHolder holder;
// convertView는 생성된적이 없으면 Null을 반환, 최초생성시 Null이므로 최초생성인지 판단
if (view == null) {
// 최초생성 View인 경우, inflation -> ViewHolder 생성 -> 해당 View에 setTag 저장
view = LayoutInflater.from(context).inflate(R.layout.listview_item, parent, false);
holder = new ViewHolder();
holder.number = view.findViewById(R.id.listitem_number);
holder.title = view.findViewById(R.id.listitem_title);
holder.image = view.findViewById(R.id.listitem_image);
// 해당 View에 setTag로 Holder 객체 저장
view.setTag(holder);
} else {
// ConvertView가 이미 생성된적 있다면, 저장되어있는 Holder 가져오기
holder = (ViewHolder) convertView.getTag();
}
// Holder 객체 내의 뷰(TextView,ImageView)를 세팅
ListView_Item item = items.get(position);
holder.number.setText(String.valueOf(position + 1));
holder.title.setText(item.getTitle());
holder.image.setImageResource(item.getImage());
// 해당 View 반납 필수
return view;
}
}
참조
- "ListView 구현" - https://Iktprogrammer.tistory.com/163