# ViewModifier

[SwiftUI](https://lochiwei.gitbook.io/ios/swiftui) ⟩ [views](https://lochiwei.gitbook.io/ios/swiftui/view) ⟩ [modifier](https://lochiwei.gitbook.io/ios/swiftui/view/modifier) ⟩ ViewModifier (protocol)

{% hint style="success" %}
🚧

```swift
// ViewModifier (protocol)
protocol ViewModifier {
    // input type of body()
    typealias Content            
    // output type of body()
    associatedtype Body: View    
    // ⭐️ only requirement
    func body(content: Self.Content) -> Self.Body
}
```

{% endhint %}

{% tabs %}
{% tab title="🔸 定義" %}

```swift
protocol ViewModifier {
    typealias Content            // input type of body()
    associatedtype Body: View    // output type of body()
    // ⭐️ only requirement
   func body(content: Self.Content) -> Self.Body
}
```

{% hint style="warning" %}
問：「[為什麼 Content 是 typealias，而 Body 是 associatedtype](https://stackoverflow.com/questions/63829538/why-does-viewmodifier-protocol-has-an-associatedtype-and-a-typealias)❓」
{% endhint %}

{% hint style="success" %}
答：

* <mark style="color:purple;">**Content**</mark> 是 **body**() 的<mark style="color:red;">**輸入型別**</mark>（`_ViewModifier_Content<Self>`），使用者<mark style="color:red;">**無法改變**</mark>，只是為了使用者方便而設的 <mark style="color:purple;">**typealias**</mark>。
* <mark style="color:purple;">**Body**</mark> 是 **body**() 的<mark style="color:red;">**輸出型別**</mark>，可以由使用者<mark style="color:red;">**自由指定**</mark>（但由 **compiler** 自動辨識），所以是個 <mark style="color:purple;">**associatedtype**</mark>，也因此 **ViewModifier** 變成一個 <mark style="color:orange;">**generic protocol**</mark>。
  {% endhint %}

💾 模板

```swift
import SwiftUI

// (internal) view modifier
struct MyViewModifier: ViewModifier {
    
    // ⭐️ new states
    @State private var blur = true              
    
    // body
    func body(content: Content) -> some View {
        // ⭐️ handle input `content`
        content
            .blur(radius: blur ? 20 : 0)
            .clipped()
            .onTapGesture { 
                withAnimation {
                    self.blur.toggle()
                }
            }
    }
}

// ⭐️ public helper
extension View {
    public func myModifier() -> some View { 
        modifier(MyViewModifier()) 
    }
}
```

{% endtab %}

{% tab title="⭐️ 重點" %}
{% hint style="success" %}
當 **ViewModifier** 的好處就是：可以幫原來的 view 加入<mark style="color:red;">**新的屬性**</mark>、[**State**](https://lochiwei.gitbook.io/ios/swiftui/view/state/value/state) 變數(例如： [nsfw](https://lochiwei.gitbook.io/ios/swiftui/view/modifier/examples/nsfw "mention"))。 👉 Sundell ⟩ [Configuring SwiftUI Views](https://www.swiftbysundell.com/articles/configuring-swiftui-views/)
{% endhint %}

{% hint style="info" %}
**ViewModifier** is a modifier that you apply to a **view** or **another view modifier**, producing a different version of the original value.
{% endhint %}

{% hint style="warning" %}
既然可以直接用 View extension 來改變一個 View，為什麼還需要大費周章弄一個 ViewModifier 呢❓ 👉  [why bother using a view modifier?](https://stackoverflow.com/questions/63829125/if-we-can-use-view-extensions-to-modify-a-view-why-bother-using-a-view-modifier)

[上面的討論](https://stackoverflow.com/questions/63829125/if-we-can-use-view-extensions-to-modify-a-view-why-bother-using-a-view-modifier#comment112876225_63829125)還有[網路文章](https://swiftwithmajid.com/2019/08/07/viewmodifiers-in-swiftui/)都有提到一點：「ViewModifier 也是 [View](https://lochiwei.gitbook.io/ios/swiftui/view/view)，可以自訂一些 @**State**, @**Binding** 變數，也可設定**支援動畫**的屬性」，這些特性是 View extension 辦不到的。
{% endhint %}

* Another interesting fact about **ViewModifiers** is that **it conforms to View protocol** (#todo：此訊息的資料來源？). It means you can use inside ViewModifiers **property wrappers** like @State, @Binding, @Environment, @ObservableObject, and @EnvironmentObject.\
  👉  [ViewModifiers in SwiftUI ](https://swiftwithmajid.com/2019/08/07/viewmodifiers-in-swiftui/)- Swift with Majid<br>
* in **ViewModifer** you can create your own with **stored properties**, including **states** and other **dynamic properties**, also make it **animatable**, etc.\
  👉  [StackOverflow](https://stackoverflow.com/questions/63829125/if-we-can-use-view-extensions-to-modify-a-view-why-bother-using-a-view-modifier#comment112876225_63829125) - @Asperi<br>
  {% endtab %}

{% tab title="📜 協定" %}
![](https://1830103165-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M5-JmwCZMKh_d7RfBaN%2F-MIgeBvfOqeSVQSz0B94%2F-MIggRnSvOTt6AhCnG4T%2FAnimatable%20protocol%202.png?alt=media\&token=4633d0a6-5628-403f-8f64-a62a3697cd7d)
{% endtab %}

{% tab title="📘 手冊" %}

* SwiftUI ⟩&#x20;
  * [Views and Controls](https://developer.apple.com/documentation/swiftui/views-and-controls) ⟩ [Configuring Views](https://developer.apple.com/documentation/swiftui/configuring-views)
  * [View](https://developer.apple.com/documentation/swiftui/view) ⟩&#x20;
    * [.modifier(\_:)](https://developer.apple.com/documentation/swiftui/view/modifier\(_:\))
    * [ViewModifier](https://developer.apple.com/documentation/swiftui/viewmodifier)
    * [ModifiedContent](https://developer.apple.com/documentation/swiftui/modifiedcontent) ⟩ [View Modifiers](https://developer.apple.com/documentation/swiftui/modifiedcontent-view-modifiers)
      {% endtab %}

{% tab title="📗 參考" %}

* [ ] VINSOL ⟩ [Understanding SwiftUI's ViewModifiers and ViewBuilders](https://vinsol.com/blog/2020/07/02/understanding-swiftuis-viewmodifiers-and-viewbuilders/)&#x20;
* [ ] Sundell ⟩ [Configuring SwiftUI Views](https://www.swiftbysundell.com/articles/configuring-swiftui-views/)&#x20;
* [ ] Loaf ⟩ [SwiftUI Custom View Modifiers](https://useyourloaf.com/blog/swiftui-custom-view-modifiers/)
* [x] objc.io ⟩ [Why Conditional View Modifiers are a Bad Idea](https://www.objc.io/blog/2021/08/24/conditional-view-modifiers/)
* [x] Majid ⟩ [View Modifiers in SwiftUI](https://swiftwithmajid.com/2019/08/07/viewmodifiers-in-swiftui/)&#x20;
* [x] Sarun ⟩ [SwiftUI's ViewModifier](https://sarunw.com/posts/swiftui-viewmodifier/)
* [x] PeterFriese.dev ⟩ [Using View Modifiers to Display Empty State](https://peterfriese.dev/posts/swiftui-empty-state/)
* [ ] Five Stars ⟩ [Conditional view modifiers](https://fivestars.blog/swiftui/conditional-modifiers.html)&#x20;
* [ ] dev.to ⟩ [.task() is new ViewModifier in iOS15 SwiftUI](https://dev.to/toni777772/task-new-viewmodifier-in-ios15-swiftui-16ke)
* [ ] egeniq ⟩ [A deeper understanding of SwiftUI](https://www.egeniq.com/blog/deeper-understanding-swiftui)&#x20;
* [ ] [SwiftUI 2.0: The Future is Declarative](https://infinum.com/the-capsized-eight/swiftUI-2) - [Goran Brlas](https://infinum.com/the-capsized-eight/author/goran-brlas)
  {% endtab %}

{% tab title="👥 相關" %}

* [viewbuilder-transforms](https://lochiwei.gitbook.io/ios/swiftui/view/view-builder/viewbuilder-transforms "mention") modify views too.
* can have [binding](https://lochiwei.gitbook.io/ios/swiftui/view/state/binding/binding "mention") variables.
* Can we implement [.if](https://lochiwei.gitbook.io/ios/custom/ext/view/.if "mention") with ViewModifier❓
* [animatable-modifiers](https://lochiwei.gitbook.io/ios/swiftui/anim/animatable/animatable-modifiers "mention") are [animatable](https://lochiwei.gitbook.io/ios/swiftui/anim/animatable "mention") view modifiers.
  {% endtab %}

{% tab title="🗣 討論" %}

* [Why is SwiftUI.ViewModifier a useful concept?](https://forums.swift.org/t/why-is-swiftui-viewmodifier-a-useful-concept/49702)\
  這裡討論了一個有趣的問題：「為什麼需要 ViewModifier？」一般簡單的 view modifier 用 view extension 就可以，複雜一點的、帶有 State 變數的可以另外寫一個 View，為何還需要特別設計一個 ViewModifier？（這裡提出問題，但目前沒人提供答案）
* [Using view modifiers between different iOS versions without #available](https://stackoverflow.com/questions/68892142/swiftui-using-view-modifiers-between-different-ios-versions-without-available)\
  👥 相關： [available-available](https://lochiwei.gitbook.io/ios/appendix/xcode/directives/available-available "mention")
* [What is Content in SwiftUI?](https://stackoverflow.com/questions/56833659/what-is-content-in-swiftui)
  {% endtab %}
  {% endtabs %}
