【SwiftUI】이 세상에서 가장 알기 쉬운 뷰 모디파이어를 만드는 방법

이 게시물은 무엇입니까?



SwiftUI 프레임워크를 사용한 앱 개발에서는 여러 뷰를 조합하여 화면을 구축해 나갈 것입니다. 해당 뷰의 모양과 동작을 설정하는 데 사용하는 것이 뷰 수정자입니다.
여기에서는, 독자적인 뷰 모디파이어를 정의해 호출하는 방법에 대해, 실천·해설합니다.

실행 환경



macOS 11.4
Xcode 12.5.1
Swift 5.4

핸즈온



작성하는 수정자는 '보기에 체크 표시'라는 것입니다.



ViewModifier 프로토콜



새 파일을 만들고 Mark라는 구조를 정의합니다.

Mark형
import SwiftUI

struct Mark: ViewModifier {
    func body(content: Content) -> some View {
        // ビューを返す
    }
}

「모디파이어로서 호출할 수 있는 메소드」를 구현하려면 , 그 형태를 ViewModifier 프로토콜에 적합시킬 필요가 있습니다. ViewModifier 프로토콜은, 형태에 body(_:) 메소드의 구현을 요구합니다.
이 메서드가 받는 ‘content’매개 변수는 수정자가 적용되는 뷰를 나타냅니다. 그리고, 반환값의 형태로서 선언되고 있는 some View 가, 모디파이어 적용후의 뷰입니다.

body(_:) 메서드



여기에서는 적용할 뷰의 왼쪽에 "녹색 체크 표시"를 배치합니다. 뷰 빌더 형식으로 코드를 작성할 수 있습니다.

Mark형
struct Mark: ViewModifier {
    func body(content: Content) -> some View {
        HStack {
            Image(systemName: "checkmark.circle")
                .foregroundColor(.green)
            content
        }
    }
}

이제 독자적인 수정자를 정의할 수 있었습니다.

수정자 호출



만든 수정자를 적용하려면 뷰의 modifier(_:) 메서드를 호출합니다.

ContentView
struct ContentView: View {
    var body: some View {
        Text("Hello, world!")
            .modifier(Mark())
    }
}

미리보기에서는 텍스트 왼쪽에 "녹색 체크 표시"가 배치됩니다.
다만, 이 코드는 「일반적인 뷰 모디파이어」와는 호출 방법이 다른 것을 알 수 있습니다..marked() 와 같이, 「모디파이어다운 방법」으로 호출하고 싶은 곳입니다.

모디파이어다운 호출 방법


View 형태를 확장해, 모디파이어의 바람직한 호출 방법을 구현합니다.

Mark.swift
struct Mark: ViewModifier {
    func body(content: Content) -> some View {...}
}

extension View {
    func marked() -> some View {
        return self.modifier(Mark())
    }
}

이상적인 메서드 이름을 선언하여 some View 형식을 반환합니다. 메소드의 바디에서는, 자신의 인스턴스에 대해서 「원래 모디파이어 메소드」를 적용한 뷰를 돌려주는 것입니다.

이제 수정자는 더 SwiftUI 같은 형식으로 호출할 수 있습니다.

Content.swift
struct ContentView: View {
    var body: some View {
        Text("Hello, world!")
            .marked()
    }
}

매개변수를 받는 수정자



마크 유형을 변경하기 위해 수정자가 매개변수를 수신할 수도 있습니다.

Mark.swift
struct Mark: ViewModifier {
    var isChecked: Bool

    func body(content: Content) -> some View {
        HStack {
            if isChecked {
                Image(systemName: "checkmark.circle")
                    .foregroundColor(.green)
            } else {
                Image(systemName: "xmark.circle")
                    .foregroundColor(.red)
            }
            content
        }
    }
}
extension View {
    func mark(isChecked: Bool) -> some View {
        return self.modifier(Mark(isChecked: isChecked))
    }
}

여기에서는 '녹색 체크' 또는 '빨간색 바트' 중 하나를 표시하도록 수정자를 정의했습니다.

호출자의 코드에서 수정자에 Bool 값을 지정합니다.

Content.swift
struct ContentView: View {
    var body: some View {
        Text("Hello, world!")
            .mark(isChecked: false)
    }
}

좋은 웹페이지 즐겨찾기