야미의 개발

[Android Studio] Java Recylerview 멀티뷰 구현하기 , viewtype으로 아이템 분류하기 본문

안드로이드/로또 앱

[Android Studio] Java Recylerview 멀티뷰 구현하기 , viewtype으로 아이템 분류하기

채야미 2023. 1. 3. 14:07

로또앱 안에 날짜별로 아이템들을 분류하는 기능이 필요했다.

보통 multi view를 쓰는 경우는 간단한 대화용 채팅창 구현이나, 아이템 목록이 여러개인 경우에 분류할 때 쓰는거 같지만 

이 앱에서는 날짜 아이템과 일반 아이템으로 나누어 목차처럼 구현 해보았다.

 

전체 코드는 글 마지막에

전체 복붙을 해서 보며 이해 안가는 부분은 아래의 설명을 참조하면 될 듯 싶다.

 

1.

MadeNumListAdapter

 

일단 MadeNumListAdapter 파일 부터 코드를 살펴보겠다.

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

    // view type
    private int TYPE_DATE = 201;
    private int TYPE_LIST = 202;

먼저 아이템들이 담길 리스트를 선언해준다.

여기서 분류해줄 아이템들은 직접 생성한 로또 번호들이기 때문에 MadeNumQuery를 담는 ArrayList를 선언해 주었다.

이후 두개의 아이템을 편하게 분류 하기 위해 

날짜를 의미하는 아이템은 TYPE_DATE으로 201을 일반 아이템은  202로 TYPE_LIST의 인덱스를 지정해 주었다.

 

@NonNull
@Override
public MadeNumListAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    LayoutInflater inflater = LayoutInflater.from(parent.getContext());
    View itemView = inflater.inflate(getViewScr(viewType), parent,false);

    return new MadeNumListAdapter.ViewHolder(itemView, viewType);
}

@Override
public void onBindViewHolder(@NonNull MadeNumListAdapter.ViewHolder holder, int position) {
    MadeNumQuery item = items.get(position);
    holder.bind(item);

}


    @Override
    public void onBindViewHolder(@NonNull MadeNumListAdapter.ViewHolder holder, int position) {
        MadeNumQuery item = items.get(position);
        holder.bind(item);

    }

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

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

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

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

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

    private int getViewScr(int viewType){
        if(viewType == TYPE_DATE){
            return R.layout.made_num_date;
        }else{
            return R.layout.made_num_item;
        }
    }

이 부분에서 유의해야할 부분은 inflater를 통해 xml을 view로 만들어줄 때 뷰 타입에 맞춰 xml를 적용할수 있게 해야한다는 점이다.

따라서 getViewSrc라는 메소드를 사용해 xml 레이아웃 파일을 지정해 주었다.

 

 

 

@Override
public int getItemViewType(int position) {
    if (items.get(position).getId() == -1){
        return TYPE_DATE;
    } else {
        return TYPE_LIST;
    }
}

 또, getItemViewType를 오버라이드 해야지만 아이템 타입을 분류할 수 있는데

이때 아이템을 분류하는 기준을 id로 정했다. 

일반적인 아이템은 id값을 가지고 있는 객체이고 날짜를 표현할 아이템은 id = -1 이므로

item.get(position).getId() == -1 인 경우 DTYPE_DATE를 반환해준다

 

 

 

 

    public class ViewHolder extends RecyclerView.ViewHolder{
        private int viewType;

        public ViewHolder(@NonNull View itemView, int viewType) {
            super(itemView);
            this.viewType = viewType;
            }
        }

        public void bind(MadeNumQuery item){
            if (viewType== TYPE_DATE){
                bindDate(item);
            } else if(viewType==TYPE_LIST) {
                bindItem(item);
            }
        }
        private void bindDate(MadeNumQuery item){
            TextView madeDate = itemView.findViewById(R.id.madeDate);
            madeDate.setText(item.getDate());
        }
        private void bindItem(MadeNumQuery item){
            String staticT = "총합:" + item.getTotal() + " 짝홀:" + item.getEven() + "/" +  (6 - item.getEven());

            TextView nums = itemView.findViewById(R.id.nums);
            nums.setText(item.numberString());
            TextView statics = itemView.findViewById(R.id.staticsMade);
            statics.setText(staticT);

        }
    }

바인드를 할때는 이렇게 아이템의 타입에 따라 바인드를 하는

bindData, bindItem 두가지를 따로 만들어 주었다.

 

이렇게 하면 아이템들의 리스트가 올바르게 들어오기만 한다면( 위에 언급했던 대로 Date 아이템의 id = -1 인 경우)

어뎁터가 아이템을 잘 분류해 각각의 xml에 맞추어서 정렬해줄 것이다.

이제 acitivity 파일을 보자.

 

2.

MadeNumListActivity

날짜 아이템이 없는 리스트를 불러와 리스트안에 추가해주는 작업을 하는 내용이 같이 담겨 있다.

 

public class MadeNumListActivity extends AppCompatActivity {
    List<MadeNumQuery> madeQueryList;

    @RequiresApi(api = Build.VERSION_CODES.M)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_made_num_list);

        RecyclerView recyclerView = findViewById(R.id.madeNum);

	// 기본 리스트를 가져옴
        getNumberQueryList();

	// 스티커를 포함하고 있는 리스트를 생성함
        ArrayList<MadeNumQuery> listWithSticker = (ArrayList<MadeNumQuery>) makeSticker();

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

        MadeNumListAdapter adapter = new MadeNumListAdapter();
        adapter.setItems(listWithSticker);
        recyclerView.setAdapter(adapter);

이 부분은 일반적인 리사이클러뷰와 동일하다. 코드 중간에 있는 날짜 스티커를 생성하는 메소드를 따로 살펴보면

 

public List<MadeNumQuery> makeSticker(){
    List<MadeNumQuery> newList = new ArrayList<>();
    String preDate = "1979";

    Collections.reverse(madeQueryList);

    for(MadeNumQuery numberQuery : madeQueryList){
        if(!numberQuery.getDate().equals(preDate)){
            newList.add(new MadeNumQuery(-1,numberQuery.getDate(),new int[]{0}));
            preDate = numberQuery.getDate();
        }
        newList.add(numberQuery);
    }
    return newList;
}

기본 날짜를 1979년으로 설정해 놓고

madeQuery를 하나씩 읽으며 madeQuery에 저장된 날짜값이 변경되는 경우에 id값이 -1인 DATE 아이템을 추가 해주도록 하였다.

 

 

 

전체 코드 // 

프로그램의 구현을 위한 다른 코드들은 임의적으로 삭제하였다

 

package org.techtown.lottoworld.madeNums;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;

import org.techtown.lottoworld.MadeNumQuery;
import org.techtown.lottoworld.R;

import java.util.ArrayList;

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

    // view type
    private int TYPE_DATE = 201;
    private int TYPE_LIST = 202;


    @NonNull
    @Override
    public MadeNumListAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        View itemView = inflater.inflate(getViewScr(viewType), parent,false);

        return new MadeNumListAdapter.ViewHolder(itemView, viewType);
    }

    @Override
    public void onBindViewHolder(@NonNull MadeNumListAdapter.ViewHolder holder, int position) {
        MadeNumQuery item = items.get(position);
        holder.bind(item);

    }

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

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

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

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

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

    private int getViewScr(int viewType){
        if(viewType == TYPE_DATE){
            return R.layout.made_num_date;
        }else{
            return R.layout.made_num_item;
        }
    }
    @Override
    public int getItemViewType(int position) {
        if (items.get(position).getId() == -1){
            return TYPE_DATE;
        } else {
            return TYPE_LIST;
        }
    }
    public class ViewHolder extends RecyclerView.ViewHolder{
        private int viewType;

        public ViewHolder(@NonNull View itemView, int viewType) {
            super(itemView);
            this.viewType = viewType;
            }
        }

        public void bind(MadeNumQuery item){
            if (viewType== TYPE_DATE){
                bindDate(item);
            } else if(viewType==TYPE_LIST) {
                bindItem(item);
            }
        }
        private void bindDate(MadeNumQuery item){
            TextView madeDate = itemView.findViewById(R.id.madeDate);
            madeDate.setText(item.getDate());
        }
        private void bindItem(MadeNumQuery item){
            String staticT = "총합:" + item.getTotal() + " 짝홀:" + item.getEven() + "/" +  (6 - item.getEven());

            TextView nums = itemView.findViewById(R.id.nums);
            nums.setText(item.numberString());
            TextView statics = itemView.findViewById(R.id.staticsMade);
            statics.setText(staticT);

        }
    }

}

 

package org.techtown.lottoworld.madeNums;

import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import org.techtown.lottoworld.DataAdapter;
import org.techtown.lottoworld.MadeNumQuery;
import org.techtown.lottoworld.NumberQuery;
import org.techtown.lottoworld.R;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class MadeNumListActivity extends AppCompatActivity {
    List<MadeNumQuery> madeQueryList;

    @RequiresApi(api = Build.VERSION_CODES.M)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_made_num_list);

        RecyclerView recyclerView = findViewById(R.id.madeNum);
        
	//리스트 불러옴
        getNumberQueryList();
	//DATE 아이템 포함한 리스트 생성
        ArrayList<MadeNumQuery> listWithSticker = (ArrayList<MadeNumQuery>) makeSticker();


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

        MadeNumListAdapter adapter = new MadeNumListAdapter();

        adapter.setItems(listWithSticker);

        recyclerView.setAdapter(adapter);

    }
    public int getNumberQueryList(){
        int round = 0;
        try {
            DataAdapter mDbAdapter = new DataAdapter(getApplicationContext());
            mDbAdapter.open();

            // db에 있는 값들을 model을 적용해서 넣는다.
            madeQueryList = mDbAdapter.getMadeNums();
            // db 닫기
            mDbAdapter.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return round;
    }
    public List<MadeNumQuery> makeSticker(){
        List<MadeNumQuery> newList = new ArrayList<>();
        String preDate = "1979";

        Collections.reverse(madeQueryList);

        for(MadeNumQuery numberQuery : madeQueryList){
            if(!numberQuery.getDate().equals(preDate)){
                newList.add(new MadeNumQuery(-1,numberQuery.getDate(),new int[]{0}));
                preDate = numberQuery.getDate();
            }
            newList.add(numberQuery);
        }
        return newList;
    }
    public void deleteNum(long id){
        try {
            DataAdapter mDbAdapter = new DataAdapter(getApplicationContext());
            mDbAdapter.open();

            mDbAdapter.deleteMadeNum(id);

            mDbAdapter.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

}
Comments