ListView를 가지는 Fragment 만들기. (Android ListFragment)

2016. 6. 9. 09:48


1. Fragment와 ListView

Fragment를 사용하여 UI를 구성하면, 화면을 모듈 단위로 나누어 작성하기 편하고, 한번 만들어진 Fragment를 재사용할 수 있으며, 다양한 해상도 및 화면 모드에서 유연하게 동작하는 앱을 작성할 수 있습니다. 이러한 여러 가지 장점을 가진 Fragment가 가장 많이 활용되는 경우는, ListView를 사용하여 목록(메뉴) 형태의 UI를 제공하는 앱을 개발할 때 입니다.


[안드로이드 프래그먼트 기본 사용법]에서 살펴봤듯이, Fragment를 사용하여 UI를 구성하는 것은 그리 복잡한 작업이 아닙니다. Activity에서 UI를 구성하는 것과 유사한 방법으로 화면을 표시할 수 있죠.
ListView를 사용하여 목록(메뉴) 형태의 UI를 만드는 방법 또한 마찬가지입니다. [안드로이드 리스트뷰 기본 사용법]에서 Activity에 ListView를 만드는 방법과 Fragment에 ListView를 사용할 때의 주의 사항을 설명하였으니, 충분히 참고가 되리라 생각됩니다.


그런데 안드로이드에서는, 친절하게도, ListView를 포함하는 Fragment를 별도의 클래스로 제공하고 있습니다. ListFragment라는 꽤 직관적인 이름으로 말이죠. ListFragment를 사용하면 ListView를 일일이 만들 필요 없이, ListFragment에서 제공하는 함수들을 사용해서 ListView가 표시되는 Fragment를 만들 수 있습니다.


ListFragment



2. ListFragment를 사용하여 간단한 ListView(텍스트만 표시) 만들기

[안드로이드 리스트뷰 기본 사용법]에서, 안드로이드에서 제공하는 가장 기본적인 형태(TextView만 표시)의 ListView를 만드는 방법에 대해 살펴보았습니다. 여기서는 ListFragment를 사용하여 그것과 동일한 기능을 수행하는 예제를 만들어 보겠습니다.


ListFragment를 사용한다고 해서 일반적인 Fragment 사용법의 범위를 벗어난, 대단한 작업이 필요한 것은 아닙니다. [안드로이드 프래그먼트 기본 사용법]에서 설명한 방법들이 유사하게 적용됩니다.


2.1 워크 플로우

ListFragment 작성 절차


2.2 Activity에 ListFragment 추가.

Activity에 ListFragment를 출력하기 위해 Activity의 Layout 리소스 XML에 아래의 내용을 작성합니다.


[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.listfragmentexample1.MainActivity"
    tools:showIn="@layout/activity_main">

    <fragment
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/menulistfragment"
        android:name="com.recipes4dev.examples.listfragmentexample1.MenuListFragment"
        tools:layout="@layout/activity_main" />

</RelativeLayout>


Fragment를 Layout 리소스 XML에 직접 추가해서 사용하기 위해서는 Fragment의 "android:name" 속성에 Fragment의 클래스를 지정해야 합니다. 다음 단계에서 추가할 클래스 이름을 여기에 지정하면 됩니다.


사실 여기서 "android:name"에 지정되는 클래스를 새로 생성하는 클래스가 아닌 "android.support.v4.app.ListFragment"로 해도 방법 상에 문제는 없습니다. 하지만, ListView 클릭 이벤트를 처리하기 위해서 onListItemClick() 함수를 override해야 하기 때문에 ListFragment를 상속받는 새로운 클래스를 추가하는 것입니다.

ListFragment를 사용할 때 Fragment위에 표시될 Layout 리소스 XML을 반드시 작성해야 하는 것은 아닙니다. ListFragment 자체적으로 ListView를 가지고 있기 때문에, 이미 Layout 리소스 XML을 가지고 있는 것이죠.


2.3 ListFragment 상속 및 구현.

ListFragment를 상속받은 클래스를 MenuListFragment라는 이름으로 추가합니다.


[STEP-2] "MenuListFragment.java" - ListFragment 클래스 상속. 
import android.support.v4.app.ListFragment;

public class MenuListFragment extends ListFragment {
    // TODO
}


안드로이드 스튜디오에서 클래스를 추가할 때, 이미 만들어진 템플릿을 적용하여 Fragment 클래스를 생성할 수 있습니다. 하지만 여기서는 기본적인 내용 설명을 위해 템플릿 코드 없이 클래스를 추가하였습니다.

2.4 ListFragment의 ListView에 데이터 추가.

[안드로이드 리스트뷰 기본 사용법]에서는 ListView에 데이터를 추가할 때, 아래의 코드 내용처럼 Adapter를 생성한 다음 ListView의 setAdapter() 함수를 호출하였습니다.


    ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, LIST_MENU) ;

    ListView listview = (ListView) findViewById(R.id.listview1) ;
    listview.setAdapter(adapter) ;


하지만 ListFragment에서는 위의 코드 대신 ListFragment에서 제공하는 함수를 사용하여 Adapter를 지정합니다. 사용하는 함수 이름은 setListAdapter() 입니다.


[STEP-3] "MainActivity.java" - onCreate() 함수에서 ListFragment에 Adapter 적용.
public class MainActivity extends AppCompatActivity {
    static final String[] LIST_MENU = {"LIST1", "LIST2", "LIST3"} ;
    // ... 코드 계속

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // 코드 계속 ...

        ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, LIST_MENU) ;

        ListFragment menuListFrgmt = (ListFragment) getSupportFragmentManager().findFragmentById(R.id.menulistfragment);
        menuListFrgmt.setListAdapter(adapter) ;
    }
}


기초적인 설명을 덧붙이자면, Activity에서 Layout 리소스 XML에 정의된 Fragment의 참조를 가져오려면 FragmentManager를 사용해야 합니다. 즉, 일반적인 View위젯을 가져올 때 사용했던 findViewById()함수는 사용할 수 없고, FragmentManager의 findFragmentById() 함수를 사용해야 하는 것입니다.
그럼 Activity에서 FragmentManager를 가져오려면 어떻게 해야 할까요? 예제 코드에 있는 것처럼 getSupportFragmentManager()함수를 사용하면 됩니다.


Activity의 getSupportFragmentManager() 함수를 호출하여 FragmentManager의 참조를 획득한 다음, FragmentManager의 findFragmentById() 함수를 호출하여 Fragment의 참조를 가져오는 것이죠.


여기서 한 가지 주의해야 할 것은 getSupportFragmentManager() 함수에서 "Support" 라는 이름입니다. [STEP-2]에서 추가한 MenuListFragment는 "android.support.v4.app.ListFragment"를 상속하였습니다. 그렇기 때문에 getSupportFragmentManager() 함수를 사용한 것이죠. 만약 Support Library가 아닌 "android.app.ListFragment"를 사용한다면 getFragmentManager() 함수를 사용해야 합니다.


2.5 ListFragment의 ListView 아이템 클릭 이벤트 처리.

[안드로이드 리스트뷰 기본 사용법]에서 ListView 아이템에 대한 클릭 이벤트를 처리하는 코드는 OnItemClickListener를 생성하여 ListView의 setOnItemClickListener() 함수에 전달하는 방법이었습니다.


하지만 ListFragment에서는 별도의 리스너를 만들지 않고,  onListItemClick() 이라는 함수를 override하면 됩니다.


[STEP-4] "MenuListFragment.java" - ListFragment의 onListItemClick() 함수 override.
public class MenuListFragment extends ListFragment {

    @Override
    public void onListItemClick (ListView l, View v, int position, long id) {
        // get TextView's Text.
        String strText = (String) l.getItemAtPosition(position) ;
        // TODO
    }
}


onListItemClick() 함수의 파라미터는 ListView 클릭 리스너의 onItemClick() 함수와 동일하므로 ListView의 클릭 이벤트를 다루는 방법과 동일하게 처리할 수 있습니다.

2.6 ListFragment와 간단한 ListView 예제 실행 화면.

아래는 예제 실행 화면입니다. [안드로이드 리스트뷰 기본 사용법]에서 작성했던 예제와 실행 결과가 동일한 것을 확인할 수 있습니다.

ListFragment 예제 실행 화면


3. 참고.

.END.


ANDROID 프로그래밍/FRAGMENT