ZStackにおけるViewについて考察する(001,内側外側で背景色を変える)

Rectangle をタップしてその位置は、内側か外側かを判定して、背景色を変化させる方法を紹介します。

この記事は、下記に示す記事の続きです。所望のビューのタップジェスチャが、やや外側でも反応することに注意してください。

ZStackにおけるViewについて考察する(000,超単純コード)

ZStack を使って Rectangle を配置し、それにまつわる動作を考察していきます。

最背面に、Bool なフラグを判定して色を変化させる Rectangle を配置します。
その上に、タップ座標を取得できるRectangle を配置します。
そして、その上に変数を表示するための VStack で管理された Text を配置します。

ZStack の上に載せているので、それらはすべて画面の中心に配置されます。

下記のコードの11、12行目で、内側をタップしたときと、外側をタップしたときの色を決めています。

27行目が最背面にある Rectangle の色を決定しているところで、FlagInsideRect という Bool 値を評価して、三項演算子を使って自身の色を変化させています。また、Rectangle は .frame モディファイヤを指定しなければ画面いっぱいのサイズで配置されます。

Text の上をタップしても、座標に変化がないことに気づくと思います。これは Text の下にタップジェスチャに反応する Rectangle が配置されているからです。ビューを透過してタップジェスチャを効かせる方法は、また別の記事で考察しようと思います。

import SwiftUI

struct ContentView: View {

    let RECT_W: CGFloat = 320
    let RECT_H: CGFloat = 640

    let COLOR_RECT: Color = Color.blue
    let COLOR_TEXT: Color = Color.white

    let COLOR_INSIDE: Color = Color( red: 0x00, green: 0xff, blue: 0x00, opacity: 0xff )
    let COLOR_OUTSIDE: Color = Color( red: 0xff, green: 0x00, blue: 0x00, opacity: 0xff )

    @State var TapX: CGFloat = 0.0
    @State var TapY: CGFloat = 0.0
    @State var InsideRectTapX: CGFloat = 0.0
    @State var InsideRectTapY: CGFloat = 0.0

    @State var FlagInsideRect = true

    var body: some View {

        ZStack{

            // 最背面.
            Rectangle()
                .foregroundColor( FlagInsideRect ? COLOR_INSIDE : COLOR_OUTSIDE )

            // 中層面.
            Rectangle()
                .frame( width: RECT_W, height: RECT_H ) // サイズを指定する.
                .foregroundColor( COLOR_RECT ) // 色を指定する.
                .onTapGesture {
                    tap in

                    TapX = tap.x
                    TapY = tap.y

                    // いったんそのままタップ座標を代入する.
                    InsideRectTapX = TapX
                    InsideRectTapY = TapY

                    // いったんフラグを真にしておく.
                    FlagInsideRect = true

                    // Rectangleの内側か外側か判定して InsideRectTapXとY を調整する.
                    if ( InsideRectTapX < 0.0 ){
                        InsideRectTapX = 0.0;
                        FlagInsideRect = false
                    }

                    if ( InsideRectTapY < 0.0 ){
                        InsideRectTapY = 0.0
                        FlagInsideRect = false
                    }

                    if ( InsideRectTapX >= RECT_W ){
                        InsideRectTapX = RECT_W - 1
                        FlagInsideRect = false
                    }

                    if ( InsideRectTapY >= RECT_H ){
                        InsideRectTapY = RECT_H - 1
                        FlagInsideRect = false
                    }

                }

            // 最前面.
            VStack{

                Text( String( format: "TapXY( %.1f, %.1f )", TapX, TapY ))
                    .foregroundColor( COLOR_TEXT )
                Text( String( format: "InsideRectTapXY( %.1f, %.1f )", InsideRectTapX, InsideRectTapY ))
                    .foregroundColor( COLOR_TEXT )
                Text( String( format: "FlagInsideRect is %d", FlagInsideRect ))
                    .foregroundColor( COLOR_TEXT )

            }

        }

    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}