Devlog
article thumbnail

위 글은 유튜브 정대리님의 SwiftUI fundamental Tutorial 강좌를 보고 작성한 정리글로

자세한 내용은 유튜브를 통해 확인하시길 권장합니다.

 

 

 

LazyVGrid란? 뷰를 화면에 보여줄 때 화면에 보이는 부분만 렌더링이 되는 기능

import SwiftUI


struct MyModel : Identifiable{
    
    let id = UUID()
    let title : String
    let content : String
    
}

// 더미 데이터를 가져오도록 함
extension MyModel{
    // MyModel에 대한 인스턴스를 생성하지 않아도 접근해서 가져올 수 있도록
    static var dummyDataArray: [MyModel]{
        (1...2000).map{ (number: Int) in
            MyModel(title: "title: \(number)", content: "content: \(number)")
        }
    }
}

struct ContentView: View {
    
    var dummyDataArray = MyModel.dummyDataArray
    
    var body: some View {
        
        ScrollView{ // 스크롤이 가능하도록 설정
            
            LazyVGrid(columns: [
                GridItem(.fixed(100))
            
            ], content: {
                ForEach(dummyDataArray, content:{ (dataItem: MyModel) in
                    Rectangle().foregroundColor(.blue)
                        .frame(height: 120)
                        .overlay(Text("\(dataItem.title)"))
                })
            })
        }
    }
}

LazyVGrid: 레이지 버티칼 그리드 뷰

LazyVGrid(columns: Horizontal 아이템 레이아웃을 설정하는 부분, content)

 

 

 

columns에 GridItem을 두개 붙였을 경우 

 

 

 

GridItem 옵션 알아보기: fixed / adaptive / flexible

 ScrollView{
            
            
            // 그리드 아이템 옵션 3가지
            LazyVGrid(columns: [
                GridItem(.adaptive(minimum: 50)),
                GridItem(.fixed(50)),
                GridItem(.flexible(minimum: 50))
            
            ], content: {
                ForEach(dummyDataArray, content:{ (dataItem: MyModel) in
                    Rectangle().foregroundColor(.blue)
                        .frame(height: 120)
                        .overlay(Text("\(dataItem.title)"))
                })
            })
        }

1. .fixed: 고정 값

GridItem(.fixed(50))

 

2. .adaptive: 최소 (n)만큼의 사이즈로 여러 개를 계산해서 분할로 채워줌

 GridItem(.adaptive(minimum: 50))

 

 

3. .flexible: 계산해서 하나만 채우기

GridItem(.flexible(minimum: 50))

 

 

 

 

 

LazyVGrid의 spacing 처리

ScrollView{
            
            LazyVGrid(columns: [
                GridItem(.adaptive(minimum: 50)),
                GridItem(.fixed(50)),
                GridItem(.flexible(minimum: 50))
            ], spacing: 100, content: {
                ForEach(dummyDataArray, content:{ (dataItem: MyModel) in
                    Rectangle().foregroundColor(.blue)
                        .frame(height: 120)
                        .overlay(Text("\(dataItem.title)"))
                })
            })
        }

spacing: 각 줄에 대한 spacing (default = 10)

spacing: 100

 

 

 

 

 

기본 적용하기

import SwiftUI

enum LayoutType : CaseIterable{
    case table, grid, multiple
}

extension LayoutType{

    var columns : [GridItem]{
        switch self {
        case .table:
            return [
                //flexible 하나로 한줄로 표현
                GridItem(.flexible())
            ]
        case .grid:
            return [
               
                GridItem(.flexible()),
                GridItem(.flexible())
            ]
        case .multiple:
            return [
               
                GridItem(.adaptive(minimum: 100))
            ]
        }
    }
}

struct lazyVGrid_apply: View {
    
    @State var dummyData = MyModel.dummyDataArray
    
    @State var selected: LayoutType = .table
    
    var body: some View {
        
        VStack{
            Picker(selection: $selected, label: Text("LayoutType"), content: {
               
                ForEach(LayoutType.allCases, id: \.self, content: { layoutType
                    in
                    switch layoutType{
                    case .table:
                        Image(systemName: "list.dash")
                    case .grid:
                        Image(systemName: "square.grid.2x2.fill")
                    case .multiple:
                        Image(systemName: "circle.grid.3x3.fill")
                    }
                })
            }).pickerStyle(SegmentedPickerStyle())
            
            //CONTENTS
            ScrollView{
                LazyVGrid(columns: selected.columns, content: {
                    ForEach(dummyData){ dataItem in
                        Rectangle()
                            .foregroundColor(.blue)
                            .frame(height: 100)
                    }
                    
                })
            }
        }
    }
}

1. LayoutType을 ForEach로 돌리려면 CaseIterable를 해줘야 함

이는 case를 collection으로 제공한다는 의미

 

enum LayoutType : CaseIterable{
    case table, grid, multiple
}

 

LayoutType.allCases: LayoutType이 가지고 있는 모든 케이스들이 반복해서 들어옴

VStack{
            Picker(selection: $selected, label: Text("LayoutType"), content: {
             
                ForEach(LayoutType.allCases, id: \.self, content: { layoutType
                    in
                    switch layoutType{
                    case .table:
                        Image(systemName: "list.dash")
                    case .grid:
                        Image(systemName: "square.grid.2x2.fill")
                    case .multiple:
                        Image(systemName: "circle.grid.3x3.fill")
                    }
                })
            }).pickerStyle(SegmentedPickerStyle())

 

 

2. LayoutType 자체를 extension하기

 

extension LayoutType{
    var columns : [GridItem]{  // LayoutType에 대한 columns이 자동으로 설정되도록 함
        switch self {
        case .table:
            return [
                //flexible 하나로 한줄로 표현
                GridItem(.flexible())
            ]
        case .grid:
            return [
                // flexible 두개를 넣어서 두개의( 아이템을 들어가게 )레이아웃 표현
                GridItem(.flexible()),
                GridItem(.flexible())
            ]
        case .multiple:
            return [
                // adaptive를 통해 크기를 닿는데까지 아이템을 여러개 넣기
                GridItem(.adaptive(minimum: 100))
            ]
        }
    }
}

 

 

 

 

                

LazyVGrid에 애니메이션 효과 주기: LazyVGrid 자체적으로 제공 함

	ScrollView{
                LazyVGrid(columns: selected.columns, content: {
                    ForEach(dummyData){ dataItem in
                        Rectangle()
                            .foregroundColor(.blue)
                            .frame(height: 100)
                    }
                    
                }).animation(.easeIn/.easeInOut)
            }

색상이 똑같아서 차이점을 못 느낄듯 함...

 

 

 

Picker의 select value 값에 따라 CONTENTS 바꾸기

import SwiftUI

enum LayoutType : CaseIterable{
    case table, grid, multiple
}

extension LayoutType{
   
    var columns : [GridItem]{
        switch self {
        case .table:
            return [
               
                GridItem(.flexible())
            ]
        case .grid:
            return [
               
                GridItem(.flexible()),
                GridItem(.flexible())
            ]
        case .multiple:
            return [
               
                GridItem(.adaptive(minimum: 100))
            ]
        }
    }
}

struct lazyVGrid_apply: View {
    
    @State var dummyData = MyModel.dummyDataArray
    
    @State var selected: LayoutType = .table
    
    var body: some View {
        
        VStack{
            Picker(selection: $selected, label: Text("LayoutType"), content: {
               
                ForEach(LayoutType.allCases, id: \.self, content: { layoutType
                    in
                    switch layoutType{
                    case .table:
                        Image(systemName: "list.dash")
                    case .grid:
                        Image(systemName: "square.grid.2x2.fill")
                    case .multiple:
                        Image(systemName: "circle.grid.3x3.fill")
                    }
                })
            })
            .frame(width: 250)
            .pickerStyle(SegmentedPickerStyle())
            
            //CONTENTS
            ScrollView{
                LazyVGrid(columns: selected.columns, content: {
                    ForEach(dummyData){ dataItem in
                        
                        switch selected{
                            case .table :
                                Rectangle()
                                    .foregroundColor(.red)
                                    .frame(height: 100)
                            case .grid:
                                Rectangle()
                                    .foregroundColor(.blue)
                                    .frame(height: 100)
                            case .multiple:
                                Rectangle()
                                    .foregroundColor(.yellow)
                                    .frame(height: 100)
                            
                        }
                    }
                    
                })
                .animation(.easeInOut)
                .padding(.horizontal, 10)
            }
        }
    }
}

 

 

 

 

View를 따로 만들어서 CONTENTS에 적용하기

import SwiftUI

struct MyTable : View{
    
    var icon : String
    var title : String
    var start : String
    var end : String
    var color : Color
    
    var body: some View{
        HStack(spacing: 10){
            Image(systemName: icon)
                .font(.system(size: 40))
                .foregroundColor(.white)
            
            VStack(alignment: .leading, spacing: 0) {
                Divider().opacity(0)
                Text(title)
                    .fontWeight(.bold)
                    .font(.system(size: 23))
                    .foregroundColor(.white)
                Spacer().frame(height:5)
                Text("\(start)-\(end)")
                    .foregroundColor(.white)
            }
        }
        .padding(20)
        .background(color)
        .cornerRadius(20)
    }
}

struct MyTable_Previews: PreviewProvider{
    static var previews: some View{
        MyTable(icon: "book.fill", title: "공부하기", start: "아침에 눈 뜨고", end: "뒤지기 전까지", color: Color.blue)
    }
}
import SwiftUI

enum LayoutType : CaseIterable{
    case table, grid, multiple
}

extension LayoutType{
   
    var columns : [GridItem]{
        switch self {
        case .table:
            return [
               
                GridItem(.flexible())
            ]
        case .grid:
            return [
                
                GridItem(.flexible()),
                GridItem(.flexible())
            ]
        case .multiple:
            return [
                
                GridItem(.adaptive(minimum: 100))
            ]
        }
    }
}

struct lazyVGrid_apply: View {
    
    @State var dummyData = MyModel.dummyDataArray
    
    @State var selected: LayoutType = .table
    
    var body: some View {
        
        VStack{
            Picker(selection: $selected, label: Text("LayoutType"), content: {
               
                ForEach(LayoutType.allCases, id: \.self, content: { layoutType
                    in
                    switch layoutType{
                    case .table:
                        Image(systemName: "list.dash")
                    case .grid:
                        Image(systemName: "square.grid.2x2.fill")
                    case .multiple:
                        Image(systemName: "circle.grid.3x3.fill")
                    }
                })
            })
            .frame(width: 250)
            .pickerStyle(SegmentedPickerStyle())
            
            //CONTENTS
            ScrollView{
                LazyVGrid(columns: selected.columns, content: {
                    ForEach(dummyData){ dataItem in
                        
                        switch selected{
                            case .table :
                                MyTable(icon: "book.fill", title: "공부하기", start: "아침에 눈 뜨고", end: "뒤지기 전까지", color: Color.blue)
                            case .grid:
                                RoundedRectangle(cornerRadius: 25)
                                    .foregroundColor(Color.init(#colorLiteral(red: 0.1764705926, green: 0.4980392158, blue: 0.7568627596, alpha: 1)))
                                    .frame(height: 200)
                                    .overlay(
                                        VStack(spacing: 2){
                                            Circle().frame(height: 100)
                                                .foregroundColor(Color.init(#colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1)))
                                            Spacer().frame(height: 10)
                                            Text("\(dataItem.title)")
                                                .font(.system(size: 20))
                                                .fontWeight(.bold)
                                            Text("\(dataItem.content)")
                                        }
                                    )
                            case .multiple:
                                Rectangle()
                                    .foregroundColor(Color.init(#colorLiteral(red: 0.2588235438, green: 0.7568627596, blue: 0.9686274529, alpha: 1)))
                                    .frame(height: 100)
                            
                        }
                    }
                    
                })
                .animation(.easeInOut)
                .padding(.horizontal, 10)
            }
        }
    }
}

profile

Devlog

@덩이

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

검색 태그