😎

Genericを利用してSwiftUIカスタムViewを活用しましょう

2022/02/09に公開

上のアプリ画面に画像が4つあリます。
画像①のViewはこちらです。

Image("画像名")
    .resizable()
    .frame(width: 60, height: 60)
    .padding()
    .background(.ultraThinMaterial)
    .clipShape(Circle())

Material型の.ultraThinMaterialを使って背景に薄い白にしました

画像②〜④のViewはこちらです

Image("画像名2")
    .resizable()
    .frame(width: 60, height: 60)
    .padding()
    .background(.blue) //実際それぞれのカスタムカラーを使いましたが、一応デフォルトカラーで説明します
    .clipShape(Circle())

.backgroundの部分にColorを入れました

一つのCustom Viewを統合するために

画像①〜④のViewの違う部分をあげると

  • Image()に入れる画像名
  • .background()に入れるやつ

特に.background()の部分はやっかいです。
.blueからColor型で、.ultraThinMaterialMaterial型で、違う型なので容易く同じStructに入れることができません。

その問題を解決するために、Genericの登場です

Generic ってなに

Genericは、型をそんなに細かく指定しないときに使う、型指定を曖昧化するテクニックです

まずはカスタムViewとしてHandView()を作りましょう

struct HandView: View {
    var name: String
    var color: Color //Material ????
    
    var body: some View {
        Image(name)
            .resizable()
            .frame(width: 60, height: 60)
            .padding()
            .background(color)
            .clipShape(Circle())
    }
}

var colorの型指定に困りました。片一方を指定してしまうと、もう一方のViewには適用できなくなります。

そこで、Genericを入れて、colorの型を曖昧化しましょう

+ struct HandView<T>: View {
     var name: String
+    var color: T
    
     var body: some View {
         Image(name)
             .resizable()
             .frame(width: 60, height: 60)
             .padding()
             .background(color)
             .clipShape(Circle())
     }
 }

TはTypeの意味です。
そして、実際に入れたいColorMaterialも、ShapeStyleというプロトコルに適合されましたので

+ struct HandView<T: ShapeStyle>: View {
     var name: String
    var color: T
    
     var body: some View {
         Image(name)
             .resizable()
             .frame(width: 60, height: 60)
             .padding()
             .background(color)
             .clipShape(Circle())
     }
 }

Tは、「Swift中の全ての型の中に、ShapeStyleに適合されるやつ」を代表しました

ちなみに、SwiftUIでは以下14の型を代表しました

  • AngularGradient
  • AnyShapeStyle
  • BackgroundStyle
  • Color
  • EllipticalGradient
  • ForegroundStyle
  • HierarchicalShapeStyle
  • ImagePaint
  • LinearGradient
  • Material
  • RadialGradient
  • SelectionShapeStyle
  • SeparatorShapeStyle
  • TintShapeStyle

最後に、HandViewを使って入れ替えましょう
画像①はこうなります

HandView(name: "画像名", color: .ultraThinMaterial)

画像②〜④はこうなります

HandView(name: "画像名2", color: .blue)

Discussion