본문 바로가기
Swift

SwiftUI: BlendMode

by songmoro 2023. 8. 9.
728x90

blendMode: Sets the blend mode for compositing this view with overlapping views.(해당 뷰를 겹치는 뷰로 합성하기 위한 블렌드 모드 설정)

 

blendMode(_:) | Apple Developer Documentation

Sets the blend mode for compositing this view with overlapping views.

developer.apple.com

func blendMode(_ blendMode: BlendMode) -> some View

BlendMode를 인자로 받아 뷰를 반환해 준다고 하는군요.

 

BlendMode | Apple Developer Documentation

Modes for compositing a view with overlapping content.

developer.apple.com

 

블렌드 모드 설정을 위해 원이 겹치는 뷰를 그려줍니다.

struct ContentView: View {
    var body: some View {
        ZStack {
            Circle()
                .fill(.red)
                .frame(width: 200, height: 200)
                .offset(x: -50)
            
            Circle()
                .fill(.blue)
                .frame(width: 200, height: 200)
                .offset(x: 50)
        }
    }
}

 

확인을 위해 임의의 블렌드 모드를 추가해 볼게요.

struct ContentView: View {
    var body: some View {
        ZStack {
            Circle()
                .fill(.red)
                .frame(width: 200, height: 200)
                .offset(x: -50)
            
            Circle()
                .fill(.blue)
                .frame(width: 200, height: 200)
                .offset(x: 50)
                .blendMode(.colorBurn)
        }
    }
}

 

정확히 어떤 모드인지는 몰라도, 블렌드 모드가 정상적으로 적용되는 것을 확인할 수 있습니다.

 

BlendMode는 Enum으로 기본 값인 normal을 포함해 21가지가 있는데, 각 값들이 어떤 식으로 표현되는지 확인을 위해 Picker에서 선택해 변화를 확인할 수 있도록 코드를 작성해 보겠습니다.

 

BlendMode의 상태가 변화할 때마다 뷰를 새로고침 할 수 있도록 State 변수를 선언하고, 할당해줍니다.

struct ContentView: View {
    @State var blendState: BlendMode = BlendMode.normal
    
    var body: some View {
        ZStack {
            Circle()
                .fill(.red)
                .frame(width: 200, height: 200)
                .offset(x: -50)
            
            Circle()
                .fill(.blue)
                .frame(width: 200, height: 200)
                .offset(x: 50)
                .blendMode(blendState)
        }
    }
}

 

Picker와 ForEach를 사용해서 선택한 블렌드 모드가 적용되길 바랐는데, Enum 타입이라 적용이 되지 않네요.

 

extension을 통해 BlendMode를 Picker에서 사용할 수 있도록 만들어주겠습니다.

extension을 위해 파일을 추가한 후, CaseIterable 프로토콜을 추가해 줄게요.

import SwiftUI

extension BlendMode: CaseIterable {
    public static var allCases: [BlendMode]
}

 

BlendMode.allCases에 값을 넣어줍니다.

extension BlendMode: CaseIterable {
    public static var allCases: [BlendMode] = [.color, .colorBurn, .colorDodge, .darken,
                                               .destinationOut, .destinationOver, .difference, .exclusion,
                                               .hardLight, .hue, .lighten, .luminosity,
                                               .multiply, .normal, .overlay, .plusDarker,
                                               .plusLighter, .saturation, .screen, .softLight,
                                               .sourceAtop]
}

 

수정한 extension에 맞춰 Picker를 고치고 확인해 보면 0부터 20까지 21개가 모두 들어있는 걸 확인할 수 있습니다.

Picker(selection: $blendState) {
                ForEach(BlendMode.allCases.indices) { state in
                    Text(state.description)
                }
            } label: { }

 

하지만, 우리가 원하는 건 숫자로 나오는 게 아니죠. extension에 코드를 추가해줍시다.

extension BlendMode: CaseIterable {
    public static var allCases: [BlendMode] = [.color, .colorBurn, .colorDodge, .darken,
                                               .destinationOut, .destinationOver, .difference, .exclusion,
                                               .hardLight, .hue, .lighten, .luminosity,
                                               .multiply, .normal, .overlay, .plusDarker,
                                               .plusLighter, .saturation, .screen, .softLight,
                                               .sourceAtop]
    
    var state: String {
        switch self {
        case .normal:
            return "normal"
        case .multiply:
            return "multiply"
        case .screen:
            return "screen"
        case .overlay:
            return "overlay"
        case .darken:
            return "darken"
        case .lighten:
            return "lighten"
        case .colorDodge:
            return "colorDodge"
        case .colorBurn:
            return "colorBurn"
        case .softLight:
            return "softLight"
        case .hardLight:
            return "hardLight"
        case .difference:
            return "difference"
        case .exclusion:
            return "exclusion"
        case .hue:
            return "hue"
        case .saturation:
            return "saturation"
        case .color:
            return "color"
        case .luminosity:
            return "luminosity"
        case .sourceAtop:
            return "sourceAtop"
        case .destinationOver:
            return "destinationOver"
        case .destinationOut:
            return "destinationOut"
        case .plusDarker:
            return "plusDarker"
        case .plusLighter:
            return "plusLighter"
        @unknown default:
            fatalError()
        }
    }
}

 

마지막으로, Picker를 수정해 주면 끝입니다.

결과물

Picker(selection: $blendState) {
                ForEach(BlendMode.allCases, id: \\.self) { state in
                    Text(state.state)
                }
            } label: { }

 

 

각 BlendMode에 따른 변화

Dark Mode

Light Mode

728x90

'Swift' 카테고리의 다른 글

Vision: visionOS simulator  (0) 2023.08.22
Vision: visionOS란?  (0) 2023.08.22
SwiftUI: map, compactMap, flatMap  (0) 2023.08.11
SwiftUI: Mask Design  (0) 2023.08.11
SwiftUI: 온보딩  (0) 2023.08.07