ListView와 ArrayAdapter, ArrayList를 이용하기 + 커스텀 리스트화면 만들기

5 분 소요

ListView 사용 까닭

리스트 뷰는 단순하게 수직 리스트 화면을 구성하는 뷰다. View –> AdapterVIew –> ListView 의 상속관계를 갖고 있다.

리스트 뷰를 이용하는 까닭은? 우리가 뮤직 앱이나 트위터 같이 한정을 을수 없이 길게 늘어진 리스트를 구성할 떄 단순히 linear layout으로 구성한다면 어떻게 될까? 각각의 child를 한 번에 생성해야 하기 때문에 엄청난 메모리 소모가 있을 것이다. 이 때 ListView를 사용하면, 화면 밖에 안 보이는 부분의 child는 만들지 않고 스크롤 함에 따라 재사용 하여 메모리 소모를 최소화한다. (최근에는 더 발전한 RecyclerView)라는 게 나온 듯 싶다.)

링크 참조
https://developer.android.com/reference/android/widget/ListView

사용방법

ListView 는 혼자서는 작동할 수 없고, 그 안에 들어갈 resource 가 필요한데 ArrayList 오브젝트를 이용한다. 단 이 때 Arraylist가 바로 들어가는 게 아니고 ArrayAdapter가 중간에서 매개자 역할을 한다. 관계를 나타내면 다음과 같다.

ListView <–> ArrayAdapter(ArrayList)

즉 ListView가 화면을 구성하기 위해, 그 내용을 ArrayAdapter에게 요청하는 식이다. 리스트뷰는 껍데기라고 생각하자.

아래와 같이 출력을 원하는 xml에 리스트뷰를 하나 생성한다.

<ListView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/list"
    android:orientation="vertical"
    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"/>

해당 activity 의 oncreat method에 ArrayAdapter와 Arraylist를 구성해 보자.

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.example_activity);

        // 먼저 리소스 파일인 Arraylist를 만든다. 
        ArrayList<String> words = new ArrayList<String>();
        words.add("one");
        words.add("two");
        words.add("three");
        words.add("four");
        words.add("five");


        //ArrayAdapter를 만들어준다. 
        //android.R.layout에서 제공하는 custom layout을 이용하자. 단순히 TextView가 하나 있는 xml이다. 
        //ArrayList words 를 마지막 인수로 넣어준다.  
        ArrayAdapter<String> itemsAdapter =
                new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, words);


        //아까 만든 xml파일에 있는 listView를 불러온다. 
        ListView listView = (ListView) findViewById(R.id.list);

        //SetAdapter를 이용해 ListView와 ArrayAdapter를 연결한다. 
        listView.setAdapter(itemsAdapter);
    }

custom list화면 만들기

ArrayAdapter는 각 행에 텍스트요소 하나씩만 들어갈 때만 사용 가능하다. 하지만 각 열에 텍스트가 두개라면? 이미지가 있다면? 이 때 custom object 와 custom Adapter가 필요할 때다.

custom class

텍스트가 두 개 들어가는 CustomWord class를 구성해 보자.


public class CustomWord {

    private String mS1;

    private String mS2;

    public String getS1(){
        return mS1;
    }

    public String getS2(){
        return mS2;
    }

    public CustomWord(String s1, String s2){
        mS1 = s1;
        mS2 = s2;
    }

}

다음으로 android에서 기존 제공해줬던 android.R.layout.simple_list_item_1 대신에 사용할 textView를 두 개 갖는 layout xml파일을 하나 만들자. 이름은 customLayout.xml로 하자.

리니어 레이아웃에 TextView 두 개를 넣으면 됨.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">


    <TextView
        android:id="@+id/text_view_1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceListItemSmall"
        android:gravity="center_vertical"
        android:padding="16dp"
        android:minHeight="?android:attr/listPreferredItemHeightSmall" />

    <TextView
        android:id="@+id/text_view_2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceListItemSmall"
        android:gravity="center_vertical"
        android:padding="16dp"
        android:minHeight="?android:attr/listPreferredItemHeightSmall" />
</LinearLayout>

이후 아까 구성해놨던 onCreat을 이렇게 바꾸자.

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.example_activity);
 
        ArrayList<CustomWord> customWords = new ArrayList<CustomWord>();
        words.add(new CustomWords("one","1"));
        words.add(new CustomWords("two","2"));
        words.add(new CustomWords("three","3"));
        words.add(new CustomWords("four","4"));
        words.add(new CustomWords("five","5"));


        CustomArrayAdapter<CustomWord> itemsAdapter =
                new CustomArrayAdapter<CustomWord>(this, customLayout.xml, words);


        //아까 만든 xml파일에 있는 listView를 불러온다. 
        ListView listView = (ListView) findViewById(R.id.list);

        //SetAdapter를 이용해 ListView와 ArrayAdapter를 연결한다. 
        listView.setAdapter(itemsAdapter);
    }

ArrayAdapter 의 subclass만들기

다음으로는 AdapterAdapter의 subclass로서 텍스트 두개짜리 오브젝트를 가진 ArrayList를 받아줄 수 있는 CustomArrayAdapter를 만들자. 여기서 ArrayAdapter의 `getView()` 를 orverride해야 한다. 디벨로퍼 페이지 참조.[클릭](https://developer.android.com/reference/android/widget/ArrayAdapter.html#ArrayAdapter(android.content.Context,%20int,%20java.util.List%3CT%3E))


public class CustomArrayAdapter extends ArrayAdapter<CustomWord> {

    private static final String LOG_TAG = WordAdapter.class.getSimpleName();

    public CustomArrayAdapter(Activity context, ArrayList<CustomWord> CustomWords){
        //컨스트럭터는 ArrayAdapter것을 갖다 썼다. 
        //두 번쨰 인수는 하나의 TextView를 사용할 떄만 들어가는 값이므로 여기서는 그냥 0을 넣었다. 
        super(context,0,words);
    }

    //아래와 같이 getView를 override하자. 
    @NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {

    	// listItemView 에 convertView를 설정한다. convertView는 스크롤이 넘어가서 안 보이게 될 때
    	// 재활용되는 view다. 그래서 빈 값일 떄는 새로 만들어야 한다. 
        View listItemView = convertView;
        if (listItemView ==null){
            listItemView = LayoutInflater.from(getContext()).inflate(R.layout.list_item,parent,false);
        }

        // 아까 만든 클래스의 인스턴스를 만들고 getItem method를 이용 위치에 따른 내용물을 넣어준다. 
        CustomWord currentWord = getItem(position);

        // 이후 각 TextView값을 get 메소드를 이용해 설정한다. 
        TextView textView1 = (TextView) listItemView.findViewById(R.id.text_view_1);
        textView1.setText(currentWord.getS1());


        TextView textView2 = (TextView) listItemView.findViewById(R.id.text_view_2);
        textView2.setText(currentWord.getS2());

        return listItemView;
    }
}

댓글남기기