๋ฆฌ์คํธ๋ ์๋น์ค ๋๊ณ ์๋ ์ฑ์์ ๋น ์ง์ง ์๊ณ ๋ฑ์ฅํ๋ UI ์ค ํ๋์ ๋๋ค. ๋ง์ ๋ฐ์ดํฐ๋ฅผ ์๋ฒ๋ก ๋ถํฐ ํ๋ฒ์ ๊ฐ์ ธ์ค๋ ๊ฒ์ด ์๋ ์ผ๋ถ๋ง ๊ฐ์ ธ์จ ๋ค ์ฌ์ฉ์๊ฐ ๊ทธ ์ผ๋ถ๋ฅผ ๋ค ๋ณด๋ฉด ์๋ก์ด ๋ชฉ๋ก์ ์๋ฒ๋ก ๋ถํฐ ๊ฐ์ง๊ณ ์ค๋ ๋ฐฉ์์ด ์๋๋ฐ ์ด๋ฅผ load more ํน์ infinite scroll ์ด๋ผ๊ณ ํฉ๋๋ค.
SwiftUI์์๋ ๋ฆฌ์คํธ๋ฅผ ์ํ ์ฌ๋ฌ๊ฐ์ง View๋ค์ด ์ ๊ณต๋ฉ๋๋ค. ๊ทธ ์ค์ VStack์ ์์ดํ ๋ค์ ์ธ๋ก ๋ฐฉํฅ์ผ๋ก ์์ต๋๋ค. ์ด VStack์ด ScrollView์ ๋ง๋๋ฉด ์ ํฌ๊ฐ UIKit์์ ๋ณด์๋ UITableView ํน์ UICollectionView์ ๋์ผํ UI๋ฅผ ๊ตฌ์ฑํ ์ ์์ด์. ๊ทธ๋ฐ๋ฐ ์ฌ๊ธฐ์ LazyVStack์ด๋ผ๋ ๊ฒ์ด ์์ต๋๋ค! ๊ฐ์ ์ด๋์ ์ฌ์ฉํ๋๊ฒ ์ข์๊น์?
์ฐจ์ด์ ๊ณผ ๊ฐ๊ฐ ๋์ํ๋ ๋งค์ปค๋์ฆ์ ์์๋ด ์๋ค ๐
์ฝ๋ ์ค๋นํ๊ธฐ
๋ณธ๊ฒฉ์ ์ผ๋ก ์์๋ณด๊ธฐ ์ ์ ์ค๋นํด์ผ ํ ์ฝ๋๊ฐ ์์ต๋๋ค. ๋ฆฌ์คํธ์ ์์ดํ ๋ค์ ๋ณด์ฌ์ค ๊ฑฐ๊ธฐ ๋๋ฌธ์ ๋น์ฆ๋์ค ๋ก์ง์ ์์ฑํ ViewModel๊ณผ ๋ฐ์ดํฐ ๋ชจ๋ธ์ ์์ฑํด ๋ณผ๊น์?
struct Product: Identifiable {
var id: UUID
var name: String
var price: Int
init(name: String, price: Int) {
self.id = UUID()
self.name = name
self.price = price
}
}
์ด ๋ฐ์ดํฐ ๋ชจ๋ธ์ ๋ฐ์ดํฐ ์ด๋ ์ด๋ฅผ ์ด๋ฃจ๊ณ ๊ฐ๊ฐ์ ๋ฐ์ดํฐ๋ ๋ฆฌ์คํธ์์ ํ๋์ ํ์ผ๋ก ํ์๋ ๊ฑฐ์์!
class InfiniteScrollViewModel: ObservableObject {
@Published var products = [Product]()
/// ๋ด๋ถ์ ์ผ๋ก ํ์ฌ ๋ช ๋ฒ์งธ ํ์ด์ง๋ฅผ ๋ถ๋ฌ์๋์ง ํ์ธํ๊ธฐ ์ํด ์ฌ์ฉ
private var page: Int = 0
/// paging x
func requestProducts() {
// ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ค๋๋ฐ ๊ฑธ๋ฆฌ๋ ์๊ฐ์ 2์ด๋ก ์ค์
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
self.products.append(contentsOf: (0...20).map {
Product(name: "page\(self.page), \($0)item", price: (1000...30000).randomElement() ?? 0)
})
self.page += 1
}
}
/// paging
func requestProductsWith(id: UUID? = nil) {
if page == 5 { return } // ์์๋ก ํ์ด์ง ๊ฐฏ์ ์ ํ ๋
if (id == nil) || (id == products.last?.id) {
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
self.products.append(contentsOf: (0...20).map {
Product(name: "page\(self.page), \($0)item", price: (1000...30000).randomElement() ?? 0)
})
print("ViewModel ์
๋ฐ์ดํธ ์ฑ๊ณต ํ์ด์ง : \(self.page)")
self.page += 1
}
}
}
}
ViewModel์ด ์กฐ๊ธ ๋ณต์กํด ๋ณด์ด์ง๋ง ํ๋์ฉ ๋ฏ์ด๋ณด๋ฉด, View์์ ๋ณด์ฌ์ค products ๋ผ๋ ๋ฆฌ์คํธ๋ฅผ @Published๋ก ๊ฐ์ง๊ณ ์์ต๋๋ค. ์ Published ์ด๋๋ฉด ์ด ๊ฐ์ด ๋ณ๊ฒฝ๋์ด View์๊ฒ UI๋ฅผ ์ ๋ฐ์ดํธ ํด์ผ ํจ์ ์๋ฆฌ๊ธฐ ์ํจ์ ๋๋ค
๊ทธ๋ฆฌ๊ณ ๋ ๊ฐ์ ํจ์๋ ๋คํธ์ํฌ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ๊ฐ์ฅํ ํจ์์ ๋๋ค ใ ใ ใ 2์ด ํ์ products๋ผ๋ ๋ฆฌ์คํธ์ ์์ดํ ๋ค์ ์ถ๊ฐํด ์ค๋๋ค. ์ฒซ๋ฒ์งธ๋ก ๋ณด์ด๋ ํจ์์ธ requestProducts๋ ํ์ด์ง์ ํ์ง ์๊ณ ํธ์ถํ๋ฉด ๋จ์ํ ๋ฐ์ดํฐ๋ฅผ ์ถ๊ฐํด์ฃผ๋ ์ญํ๋ง ํฉ๋๋ค. requestProductsWith(id:)๋ Product์ id๋ฅผ ๋ฐ์์ ์ด id ๋ค์ ํญ๋ชฉ์ ๋ถ๋ฌ์ค๋ ๊ฒ์ฒ๋ผ ์ง์ฌ์ง ์ฝ๋์ ๋๋ค. ์ ์๋ VStack์์ ํ์๋ LazyVStack์์ ์ฌ์ฉํฉ๋๋ค! ๐โ๏ธ
๋ง์ง๋ง์ผ๋ก ์์ฃผ ๊ฐ๋จํ View struct๊ฐ ๋จ์ ์์ต๋๋ค
struct RowView: View {
let product: Product
var body: some View {
let _ = print("body draw:::", product.name)
HStack {
Text(product.name)
.font(.headline)
.fontWeight(.bold)
Text("\(product.price) ์")
.foregroundStyle(.gray)
}
.frame(maxWidth: .infinity)
.frame(height: 150)
.background(.green.opacity(0.3))
}
}
Product๋ฅผ ํ์ํด ์ฃผ๋ RowView๋ VStack๊ณผ LazyVStack์์ ํ๋์ ํ์ผ๋ก ํํ๋ ๊ฑฐ์์. ๋จ์ํ๊ฒ ๋ฐ์ดํฐ๋ฅผ ๋ณด์ฌ์ฃผ๋ ๊ตฌ์กฐ์ ๋๋ค. RowView๊ฐ ์ธ์ ๊ทธ๋ ค์ง๋ ์ง ํ์ธํ๊ธฐ ์ํด body ํ๋กํผํฐ ๋ด๋ถ์ print ๋ฌธ์ ํ๋ ์ถ๊ฐํด ์คฌ์ด์.
VStack
VStack์ ์๋ธ ๋ทฐ๋ค์ ์์ง ๋ฐฉํฅ์ผ๋ก ์์์. ViewBuilder๋ก SubView๋ฅผ ๋ฐ๊ธฐ ๋๋ฌธ์ VStack ๋ด๋ถ์๋ ์ฌ๋ฌ๊ฐ์ ๋ค์ํ View๋ค์ SubView๋ก ๋ฃ์ ์ ์์ด์.
VStack {
Text("row1")
Text("row2")
}
VStack {
ForEach(1...10, id: \.self) {
Text("Item \($0)")
}
}
ForEach๋ฅผ ์ฌ์ฉํ๋ฉด ์ฌ๋ฌ๊ฐ์ ์์ดํ ์ ํ๋ฒ์ ์ฝ๊ฒ ๊ทธ๋ ค์ค ์ ์์ด์. ๋ง์ฝ์ VStack์ ๋ค์ด๊ฐ๋ SubView ๋ค์ด ํ๋ฉด์ ๋์ด๊ฐ๋ค๋ฉด ScrollView๋ก ํ๋ฒ ๊ฐ์ธ์ค ์ ์์ต๋๋ค.
VStack์ LazyVStack๊ณผ ๋ค๋ฅด๊ฒ ํ๋ฒ์ ๋ชจ๋ ๋ทฐ๋ฅผ ๊ทธ๋ฆฝ๋๋ค! ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ๋ง์ ๋์ ๋ฐ์ดํฐ๋ฅผ ๋ฆฌ์คํธ์ ํํํด ์ฃผ๊ธฐ์๋ ์ ํฉํ์ง ์์ ์ ์์ด์. ์ด๋ฅผ ์์๋ณด๊ธฐ ์ํด TestVStackView ์ฝ๋๋ฅผ ์ดํด ๋ณผ๊ฒ์
struct TestVStackView: View {
@StateObject var viewModel = InfiniteScrollViewModel()
var body: some View {
let _ = print("TestVStackView body property draw")
ScrollView {
VStack {
ForEach(viewModel.products, id: \.id) { product in
RowView(product: product)
.onAppear {
print("onAppear::: ", product.name)
}
}
}
.task {
print("๋ฐ์ดํฐ ํธ์ถ")
viewModel.requestProducts()
}
.onAppear {
print("VStack ๋ํ๋จ")
}
}
}
}
์์์ ๋ถํฐ ํ๋์ฉ ์ดํด ๋ณด๋ฉด
@StateObject var viewModel = InfiniteScrollViewModel()
์์ดํ ๋ชฉ๋ก์ธ product๋ฅผ ๋ฐ์์ค๊ธฐ ์ํด ViewModel์ StateObject๋ก ์ ์ธํด ์ฃผ์์ด์. RowView์ ๋ง์ฐฌ๊ฐ์ง๋ก ์ด๋์์ ์ ๊ทธ๋ ค์ง๋์ง ํ์ธํ๊ธฐ ์ํด print ๋ฌธ์ body์ ํฌํจ์์ผฐ์ต๋๋ค.
VStack์ ๋จ์ํ SubView์ ์์ง ๋ฐฉํฅ์ผ๋ก ์๋ View์ด๊ธฐ ๋๋ฌธ์ ์คํฌ๋กค์ ๊ฐ๋ฅํ๊ฒ ํ๋ ค๋ฉด ScrollView๋ก ๊ฐ์ธ์ฃผ์ด์ผ ํด์.
VStack์์ task modifier์ ๋ณผ ์ ์๋๋ฐ ์ฌ๊ธฐ์ viewModel์ ๋น๋๊ธฐ ํจ์๋ฅผ ํธ์ถํด ์ค๋๋ค.
VStack๋ด๋ถ์์๋ ForEach๋ฅผ ์ฌ์ฉํด viewModel์ products ์์ดํ ๋ค์ ๊ทธ๋ ค์ฃผ๋ ์ฝ๋์์
์ด ์ฝ๋๋ฅผ ์คํํ๋ฉด ์ฝ์์์ ์ด๋ ๊ฒ ์ฐํ๋๋ค! ์ฒ์ TestVStackView๊ฐ ํ๋ฉด์ ๋ํ๋๊ณ task modifier์ ํตํด viewModel์ ๊ฐ์ง ๋คํธ์ํฌ ํจ์๊ฐ ํธ์ถ๋์. ์ด๋ 0~20 ์ ์์ดํ ์ด ์ถ๊ฐ๋ฉ๋๋ค.
์ฝ์์์ ํ์ธํ ์ ์๋ค ์ถ์ด ํ๋ฒ์ 21๊ฐ (0์์ 20์ด๋ฏ๋ก)๊ฐ ๊ทธ๋ ค์ง๊ณ ํ๋ฉด์ ๋ํ๋ ๊ฒ์ ๋๋ค! ์ด๊ฑธ ๋ทฐ ๊ณ์ธต ๊ตฌ์กฐ๋ก ํ์ธํ๋ฉด ์ข๋ ์ฒด๊ฐ์ด ๋์!
Hide Clipped Content๋ฅผ ๋๋ฅด๋ฉด ํ๋ฉด ๋ฐ์ ์๋ View๋ฅผ ๋ณผ ์ ์์ด์. ๊ทธ๋ฆผ๊ณผ ๊ฐ์ด ๋ชจ๋ ํ์ View๊ฐ ๋ฏธ๋ฆฌ ๊ทธ๋ ค์ง๊ณ ์ค๋น๋์ด ์์ต๋๋ค. ๋ง์ฝ ์ ํฌ๊ฐ 21๊ฐ๊ฐ ์๋ 42๊ฐ์๋ค๋ฉด? 63๊ฐ ์๋ค๋ฉด? ๊ทธ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ํ์ํ๊ธฐ ์ํ ๋ทฐ๊ฐ ํ๋ฉด์ ๊ทธ๋ ค์ก์ ๊ฑฐ์์ (๊ฐ์ด ๋ณ๊ฒฝ๋๋ฉด ์ด ๋ชจ๋ ๋ทฐ๋ฅผ ๋ค์ ๊ทธ๋ฆฌ๊ฒ ์ฃ ?)
์ด๋ UIKit์์ UITableView ์ฒ๋ผ ๋์ํ๋ ๊ฒ์ด ์๋ just UIScrollView ์ฒ๋ผ ๋์ํ๊ณ ์๋ ๊ฑฐ์์!
์ฌ๊ธฐ์ ์ ์ SwiftUI์ ๋งค์ปค๋์ฆ์ ์ดํด๋ณด๋ฉด
TestVStackView์์ body ํ๋กํผํฐ๋ฅผ ๊ทธ๋ฆฝ๋๋ค. ์ด๋ body ํ๋กํผํฐ ๋ด๋ถ์ ํฌํจ๋ print๋ฌธ์ด ํธ์ถ๋์ด ์ฝ์์ ๋ํ๋ฉ๋๋ค
๊ทธ ๋ค์์ผ๋ก๋ ๋ด๋ถ์ VStack์ด ๋ํ๋๊ณ task modifier์ ์ํด ViewModel์ด ํธ์ถ๋์
ViewModel์ด ํธ์ถ๋๋ฉด Published๋ก ์ ์ธ๋ ํ๋กํผํฐ์ ๊ฐ์ ์ ๋ฐ์ดํธ ํ๊ฒ ๋๋๋ฐ View์์ ์ด ๊ฐ์ ์ฌ์ฉํฉ๋๋ค.
์ฆ ์ด published๋ก ์ ์ธ๋ ํ๋กํผํฐ์ ๊ฐ์ด ์ ๋ฐ์ดํธ ๋๋ฉด View struct์ body property๋ฅผ ์๋ก ๊ทธ๋ฆฌ๊ฒ ๋ฉ๋๋ค.
์ ๋ฐ์ดํธ ๋ products ๊ฐ์ผ๋ก UI๋ฅผ ๊ทธ๋ ค์ฃผ๋ฏ๋ก ํ๋ฉด์ ๋ฆฌ์คํธ๊ฐ ๋ ธ์ถ๋์
LazyVStack
๋ค์์ผ๋ก LazyVStack์ ์์๋ณผ๊ฒ์! LazyVStack์ ์ด๋ฆ์์ ๋ถํฐ ๋๋ฆฌ๊ฒ View๋ฅผ ๊ทธ๋ฆฌ๊ฒ ๋ค๋ผ๋ ๊ฒ ๋๊ปด์ง์ง ์๋์?
LazyVStack์ ํ์๋ก ํ ๋ SubView๋ฅผ ๊ทธ๋ฆฝ๋๋ค.
์ VStack ์ ํ ์คํธํ ๋ ์ฌ์ฉํ๋ ํ ์คํธ ์ฝ๋์์ VStack์ LazyVStack์ผ๋ก ๋ฐ๊พธ์ด ์ค๋๋ค
struct TestLazyVStackView: View {
@StateObject var viewModel = InfiniteScrollViewModel()
var body: some View {
let _ = print("TestLazyVStackView body property draw")
ScrollView {
VStack {
ForEach(viewModel.products, id: \.id) { product in
RowView(product: product)
.onAppear {
viewModel.requestProductsWith(id: product.id)
}
}
}
.task {
print("๋ฐ์ดํฐ ํธ์ถ")
viewModel.requestProducts()
}
.onAppear {
print("VStack ๋ํ๋จ")
}
}
}
}
VStack๊ณผ ๋ค๋ฅด๊ฒ LazyVStack์ ์๋ ์ด๋ฏธ์ง ์ฒ๋ผ ๋ก๊ทธ๊ฐ ์ฐํ๊ฒ ๋์
0๋ถํฐ 5๊น์ง์ ์์ดํ ์ด ๊ทธ๋ ค์ง๊ณ ํ๋ฉด์ ๋ํ๋๊ฑธ ํ์ธํ ์ ์์ด์. ์๋ฎฌ๋ ์ดํฐ์์๋ 0๋ฒ์งธ ์์ดํ ๊ณผ ํ๋จ์ 5๋ฒ์งธ ์์ดํ ์ด ์ด์ง ๋ณด์ ๋๋ค. ์ด๋ฅผ ๋ทฐ ๊ณ์ธต๊ตฌ์กฐ์์ ํ์ธํ๋ฉด ๋ ํ์คํ ์ฐจ์ด๊ฐ ๋๊ปด์ ธ์
์ ๊ธฐํ๋ ๊ฑด Scroll์ ์์ญ์ด ๋ฏธ๋ฆฌ ์กํ ์๋ค๋ผ๋ ๊ฑฐ์๋๋ฐ, Row๋ ํ์ํ View๋ง ๊ทธ๋ ค์ฃผ๊ณ ์๋๊ฑธ ํ์ธํ ์ ์์ต๋๋ค.
์คํฌ๋กค ํด์ ํ๋จ์ผ๋ก ๋ด๋ ค๋ณด๋ฉด ์ญ์๋ ํ๋ฉด์ ๋ํ๋๋ ๋ทฐ๋ฅผ ๊ทธ๋ฆฌ๋๊ฑธ ํ์ธํ ์ ์์ด์ (๊ฐ์ฅ ์๋จ์ ์ฒซ ๋ฒ์งธ ๋ก์ฐ๋ ์ ์กํ๋์ง ๋ชจ๋ฅด๊ฒ ์ ใ ใ ์คํฌ๋กค์ ๋นจ๋ฆฌํด์ ๊ทธ๋ฐ๊ฐ)
Infinite Scroll
๋ค์ ์ฒ์์ผ๋ก ๋์์์ ๋ฌดํ ์คํฌ๋กค์ ๋ง๋ค์ด ๋ณผ๊ฒ์! ๋ก์ง์ด๋ ์ ์์ ๋ฐ๋ผ ์ฝ๋๊ฐ ๋ฌ๋ผ์ง ์ ์์ด์!
struct InfiniteScrollView: View {
@StateObject var viewModel = InfiniteScrollViewModel()
var body: some View {
ScrollView {
LazyVStack {
ForEach(viewModel.products, id: \.id) { product in
RowView(product: product)
.onAppear {
viewModel.requestProductsWith(id: product.id)
}
}
}
.task {
viewModel.requestProductsWith()
}
}
}
}
InfiniteScrollView๋ LazyVStack์ผ๋ก viewModel์ products๋ฅผ ๋ฆฌ์คํธ๋ก ๋ณด์ฌ์ค๋๋ค. ๊ทธ๋ฆฌ๊ณ ๊ฐ ํ์ด appear ๋ ๋ ๋ง๋ค viewModel์ requestProductsWith(id:) ํจ์๋ฅผ ํธ์ถํด์. ์ด๋ id ํ๋ผ๋ฏธํฐ๋ก ํด๋น ํ์ ๋ฐ์ดํฐ์ id ๊ฐ์ ๋๊ฒจ์ค๋๋ค. ์ด ๊ฐ์ ์ ์์ ๋ฐ๋ผ index ๊ฐ ๋ ์๋ ์๊ณ page๊ฐ ๋ ์ ์๊ฒ ์ฃ ? ์ด๋ ์ฃผ์ ํด์ผ ํ ๊ฒ์ onAppear์ View๊ฐ ํ๋ฉด์ ๋ํ๋ ๋, ์ฌ๋ผ์ก๋ค ๋ค์ ๋ํ๋ ๋ ํธ์ถ๋ฉ๋๋ค. ์ต์ด์ ํ๋ฒ์ด ์๋๊ธฐ ๋๋ฌธ์ ์ฃผ์ํด์ผ ํด์. body ํ๋กํผํฐ๋ ์์ฃผ ์ ๋ฐ์ดํธ ๋๊ณ ๊ทธ๋ ค์ง๊ธฐ ๋๋ฌธ์ ์ฌ๊ธฐ์ ๋ก์ง์ ๋ฃ๋๊ฒ ์๋๋ผ ViewModel์์ ๋ก์ง์ ์์ฑํด ์ค๊ฒ์
/// paging
func requestProductsWith(id: UUID? = nil) {
if page == 5 { return } // ์์๋ก ํ์ด์ง ๊ฐฏ์ ์ ํ ๋
if (id == nil) || (id == products.last?.id) {
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
self.products.append(contentsOf: (0...20).map {
Product(name: "page\(self.page), \($0)item", price: (1000...30000).randomElement() ?? 0)
})
print("ViewModel ์
๋ฐ์ดํธ ์ฑ๊ณต ํ์ด์ง : \(self.page)")
self.page += 1
}
}
}
InfiniteScrollViewModel์ ์ด์ ViewModel๊ณผ ๋์ผํ๋ ํจ์ ๋ถ๋ถ์ด ๋ค๋ฆ ๋๋ค. page๋ ์ด์ ๋ ์ด์ ์๋ฒ๋ก ๋ถํฐ ๋ถ๋ฌ์ฌ ๋ฐ์ดํฐ๊ฐ ์๋ค๋ ์ํฉ์ ๋์ ํด์ ์์ฑํด ์ค ๊ฒ์ธ๋ฐ, ๋ถ๋ฌ์จ ๋ชฉ๋ก์ด 0๊ฐ ์ด๊ฑฐ๋ ๋ค๋ฅธ ํ๋๊ทธ๊ฐ ์๋ค๋ฉด ์ฝ๋๊ฐ ๋ฌ๋ผ์ง๊ฒ ์ฃ ?
id == nil์ InfiniteScrollView๊ฐ ํ๋ฉด์ ๋ํ๋ฌ์ ๋ ์ต์ด ๋ชฉ๋ก์ ๊ฐ์ ธ์ค๊ธฐ ์ํจ์ด๊ณ ์ด๋ id ๊ฐ์ด ์์ผ๋ฏ๋ก nil์ด๋ผ๋ ์ํฉ์ ๊ฐ์ ํด์ ์์ฑํด์ค ์ฝ๋์์.
product์ id ๋ฅผ ๋ฐ์์ ์ด id๊ฐ product์ ๋ง์ง๋ง id์ ์ผ์นํ ๋์๋ ์๋ก์ด ๋ชฉ๋ก์ ๋ถ๋ฌ์ต๋๋ค. ์ฌ๊ธฐ ViewModel์ isLoding ์ด๋ผ๋ Published๋ฅผ ํ๋ ๋ ๋ฃ์ด์ ๋ก๋ฉ์ ํ์ํ๊ฑฐ๋ ๋ก๋ฉ์ด ๋๊ณ ์๋ ๋ก์ฐ๋ฅผ ํ๋ฉด์ ๋ณด์ฌ์ค ์๋ ์์ต๋๋ค. ViewModel์์๋ ๋ก๋ฉ ์ค์ requestProductsWith๊ฐ ์คํ๋๋ฉด ์๋ก์ด ๋ชฉ๋ก์ ๋ถ๋ฌ์ค์ง ๋ชปํ๋๋ก ๋ง์ ์๋ ์์ด์
์ ๋ฆฌํด ๋ณด์๋ฉด VStack์ ๋ชจ๋ row๋ฅผ ๋ค ๊ทธ๋ฆฌ๊ธฐ ๋๋ฌธ์ ์ ์ ๊ฐฏ์๋ ๊ฐ๋จํ ๋ฐ์ดํฐ, ์์ง์ผ๋ก ์์ด๋ UI๋ฅผ ํ์ํด ์ฃผ๋๋ฐ ์ ํฉ ํฉ๋๋ค.
LazyVStack์ ํ๋ฉด์ ๋ํ๋ ๋์๋ง View๋ฅผ ๊ทธ๋ฆฝ๋๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ์์๋๋ก ๋น ๋ฅด๊ฒ ์คํฌ๋กค ํ๋ค๋ฉด VStack์ ๊ฐ ํ View๋ ํ ๋ฒ์ appear๋ง ํธ์ถ๋๊ณ , LazyVStack์ ์ฒ์ ํ๋ฉด์ ๋ณด์์ ๋์ ํ๋ฉด์ ์ฌ๋ผ์ก๋ค๊ฐ ๋ค์ ๋ํ๋ฌ์ ๋์๋ appear๋ฅผ ํธ์ถํ๊ฒ ๋ฉ๋๋ค.
๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ๋ก์ง์ ์์ฑํ ๋ ์ด ๋์ ์ฐจ์ด์ ๊ณผ ํน์ง์ ์๊ฐํ๊ณ ์ฝ๋๋ฅผ ์์ฑํด์ฃผ์ด์ผ ํด์!
SwiftUI ์ ๋ง ์ฌ๋ฏธ์์ง ์๋์? ์ค๋ง ์๊ฒ ์ด? ํ๋๊ฑด ์๊ณ ์ค๋ง ์๊ฒ ์ด ํ๋๊ฑด ์๋ ๊ทธ๋ฐ ์ ๋ SwiftUI์ ๋งค๋ ฅ! ๋ค๋ค SwiftUI ํ์ธ์! ๐ฎ
'iOS ๐ > SwiftUI' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[SwiftUI] Shape path๋ก Tooltip ๊ทธ๋ฆฌ๊ธฐ (0) | 2023.11.06 |
---|---|
SwiftUI LifeCycle ํํค์น๊ธฐ ๐ฎ (1) | 2023.10.31 |
[SwiftUI] NavigationView (1) | 2023.09.22 |
[SwiftUI] ๊ฐ๋ก๋ชจ๋, ์ธ๋ก๋ชจ๋ ์ง์ํ๊ธฐ with @ViewBuilder (0) | 2023.09.20 |
[SwiftUI] ViewBuilder ์์๋ณด๊ธฐ (0) | 2023.09.19 |