본문 바로가기
Android/소스

안드로이드 리스트뷰 예제

by 므시칸곰틔군 2018. 3. 22.

안드로이드 리스트 뷰 사용법.


리스트뷰를 만들어보다가 생각나서 기본 내용을 만들어 본다.

간단한 예로 기본 리스트뷰 다음 각 항목의 클릭리스너를 적용하여

항목별로 클릭할 수 있도록 한다.





클래스 정보.


정보를 담을 데이터 변수

UserData.java


화면에 보여질 액티비티.

MainActivity.java

activity_main 리스트뷰 등록.



리스트뷰에 보여줄 아답터.

UserDataAdapter.java

각 항목마다 보여줄 레이아웃 xml 등록.




안드로이드 스튜디오로 프로젝트를 만들면 기본 매인액티비티와 xml생성된다.

리스트뷰에 보여줄 데이터 클래스를 하나 만들고 매인액티비티에서 데이터를 생성 한다.

 

UserData.java

public class UserData {


    /**

     * 기본 생성자

     */

    public UserData() {

    }


    /**

     * 데이터를 입력받는 생성자

     */

    public UserData(int image, String name, String address) {

        this.image = image;

        this.name = name;

        this.address = address;

    }


    private int image;


    private String name;


    private String address;



    public int getImage() {

        return image;

    }


    public void setImage(int image) {

        this.image = image;

    }


    public String getName() {

        return name;

    }


    public void setName(String name) {

        this.name = name;

    }


    public String getAddress() {

        return address;

    }


    public void setAddress(String address) {

        this.address = address;

    }

}



매인액티비티에 리스트뷰 , 리스트뷰 아답터, 유저 정보를담을 어래이리스트 변수를 선언한다.



MainActivity.java


import android.os.Bundle;

import android.support.v7.app.AppCompatActivity;

import android.util.Log;

import android.view.View;

import android.widget.AdapterView;

import android.widget.ListView;


import java.util.ArrayList;


public class MainActivity extends AppCompatActivity {


    /**리스트뷰*/

    private ListView listView;

    /**리스트뷰 아답터*/

    private UserDataAdapter userDataAdapter;

    /**보여줄 데이터의 어래이리스트 생성.*/

    private ArrayList<UserData> userDataArrayList = new ArrayList<>();



    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);


//리스트뷰 등록.

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


//데이터등록.

        userDataArrayList.add(new UserData(R.mipmap.ic_launcher, "aaabb", "address1111111"));

        userDataArrayList.add(new UserData(R.mipmap.ic_launcher, "aaadd", "address11111112"));

        userDataArrayList.add(new UserData(R.mipmap.ic_launcher, "aaad", "address11111113"));

        userDataArrayList.add(new UserData(R.mipmap.ic_launcher, "aaae", "address11111114"));

        userDataArrayList.add(new UserData(R.mipmap.ic_launcher, "aaa", "address11111115"));

        userDataArrayList.add(new UserData(R.mipmap.ic_launcher, "aa43a", "address11111116"));

        userDataArrayList.add(new UserData(R.mipmap.ic_launcher, "aafda", "address11111117"));

        userDataArrayList.add(new UserData(R.mipmap.ic_launcher, "aabvxa", "address11111118"));

        userDataArrayList.add(new UserData(R.mipmap.ic_launcher, "aaabxv", "address11111119"));

        userDataArrayList.add(new UserData(R.mipmap.ic_launcher, "aabva", "address1111111112"));

        userDataArrayList.add(new UserData(R.mipmap.ic_launcher, "aaxbvca", "address1111111113"));

        userDataArrayList.add(new UserData(R.mipmap.ic_launcher, "aabxa", "address1111111114"));

        userDataArrayList.add(new UserData(R.mipmap.ic_launcher, "abxvaa", "address1111111115"));

        userDataArrayList.add(new UserData(R.mipmap.ic_launcher, "aaxba", "address11111111167"));

        userDataArrayList.add(new UserData(R.mipmap.ic_launcher, "aaxbvca", "address11111112325"));

        userDataArrayList.add(new UserData(R.mipmap.ic_launcher, "aaaxbv", "address1111111546346"));

        userDataArrayList.add(new UserData(R.mipmap.ic_launcher, "aaxbca", "address11111117564765"));


    // 데이터가 있을때 인자로 받는 아답터.

        userDataAdapter = new UserDataAdapter(userDataArrayList);

        listView.setAdapter(userDataAdapter);


// 통신을 하게 되면 내용을 받아야 하기 전 설정을하고 데이터가 다 받아지면 

// 아답터 내의 데이터를 갱신하여 리스트뷰를 다시 그려준다.


// 데이터가 없을때 아답터 생성.

        // userDataAdapter = new UserDataAdapter();

// listView.setAdapter(userDataAdapter);

// 데이터 등록.

// 통신완료된 시점에 해당 메서드를 호출하여 데이터를 입력하면 리스트뷰가 갱신된다.

        // userDataAdapter.setUserData(userDataArrayList);



        //리스트뷰 항목을 클릭할때...

        // 하나만 된다.....

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {

            @Override

            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {


                Log.i("tag", "이건?? :: " + position);



            }

        });

    }

}


//단순히 리스트뷰 만 보여주는 xml

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>

<android.support.constraint.ConstraintLayout 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">


    <ListView

        android:id="@+id/listView"

        android:layout_width="match_parent"

        android:layout_height="match_parent" />


</android.support.constraint.ConstraintLayout>




리스트뷰의 각 항목을 만들 레이아웃.

이미지, 유저 이름, 유저 주소 를 보여줄 레이아웃을 등록한다.



userdata_row.xml

<?xml version="1.0" encoding="utf-8"?>

<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:app="http://schemas.android.com/apk/res-auto"

    android:layout_width="match_parent"

    android:layout_height="match_parent">



    <android.support.constraint.ConstraintLayout

        android:layout_width="match_parent"

        android:layout_height="80dp"

        android:layout_margin="5dp"

        app:layout_constraintTop_toTopOf="parent"


        >

<--이미지 등록-->

        <ImageView

            android:id="@+id/userData_pic"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:background="@mipmap/ic_launcher"

            app:layout_constraintBottom_toBottomOf="parent"

            app:layout_constraintTop_toTopOf="parent" />



<--텍스트 레이아웃을 처리하기위해 서브 레이아웃 등록-->

        <android.support.constraint.ConstraintLayout

            android:layout_width="wrap_content"

            android:layout_height="0dp"

            android:layout_marginLeft="15dp"

            app:layout_constraintBottom_toBottomOf="@+id/userData_pic"

            app:layout_constraintLeft_toRightOf="@+id/userData_pic"

            app:layout_constraintTop_toTopOf="@+id/userData_pic">


<--위로 정렬되어 보여줄 텍스트뷰 등록-->

            <TextView

                android:id="@+id/userData_name"

                android:layout_width="wrap_content"

                android:layout_height="wrap_content"

                android:text="여기는 이름입니다"

                android:textSize="20dp"

                app:layout_constraintBottom_toTopOf="@+id/userData_address"

                app:layout_constraintTop_toTopOf="parent"


                />


<--레이아웃 하단에 보여줄 텍스트뷰 등록-->

            <TextView

                android:id="@+id/userData_address"

                android:layout_width="wrap_content"

                android:layout_height="wrap_content"

                android:text="여긴 주소를 입력합니다"

                android:textSize="20dp"

                app:layout_constraintBottom_toBottomOf="parent"

                app:layout_constraintTop_toBottomOf="@+id/userData_name"



                />


        </android.support.constraint.ConstraintLayout>

    </android.support.constraint.ConstraintLayout>

</android.support.constraint.ConstraintLayout>




리스트뷰를 보여줄 아답터.


홀더 생성.

홀더에 대한 좋은 웹사이트가 있어서 참고하여도 좋다.

http://www.kmshack.kr/tag/%EB%B7%B0%ED%99%80%EB%8D%94/


레이아웃 재사용에 사용할 홀더이고 홀더에서 뷰를 받은 위젯을 등록.


보여줄 데이터에 대하여 어래이 리스트 초기화.


아답터 생성자를 2개로 기본생성자와 데이터를 받는 생성자


UserDataAdapter.java

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;


/**

 * Created by jojaeyeong-pc on 2018. 3. 22..

 */


public class UserDataAdapter extends BaseAdapter {



    /**

     * 레이아웃의 홀더

     */

    class UserDataHolder {


        // 변수 지정.. 리사이클러 뷰처럼..

        private View view;


        //홀더에 적용할 레이아웃 지정.

        //userdata_row.xml의 위젯 아이디 등록.

        private ImageView userData_pic;


        private TextView userData_name;


        private TextView userData_address;


        /**

         * 생성자

         */

        public UserDataHolder(View view) {


            //뷰를 매개변수로 받음.

            // 위젯 등록

            userData_pic = (ImageView) view.findViewById(R.id.userData_pic);

            userData_name = (TextView) view.findViewById(R.id.userData_name);

            userData_address = (TextView) view.findViewById(R.id.userData_address);

        }

    } // 홀더 클래스 끝



    /**

     * 맴버변수의 new 하는 이유는 초기화 때문.

     */

    private ArrayList<UserData> userDataArrayList = new ArrayList<>();



    /**

     * 데이터 setter

     */

    public void setUserData(ArrayList<UserData> userData) {

        userDataArrayList = userData;

        // 리스트뷰 갱신위한 아답터 설정

        notifyDataSetChanged();



    }



    /**

     * 아답터의 기본 생성자

     */

    public UserDataAdapter() {

    }


    /**

     * 어레이 리스트를 받는 생성자

     */

    public UserDataAdapter(ArrayList<UserData> userDataArrayList) {

        this.userDataArrayList = userDataArrayList;

    }


    @Override

    public int getCount() {

        return userDataArrayList.size();

    }


    @Override

    public Object getItem(int position) {

        return userDataArrayList.get(position);

    }


    @Override

    public long getItemId(int position) {

        return position;

    }


    @Override

    public View getView(final int position, View convertView, final ViewGroup parent) {



        //홀더 객체

        UserDataHolder holder;


        if (convertView == null) {

    //상위 뷰그룹에서 컨텍스트를 받아옴 생성자에 컨텍스트를 변수로 만들 필요가 없어짐

            convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.userdata_row, null);

            holder = new UserDataHolder(convertView);

            convertView.setTag(holder);

        } else {

            holder = (UserDataHolder) convertView.getTag();

        }


        holder.userData_pic.setBackgroundResource(userDataArrayList.get(position).getImage());

        holder.userData_name.setText(userDataArrayList.get(position).getName());

        holder.userData_address.setText(userDataArrayList.get(position).getAddress());   


        return convertView;

    }


 }



겟뷰에서 홀더를 이용하여 뷰가 생성되어 있지 않으면 뷰를 인플레이트하고 홀더에 뷰를 등록하여 위젯들을 초기화 함.


각항목에 어레이 데이터에 있는 값들을 적용 시켜줌.





위에는 리스트뷰 항목만 클릭이 되어 있으나 위젯의 항목별 클릭을 위해선 아답터 내에서 클릭 이벤트를 준다.



매인 액티비티에서 

//리스트뷰 항목을 클릭할때...

        // 하나만 된다.....

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {

            @Override

            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {


                Log.i("tag", "이건?? :: " + position);



            }

        });

를 주석처리하고  아답터에서 클릭 이벤트를 준다.


아답터 getView 에서   return convertView; 위에 해당 내용을 추가하면 된다.


        // //클릭이벤트를 각 항목에서 주는 방법

        holder.userData_pic.setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View v) {

                v.setTag("userData_pic");

                Log.i("tag", "position : " + position + "  ,userData_pic 클릭");

                Toast.makeText(parent.getContext(), "tag: " + v.getTag() + "   position : " + position, Toast.LENGTH_LONG).show();


            }

        });

        holder.userData_name.setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View v) {

                v.setTag("userData_name");

                Log.i("tag", "position : " + position + "  ,userData_name 클릭");

                Toast.makeText(parent.getContext(), "tag: " + v.getTag() + "   position : " + position, Toast.LENGTH_LONG).show();

            }

        });


        holder.userData_address.setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View v) {

                v.setTag("userData_address");

                Log.i("tag", "position : " + position + "  ,userData_address 클릭");

                Toast.makeText(parent.getContext(), "tag: " + v.getTag() + "   position : " + position, Toast.LENGTH_LONG).show();

            }

        });


        convertView.setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View v) {

                v.setTag("convertView");

                Log.i("tag", "position : " + position + "  ,convertView 클릭");

                Toast.makeText(parent.getContext(), "tag: " + v.getTag() + "   position : " + position, Toast.LENGTH_LONG).show();

            }

        });


토스트에 컨텍스트를 따로 만들지 않고 final ViewGroup parent의 컨텍스트를 가져와 처리함.

 

 

 인터페이스를 사용해서 클릭이벤트를 다른곳에서 제어 할수도 있다.

 

 인터페이스를 사용해서 클릭을 적용할수있는 아답터.

 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;


/**

 * Created by jojaeyeong-pc on 2018. 3. 22..

 */


public class UserDataAdapter extends BaseAdapter {



    /**

     * 레이아웃의 홀더

     */

    class UserDataHolder {


        // 변수 지정.. 리사이클러 뷰처럼..

        private View view;


        //홀더에 적용할 레이아웃 지정.

        //userdata_row.xml의 위젯 아이디 등록.

        private ImageView userData_pic;


        private TextView userData_name;


        private TextView userData_address;


        /**

         * 생성자

         */

        public UserDataHolder(View view) {


            //뷰를 매개변수로 받음.

            // 위젯 등록

            userData_pic = (ImageView) view.findViewById(R.id.userData_pic);

            userData_name = (TextView) view.findViewById(R.id.userData_name);

            userData_address = (TextView) view.findViewById(R.id.userData_address);

        }

    } // 홀더 클래스 끝



    /**

     * 맴버변수의 new 하는 이유는 초기화 때문.

     */

    private ArrayList<UserData> userDataArrayList = new ArrayList<>();



    /**

     * 데이터 setter

     */

    public void setUserData(ArrayList<UserData> userData) {

        userDataArrayList = userData;

        // 리스트뷰 갱신위한 아답터 설정

        notifyDataSetChanged();



    }



    /**

     * 아답터의 기본 생성자

     */

    public UserDataAdapter() {

    }


    /**

     * 어레이 리스트를 받는 생성자

     */

    public UserDataAdapter(ArrayList<UserData> userDataArrayList) {

        this.userDataArrayList = userDataArrayList;

    }


    @Override

    public int getCount() {

        return userDataArrayList.size();

    }


    @Override

    public Object getItem(int position) {

        return userDataArrayList.get(position);

    }


    @Override

    public long getItemId(int position) {

        return position;

    }


    @Override

    public View getView(final int position, View convertView, final ViewGroup parent) {



        //홀더 객체

        UserDataHolder holder;


        if (convertView == null) {

            //상위 뷰그룹에서 컨텍스트를 받아옴 생성자에 컨텍스트를 변수로 만들 필요가 없어짐

            convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.userdata_row, null);

            holder = new UserDataHolder(convertView);

            convertView.setTag(holder);

        } else {

            holder = (UserDataHolder) convertView.getTag();

        }


        holder.userData_pic.setBackgroundResource(userDataArrayList.get(position).getImage());

        holder.userData_name.setText(userDataArrayList.get(position).getName());

        holder.userData_address.setText(userDataArrayList.get(position).getAddress());



        // // //클릭이벤트를 각 항목에서 주는 방법

        // holder.userData_pic.setOnClickListener(new View.OnClickListener() {

        //     @Override

        //     public void onClick(View v) {

        //         v.setTag("userData_pic");

        //         Log.i("tag", "position : " + position + "  ,userData_pic 클릭");

        //         Toast.makeText(parent.getContext(), "tag: " + v.getTag() + "   position : " + position, Toast.LENGTH_LONG).show();

        //

        //     }

        // });

        // holder.userData_name.setOnClickListener(new View.OnClickListener() {

        //     @Override

        //     public void onClick(View v) {

        //         v.setTag("userData_name");

        //         Log.i("tag", "position : " + position + "  ,userData_name 클릭");

        //         Toast.makeText(parent.getContext(), "tag: " + v.getTag() + "   position : " + position, Toast.LENGTH_LONG).show();

        //     }

        // });

        //

        // holder.userData_address.setOnClickListener(new View.OnClickListener() {

        //     @Override

        //     public void onClick(View v) {

        //         v.setTag("userData_address");

        //         Log.i("tag", "position : " + position + "  ,userData_address 클릭");

        //         Toast.makeText(parent.getContext(), "tag: " + v.getTag() + "   position : " + position, Toast.LENGTH_LONG).show();

        //     }

        // });

        //

        // convertView.setOnClickListener(new View.OnClickListener() {

        //     @Override

        //     public void onClick(View v) {

        //         v.setTag("convertView");

        //         Log.i("tag", "position : " + position + "  ,convertView 클릭");

        //         Toast.makeText(parent.getContext(), "tag: " + v.getTag() + "   position : " + position, Toast.LENGTH_LONG).show();

        //     }

        // });


        //////// 람다식을 적용하기 윈한 인터페이스 등록 ????


        if (this.itemClick != null) {


            convertView.setOnClickListener(new View.OnClickListener() {

                @Override

                public void onClick(View v) {

                    v.setTag("convertView");

                    itemClick.onClick(v, position);

                }

            });

            holder.userData_pic.setOnClickListener(new View.OnClickListener() {

                @Override

                public void onClick(View v) {

                    v.setTag("userData_pic");

                    itemClick.onClick(v, position);

                }

            });

            holder.userData_name.setOnClickListener(new View.OnClickListener() {

                @Override

                public void onClick(View v) {

                    v.setTag("userData_name");

                    itemClick.onClick(v, position);

                }

            });

            holder.userData_address.setOnClickListener(new View.OnClickListener() {

                @Override

                public void onClick(View v) {

                    v.setTag("userData_address");


                    itemClick.onClick(v, position);

                }

            });


        }


        return convertView;

    }


    /**클릭 인터페이스 등록*/

    public interface ItemClick {


        void onClick(View view, int position);

    }


    /**인터페이스 변수 선언*/

    private ItemClick itemClick;

    /**인터페이스 사용 등록 메서드*/

    public void setItemClick(ItemClick itemClick) {

        this.itemClick = itemClick;

    }



}


매인액티비티 에서는 

      

        //매인에서 클릭에 대한 처리

        userDataAdapter.setItemClick(new UserDataAdapter.ItemClick() {

            @Override

            public void onClick(View view, int position) {

                Log.i("tag", ":: " + view.getTag());


                Log.i("tag", ":: " + position);


                Toast.makeText(view.getContext(), "" + view.getTag() + " _position :" + position, Toast.LENGTH_SHORT).show();



            }

        });


하면 각항목의 클릭 이벤트를 확인할수 있다..


인터페이스를 등록한 이유는  람다식으로 처리할수 있도록 하기 위함이기도 한데

익명이너클래스 사용시 간단한 코드를 작성이 가능하다..


//////// 람다식을 적용하기 윈한 인터페이스 등록 ????

        if (this.itemClick != null) {


            convertView.setOnClickListener(v -> {

                v.setTag("convertView");

                itemClick.onClick(v, position);

            });


            holder.userData_pic.setOnClickListener(v -> {

                v.setTag("userData_pic");

                itemClick.onClick(v, position);

            });

            holder.userData_name.setOnClickListener(v -> {

                v.setTag("userData_name");

                itemClick.onClick(v, position);

            });

            holder.userData_address.setOnClickListener(v -> {

                v.setTag("userData_address");

                itemClick.onClick(v, position);

            });


        }

        

매인 액티비에서는 

userDataAdapter.setItemClick((view, position) -> {


            Log.i("tag", " :: " + view.getTag());


            Log.i("tag", " :: " + position);


            Toast.makeText(view.getContext(), "" + view.getTag() + " _position :" + position, Toast.LENGTH_SHORT).show();



        });

        

        매우 간략하게 표현된다.

        

        

클릭이벤트 까지 구현 해본 소스이다.