ZStackでいろいろな図形を描画する
図形の描画は色々ありますが、多くの場合、Rectangle、RoundedRectangle、Ellipse、Circle、Pathによる線描画、で用が済みます。Path を除くほとんどの図形は rotationEffect というモディファイアがあり、回転角度を指定できます。単位は弧度ラジアンと角度デグリーで指定できます。
スライダを使って、回転角度を変化させた様子が下記の図です。-1.57 ラジアンは -90 度(-90デグリー)、-0.78 ラジアンは -45 度、+0.78 ラジアンは +45 度、+1.57 ラジアンは +90 度を意味します。
コードの解説をします。
13行目、ZStack のサイズを取得したいので GeometryReader で囲みます。
27〜29行目、ZStack の領域の幅の半分、高さの半分のサイズで図形を描画します。
57〜59行目、Circle に .frame で違った幅と高さを指定しても、どちらか小さいほうのサイズが直径に割り当てられます。
import SwiftUI
struct ContentView: View {
let COLOR_BG = Color( red: 0.0, green: 0.0, blue: 0.25, opacity: 1.0 )
let LINE_WIDTH = 2.0
let LINE_WIDTH_THIN = 1.0
@State var RotValue = 0.0
var body: some View {
GeometryReader {
geom in
ZStack{
let geom_w = geom.size.width
let geom_h = geom.size.height
// セーフエリアを除いた背景を塗りつぶす.
Rectangle()
.frame( width: geom_w, height: geom_h )
.foregroundColor( COLOR_BG )
let RATE = 0.5
let rect_w = geom_w * RATE
let rect_h = geom_h * RATE
// 矩形を描画する.
Rectangle()
.stroke( .yellow, lineWidth: LINE_WIDTH )
.frame( width: rect_w, height: rect_h )
// 楕円を描画する.
Ellipse()
.stroke( .green, lineWidth: LINE_WIDTH )
.frame( width: rect_w, height: rect_h )
.rotationEffect( .degrees( 0.0 ) )
// 角丸矩形を描画する(回転も含む).
RoundedRectangle( cornerRadius: 40.0 )
.stroke( .cyan, lineWidth: LINE_WIDTH )
.frame( width: rect_w, height: rect_h )
.rotationEffect( .radians( RotValue ) ) // radian で回転させる場合.
//.rotationEffect( .degrees( RotValue ) ) // degee で回転させる場合.
// 楕円を描画する(回転も含む).
Ellipse()
.stroke( .orange, lineWidth: LINE_WIDTH )
.frame( width: rect_w, height: rect_h )
.rotationEffect( .radians( RotValue ) ) // radian で回転させる場合.
//.rotationEffect( .degrees( RotValue ) ) // degee で回転させる場合.
// 真円を描画する.
Circle()
.stroke( .pink, lineWidth: LINE_WIDTH )
.frame( width: rect_w, height: rect_h )
// めやすの描画中心の十字線を描画する.
Path {
path in
let center_x = rect_w * 0.5
let center_y = rect_h * 0.5
path.move( to: CGPoint( x: center_x, y: 0.0 ) )
path.addLine( to: CGPoint( x: center_x, y: rect_h ) )
path.move( to: CGPoint( x: 0.0, y: center_y ) )
path.addLine( to: CGPoint( x: rect_w, y: center_y ) )
}
.stroke( .brown, lineWidth: LINE_WIDTH_THIN )
.frame( width: rect_w, height: rect_h )
// 各種サイズ情報を表示するビュー.
MyTextShowZstacWHRateRectWH(
geometry_w: geom_w,
geometry_h: geom_h,
rate_wh: RATE,
rectangle_w: rect_w,
rectangle_h: rect_h
)
// 下部に配置されるスライダとその現在値をテキストで表示するビュー.
MyTextAndSliderAlignBottom( value: $RotValue )
}
}
}
}
struct MyTextShowZstacWHRateRectWH: View {
var geometry_w: Double
var geometry_h: Double
var rate_wh: Double
var rectangle_w: Double
var rectangle_h: Double
var body: some View {
VStack{
Text( String( format: "zstack: %.1f * %.1f", geometry_w, geometry_h ) )
.foregroundColor( .white )
Text( String( format: "Rate: %.2f", rate_wh ) )
.foregroundColor( .white )
Text( String( format: "rect: %.1f * %.1f", rectangle_w, rectangle_h ) )
.foregroundColor( .white )
}
}
}
struct MyTextAndSliderAlignBottom: View {
@Binding var value: Double
var body: some View {
// radian で管理する場合.
let ROT_MIN = -2.0 * Double.pi
let ROT_MAX = +2.0 * Double.pi
let ROT_TICKS = 0.01
// degree で管理する場合.
// let ROT_MIN = -360.0
// let ROT_MAX = +360.0
// let ROT_TICKS = 1.0
VStack
{
// radian と degree で表示の単位を変える.
let FMT = "%.2f rad"
// let FMT = "%.2f deg"
Text( String( format: FMT, value ) )
.foregroundColor( .white )
Slider(
value: $value,
in: ROT_MIN...ROT_MAX,
step: ROT_TICKS
)
}
.frame( maxWidth: .infinity, maxHeight: .infinity, alignment: .bottom )
.padding( 20.0 )
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}