独自のビューを定義してコードの見通しをよくする

この記事は下記の記事の発展形です。

スライダを利用する

あらかじめ決められた区間の数値を連続的に変化しつつ決定するにはスライダを使うのが便利です。単純な使い方と、同じようなスライダの機能をまとめる方法を紹介します。

上記の記事では、スライダ機能やテキスト機能を独自ビューで定義しただけですが、本記事では

「レクタングル Rectangle とテキスト Text 」
「スライダ Sliderとテキスト Text 」

としてまとめたビューをユーザ定義して、さらにコードの見通しをよくしてみます。

独自のビューは MyRectangleAndText と MyTextAndSlider という名前で定義します。

60行目、MyRectangleAndText は、Rectangle と Text を包含しています。
107行目、MyTextAndSlider は、Text と Slider を包含しています。

24 〜 57行目の var body: some View{} が極めて簡潔に記述できていることに注目してください。

MyRectangleAndText や MyTextAndSlider のコードの中でコメントしていますが、VStack を HStack や ZStack に書き換えるとそれに応じて画面の見た目が変更されることをぜひ確認してみてください。

MyRectangleAndText の中身の配置は ZStack にするとかっこいいのですが Text の色がデフォルトの Color.black なので、Text は Rectangle の塗りつぶし色の反対色にしないとまずいですね。

import SwiftUI

struct SLIDER {
    static let MIN:  Double =   0.0
    static let MAX:  Double = 255.0
    static let STEP: Double =   1.0
}

struct ContentView: View {

    @State var FlagNowEditingR = false
    @State var FlagNowEditingG = false
    @State var FlagNowEditingB = false
    @State var FlagNowEditingA = false

    @State var SliderR: Double =  32.0 * 1
    @State var SliderG: Double =  32.0 * 3
    @State var SliderB: Double =  32.0 * 5
    @State var SliderA: Double =  32.0 * 7

    let RECT_W = 240.0
    let RECT_H = 160.0

    var body: some View {

        Spacer()

        VStack {

            MyRectangleAndText(
                r_0_to_255: SliderR,
                g_0_to_255: SliderG,
                b_0_to_255: SliderB,
                a_0_to_255: SliderA,
                rectangle_w: RECT_W,
                rectangle_h: RECT_H
            )

        }

        Spacer()

        VStack {

            MyTextAndSlider( value: $SliderR, flag_now_editing: $FlagNowEditingR, color_name: "R" )
            MyTextAndSlider( value: $SliderG, flag_now_editing: $FlagNowEditingG, color_name: "G" )
            MyTextAndSlider( value: $SliderB, flag_now_editing: $FlagNowEditingB, color_name: "B" )
            MyTextAndSlider( value: $SliderA, flag_now_editing: $FlagNowEditingA, color_name: "A" )

        }
        .padding( 30.0 )

        Spacer()

    }

}

// 独自のレクタングルとテキスト.
struct MyRectangleAndText: View {

    var r_0_to_255: Double
    var g_0_to_255: Double
    var b_0_to_255: Double
    var a_0_to_255: Double

    var rectangle_w: Double
    var rectangle_h: Double

    var body: some View {

        // ZStack や HStasck にして効き目を確認すること.
        VStack{

            // 色成分は 0.0 〜 1.0 で指定する.
            let r_0_to_1 = Double( r_0_to_255 )/Double( 255.0 )
            let g_0_to_1 = Double( g_0_to_255 )/Double( 255.0 )
            let b_0_to_1 = Double( b_0_to_255 )/Double( 255.0 )
            let a_0_to_1 = Double( a_0_to_255 )/Double( 255.0 )
            let the_color = Color(
                                red:     r_0_to_1,
                                green:   g_0_to_1,
                                blue:    b_0_to_1,
                                opacity: a_0_to_1
                                )

            // 指定した色で塗りつぶした矩形を表示する.
            Rectangle()
                .stroke( .black, lineWidth: 2.0 )
                .background( the_color )
                .frame(width: rectangle_w, height: rectangle_h )

            // 0 〜 255 で表示する.
            let r = Int( r_0_to_255.rounded() )
            let g = Int( g_0_to_255.rounded() )
            let b = Int( b_0_to_255.rounded() )
            let a = Int( a_0_to_255.rounded() )
            Text( String( format: "RGBA( %d, %d, %d, %d )", r, g, b, a ) )

        }

    }

}

// 独自のテキストとスライダをワンセット.
struct MyTextAndSlider: View {

    @Binding var value: Double
    @Binding var flag_now_editing: Bool
    var color_name: String

    var body: some View {

        // HStack や ZStasck にして効き目を確認すること.
        VStack{

            Text( String( format: "%@ is %.1f", color_name, value ))
                .foregroundColor( flag_now_editing ? .red : .black )

            Slider(
                value: $value,
                in: SLIDER.MIN...SLIDER.MAX,
                step: SLIDER.STEP,
                onEditingChanged: {
                        editing in
                        flag_now_editing = editing
                    }
                )

        }

    }

}

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