🖥️練習用 SwiftUI 畫 Mac mini:底部

講解用 SwiftUI 畫 Mac mini M4 底部的實作重點:金屬機殼與塑膠殼的同心圓角、畫出一整圈散熱孔的技巧。

接續前篇,繼續畫 Mac mini M4 的底部。

官網上的圖片是這樣:


這一面最大的挑戰,是要怎麼畫出一整圈的散熱孔,以及塑膠殼與金屬機殼的同心圓角。如果你知道方法的話,其實很簡單。但我強烈建議你不要看答案,先自己想想看

這是我的實作與 Preview 截圖:

MacminiM4BottomView 與 Preview
MacminiM4BottomView 與 Preview

練習用的程式碼如下,完整版放在文章最後:

import SwiftUI

struct MacminiM4BottomView: View {
  private let bodyWidth = 512.0

  var body: some View {
    chassis
      .aspectRatio(1, contentMode: .fit)
      .frame(width: bodyWidth)
      .foregroundStyle(Color(white: 0.7))
      .overlay {
        plasticCover
      }
      .overlay {
        vents
          .frame(height: bodyWidth * 0.8)
      }
      .overlay {
        macMiniLogo
      }
      .overlay(alignment: .topTrailing) {
        powerButton
      }
  }

  private var chassis: RoundedRectangle {
    RoundedRectangle(cornerRadius: bodyWidth / 4)
  }

  @ViewBuilder
  private var plasticCover: some View {
    ContainerRelativeShape()
      .aspectRatio(1, contentMode: .fit)
      .foregroundStyle(Color(white: 0.2))
      .padding(bodyWidth / 50)
      .containerShape(chassis)
  }

  @ViewBuilder
  private var vents: some View {
    ZStack {
      // 試著自行實作
    }
  }

  @ViewBuilder
  private var macMiniLogo: some View {
    Text("Mac mini")
      .font(.system(size: bodyWidth / 12))
      .fontWeight(.medium)
      .foregroundStyle(Color(white: 0.1))
  }

  @ViewBuilder
  private var powerButton: some View {
    Button(
      action: {},
      label: {
        Circle()
          .foregroundStyle(Color(white: 0.1))
          .frame(width: bodyWidth / 12)
          .overlay {
            Image(systemName: "power")
              .foregroundStyle(Color.white)
          }
          .padding(bodyWidth / 9)
      }
    )
  }
}

#Preview {
  MacminiM4BottomView()
}

macMiniLogopowerButton 相對簡單,我就不做說明了。

塑膠殼與金屬機殼的同心圓角

金屬外殼 chassis 使用 RoundedRectangle。而它裡面一圈的則是黑色的塑膠殼。這部分的小挑戰是,怎樣畫出同心(concentric)的圓角?

我們可以使用 ContainerRelativeShape,並且用 .containerShape 指定它的 container 形狀就等於是 chassis 這個 RoundedRectangle。這樣子我們就不用自行計算內圈的 cornerRadius 要減多少,直接達到同心的效果。

怎麼畫一圈散熱孔