티스토리 뷰

 

 

오늘은 ScrollViewReader에 대해 알아보자

 

먼저 ScrollView와 ScrollViewReader는 무엇이 다른걸까??

 

ScrollView

 

스크롤 뷰는 단순히 스크롤 할 수 있는 뷰를 의미한다!

그래서 스크롤이 가능한 뷰에 사용하고 싶을 때 사용하면 된다.

 

 

ScrollViewReader

 

반면 ScrollViewReader는 현재 스크롤링을 감지하여 자동으로 스크롤되어 필요한 포인트로 위치 변경해주는 기능이 있다

 

 

하위 View, ScrollView를 스크롤하기 위해 Proxy라는것과 함께 작업할 수 있도록 프로그래밍 방식의 스크롤을 제공하는 뷰이다.

ScrollViewReader를 사용하려면 내부 뷰가 ScrollView로 감싸져있어야 한다.

 

-> ScrollViewReader를 사용한다고 ScrollView를 사용하지 않거나 단독으로 사용하면 안됨!!!!

 

 

 

 

 

ScrollViewReader를 적용한 예시

 

 

 

 

오늘 날짜가 27일이면, 캘린더에서 22일을 눌렀을 때 22일로 지출내역로 이동하는 것을

시뮬레이터에서 확인할 수 있다

 

 

 

사용방법

                ScrollViewReader { proxy in
                    ScrollView {
                        VStack {
                            if groupedSpendings().isEmpty {
                                NoSpendingHistoryView()
                            } else {
                                LazyVStack(spacing: 0 * DynamicSizeFactor.factor()) {
                                    ForEach(groupedSpendings(), id: \.key) { date, spendings in
                                        Spacer().frame(height: 10 * DynamicSizeFactor.factor())

                                        Section(header: headerView(for: date)) {
                                            Spacer().frame(height: 12 * DynamicSizeFactor.factor())
                                            ForEach(spendings, id: \.id) { item in
                                                let iconName = SpendingListViewCategoryIconList(rawValue: item.category.icon)?.iconName ?? ""
                                                ExpenseRow(categoryIcon: iconName, category: item.category.name, amount: item.amount, memo: item.memo)
                                                Spacer().frame(height: 12 * DynamicSizeFactor.factor())
                                            }
                                            .onAppear {
                                                Log.debug("spendings: \(spendings)")
                                                Log.debug("group: \(groupedSpendings())")
                                            }
                                        }
                                        .id(date) // ScrollViewReader를 위한 ID 추가
                                    }
                                    Spacer().frame(height: 18 * DynamicSizeFactor.factor())
                                }
                            }
                        }
                        if !groupedSpendings().isEmpty {
                            Button(action: {
                                changeMonth(by: -1)

                            }, label: {
                                ZStack {
                                    Rectangle()
                                        .frame(width: 103 * DynamicSizeFactor.factor(), height: 40 * DynamicSizeFactor.factor())
                                        .foregroundColor(Color("Gray01"))
                                        .cornerRadius(26)

                                    Text(monthTitle(from: spendingHistoryViewModel.currentDate))
                                        .font(.B1SemiboldeFont())
                                        .foregroundColor(Color("Gray04"))
                                        .padding(.horizontal, 20)
                                        .padding(.vertical, 12)
                                }
                            })
                            .padding(.bottom, 48)
                            .onChange(of: selectedDateToScroll) { date in
                                if let date = date {
                                    withAnimation {
                                        proxy.scrollTo(date, anchor: .top)
                                    }
                                }
                            }
                            .onAppear {
                                proxy.scrollTo(selectedDateToScroll, anchor: .top)
                            }
                        }
                    }
                }

 


ScrollViewReader가 필요한 뷰 최상단에 ScrollViewReader를 사용하고 하위에 ScrollView를 사용하여 뷰를 감싸준다.

 

그리고 ScrollViewReader가 감지가 필요한 부분에 id()를 넣어주면

scrollTo메서드에 의해서 필요한 id로 자동으로 스크롤링이 되는 구조이다.

 

 

적용된 예시에서를 살펴보자

 

1️⃣ onChange를 통해 selectedDateToScroll이라는 변수의 값이 변경될 때 마다 proxy.scrollTo(date, anchor: .top)을 실행시켰다.

2️⃣ onAppear를 통해 proxy.scrollTo(selectedDateToScroll, anchor: .top) 을 통하여 사용자가 선택했던 날짜를 기준으로 뷰가 로드되어 해당 날짜로 스크롤을 감지하도록 뷰를 새로고침하게 한다!

 

 

 

 

anchor .top, .bottom, .center이 있고 어떤 방향으로 스크롤 될 지를 결정해주기 때문에 원하는 방식에 맞춰서 사용하면 될 듯하다~

 

 

 

 

 

 

 

 


참고 자료: https://green1229.tistory.com/295

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함