ListFragment에 Custom ListView 만드는 방법. (ListFragment with Custom ListView)
1. ListFragment
Fragment에 ListView를 만드는 방법이 그리 어렵지는 않지만, 그 마저도 쉽게 구현할 수 있도록, 안드로이드에서는 ListFragment라는 클래스를 제공하고 있습니다. 지난 글 [ListView를 가지는 Fragment 만들기]을 통해 기본적인 형태(TextView만 사용)의 ListFragment를 구현하는 방법에 대해 살펴볼 수 있습니다.
ListFragment에 Adapter를 지정하는 setListAdapter() 함수의 존재를 보면 알 수 있듯이, ListFragment는 ListView의 Wrapper(감싸기, 포장) 클래스 역할을 하는 Fragment라고 정의할 수 있습니다. 즉, ListFragment는 ListView를 멤버로 가지면서, ListView에 대한 구현 절차를 ListView에 대한 직접적인 접근이 아닌, ListFragment에서 제공하는 함수를 통해 수행하도록 만든 클래스인 것입니다.
이렇게 함으로써 Fragment와 ListView가 제공하는 기능들을 한번에 구현할 수 있고, 각각을 구현하는 과정을 다소 간소화할 수 있는 장점이 있습니다. 하지만 ListFragment를 익숙하게 사용하기 위해서는 Fragment와 ListView의 구현작업에 대한 이해가 필수적이므로, 먼저 설명한 [ListView] 및 [Fragment] 에 관한 내용들을 살펴보시길 바랍니다.
1.1 Custom ListView
[안드로이드 커스텀 리스트뷰 만드는 방법]에서 살펴봤듯이, ListView를 사용할 때, 하나의 ListView 아이템에 이미지나 버튼, 텍스트 등의 View 위젯을 조합하여 여러 정보를 한번에 보여주는 경우가 흔합니다. 하지만 텍스트만으로 아이템을 표시하는 [안드로이드 리스트뷰 기본 사용법]에 비해 몇 가지 추가적인 작업이 필요합니다.
ListFragment 또한 마찬가지입니다. ListFragment에 Custom ListView를 만들기 위해서는 [ListView를 가지는 Fragment 만들기]에서 살펴본 과정에 몇 가지 작업을 더 해줘야 합니다.
2. ListFragment에 Custom ListView 사용하기
[안드로이드 커스텀 리스트뷰 만드는 방법]에서 작성한 예제를 ListFragment를 사용하여 만들어 보도록 하겠습니다.
2.1 워크 플로우
2.2 Activity에 Fragment 추가
Activity의 Layout 리소스 XML에 ListFragment를 추가합니다.
[STEP-1] "activity_main.xml" - MainActivity에 Fragment 추가.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="com.recipes4dev.examples.customlistfragmentexample1.MainActivity"
tools:showIn="@layout/activity_main">
<fragment
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/customlistfragment"
android:name="com.recipes4dev.examples.customlistfragmentexample1.CustomListFragment"
tools:layout="@layout/activity_main" />
</RelativeLayout>
2.3 ListFragment 상속 및 구현
ListFragment를 상속한 새로운 클래스를 추가합니다.
[STEP-2] "CustomListFragment.java" - ListFragment 클래스 상속.
import android.support.v4.app.ListFragment;
public class CustomListFragment extends ListFragment {
// TODO
}
2.4 ListView 아이템에 대한 Layout 구성
ListFragment의 ListView 아이템에 표시될 Layout을 구성합니다. [안드로이드 커스텀 리스트뷰 만드는 방법]에서 사용한 Layout 리소스 XML을 그대로 사용합니다.
[STEP-3] "/res/layout/listview_item.xml" - ListView 아이템 Layout 작성.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="@+id/imageView1"
android:layout_weight="1" />
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="4">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="New Text"
android:id="@+id/textView1"
android:textSize="24sp"
android:textColor="#000000"
android:gravity="center_vertical"
android:layout_weight="2" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="New Text"
android:id="@+id/textView2"
android:textSize="16sp"
android:textColor="#666666"
android:layout_weight="1" />
</LinearLayout>
</LinearLayout>
2.5 아이템 데이터에 대한 클래스 정의
ListView 아이템 클래스 또한 [안드로이드 커스텀 리스트뷰 만드는 방법]의 클래스를 사용합니다.
[STEP-4] "ListViewItem.java" - ListView 아이템 데이터 클래스 정의.
package com.recipes4dev.examples.customlistfragmentexample1;
import android.graphics.drawable.Drawable;
public class ListViewItem {
private Drawable iconDrawable ;
private String titleStr ;
private String descStr ;
public void setIcon(Drawable icon) {
iconDrawable = icon ;
}
public void setTitle(String title) {
titleStr = title ;
}
public void setDesc(String desc) {
descStr = desc ;
}
public Drawable getIcon() {
return this.iconDrawable ;
}
public String getTitle() {
return this.titleStr ;
}
public String getDesc() {
return this.descStr ;
}
}
2.6 Adapter 클래스 상속 및 구현.
BaseAdapter를 상속하여 새로운 Adapter 클래스를 추가합니다. (ListViewAdapter의 각 함수에 관한 설명은 [안드로이드 커스텀 리스트뷰 만드는 방법] 또는 코드의 주석을 참고하시기 바랍니다.)
[STEP-5] "ListViewAdapter.java" - BaseAdapter 상속 및 ListViewAdapter 구현.
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
public class ListViewAdapter extends BaseAdapter {
// Adapter에 추가된 데이터를 저장하기 위한 ArrayList
private ArrayList<ListViewItem> listViewItemList = new ArrayList<ListViewItem>() ;
// ListViewAdapter의 생성자
public ListViewAdapter() {
}
// Adapter에 사용되는 데이터의 개수를 리턴. : 필수 구현
@Override
public int getCount() {
return listViewItemList.size() ;
}
// position에 위치한 데이터를 화면에 출력하는데 사용될 View를 리턴. : 필수 구현
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final int pos = position;
final Context context = parent.getContext();
// "listview_item" Layout을 inflate하여 convertView 참조 획득.
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.listview_item, parent, false);
}
// 화면에 표시될 View(Layout이 inflate된)으로부터 위젯에 대한 참조 획득
ImageView iconImageView = (ImageView) convertView.findViewById(R.id.imageView1) ;
TextView titleTextView = (TextView) convertView.findViewById(R.id.textView1) ;
TextView descTextView = (TextView) convertView.findViewById(R.id.textView2) ;
// Data Set(listViewItemList)에서 position에 위치한 데이터 참조 획득
ListViewItem listViewItem = listViewItemList.get(position);
// 아이템 내 각 위젯에 데이터 반영
iconImageView.setImageDrawable(listViewItem.getIcon());
titleTextView.setText(listViewItem.getTitle());
descTextView.setText(listViewItem.getDesc());
return convertView;
}
// 지정한 위치(position)에 있는 데이터와 관계된 아이템(row)의 ID를 리턴. : 필수 구현
@Override
public long getItemId(int position) {
return position ;
}
// 지정한 위치(position)에 있는 데이터 리턴 : 필수 구현
@Override
public Object getItem(int position) {
return listViewItemList.get(position) ;
}
// 아이템 데이터 추가를 위한 함수. 개발자가 원하는대로 작성 가능.
public void addItem(Drawable icon, String title, String desc) {
ListViewItem item = new ListViewItem();
item.setIcon(icon);
item.setTitle(title);
item.setDesc(desc);
listViewItemList.add(item);
}
}
2.7 Adapter 생성 후 ListView에 지정.
[ListView를 가지는 Fragment 만들기]에서는 Activity에서 Adapter를 생성한 다음, ListFragment.setListAdapter() 함수를 호출하여 Adapter를 지정하였습니다. 하지만 ListFragment를 상속받은 이상, 굳이 Adapter를 ListFragment의 외부에서 생성할 필요가 없죠. 대신, ListFragment의 내부에서 Adapter와 관련된 처리를 수행해주면 됩니다.
[STEP-6] "CustomListFragment.java" - CustomListFragment에서 Adapter 생성 및 지정.
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.support.v4.content.ContextCompat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.R.id.*;
import android.widget.ListView;
public class CustomListFragment extends ListFragment {
ListViewAdapter adapter ;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Adapter 생성 및 Adapter 지정.
adapter = new ListViewAdapter() ;
setListAdapter(adapter) ;
// 첫 번째 아이템 추가.
adapter.addItem(ContextCompat.getDrawable(getActivity(), R.drawable.ic_account_box_black_36dp),
"Box", "Account Box Black 36dp") ;
// 두 번째 아이템 추가.
adapter.addItem(ContextCompat.getDrawable(getActivity(), R.drawable.ic_account_circle_black_36dp),
"Circle", "Account Circle Black 36dp") ;
// 세 번째 아이템 추가.
adapter.addItem(ContextCompat.getDrawable(getActivity(), R.drawable.ic_assignment_ind_black_36dp),
"Ind", "Assignment Ind Black 36dp") ;
return super.onCreateView(inflater, container, savedInstanceState);
}
}
2.8 ListView 클릭 이벤트 처리
ListFragment의 onListItemClick() 함수를 override하여 ListView 아이템 클릭 이벤트를 처리합니다.
[STEP-7] "CustomListFragment.java" - onListItemClick() 함수를 override하여 클릭 이벤트 처리
public class CustomListFragment extends ListFragment {
// 코드 계속 ...
@Override
public void onListItemClick (ListView l, View v, int position, long id) {
// get TextView's Text.
ListViewItem item = (ListViewItem) l.getItemAtPosition(position) ;
String titleStr = item.getTitle() ;
String descStr = item.getDesc() ;
Drawable iconDrawable = item.getIcon() ;
// TODO : use item data.
}
// ... 코드 계속
}
2.9 ListFragment 외부(Activity)에서 아이템 추가를 위한 함수 구현.
[STEP-6]의 onCreateView에서 Adapter를 생성하고 ListView에 지정한 다음, 샘플 데이터를 추가하였지만, 이는 앱 시작 시 ListFragment 내부에서만 사용할 수 있는 방법입니다. 일반적으로 ListView에 아이템이 추가될 때는 Activity에 정의된 이벤트 핸들러 함수에서 데이터가 로드 되는 것과 같이 앱 실행 중 동적으로 이루어지므로 ListFragment 외부에서 데이터를 추가할 수 있는 방법이 있어야 합니다.
이를 위해 CustomListFragment에 아이템 추가를 위한 함수를 정의하고, Activity에서 해당 함수를 통해 아이템을 추가하는 코드를 작성하겠습니다.
[STEP-8] "CustomListFragment.java" - 아이템 추가 함수 정의.
public class CustomListFragment extends ListFragment {
// 코드 계속 ...
public void addItem(Drawable icon, String title, String desc) {
adapter.addItem(icon, title, desc) ;
}
}
[ListView를 가지는 Fragment 만들기]에서 살펴봤듯이, Activity에 추가한 CustomListFragment의 참조를 가져오기 위해, FragmentManager의 findFragmentById() 함수를 호출합니다. 그리고 addItem() 함수를 호출하여 새로운 아이템을 추가하였습니다.
[STEP-9] "MainActivity.java" - Activity에서 아이템 추가.
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
CustomListFragment customListFrgmt = (CustomListFragment) getSupportFragmentManager().findFragmentById(R.id.customlistfragment);
customListFrgmt.addItem(ContextCompat.getDrawable(this, R.drawable.ic_account_box_black_36dp),
"New Box", "New Account Box Black 36dp") ;
}
}
3. 예제 실행 화면
예제를 작성하고 실행하면 다음과 같은 실행화면이 표시됩니다.
4. 참고.
- 프래그먼트 기본 사용법
- [안드로이드 프래그먼트 기본 사용법]을 참고하세요.
- ListFragment의 기본 사용법
- [ListView를 가지는 Fragment 만들기]을 참고하세요.
- Fragment에 대한 자세한 도움말.
- [안드로이드 개발 API 가이드. 프래그먼트 항목]을 참고하세요.
- [안드로이드 개발 참조문서. ListFragment 항목]을 참고하세요.
.END.
'ANDROID 프로그래밍 > FRAGMENT' 카테고리의 다른 글
제목과 상세 내용으로 나뉘어진 Fragment 예제. (Titles and Details Fragment Example) (18) | 2016.07.09 |
---|---|
ListView를 가지는 Fragment 만들기. (Android ListFragment) (26) | 2016.06.09 |
안드로이드 프래그먼트 기본 사용법. (Android Fragment) (55) | 2016.04.21 |