4. 기본 컨트롤 – 12. Custom ListView

이번에는 ListView의 항목을 개발자가 정의하여 사용하는 실습을 합시다. 여기에서는 도서 제목과 저자를 ListView의 항목으로 정의할게요. 그리고 항목을 클릭하였을 때의 도서 정보를 TextView로 보여주고 EditText에 도서 정보를 입력하여 추가 Button을 누르면 ListView에 항목으로 나타나게 합시다.

[그림] Custom ListView 실습 실행화면

먼저 activity_main.xml에 컨트롤을 배치하세요. 최상위 요소는 LinearLayout을 배치합니다. 그리고 선택한 항목의 도서 정보를 표시할 TextView를 두 개 배치하세요. 그리고 ListView를 배치합니다. 또한 추가할 도서 정보를 입력하기 위해 EditText를 두 개 배치하고 Button을 추가하세요. 추가 버튼의 onClick 속성을 설정할 수도 있습니다. 이 때는 해당 메서드를 Java 소스 파일에서 정의해야 합니다.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    tools:context="com.example.ehclub.ex_custom_listview.MainActivity"
    android:orientation="vertical">
    <TextView
        android:id="@+id/tv_title"
        android:textColor="#FF0000"
        android:textSize="30sp"
        android:text="[제목]"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <TextView
        android:id="@+id/tv_author"
        android:textColor="#FF0000"
        android:textSize="30sp"
        android:text="[저자]"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <ListView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/lv"
        android:layout_gravity="center_vertical"
        android:layout_weight="1"
        ></ListView>
    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="제목"
        android:textSize="30sp"
        android:id="@+id/et_title"/>
    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="저자"
        android:textSize="30sp"
        android:id="@+id/et_author"/>
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="추가"
        android:onClick="addButtonClick"/>

</LinearLayout>

이번에는 관리할 도서를 클래스로 정의하세요. 제목과 저자를 멤버 필드로 갖고 있으며 생성자를 통해 멤버 필드를 초기화하고 get메서드를 제공합시다.

package com.example.ehclub.ex_custom_listview;

/**
 * Created by ehclub on 2017-05-29.
 */

public class Book {
    String title;
    String author;
    public  String getTitle(){
        return title;
    }
    public String getAuthor() {
        return author;
    }
    public  Book(String title, String author){
        this.title = title;
        this.author = author;
    }

}

ListView에 설정할  Adpter 클래스를 정의합시다. 여기에서는 BookAdapter이름으로 정의할게요. 아답터 클래스는 BaseAdapter에서 파생합니다. 멤버 필드로 Book을 보관할 ArrayList형식 books를 선언 및 생성하고 Context와 LayoutInflater, layout 값을 선언하세요.

생성자에서는 context와 layout값을 입력 인자로 받고 멤버 필드를 설정합니다. 그리고 context의 getSystemService 메서드를 통해 inflater 개체를 참조합니다.

getCount 메서드에서는 books에 보관한 도서 개수를 반환하고 getItem에서는 books의 get 메서드로 해당 항목을 bypass하세요.

getView 메서드에서는 contextView가 null일 때 inflater의 inflate 메서드를 통해 contextView를 참조합니다.

그리고 contextView에 배치한 두 개의 TextView(도서 제목, 저자명)를 참조하여 현재 위치의 도서 정보로 설정합니다.

마지막으로 addBook 메서드를 정의하여 입력받은 도서 개체를 아답터에 추가합니다.

package com.example.ehclub.ex_custom_listview;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import com.example.ehclub.ex_custom_listview.Book;
import com.example.ehclub.ex_custom_listview.R;

import java.util.ArrayList;

/**
 * Created by ehclub on 2017-05-29.
 */

public class BookAdapter extends BaseAdapter {
    private ArrayList<Book> books = new ArrayList<>();
    Context context;
    LayoutInflater inflacter;
    int layout;
    public  BookAdapter(Context context, int layout){
        this.context = context;
        inflacter = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        this.layout = layout;
    }
    @Override
    public int getCount() {
        return books.size();
    }

    @Override
    public Object getItem(int position) {
        return books.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if(convertView == null){
            convertView = inflacter.inflate(layout,parent,false);
        }

        TextView tv_title = (TextView)convertView.findViewById(R.id.tv_title);
        tv_title.setText(books.get(position).title);

        TextView tv_author = (TextView)convertView.findViewById(R.id.tv_author);
        tv_author.setText(books.get(position).author);

        return convertView;
    }

    public  void addBook(Book book){
        books.add(book);
    }
}

이제 ListView에 하나의 항목을 표시할 Layout을 추가합니다. 여기에서는 item.xml 이름으로 정의할게요.

최상위 요소로 LinearLayout을 지정하고 자식으로 제목과 저자명을 표시할 TextView를 추가합니다.

<?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:orientation="vertical">
    <TextView
        android:id="@+id/tv_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <TextView
        android:id="@+id/tv_author"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

마지막으로 MainActivity.java 파일을 편집합시다. 먼저 MainActivity 클래스에 BookAdapter와 ListView 형식의 멤버 필드를 선언하세요.

    BookAdapter bookAdapter;
    ListView lv;

onCreate 메서드에서는 activity_main.xml에 배치한 ListView 개체를 참조합니다.

        lv = (ListView)findViewById(R.id.lv);

BookAdapter 개체를 생성한 후에 리스트 뷰 개체에 아답터를 설정합니다.

        bookAdapter = new BookAdapter(this,R.layout.item);
        lv.setAdapter(bookAdapter);

초기에 표시할 도서 정보를 아답터에 추가할게요.

        bookAdapter.addBook(new Book("C언어","언휴"));
        bookAdapter.addBook(new Book("Java","EH"));
        bookAdapter.addBook(new Book("파이썬","언제나"));

리스트 뷰의 항목 클릭 리스너를 설정합니다. 리스너에서는 입력 인자로 전달받은 parent를 ListView 형식으로 참조 연산할 수 있습니다. 이 후에 ListView의 getItemAtPosition 메서드로 도서 항목을 참조합니다. 그리고 참조한 도서 정보로 두 개의 TextView의 text 속성을 설정하세요.

        lv.setOnItemClickListener(new AdapterView.OnItemClickListener(){
            @Override
            public void onItemClick(AdapterView<?> parent, View v, int position, long id){
                ListView lv = (ListView)parent;
                Book book = (Book)lv.getItemAtPosition(position);
                TextView tv_title = (TextView)findViewById(R.id.tv_title);
                tv_title.setText(book.getTitle());
                TextView tv_author = (TextView)findViewById(R.id.tv_author);
                tv_author.setText(book.getAuthor());
            }
        });

addButtonClick 메서드에서는 두 개의 EditText를 참조하여 text 속성 값을 얻어온 후에 도서 개체를 생성하여 아답터에 추가하세요.

    public  void addButtonClick(View view){
        EditText et_title = (EditText)findViewById(R.id.et_title) ;
        String title = et_title.getText().toString();
        EditText et_author = (EditText)findViewById(R.id.et_author) ;
        String author = et_author.getText().toString();

        bookAdapter.addBook(new Book(title,author));
        et_title.setText("");
        et_author.setText("");
    }

다음은 MainActivity.java 파일의 내용입니다.

package com.example.ehclub.ex_custom_listview;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    BookAdapter bookAdapter;
    ListView lv;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        lv = (ListView)findViewById(R.id.lv);

        bookAdapter = new BookAdapter(this,R.layout.item);
        lv.setAdapter(bookAdapter);

        bookAdapter.addBook(new Book("C언어","언휴"));
        bookAdapter.addBook(new Book("Java","EH"));
        bookAdapter.addBook(new Book("파이썬","언제나"));

        lv.setOnItemClickListener(new AdapterView.OnItemClickListener(){
            @Override
            public void onItemClick(AdapterView<?> parent, View v, int position, long id){
                ListView lv = (ListView)parent;
                Book book = (Book)lv.getItemAtPosition(position);
                TextView tv_title = (TextView)findViewById(R.id.tv_title);
                tv_title.setText(book.getTitle());
                TextView tv_author = (TextView)findViewById(R.id.tv_author);
                tv_author.setText(book.getAuthor());
            }
        });
    }
    public  void addButtonClick(View view){
        EditText et_title = (EditText)findViewById(R.id.et_title) ;
        String title = et_title.getText().toString();
        EditText et_author = (EditText)findViewById(R.id.et_author) ;
        String author = et_author.getText().toString();

        bookAdapter.addBook(new Book(title,author));
        et_title.setText("");
        et_author.setText("");
    }
}