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

上のアプリ画面に画像が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型で、.ultraThinMaterialはMaterial型で、違う型なので容易く同じ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の意味です。
そして、実際に入れたいColorもMaterialも、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の型を代表しました
AngularGradientAnyShapeStyleBackgroundStyleColorEllipticalGradientForegroundStyleHierarchicalShapeStyleImagePaintLinearGradientMaterialRadialGradientSelectionShapeStyleSeparatorShapeStyleTintShapeStyle
最後に、HandViewを使って入れ替えましょう
画像①はこうなります
HandView(name: "画像名", color: .ultraThinMaterial)
画像②〜④はこうなります
HandView(name: "画像名2", color: .blue)
Discussion