ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [SwiftUI] Background, Grid, ScrollView 등(+View)
    SwiftUI 2024. 9. 8. 23:28

     

    안녕하세요. 1000JI입니다 :)
    저번 글에 이어서 계속 SwiftUI View 관련 코드를 이어가려고 합니다.

     


     

    Background & Overlay
    첫 번째 예제

    Text 또는 Circle 등 View를 생성 한 뒤 배경 설정 또는 맨 앞에 배치하는 방법에 대한 내용 입니다.

    Text("Hellow, World!")
        .frame(width: 100, height: 100)
        .background(
            Circle()
                .fill(
                    LinearGradient(
                        gradient: Gradient(
                            colors: [
                                Color.red,
                                Color.blue
                            ]
                        ),
                        startPoint: .leading,
                        endPoint: .trailing
                    )
                )
        )
        .frame(width: 120, height: 120)
        .background(
            Circle()
                .fill(Color.red)
        )

     

    위 코드를 살펴보게 되면, Text("Hellow, World!")를 생성 한 뒤 frame, background 설정을 하고 있습니다.

    코드 그대로 텍스트의 사이즈를 100으로 설정한 후 background에 Circle을 생성하고 있습니다.

    frame의 크기를 그대로 받아 생성하기 때문에 Circle의 사이즈도 100으로 설정 됩니다.

    첫 번째 예제 결과

     

    두 번째 예제
    Circle()
        .fill(Color.pink)
        .frame(width: 100, height: 100)
        .overlay(
            Text("1")
                .font(.title)
                .foregroundColor(Color.white)
        )
        .background( // Background 뒤쪽에 깔리는 도형/색상을 지정 할 수 있음.
            Circle()
                .fill(Color.purple)
                .frame(width: 120, height: 120)
        )

     

    overlay를 통해 Circle 위에 텍스트를 삽입 하였습니다.

    이후 background를 사용하여 뒤쪽에 도형을 배치하였습니다.

    두번째 예제 결과

     

     

     

    Stack

    Stack 뷰는 정말 다양하게 활용 할 수 있으며, 필수적인 뷰 중에 하나 입니다 :)

     

    첫 번째 예제(ZStack, VStack, HStack)

    1. ZStack

    • 개요: ZStack은 자식 뷰를 Z축(깊이 축)으로 쌓는 스택입니다. 즉, 뷰를 겹쳐 쌓아올려서 배치합니다.
    • 사용 예시: 배경 이미지 위에 텍스트를 겹쳐 놓거나, 여러 개의 뷰를 한 위치에 겹쳐서 놓아야 할 때 사용합니다.

    2. HStack

    • 개요: HStack은 자식 뷰를 가로축(X축)으로 나란히 배치하는 스택입니다.
    • 사용 예시: 여러 개의 뷰를 수평으로 정렬해야 할 때 사용합니다. 예를 들어, 여러 개의 버튼이나 이미지를 가로로 나란히 배치하고자 할 때 적합합니다.

    3. VStack

    • 개요: VStack은 자식 뷰를 세로축(Y축)으로 나란히 배치하는 스택입니다.
    • 사용 예시: 여러 개의 뷰를 수직으로 정렬해야 할 때 사용합니다. 예를 들어, 리스트 형태로 텍스트나 이미지 등을 세로로 배치하고자 할 때 적합합니다.
    ZStack (alignment: .top) {
        Rectangle()
            .fill(Color.yellow)
            .frame(width: 350, height: 500)
    
        VStack(alignment: .leading, spacing: 30) {
            Rectangle()
                .fill(Color.red)
                .frame(width: 150, height: 150)
    
            Rectangle()
                .fill(Color.green)
                .frame(width: 100, height: 100)
    
            HStack(alignment: .bottom, spacing: 10) {
                Rectangle()
                    .fill(Color.purple)
                    .frame(width: 50, height: 50)
    
                Rectangle()
                    .fill(Color.pink)
                    .frame(width: 75, height: 75)
    
                Rectangle()
                    .fill(Color.blue)
                    .frame(width: 25, height: 25)
            }
            .background(Color.white)
        }
        .background(Color.black)
    }

    첫 번째 예제 결과

    두 번째 예제(ZStack vs Background)

    ZStack과 Background를 활용해서 같은 뷰를 다른 방법으로 구현 할 수 있습니다.

     

    VStack(spacing: 50) {
        // ZStack 을 사용해서 원에 1을 표현 - layer 가 복잡할때 ZStack 사용하면 좋음
        ZStack(alignment: .center) {
            Circle()
                .frame(width: 100, height: 100)
    
            Text("1")
                .font(.title)
                .foregroundColor(.white)
        }
    
        // Background 를 사용해서 원에 1을 동일하게 표현 - layer 가 단순할 경우 추천
        Text("1")
            .font(.title)
            .foregroundColor(.white)
            .background(
                Circle()
                    .frame(width: 100, height: 100)
            )
    }

     

    두번째 예제 결과

     

     

    Spacer

     

    Spacer는 SwiftUI에서 레이아웃을 구성할 때 빈 공간을 추가하는 데 사용하는 뷰입니다. Spacer는 가변적인 크기의 빈 공간을 만들어서 다른 뷰들 사이에 일정한 간격을 유지하거나, 원하는 위치로 뷰를 밀어낼 수 있도록 해줍니다.

    Spacer의 특징

    • 유연한 공간 제공: Spacer는 레이아웃에서 가능한 모든 여유 공간을 차지하려고 시도합니다. 여러 Spacer가 있을 경우, 해당 공간을 균등하게 나누어 가집니다.
    • 수평 및 수직 정렬에 사용: Spacer는 HStack(수평 스택)과 VStack(수직 스택)에서 모두 사용되어 빈 공간을 추가할 수 있습니다.
    • 간격 조절: Spacer를 사용하면 뷰 간의 간격을 자유롭게 조절할 수 있습니다. 예를 들어, Spacer를 HStack이나 VStack 내에서 사용하여 뷰들을 원하는 위치로 밀어낼 수 있습니다.
    VStack {
        HStack(spacing: 0) {
            Image(systemName: "xmark")
    
            Spacer() // Spacer는 최대한 공간을 차지하려는 속성이 있기 때문에 좌우로 밀어냄
    
            Image(systemName: "gear")
        }
        .font(.title)
        .padding(.horizontal)
    
        Spacer()
    }

     

     

    ForEach

     

    ForEach는 SwiftUI에서 반복적으로 뷰를 생성하고 배열하거나 목록을 만들 때 사용하는 구조입니다. 주어진 데이터 컬렉션을 순회하며 각 요소에 대해 뷰를 생성하여 화면에 표시할 수 있도록 도와줍니다.

    ForEach의 특징

    • 반복적으로 뷰 생성: 주어진 데이터 컬렉션의 각 요소에 대해 반복적으로 뷰를 생성합니다.
    • 식별 가능한 데이터 사용: SwiftUI는 각 뷰를 고유하게 식별해야 하기 때문에, ForEach에서 사용하는 데이터는 고유한 식별자를 가져야 합니다. 식별자는 데이터가 변경되었을 때 SwiftUI가 뷰를 효율적으로 업데이트할 수 있도록 도와줍니다.
    • 동적 목록 생성: ForEach를 사용하면 고정된 개수가 아닌 데이터 기반의 동적인 개수의 뷰를 생성할 수 있습니다.
    var data: [String] = ["Hi", "Hello", "Hey everyone"]
    
    VStack {
        // View를 반복 사용하기 위해서 ForEach 구분을 사용해야 함.
        // 컬렉션 데이터 값을 기반으로 뷰를 계산하는 구조임.
        ForEach(0..<10) { index in
            HStack {
                Circle()
                    .frame(width: 20, height: 20)
    
                Text("인덱스 번호 : \(index)번")
            }
        }
    
        Divider()
    
        // 2번
        /*
         * ForEach는 랜덤 액세스 컬렉션 타입임. 따라서 데이터 값에 하나씩 아이디 값을 넣어줘야함.
         * id 파라미터는 ForEach에서 각 항목을 고유하게 식별하기 위한 값입니다.
         * SwiftUI는 이 값을 사용하여 각 항목의 상태를 추적하고, 컬렉션의 데이터가 변경될 때 뷰를 최소한으로 업데이트할 수 있도록 합니다.
         * id: \.self를 사용하는 것은 데이터가 고유한 값을 가지고 있을 때 적합합니다.
           예를 들어, String이나 Int와 같은 기본 데이터 유형은 이미 고유성을 가지므로 id: \.self를 사용할 수 있습니다.
           하지만 커스텀 데이터 유형을 사용하는 경우, 그 데이터 타입이 Hashable을 준수하거나, 특정 속성(id)을 사용하여 고유 식별자를 제공해야 합니다.
         */
        ForEach(data, id: \.self) { item in
            Text(item)
        }
    }

     

    ScrollView

     

    ScrollView는 SwiftUI에서 콘텐츠가 현재 화면에 다 담기지 않을 때 스크롤 가능한 영역을 만들어주는 뷰입니다. ScrollView는 사용자가 손가락을 움직여서 화면을 위아래 또는 양옆으로 이동할 수 있게 해주며, 긴 텍스트, 목록, 이미지, 또는 다양한 뷰들을 스크롤하여 볼 수 있도록 합니다.

    ScrollView의 특징

    • 스크롤 가능한 콘텐츠 영역: ScrollView를 사용하면 콘텐츠가 화면 밖으로 넘칠 때 해당 콘텐츠를 스크롤할 수 있도록 만들어줍니다.
    • 수직 및 수평 스크롤: ScrollView는 수직(vertical) 또는 수평(horizontal)으로 스크롤할 수 있으며, 필요에 따라 스크롤 방향을 지정할 수 있습니다.
    • 동적 콘텐츠: 긴 리스트, 다량의 데이터 또는 동적 콘텐츠를 스크롤을 통해 쉽게 표시할 수 있습니다.
    • 내부 레이아웃 구성 지원: ScrollView 안에 다양한 레이아웃(VStack, HStack, ZStack 등)을 사용할 수 있습니다.

    HStack과 LazyHStack은 SwiftUI에서 뷰를 수평으로 나란히 배치하는 데 사용하는 레이아웃 컨테이너입니다. 두 가지 모두 수평 방향으로 뷰를 배치하지만, 주요 차이점은 뷰의 로딩 방식에 있습니다.

    주요 차이점

    1. 뷰 로딩 방식
      • HStack: 모든 자식 뷰를 한 번에 메모리에 로드합니다. 즉, HStack에 포함된 모든 뷰가 초기화될 때 즉시 메모리에 로드되고, 레이아웃이 설정됩니다.
      • LazyHStack: 필요할 때만 자식 뷰를 로드합니다. 스크롤 가능한 컨테이너 안에 있을 때, 화면에 나타나는 뷰들만 로드하고 나머지는 스크롤할 때 필요할 때 로드합니다. 따라서 많은 수의 뷰가 있을 때 성능이 더 효율적입니다.
    2. 사용 목적
      • HStack: 소수의 뷰가 있을 때 적합합니다. 모든 뷰를 한 번에 메모리에 로드하기 때문에, 소규모의 정적인 뷰를 나열할 때 사용합니다.
      • LazyHStack: 많은 수의 뷰가 있을 때 적합합니다. 특히 스크롤 가능한 컨테이너(예: ScrollView) 내에서 사용하여 성능을 최적화하고, 불필요한 메모리 사용을 줄입니다.
    // 기본 값은 .vertical && showIndicators = true
    ScrollView(.vertical, showsIndicators: true) {
        // 데이터 양이 많아지는 경우 LazyVStack, LazyHStack을 사용하게 되면 화면에 보여지는 부분만 로딩이 되고,
        // 스크롤을 하게 되면 나중에 정보가 업데이트 하는 방식임.
        LazyVStack {
            ForEach(0..<10) { _ in
                ScrollView(.horizontal, showsIndicators: false) {
                    LazyHStack {
                        ForEach(0..<20) { _ in
                            RoundedRectangle(cornerRadius: 25.0)
                                .fill(Color.white)
                                .frame(width: 200, height: 150)
                                .shadow(radius: 10)
                                .padding()
                        }
                    }
                }
            }
        }
    }

     

    Grid

    Grid는 SwiftUI에서 iOS 17, macOS 14, watchOS 10 및 tvOS 17 이후 사용할 수 있는 새로운 레이아웃 시스템으로, 행(row)과 열(column)로 구성된 격자 형태의 레이아웃을 만들 수 있게 해줍니다. Grid는 HStack과 VStack보다 유연하게 뷰를 배치할 수 있으며, 복잡한 레이아웃을 보다 직관적이고 간단하게 만들 수 있도록 도와줍니다.

    Grid의 특징

    • 격자 형태의 배치: Grid는 행과 열을 사용하여 뷰를 배치합니다. 이를 통해 가로와 세로로 복잡한 레이아웃을 쉽게 구성할 수 있습니다.
    • 유연한 레이아웃 구성: 각 열과 행의 크기와 위치를 자유롭게 설정할 수 있어, 고정된 크기나 비율, 자동 크기 조절 등의 다양한 요구에 맞게 레이아웃을 구성할 수 있습니다.
    • 자동화된 셀 크기 조정: Grid는 자식 뷰의 크기에 따라 셀 크기를 자동으로 조정할 수 있습니다.
    • 컬럼 설정: 열의 개수와 크기를 정의하고, 각각의 열이 고정 너비 또는 비율에 따라 크기를 조정하도록 설정할 수 있습니다.

    Grid의 주요 구성 요소

    • Grid: 행과 열로 구성된 격자 형태의 기본 레이아웃 컨테이너입니다.
    • GridRow: Grid 내에서 하나의 행을 정의하며, 행 안에 여러 개의 열을 포함할 수 있습니다.
    • 열 크기 및 정렬: 열의 크기를 고정된 값으로 지정하거나, 콘텐츠에 따라 자동으로 조정되도록 설정할 수 있습니다.
    /*
     * List: 일반적 목록 배열 방식(일반적인 수직 방향으로 목록 표출)
     * Grid: box 형태로 나타내는 배열 방식(가로 세로 방향으로 사진 배열 같은 형태 표출)
     */
    
    // LazyVGrid
    // columns 의 갯수를 3개로 설정
    // .flexible() -> Single Flexible Item 그 크기를 화면 프로엠이 맞춰줌
    // .flexible(minimum: 10, maximum: .infinity)
    let columns: [GridItem] = [
        GridItem(.flexible(), spacing: 6, alignment: nil),
        GridItem(.flexible(), spacing: 6, alignment: nil),
        GridItem(.flexible(), spacing: 6, alignment: nil),
    ]
    
    var body: some View {
    
        // 1 - LazyVGrid
        ScrollView {
    
            // Hero 부분 (위에 사진 부분)
            Rectangle()
                .fill(Color.orange)
                .frame(height: 400)
    
            LazyVGrid(
                columns: columns,
                alignment: .center,
                spacing: 6,
                pinnedViews: [.sectionHeaders]) {
                    // Section 1
                    Section(
                        header: Text("Section1")
                            .foregroundColor(.white)
                            .font(.title)
                            .frame(maxWidth: .infinity, alignment: .leading)
                            .background(Color.blue)
                            .padding()
                    ) {
                        ForEach(0..<20) { index in
                            Rectangle()
                                .fill(Color.gray)
                                .frame(height: 150)
                                .overlay(
                                    Text("\(index) 번")
                                        .frame(maxWidth: .infinity)
                                        .background(Color.red)
                                )
                        }
                    } //: Section 1
    
                    // Section 2
                    Section(header: Text("Section2")
                        .foregroundColor(.white)
                        .font(.title)
                        .frame(maxWidth: .infinity, alignment: .leading)
                        .background(Color.red)
                        .padding()
                    ) {
                        ForEach(0..<20) { index in
                            Rectangle()
                                .fill(Color.green)
                                .frame(height: 150)
                                .overlay(
                                    Text("\(index) 번")
                                )
                        }
                    } //: Section 2
                }
        } // :1번
    }

     

    Button

    가장 많이 사용하게 될 View 중 하나인 Button이다.

    다양한 예제로 살펴보자!

     

    // property
    
    // @State: UI 화면에 변경이 되면 자동으로 알아차려서 UI 화면에 업데이트를 해줌.
    @State var mainTitle: String = "아직 버튼 안눌림"
    
    var body: some View {
        VStack (spacing: 20) {
            // 리셋 버튼
            Button  {
                // Action: 사용자가 버튼을 클릭할 경우 작업 수행 메서드
                mainTitle = "리셋"
            } label: {
                // Label: 텍스트, 아이콘 등 버튼을 라벨링하기
                Text("리셋버튼")
            }
    
    
            // 라벨
            Text(mainTitle)
                .font(.title)
    
            Divider()
    
            // 1번 버튼
            // action 은 button을 눌렀을때 실행할 event 넣기
            // label 은 button 모양을 디자인 하기
            Button {
                // action
                mainTitle = "기본 버튼 눌림"
            } label: {
                // label
                Text("기본 버튼")
            }
            .accentColor(.red)
    
            Divider()
    
            // 2번 버튼
            Button {
                mainTitle = "저장 버튼 눌림"
            } label: {
                Text("저장")
                    .font(.headline)
                    .fontWeight(.semibold)
                    .foregroundColor(.white)
                    .padding() // 왜 padding을 2개를 쓰는거지?
                    .padding(.horizontal, 20)
                    .background(
                        Color.blue
                            .cornerRadius(10)
                            .shadow(radius: 10)
                    )
            }
    
            Divider()
    
            // 3번 버튼
            Button {
                mainTitle = "하트 버튼 눌림"
            } label: {
                Circle()
                    .fill(Color.white)
                    .frame(width: 75, height: 75)
                    .shadow(radius: 10)
                    .overlay(
                        Image(systemName: "heart.fill")
                            .font(.largeTitle)
                            .foregroundColor(Color.red)
                    )
            }
    
            // 4번 버튼
            Button {
                mainTitle = "완료 버튼 눌림"
            } label: {
                Text("완료")
                    .font(.caption)
                    .bold()
                    .foregroundColor(.gray)
                    .padding() // 상하좌우에 균등한 기본 패딩(여백)을 추가 함.
                    .padding(.horizontal, 10) // 가로 방향으로 10포인트 추가 패딩을 적용
                    .background(
                        Capsule()
                            .stroke(Color.gray, lineWidth: 2.5)
                    )
            }
    
    
        }
    }

     

     

    이상으로 SwiftUI의 주요한 뷰들을 예제와 함께 살펴보았습니다.

    다음에는 @state, @binding 같은 상태 관리 로직도 살펴보겠습니다.

     

    감사합니다!

    'SwiftUI' 카테고리의 다른 글

    [SwiftUI] Gradient, Icon, Image, Frame  (0) 2024.08.28
    [SwiftUI] Preview, Text, Shape  (0) 2024.08.26
    [SwiftUI] SwiftUI란?  (0) 2024.08.25
Designed by Tistory.