안녕하세요
오늘은 멀티뷰 타입을 지원하는 리사이클러뷰를 만들어보겠습니다.
리사이클러뷰를 사용하여 목록을 만들 때,
다르게 생긴 아이템들을 하나의 리사이클러뷰 내에서 보여주고 싶을 때가 있습니다.
리사이클러뷰에서는 다양한 레이아웃을 지원하는 아이템들을
하나의 리스트에서 처리할 수 있도록 하는 기능을 제공합니다.
본 게시글에서는 View Type 을 활용하여 데이터의 타입을 구분하고 각 타입에 맞는 아이템 레이아웃을 적용시켜보도록 하겠습니다.
먼저 메인 액티비티에 대한 레이아웃 입니다.
activity_main.xml
<?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:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
tools:context=".MainActivity">
<EditText
android:id="@+id/amount_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="금액을 작성해 주세요"/>
<Spinner
android:id="@+id/type_spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:entries="@array/types_array"/>
<Button
android:id="@+id/add_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="작성하기"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
</LinearLayout>
아이템을 추가하기 위한 텍스트 입력칸, 데이터 타입을 선택하기 위한 spinner, 리사이클러뷰가 포함되어 있습니다.
spinner 에 들어갈 내용은 string.xml 에 string arrary 로 정의해줍니다.
<resources>
<string name="app_name">ledger_example</string>
<string-array name="types_array">
<item>수입 내역</item>
<item>지출 내역</item>
<item>저축 내역</item>
</string-array>
</resources>
아래는 아이템에 관한 레이아웃 파일입니다. 총 3개의 아이템을 사용해보겠습니다.
item_income.xml
<?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="wrap_content"
android:orientation="horizontal"
android:padding="16dp" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="수입 : "
android:textSize="18sp"/>
<TextView
android:id="@+id/income_amount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Income Amount"
android:textSize="18sp"/>
</LinearLayout >
item_expense.xml
<?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="wrap_content"
android:orientation="horizontal"
android:padding="16dp" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="지출 : "
android:textSize="18sp"/>
<TextView
android:id="@+id/expense_amount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Expense Amount"
android:textSize="18sp"/>
</LinearLayout >
item_savings.xml
<?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="wrap_content"
android:orientation="horizontal"
android:padding="16dp" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="저축 : "
android:textSize="18sp"/>
<TextView
android:id="@+id/savings_amount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Savings Amount"
android:textSize="18sp"/>
</LinearLayout >
다음으로는 아이템 레이아웃에 들어갈 데이터를 정의한 모델 클래스입니다.
수입, 지출, 저축 항목 각각에 대해 금액(amount)과 타입(type)을 포함합니다.
데이터 클래스를 따로 설정함으로써 RecyclerView 어댑터에서 아이템 데이터를 쉽게 관리하고 바인딩할 수 있습니다.
TransactionItem.java
package com.example.ledger_example;
public class TransactionItem {
public static final int TYPE_INCOME = 1;
public static final int TYPE_EXPENSE = 2;
public static final int TYPE_SAVINGS = 3;
private int amount;
private int type;
public TransactionItem(int amount, int type) {
this.amount = amount;
this.type = type;
}
public int getAmount() {
return amount;
}
public int getType() {
return type;
}
}
다음으로 리사이클러뷰 어댑터입니다.
각각의 아이템 뷰를 초기화하고 데이터를 바인딩하며, 리사이클러뷰에 아이템을 추가하는 역할을 합니다.
public class TransactionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int TYPE_INCOME = 1;
private static final int TYPE_EXPENSE = 2;
private static final int TYPE_SAVINGS = 3;
private ArrayList<TransactionItem> transactionList;
public TransactionAdapter() {
this.transactionList = new ArrayList<>();
}
@Override
public int getItemViewType(int position) {
return transactionList.get(position).getType();
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view;
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
// 뷰타입에 따라 각자 다른 아이템 레이아웃을 추가합니다
switch (viewType) {
case TYPE_INCOME:
view = inflater.inflate(R.layout.item_income, parent, false);
return new IncomeViewHolder(view);
case TYPE_EXPENSE:
view = inflater.inflate(R.layout.item_expense, parent, false);
return new ExpenseViewHolder(view);
case TYPE_SAVINGS:
view = inflater.inflate(R.layout.item_savings, parent, false);
return new SavingsViewHolder(view);
default:
throw new IllegalArgumentException("Invalid view type");
}
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
TransactionItem item = transactionList.get(position);
switch (holder.getItemViewType()) {
case TYPE_INCOME:
((IncomeViewHolder) holder).bind(item);
break;
case TYPE_EXPENSE:
((ExpenseViewHolder) holder).bind(item);
break;
case TYPE_SAVINGS:
((SavingsViewHolder) holder).bind(item);
break;
}
}
@Override
public int getItemCount() {
return transactionList.size();
}
public void addItem(TransactionItem item) {
transactionList.add(item);
notifyDataSetChanged();
}
public static class IncomeViewHolder extends RecyclerView.ViewHolder {
TextView incomeAmount;
public IncomeViewHolder(@NonNull View itemView) {
super(itemView);
incomeAmount = itemView.findViewById(R.id.income_amount);
}
public void bind(TransactionItem item) {
incomeAmount.setText(String.valueOf(item.getAmount()));
}
}
public static class ExpenseViewHolder extends RecyclerView.ViewHolder {
TextView expenseAmount;
public ExpenseViewHolder(@NonNull View itemView) {
super(itemView);
expenseAmount = itemView.findViewById(R.id.expense_amount);
}
public void bind(TransactionItem item) {
expenseAmount.setText(String.valueOf(item.getAmount()));
}
}
public static class SavingsViewHolder extends RecyclerView.ViewHolder {
TextView savingsAmount;
public SavingsViewHolder(@NonNull View itemView) {
super(itemView);
savingsAmount = itemView.findViewById(R.id.savings_amount);
}
public void bind(TransactionItem item) {
savingsAmount.setText(String.valueOf(item.getAmount()));
}
}
}
마지막으로 메인 액티비티입니다.
금액 입력, 유형 선택 후 작성 버튼을 누르면 선택한 유형에 따라 뷰타입이 구분됩니다.
어댑터에서는 사용자가 아이템을 추가하면 선택한 유형에 맞는 레이아웃에 데이터를 바인딩 하여
리사이클러뷰에 추가해줍니다.
addButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String amountStr = amountEditText.getText().toString();
if (amountStr.isEmpty()) {
Toast.makeText(MainActivity.this, "금액을 입력하세요", Toast.LENGTH_SHORT).show();
return;
}
int amount = Integer.parseInt(amountStr);
String type = typeSpinner.getSelectedItem().toString();
int typeId;
switch (type) {
case "Income":
typeId = TransactionItem.TYPE_INCOME;
break;
case "Expense":
typeId = TransactionItem.TYPE_EXPENSE;
break;
case "Savings":
typeId = TransactionItem.TYPE_SAVINGS;
break;
default:
throw new IllegalArgumentException("Invalid type");
}
TransactionItem item = new TransactionItem(amount, typeId);
adapter.addItem(item);
amountEditText.setText("");
}
});
}
아래는 메인 액티비티의 전체 코드입니다.
package com.example.ledger_example;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private EditText amountEditText;
private Spinner typeSpinner;
private Button addButton;
private RecyclerView recyclerView;
private TransactionAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
amountEditText = findViewById(R.id.amount_edit_text);
typeSpinner = findViewById(R.id.type_spinner);
addButton = findViewById(R.id.add_button);
recyclerView = findViewById(R.id.recycler_view);
adapter = new TransactionAdapter();
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(adapter);
addButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String amountStr = amountEditText.getText().toString();
if (amountStr.isEmpty()) {
Toast.makeText(MainActivity.this, "금액을 입력하세요", Toast.LENGTH_SHORT).show();
return;
}
int amount = Integer.parseInt(amountStr);
String type = typeSpinner.getSelectedItem().toString();
int typeId;
switch (type) {
case "Income":
typeId = TransactionItem.TYPE_INCOME;
break;
case "Expense":
typeId = TransactionItem.TYPE_EXPENSE;
break;
case "Savings":
typeId = TransactionItem.TYPE_SAVINGS;
break;
default:
throw new IllegalArgumentException("Invalid type");
}
TransactionItem item = new TransactionItem(amount, typeId);
adapter.addItem(item);
amountEditText.setText("");
}
});
}
}
이상으로 리사이클러뷰에 멀티뷰를 추가하는 방법을 알아보았습니다.
감사합니다 !
'안드로이드 자바' 카테고리의 다른 글
[JAVA][Android]ActivityResultLauncher 앨범 에서 사진 선택 후 이미지뷰에 이미지 넣기 (0) | 2024.07.30 |
---|---|
[JAVA][Android] 어댑터 재활용 하여 중첩 리사이클러뷰 만들기 (0) | 2024.07.29 |
[JAVA][Android]항목 선택 다이얼로그 만들기 (0) | 2024.07.27 |
[JAVA][Android] CoordinatorLayout과 BottomSheet 사용해서 유투브 화면 따라 만들기(1) (0) | 2024.07.26 |
[Java][Android] 암시적 인텐트 사용해서 웹 검색하기 (0) | 2024.07.25 |