Swiftuiの理解:修飾子


ビューは、一般的に、Back/Hstack/ZStackとButton用のアクションのような、ボディプロパティと本質的に必要なプロパティだけを持つ軽量構造です.彼らは非常に自分自身でカスタマイズされていません、そして、それはビュー修飾子が遊びに来るときです.
解凍する重要なことは、修飾子をビューに適用するとき、直接変更しないことです.本当に変更されるべきプロパティはありません.代わりに、修飾子が適用されると、変更された内容が返されます.これは、修飾子を適用したビューをラップします.
let view = Rectangle().frame(width: 100, height: 100)
type(of: view) // ModifiedContent<Rectangle, _FrameLayout>
ModifiedContentは、実行時に適用されるコンテンツと修飾子を保持する別の非常にシンプルな構造体です.
struct ModifiedContent<Content, Modifier> {

  var content: Content
  var modifier: Modifier

}
変更されたコンテンツは、その宣言のビュープロトコルを実装していないことに注意してください.代わりに、ModifiedContentは、コンテンツと修飾子のジェネリックプロパティによって実装されたプロトコルに基づいて異なるプロトコルを実装します.このアプローチは、変更された内容自体をできるだけ簡単に保ち、拡張可能である.
ModifiedContentは、例えば、コンテンツと修飾子がビューとビューモディファイアのプロトコルを実装したときにビューを実装します.
extension ModifiedContent: View 
where Content: View, Modifier: ViewModifier 
{ ... }

ModifiedContent for Scene and Widget are also implemented in the same way, but using SceneModifier and WidgetModifier.


ViewModiferは要件だけがボディー関数であるプロトコルです.
public protocol ViewModifier {
  associatedtype Body : SwiftUI.View
  func body(content: Self.Content) -> Self.Body
}

Just like Views, most built-in ViewModifiers actually return Never from body function because SwiftUI uses only its properties.


カスタム修飾子を作成するには、このプロトコルを実装できます.
struct CustomModifier: ViewModifier {
func body(content: Content) -> some View {
        content
            .padding()
            .background(Color.gray)
            .clipShape(RoundedRectangle(cornerRadius: 10))
    }
}
すべてのSwiftUI修飾子は、内部的に修飾子関数によって戻されます.
extension View {
  public func modifier<T>(_ modifier: T) -> SwiftUI.ModifiedContent<Self, T> {
        return .init(content: self, modifier: modifier)
    }
}
この関数は、カスタム修飾子を適用するために使用するものです.
Rectangle().modifier(CustomModifier())
組み込みの修飾子に関係なく、以下のコードが等価であるが、最後の2つを使用することはできません.

Rectangle().frame(width: 100, height: 100)

Rectangle().modifier(_FrameLayout(width: 100, height: 100))

ModifedContent(content: Rectangle(), modifier: _FrameLayout(width: 100, height: 100))

There are some ViewModifiers that for some reason have a public initializer, _PaddingLayout for example, but they are not mean to be used directly and there is no guarantee that they will remain accessible in future versions of SwifUI.



機能的アプローチ
修飾子とスタックは、それらが両方のコンテンツをラップするという意味で同様です.スタックはクロージャを使用して内容をラップします.このため、修飾子に対してこの同じアプローチを使用しないのでしょう.
FrameLayout(width: 100, height: 100) {
    Rectangle()
}
私は個人的には、このアプローチは、私たちが修飾子を適用するときに何が起こっているかを理解することがいくつかのケースで少し簡単になりますと思います.問題は、すぐにすぐに運命のピラミッドになる複数の修飾子を適用を開始するということです.それはよくエスカレートしません.
CornerRadius(5) {
    Background(Color.red) {
        Padding(10) {
            FrameLayout(width: 100, height: 100) {
                Rectangle()
            }
        }
    }
}
選択された機能的アプローチは、よりスケーラブルでクリーナーであり、一度使用すると、それが正しい選択であることが明らかになります.
Rectangle()
    .frame(width: 100, height: 100)
    .padding(10)
    .background(Color.red)
    .cornerRadius(5)

結論
修飾子はSwiftuiのビューとして重要であり、その賢明に選択された機能的アプローチのおかげで、きれいなコードを維持しながら、必要に応じてビューをカスタマイズできます.