Android

RecyclerView를 이용해서 list 만들기

worri-pi 2021. 7. 8. 00:44

 

 

<?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">

    <LinearLayout
        android:id="@+id/layout1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <EditText
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:id="@+id/editText"
            android:hint="이름" />

        <EditText
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:id="@+id/editText2"
            android:hint="전화번호" />

    </LinearLayout>

    <LinearLayout
        android:id="@+id/layout2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/editText3"
            android:hint="생년월일" />

    </LinearLayout>

    <RelativeLayout
        android:id="@+id/layout3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:text="추가"
            android:id="@+id/button" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_alignBaseline="@+id/button"
            android:layout_marginRight="14dp"
            android:text="0명"
            android:textColor="#000000"
            android:textSize="14dp"
            android:id="@+id/textView" />

    </RelativeLayout>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

activity_main.xml

xml에 RecyclerView를 추가하면 item 들이 가상으로 보인다. 각 item을 위한 class를 만들어서 그 class를 ArrayList에 담아서 관리해야한다.

 

그 class 를 만들어보자.

public class Person {

    String name;
    String mobile;
    String birth;
    int ResId;

    public Person(String name, String mobile,String birth,int ResId) {
        this.name = name;
        this.mobile = mobile;
        this.ResId = ResId;
        this.birth = birth;
    }

    public String getBirth() {
        return birth;
    }

    public void setBirth(String birth) {
        this.birth = birth;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getMobile() {
        return mobile;
    }

    public void setMobile(String mobile) {
        this.mobile = mobile;
    }

    public int getResId() {
        return ResId;
    }

    public void setResId(int resId) {
        ResId = resId;
    }
}

Person.java

 

연락처 하나를 이 Person class 에 정의한다. (한 item을 위한 data 라고 생각하면 된다.)

data를 담아두기 위한 목적이니 getter, setter 를 추가한다.

이제 Person 에 data를 넣을 수 있고, 그 data는 adapter에 넣어야 한다.

 

RecyclerView 는 선택 위젯이고 눈에 보이는 모양을 담당한다.

실제 데이터 관리는 adapter를 사용한다.

 

adapter를 만들어보자. 

 

public class PersonAdapter {
  
    static class ViewHolder extends RecyclerView.ViewHolder{
        TextView textView1;
        TextView textView2;
        TextView textView3;
        ImageView imageView;

        public ViewHolder(View itemView,final OnPersonItemClickListener listener) {
            super(itemView);

            textView1 = itemView.findViewById(R.id.textView1);
            textView2 = itemView.findViewById(R.id.textView2);
            textView3 = itemView.findViewById(R.id.textView3);
            imageView = itemView.findViewById(R.id.imageView);

        public void setItem(Person item){
            textView1.setText(item.getName());
            textView2.setText(item.getBirth());
            textView3.setText(item.getMobile());
            imageView.setImageResource(item.getResId());
        }
    }
}

personAdapter.java

 

 

RecyclerView.ViewHolder 를 상속한 ViewHolder 클래스를 만들었다. ViewHolder는 각 item을 위한 뷰를 담는 역할이다. 재사용이 가능하다.

ViewHolder 생성자 함수도 만들었다. 이 생성자에는 View 객체가 전달되고, 전달 받은 객체를 부모 클래스의 변수에 담아두게 되는데 생성자 안에서 super() 메서드를 호출하면 된다.

그리고 방금 만든 Person 데이터를 View 에 보여주는 역할을 하는 setItem 메서드를 만들었다.

 

 

public class PersonAdapter extends RecyclerView.Adapter<PersonAdapter.ViewHolder>{
    ArrayList<Person> items = new ArrayList<>();

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(parent.getContext()); //LayoutInflater 객체 참조.
        View itemView = inflater.inflate(R.layout.person_item,parent,false); //각 item을 위한 View를 만들었다. 
        return new ViewHolder(itemView,this); //우리가 만든 ViewHolder에 itemView를 전달한다.
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Person item = items.get(position);
        holder.setItem(item);
    }

    @Override
    public int getItemCount() {
        return items.size();
    }

...

    static class ViewHolder extends RecyclerView.ViewHolder{
        TextView textView1;
        TextView textView2;
        TextView textView3;
        ImageView imageView;

        public ViewHolder(View itemView,final OnPersonItemClickListener listener) {
            super(itemView);

            textView1 = itemView.findViewById(R.id.textView1);
            textView2 = itemView.findViewById(R.id.textView2);
            textView3 = itemView.findViewById(R.id.textView3);
            imageView = itemView.findViewById(R.id.imageView);

        }

        public void setItem(Person item){
            textView1.setText(item.getName());
            textView2.setText(item.getBirth());
            textView3.setText(item.getMobile());
            imageView.setImageResource(item.getResId());
        }
    }
}

personAdapter.java

  1. Adapter 는 여러개의 item을 가지고 있으므로 ArrayList를 만들어 data를 넣을 수 있게 했다.
  2. ViewHoler를 담고있는 Adapter를 상속하도록 RecyclerView.Adapter<PersonAdapter.ViewHolder> 를 상속받았다.
  3. 필요한 세개의 메소드를 추가했다. 
  • getItemCount() : items 에 들어있는 개수를 return 받기 위한 함수이다.
  • onCreateViewHolder() : ViewHolder 가 생성되는 시점에 자동으로 실행된다. (item 을 위한 layout을 이 안에서 inflation한다. -> inflation 한 View를 ViewHolder에 넣는다. -> 그 ViewHolder를 return한다. -> 하나의 item을 위한 ViewHolder가 만들어져서 return 된다.) 
  • onBindViewHoler() : 스크롤을 내리거나 올릴 때, 화면에서 벗어나는 ViewHoler를 재사용할 건데, 그 사용했었던 ViewHoler를 parameter로 전달 받는다.

 

 

각 View를 위한 layout을 만들자. 

<?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"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <androidx.cardview.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:cardCornerRadius="10dp"
        app:cardElevation="5dp"
        app:cardUseCompatPadding="true">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:layout_margin="8dp">

            <ImageView
                android:id="@+id/imageView"
                android:layout_width="80dp"
                android:layout_height="80dp"
                android:padding="5dp"
                app:srcCompat="@drawable/img4" />

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical"
                android:padding="5dp">

                <TextView
                    android:id="@+id/textView1"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:duplicateParentState="true"
                    android:text="name"
                    android:textColor="#009688"
                    android:textSize="30sp" />

                <RelativeLayout
                    android:layout_width="match_parent"
                    android:layout_height="match_parent">

                    <TextView
                        android:id="@+id/textView2"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_alignParentLeft="true"
                        android:layout_alignParentBottom="true"
                        android:text="birth"
                        android:textColor="#FF9800"
                        android:textSize="15sp" />

                    <TextView
                        android:id="@+id/textView3"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_alignParentRight="true"
                        android:layout_alignParentBottom="true"
                        android:text="mobile"
                        android:textColor="#3F51B5"
                        android:textSize="15sp" />
                </RelativeLayout>

            </LinearLayout>
        </LinearLayout>
    </androidx.cardview.widget.CardView>
</LinearLayout>

person_item.xml

 

 

 

public class PersonAdapter extends RecyclerView.Adapter<PersonAdapter.ViewHolder> {
    ArrayList<Person> items = new ArrayList<>();
    OnPersonItemClickListener listener;

   ...

    public void addItem(Person item){
        items.add(item);
    }

    public void setItems(ArrayList<Person> items){
        this.items = items;
    }

    public Person getItem(int position){
        return items.get(position);
    }

    public void setItem(int position,Person item){
        items.set(position,item);
    }

    @Override
    public void onItemClick(ViewHolder holder, View view, int position) {
        listener.onItemClick(holder,view,position);
    }
    public void setOnItemClickListener(OnPersonItemClickListener listener) {
        this.listener = listener;
    }

    static class ViewHolder extends RecyclerView.ViewHolder{
        TextView textView1;
        TextView textView2;
        TextView textView3;
        ImageView imageView;

        public ViewHolder(View itemView,final OnPersonItemClickListener listener) {
            super(itemView);

            textView1 = itemView.findViewById(R.id.textView1);
            textView2 = itemView.findViewById(R.id.textView2);
            textView3 = itemView.findViewById(R.id.textView3);
            imageView = itemView.findViewById(R.id.imageView);

            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    int position = getAdapterPosition();
                    listener.onItemClick(ViewHolder.this,v,position);
                }
            });


        }

        public void setItem(Person item){
            textView1.setText(item.getName());
            textView2.setText(item.getBirth());
            textView3.setText(item.getMobile());
            imageView.setImageResource(item.getResId());
        }
    }
}

PersonAdapter.java

몇가지 메서드를 추가했다.

  1. addItem() : Adapter에 Person 객체를 추가하기 위해
  2. setItems() : ArrayList 를 전체적으로 설정하기 위해
  3. getItem() : position 번째에 있는 item을 return 하기 위해
  4. setItem()

 

이제 MainActivity에 RecyclerView 를 설정해보자.

 

public class MainActivity extends AppCompatActivity {
    EditText editText1;
    EditText editText2;
    EditText editText3;
    TextView textView;
    RecyclerView recyclerView;
    PersonAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        editText1 = findViewById(R.id.editText);
        editText2 = findViewById(R.id.editText2);
        editText3 = findViewById(R.id.editText3);
        textView = findViewById(R.id.textView);

        recyclerView = findViewById(R.id.recyclerView);

        LinearLayoutManager layoutManager = new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false); //RecyclerView 에 레이아웃 매니저 설정
        //GridLayoutManager layoutManager = new GridLayoutManager(this,2);
        recyclerView.setLayoutManager(layoutManager);
        
        adapter = new PersonAdapter();

        adapter.addItem(new Person("피아지","1990-01-01","010-1111-1111",R.drawable.img4)); //실제 Person 객체 넣기
        adapter.addItem(new Person("손아지","1990-11-01","010-1111-1234",R.drawable.img4));


        recyclerView.setAdapter(adapter);

    }
}

MainActivity.java

 

 

item을 눌렀을 때 동작하도록 해보자. 버튼을 눌렀을 때 동작할 함수를 약속할 interface를 만들자.

public interface OnPersonItemClickListener {
    public void onItemClick(PersonAdapter.ViewHolder holder, View view, int position);
}

OnPersonItemClickListener.java

item이 클릭되면 onItemClick 함수가 호출된다.

 

 

ViewHolder에도 item이 클릭되었을 때 기능을 추가해야한다.

public class PersonAdapter extends RecyclerView.Adapter<PersonAdapter.ViewHolder> implements OnPersonItemClickListener{
    ArrayList<Person> items = new ArrayList<>();
    OnPersonItemClickListener listener;

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        View itemView = inflater.inflate(R.layout.person_item,parent,false);
        return new ViewHolder(itemView,this);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Person item = items.get(position);
        holder.setItem(item);
    }

    @Override
    public int getItemCount() {
        return items.size();
    }

    public void addItem(Person item){
        items.add(item);
    }

    public void setItems(ArrayList<Person> items){
        this.items = items;
    }

    public Person getItem(int position){
        return items.get(position);
    }

    public void setItem(int position,Person item){
        items.set(position,item);
    }

    @Override
    public void onItemClick(ViewHolder holder, View view, int position) {
        listener.onItemClick(holder,view,position);
    }
    public void setOnItemClickListener(OnPersonItemClickListener listener) {
        this.listener = listener;
    }

    static class ViewHolder extends RecyclerView.ViewHolder{
        TextView textView1;
        TextView textView2;
        TextView textView3;
        ImageView imageView;

        public ViewHolder(View itemView,final OnPersonItemClickListener listener) {
            super(itemView);

            textView1 = itemView.findViewById(R.id.textView1);
            textView2 = itemView.findViewById(R.id.textView2);
            textView3 = itemView.findViewById(R.id.textView3);
            imageView = itemView.findViewById(R.id.imageView);

            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    int position = getAdapterPosition();
                    listener.onItemClick(ViewHolder.this,v,position);
                }
            });


        }

        public void setItem(Person item){
            textView1.setText(item.getName());
            textView2.setText(item.getBirth());
            textView3.setText(item.getMobile());
            imageView.setImageResource(item.getResId());
        }
    }
}

 

personAdapter.java

ViewHoler가 만들어지는 시점에 final OnPersonItemClicklistener listener 를 같이 전달받도록 하자.

그리고 이벤트 처리를 할건데, 이벤트 처리를 listener쪽으로 전달할 것이다.

 

그리고 OnPersonItemClickListener interface를 상속받아서 onItemClick과 setOnItemClickListener 메소드를 재정의해야한다.

 

 

 

 

public class MainActivity extends AppCompatActivity {
    EditText editText1;
    EditText editText2;
    EditText editText3;
    TextView textView;
    RecyclerView recyclerView;
    PersonAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        editText1 = findViewById(R.id.editText);
        editText2 = findViewById(R.id.editText2);
        editText3 = findViewById(R.id.editText3);
        textView = findViewById(R.id.textView);

        recyclerView = findViewById(R.id.recyclerView);

        LinearLayoutManager layoutManager = new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false);

        recyclerView.setLayoutManager(layoutManager);
        adapter = new PersonAdapter();

        adapter.addItem(new Person("피아지","1990-01-01","010-1111-1111",R.drawable.img4));
        adapter.addItem(new Person("손아지","1990-11-01","010-1111-1234",R.drawable.img4));


        recyclerView.setAdapter(adapter);
        adapter.setOnItemClickListener(new OnPersonItemClickListener() {
            @Override
            public void onItemClick(PersonAdapter.ViewHolder holder, View view, int position) {
                Person item = adapter.getItem(position);
                Toast.makeText(getApplicationContext(),"선택정보 : " + item.getName(),Toast.LENGTH_LONG).show();
            }
        });

        Button button = findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                adapter.addItem(new Person(editText1.getText().toString(),editText2.getText().toString(),editText3.getText().toString(),R.drawable.img4));
                adapter.notifyDataSetChanged();
                recyclerView.setAdapter(adapter);
                textView.setText(adapter.getItemCount()+"명");
            }
        });

        textView.setText(adapter.getItemCount()+"명");

    }
}

MainActivity.java

728x90