SwiftUI

SwiftUI Segmented Control

Daesiker 2021. 4. 1. 17:24
반응형

개요

UIKit에서 UISegmentedControl은 SwiftUI의 Picker와 같은 역할을 한다. 이번에는 Picker 컴포넌트와 UISegmentedControl 함수를 통해 서로 다른 이미지를 View에 표시해주는 간단한 프로젝트를 해볼 예정이다.

코드

SideOfTheForce

enum SideOfTheForce: String, CaseIterable {
    case light = "Light"
    case grey = "Grey"
    case dark = "Dark"
}

Picker의 타이틀을 정해주는 String 타입의 enum이다. light, grey, dark 총 3가지의 case가 있고 이것을 String값으로 반환해준다. CaseIterable 프로토콜을 채용하면 안에 있는 값들을 배열처럼 사용할 수 있다. 이것은 밑에서 다시 다룰 것이다.

HeroImageView

struct HeroImageView: View {
    var heroName: String
    
    var body: some View {
        Image(heroName)
            .resizable()
            .frame(width: 250, height: 400)
            .shadow(color: .white, radius: 100)
    }
}

String 타입의 heroName 변수를 선언한뒤 body에 해당 값에 맞는 이미지를 만들어 준다. .shadow 속성을 통해 그림자를 넣어 주었는데 제일 앞에 gif를 자세히 보면 캐릭터 주변이 살짝 누리끼리한 것을 알 수 있다. 여기에 컬러를 흰색으로 주고 radius를 100을 줌으로써 해당 효과를 넣을 수 있다.

ChosenHereView

struct ChosenHereView: View {
    var selectedSide: SideOfTheForce
    
    var body: some View {
        switch selectedSide {
        case .light:
            HeroImageView(heroName: "anakin")
        case .grey:
            HeroImageView(heroName: "ahsoka")
        case .dark:
            HeroImageView(heroName: "vader")
            
        }
    }
}

앞서 만든 SideOfTheForce 타입의 selectedSide 변수를 선언해 주었다. 그다음에 selectedSide의 case에 맞게 heroName 파라미터의 값을 변경하여 HeroImageView를 넣어준다.

ContentView

struct ContentView: View {
    
    init() {
        UISegmentedControl.appearance().selectedSegmentTintColor = .yellow
        UISegmentedControl.appearance().setTitleTextAttributes([.foregroundColor: UIColor.black], for: .selected)
    }
    @State private var selectedSide: SideOfTheForce = .dark
    
    var body: some View {
        NavigationView {
            VStack {
                Picker("Choose a Side", selection: $selectedSide) {
                    ForEach(SideOfTheForce.allCases, id: \.self) {
                        Text($0.rawValue)
                    }
                }
                .pickerStyle(SegmentedPickerStyle())
                .padding()
                
                Spacer()
                ChosenHereView(selectedSide: selectedSide)
                Spacer()
            }
            .navigationTitle("Choose a Side")
        }
    }
}

우선 SideOfTheForce 타입의 selectedSide를 @State로 감싸준 후 초기 값을 .dark로 선언하였다. 이제 이 selectedSide가 바뀌면 이미지가 바뀔 수 있도록 body 코드를 짜면 된다.

우선 NavigationView와 VStack으로 body안의 내용을 감싼뒤에 Picker 컴포넌트를 선언한다. Picker의 첫번째 파라미터는 해당 Picker의 키값이다. 이 Picker을 다른 함수에서 사용하고 싶을 때 이 키값을 통해 접근이 가능하다. selection은 현재 선택한 값이 무엇인지 알려주는 함수이다. 여기에 $selectedSide를 입력함으로써 selectedSide가 선택한 값에 맞게 바뀌게 할 수 있다. 그 다음에 Picker안에 어떤 컨텐츠가 있는지 알려줘야 하는데 여기서는 반복문을 통해 SideOfTheForce의 모든 케이스들을 가져왔다. SideOfTheForce에 CaseIterable 프로토콜을 채용함으로써 배열처럼 사용할 수 있게 되었고 allCases 함수를 통해 안에 내용을 하나씩 가져올 수 있다. $0에 대해서 잘 모른다면 클로져를 공부하고 오는 것을 추천한다. 여기서는 $0이 .light라면 $0.rawValue는 "Light"이다. 그 다음에 pickerStyle 속성에 SegmentPickerStyle()을 선언하면 Picker가 가로 형태로 나온다.

init() 부분에서는 UISegmentControl 함수를 이용해서 해당 Picker에 TintColor와 TextColor을 꾸며준다. 여기서 선택한 요소의 배경색을 노란색으로 텍스트는 검정색으로 바꾸어준다.

반응형