Section 06
🎧 RecyclerView
ListView vs. RecyclerView
| 기능 | ListView | RecyclerView |
|---|---|---|
| ViewHolder 패턴 | 선택 (성능 위해 권장) | 필수 (구조적으로 강제) |
| 레이아웃 구조 | 수직 스크롤만 가능 | LayoutManager로 자유롭게 변경 (수직, 수평, 그리드 등) |
| 아이템 애니메이션 | 기본 미지원 (구현 복잡) | ItemAnimator로 간단하게 기본 애니메이션 적용 및 커스텀 가능 |
| 유연성 및 확장성 | 낮음 | 높음 |
| 구현 복잡도 | 상대적으로 간단 | 초기 설정이 조금 더 복잡함 |
기능 구현 순서
- 아이템 레이아웃 만들기: 리스트에 들어갈 아이템 화면(
rv_item.xml)을 먼저 만든다. - RecyclerView 배치하기: 아이템들을 담을 전체 틀인
RecyclerView를activity_main.xml에 배치한다. - 어댑터 생성하기: 데이터와 아이템 뷰를 연결할
RVAdapter.kt를 생성한다. - Activity에서 모두 연결하기:
MainActivity에서 데이터, 어댑터,LayoutManager를RecyclerView에 최종적으로 설정한다.
🎧 Navigation & Fragment
네이게이션이란?
- Jetpack 라이브러리의 일부로 애플리케이션 내에서 화면 전환을 처리를 담당하는 기능
- 클릭 이벤트가 있거나 뒤로 가기 버튼이 눌렸을 때 다른 화면(Fragment)로 이동
[주요 구성요소]
NavHostFragment: 네비게이션 그래프의 목적지(Fragment)를 표시하는 컨테이너Navigation Graph: XML 파일로 애플리케이션의 네비게이션 구조를 정의, 시작 화면에서 도착 화면이 어디인지 등등NavHost: Navigation Graph에서 대상을 표시하는 빈 컨테이너, 화면 전환 때 사용NavController: NavHost에서 대상 콘텐츠의 전환을 조종Composables: 각각의 화면을 나타내는 함수
Navigation Graph에서 특정 경로를 따라 이동할지, 특정 대상으로 직접 이동할지 NavController에게 전달하고 NavController가 NavHost에 적절한 대상을 표시해주는 방식
Fragment

[개념]
- 하나의 액티비티 안에 포함된 작은 화면 단위(UI 조각)
- 독립적인 Lifecycle과 입력 이벤트 처리 가능
- 액티비티 실행 중에도 프레그먼트를 추가하거나 삭제가 가능
즉, 여러개의 액티비티를 생성하여 전환하는 것이 아니라 프래그먼트를 만들어서 네비게이션의 클릭 이벤트가 발생할 때마다 프래그먼트를 전환하는 것임.
[장점]
- 모듈성 - 화면을 독립된 조각으로 나눠서 관리
- 유연성 - 화면 크기에 따라 다른 레이아웃 구성 가능
- 재사용성
- 백 스택 관리 - 한 화면에서 다른 화면으로 이동하면, 새로운 화면이 스택에 추가(Push) 되고, 뒤로 가기(Back)를 하면 스택에서 제거(Pop) 됨
🎧 Fragment 만들기
1. 네비게이션 생성하기
![]() |
![]() |
|---|
- app -> New -> Android Resource File
- Resource Type을 navigation으로 하고 파일 이름 입력 (e.g.
main_nav)
2. 환경 설정
- fragment를 사용하려면 Fragment 라이브러리가 프로젝트에 포함되야 함
- 저절로 되긴 하지만 직접 추가할 수도 있음
(1) Google 저장소 추가 - setting.gradle
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
...
}
}
Android Studio가 google() 저장소를 참조하지 않으면 해당 라이브러리를 가져올 수 없기 때문
(2) Fragment 라이브러리 추가 - build.gradle
dependencies {
val fragment_version = "1.8.9"
// Java language implementation
implementation("androidx.fragment:fragment:$fragment_version")
// Kotlin
implementation("androidx.fragment:fragment-ktx:$fragment_version")
}
클래스 정의 파일이 프로젝트에 존재해야 하기 때문에 import를 위한 설정임
3. 프래그먼트 추가
*(1) 원하는 만큼 프래그먼트 추가하기 *

- 경로: kotlin -> com.example -> New -> Fragment -> Fragment (Blank)
- 이렇게 하면 Fragment 클래스(
Singer1Fragment.kt), Fragment 레이아웃(fragment_singer1.xml) 가 생성됨
*(2) Navigation Graph에 Fragment 등록하기 *

- 상단의 “New Destination (+)” 버튼 클릭
- 생성한 Fragment 목록 중에서 원하는 것 선택하여 추가
- 네비게이션 그래프에 새로운 도착지가 등록됨
*(2) Fragment 간 이동 경로(화살표) 연결하기 *

- 네비게이션 그래프 창에서 시작할 Fragment를 클릭 -> 드래그하여 다른 Fragment로 화살표 연결
- 코드로 보면 다음과 같이 추가가 됨
<fragment android:id="@+id/singer1Fragment" android:name="com.example.week04_rc.Singer1Fragment" android:label="fragment_singer1" tools:layout="@layout/fragment_singer1" > <action android:id="@+id/action_singer1Fragment_to_singer2Fragment" app:destination="@id/singer2Fragment" /> <action android:id="@+id/action_singer1Fragment_to_singer3Fragment" app:destination="@id/singer3Fragment" /> </fragment>
🎧 음악 목록 앱 만들기 - 코드 실습

프래그먼트 모두 연결된 사진
RVAdapter.kt
1. class 선언
class RVAdapter(val items: MutableList<String>): RecyclerView.Adapter<RVAdapter.ViewHolder>()
- 파리미터는 MutableList
- ViewHolder를 상속받아야 동작
2. onCreateViewHolder
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): RVAdapter.ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.rv_item, parent, false)
// LayoutInflater → XML 레이아웃을 실제 View 객체로 변환.
return ViewHolder(view)
}
- rv_item.xml 레이아웃을 화면에 붙이는(View 생성) 함수
- RecyclerView는 스크롤 시 아이템을 계속 재활용하므로, 새로운 View가 필요할 때만 이 메서드가 호출됨
3. ViewHolder(itemView: View)
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bindItems(item: String){
val rv_text = itemView.findViewById<TextView>(R.id.rvTextId)
rv_text.text = item
}
}- 하나의 아이템 View를 관리하는 클래스
- RecyclerView는 아이템이 많기 때문에 ViewHolder가 각 아이템의 View를 재활용해 메모리를 절약
Singer1Fragment.kt
Singer2Fragment.kt, Singer3Fragment.kt 도 있음
1. Fragment 기본 구조
class Singer1Fragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) { ... }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { ... }
}
2. 데이터 준비
val items = mutableListOf<String>()
items.add("Dynamite")
items.add("Butter")
- 수정 가능한 리스트인 MutableList를 만들어서 음악 제목 데이터를 추가해주기
3. RecyclerView 세팅
val rv = view.findViewById<RecyclerView>(R.id.singRV)
val rvAdapter = RVAdapter(items)
rv.adapter = rvAdapter
rv.layoutManager = LinearLayoutManager(context) // 세로 스크롤 배치 방식
- xml 레이아웃에 있는 RecyclerView 연결
- 아까 만든 어댑터 클래스 연결 -> items라는 이름의 MutableList를 넘겨줌 -> 화면에 표시
*4. 다른 Fragment로 이동 *
view.findViewById<ImageView>(R.id.blackpink).setOnClickListener {
it.findNavController().navigate(R.id.action_singer1Fragment_to_singer2Fragment)
}
view.findViewById<ImageView>(R.id.aespa).setOnClickListener {
it.findNavController().navigate(R.id.action_singer1Fragment_to_singer3Fragment)
}
- 이미지를 클릭했을 때 실행되는 동작 지정
- 네이게이션 컨트롤러를 가져와서 이동경로(action)대로 화면 전환
fragment_singer1.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".Singer1Fragment">
<TextView
android:layout_width="match_parent"
android:fontFamily="@font/hsfont"
android:layout_height="60dp"
android:background="#966AE7"
android:gravity="center"
android:text="BTS 노래 리스트"
android:textColor="@color/white"
android:textSize="30sp"
app:layout_constraintTop_toTopOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/singRV"
android:layout_marginTop="70dp"
android:layout_marginBottom="110dp"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="100dp"
app:layout_constraintBottom_toBottomOf="parent">
<ImageView
android:id="@+id/bts"
android:src="@drawable/bts"
android:layout_margin="5dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:layout_weight="1" />
<ImageView
android:id="@+id/blackpink"
android:src="@drawable/blackpink"
android:layout_margin="5dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:layout_weight="1" />
<ImageView
android:id="@+id/aespa"
android:src="@drawable/aespa"
android:layout_margin="5dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:layout_weight="1" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
🎧 실행결과

깃허브: 👾Github
'TAVE-16th' 카테고리의 다른 글
| [DIP/FE] 프로젝트 소개 & Kakao Oauth 구현 (0) | 2026.02.23 |
|---|---|
| [TAVE 스터디 5주차] 메모 앱 만들기 (0) | 2026.01.04 |
| [TAVE 스터디 4주차] ListView 만들기 & 더블클릭 종료 (0) | 2026.01.04 |
| [TAVE 스터디 3주차] 주사위 앱 만들기 (1) | 2026.01.04 |
| [TAVE 스터디 2주차] 사진앱 만들기(2) (0) | 2026.01.04 |


