iT邦幫忙

2023 iThome 鐵人賽

DAY 6
0
Mobile Development

SwiftUI 的大大小小系列 第 6

Day 6 - SwiftUI 中 ViewModifier 的基本實作

  • 分享至 

  • xImage
  •  

hero

前一篇第 5 天是提到「SwiftUI 和 Optional 屬性的綁定」,雖然本系列文章基本上沒有前後關聯,如果你是還沒讀過前一篇的讀者,也推薦你去讀讀。

問題描述

就像在寫程式碼的時候會想要封裝成 method 或是另外一個 class/struct ,在 SwiftUI 當然會想做一樣的事情。

範例

先來看本篇文章主要的例子:

0601

Text("2023 iThome 鐵人賽")
    .foregroundStyle(Color(red: 0.13, green: 0.14, blue: 0.1))
    .font(.system(size: 20, weight: .black))
    .background(
        Rectangle()
            .foregroundColor(.mint)
            .frame(height: 8)
            .offset(x: 6, y: 8)
    )

在封裝之前,假使我們有這樣樣式的一個元件,有多種 modifiers 疊加,用了不同的顏色、尺寸等。當一個 UI 程式碼包含這麼多樣式相關的設定時,除了會 降低可讀性 ,也 無法重複利用 這個樣式。

建立 VisualModifier 的步驟

  1. 建立 VisualModifier
  2. 擴展 View 方便使用

主要分這兩個步驟,接著一一來看各自該做什麼事。

1. 建立 VisualModifier

新建一個繼承 protocol VisualModifier 的 struct ,並實作指定的方法:

func body(content: Content) -> some View 

實作出來的內容如下

struct TitleStyle: ViewModifier {
    func body(content: Content) -> some View {
        content
            .foregroundStyle(Color(red: 0.13, green: 0.14, blue: 0.1))
            .font(.system(size: 20, weight: .black))
            .background(
                Rectangle()
                    .foregroundColor(.mint)
                    .frame(height: 8)
                    .offset(x: 6, y: 8)
            )
    }
}

使用 TitleStyle

最簡單直接的方式,可以透過 .modifier 傳入一個 ViewModifier 物件:

Text("2023 iThome 鐵人賽")
    .modifier(TitleStyle())

不過當有多個自家的 ViewModifiers 時,就會有數個 .modifiers 。個人認為這樣看起來變得冗余而且降低可讀性。

因此,就可以來擴展 View 、建立 helper methods ,來改善這個問題。

2. 擴展 View 、建立 ViewModifier 的 Helper Method

extension View {
    func titleStyle() -> some View {
        // TODO: 實作
    }
}

基本型如上,就像一般的方法一樣,可以自定義不相衝的方法名稱、參數,回傳為 some View 即可。

實作內容把上面的 modifier 放入即可,如下:

extension View {
    func titleStyle() -> some View {
        modifier(TitleStyle())
    }
}

實際使用

Text("iThome 鐵人賽 2013")
    .titleStyle()

像是這樣加上去即可

其他種類的 UI 元件

VisualModifier 做出來之後,不止 Text ,其他種類的 UI 元件也可以套用,例如 Label :

0602

Label("Apple", systemImage: "apple.logo")
    .titleStyle()

上半為預設樣式,只要加上一行就可以向下半部那樣套用了。

是不是很方便呀!

應用

我手上的專案,在按鈕的部分按下去會有放大縮小 (spring animation) 的效果,為了要方便使用,就有用 ViewModifier 封裝起來。

其他的像是邏輯和 UI 元件本身有關、和商業邏輯無關的時候,也有這樣封裝。例如 SwiftUI 的 TextField 沒有 clear 按鈕(對,沒有),在實作之後,也用 ViewModifier 封裝起來。

優缺點與取捨

相信會有另外一派會說,建立一個 custom view 封裝起來不就好了嗎?

沒錯,

這個部分就要看團隊的規範和取捨,看共用的樣式是不是會橫跨不同種類的 UI 元件?是不是只有用在特定情形?等等各式各樣的需要考慮的面向。

但是把這個工具記起來熟悉起來,當需要用到的時候,就能夠多一個解決方法的選項了!

結語

到這裡就是 ViewModifier 的基本實作

如果有疑問、回饋,歡迎留言討論

那今天的 SwiftUI 的大大小小就到這邊,以上,明天見!

環境

  • Xcode 15 beta 8

本篇使用到的 UI 元件和 modifiers 基本上沒有受到版本更新影響因此 Xcode 14 等環境下使用也是沒問題的。

參考


上一篇
Day 5 - SwiftUI 和 Optional 屬性的綁定
下一篇
Day 7 - 在 SwiftUI 如何實作多欄位 List - LazyVGrid 與 GridItem
系列文
SwiftUI 的大大小小30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言