ZStackでループをつかって複数の図形を描画する
ZStack などの中で複数の同じ図形を描画したいときに思い浮かぶのが for ループを使う方法です。しかし for ループではコンパイルが通りません。
この場合は ForEach ループを使います。このような画面を表示するアプリを例として解説します。
3〜6行目、データ配列の要素になる構造体の型を定義しています。
83〜108行目、表示したい矩形のサイズと描画線の色を指定してデータを初期化しています。
52行目、ForEach のループで描画コードを回します。ここを for ループにするとコンパイルエラーになります。
ForEach の謎の引数 id: ですが、これはいったいなんでしょうか?引数 id: は、ForEach がどの要素が変更されたかを識別するのに使用されます。この場合は自分自身のビュー .self です。
ためしに52行目を ForEach ( 0 ..< Data.count ) のように id: を省略して書いてみると意味がわかると思います。コンパイルは通りますが、画面には何も描画されません。
import SwiftUI
struct SIZE_AND_COLOR{
var TheSize: CGSize
var TheColor: Color
}
struct ContentView: View {
// 描画したい矩形の個数を指定する.
let REQ_NUM_DATA = 8
@State var Data: [SIZE_AND_COLOR] = []
// 描画する矩形の線の太さ.
let STROKE_LINE_WIDTH = 4.0
// 描画する矩形の基準サイズ.
let UNIT_W = 20.0
let UNIT_H = 40.0
var body: some View {
GeometryReader {
geom in
ZStack {
// 背景を塗りつぶす.
Rectangle()
.foregroundColor( .gray )
// ZStack のサイズを取得する.
let geom_w = geom.size.width
let geom_h = geom.size.height
// ZStack の中心座標を取得する.
let center_x = geom_w * 0.5
let center_y = geom_h * 0.5
// めやすとなる中心十字線を描画する.
Path{
path in
path.move( to: CGPoint( x: center_x, y: 0 ) )
path.addLine( to: CGPoint( x: center_x, y: geom_h ))
path.move( to: CGPoint( x: 0, y: center_y ) )
path.addLine( to: CGPoint( x: geom_w, y: center_y ))
}
.stroke( .white, lineWidth: 1.0 )
// データの個数ぶんループする.
ForEach ( 0 ..< Data.count, id: \.self ) { n in
// 描画する線の色をデータから取り出す.
let stroke_color = Data[n].TheColor
Path{
path in
// 描画する矩形の幅と高さをデータから取り出す.
let w = Data[n].TheSize.width
let h = Data[n].TheSize.height
// 描画する矩形の左上隅座標を取得する.
let x = center_x - w * 0.5
let y = center_y - h * 0.5
// addRect に渡す引数を作成する.
let rect = CGRect( x: x, y: y, width: w, height: h )
// 矩形を描画する.
path.addRect( rect )
}
.stroke( stroke_color, lineWidth: STROKE_LINE_WIDTH )
}
}
}
.onAppear(){
// ZStack が出現するときに実行されるコード.
// いったん配列要素をクリアする.
Data.removeAll()
// 配列要素の要求作成個数ぶんループする.
for n in 0 ..< REQ_NUM_DATA {
// 矩形のサイズ.
let w = UNIT_W * Double( n + 1 )
let h = UNIT_H * Double( n + 1 )
let the_size = CGSize( width: w, height: h )
// 矩形の描画線の色.
let r = 0.0
let g = Double(n)/Double( REQ_NUM_DATA - 1 )
let b = 0.0
let the_color = Color( red: r, green: g, blue: b, opacity: 1.0 )
// 配列に要素を追加する.
let element = SIZE_AND_COLOR( TheSize: the_size, TheColor: the_color )
Data.append( element )
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}