システム開発<基本編>SwiftUIで色選択アプリ:ColorPicker

Swift

前回は、SwiftUIQRコードを生成するアプリケーションを開発する記事を紹介しました。

QRコードを生成する関数では、SwiftUIでは直接、CIImage を表示する事が出来ないので、

CIImage CGImage UIImageImage 変換が必要でした。

SwiftUIで最初に開発するアプリケーションにしては、難易度高かったかもしれませんね。

 

今回は少し難易度を落として、SwiftUI色(Color)を選択するアプリケーション

開発する記事を紹介しようと思います。

SwiftUIで色選択アプリ:ColorPicker

 

UI(ユーザーインタフェース)開発ブログ記事の作成デザインの作業を行っていると、

文字色付けしたり、画面ボタン色を変更することも多いかと思います。

を選ぶ時に、色の基本となる三原色輝度(明暗)を指定しますが、ツールサイト

利用して、コード数値を指定する方も多いと思います。

他の開発言語で、を選択する部品は有りますが、SwiftUIUIKitでも、ColorPicker という

を選択出来る部品が提供されていますので、こちらを利用してみましょう。

 

習得内容

今回、SwiftUI色(Color)を選択するアプリケーションを生成する事で、下記の内容を

習得する事が出来ます。

  • 三原色(RGB)三属性(HSB)
  • モーダル表示sheet()
  • カラーSwiftUI色(Color)の使い方
  • カラーピッカーSwiftUI色(Color)選択(ColorPicker)
  • フォーマット数値文字列(String)に変更する方法(format)
  • extensionColor拡張

 

動作環境

今回も、アプリが動作する環境は下記になります。

  • mac OS:Sequoia 15.6.1
  • iOS:26.0
  • Xcode:26.0.1
  • Swift:6.2.1

 

光の三原色と色の三属性

を利用する時は、三原色三要素が頻繁に利用されますので、簡単に紹介します。

 

光の三原色:RGB

三原色(RGB)は、下記で構成されています。

  1. 赤(red)0~255で表現します。
  2. 緑(green)0~255で表現します。
  3. 青(blue)0~255で表現します。

 

ちなみに、絵の具インクなどの色料に利用される三原色(CMY)は、

下記で構成されています。

  1. シアン(Cyan)
  2. マゼンタ(Magenta)
  3. イエロー(Yellow)

 

色の三属性:HSB

三属性(HSB)は、下記で構成されています。

  1. 色相(hue)などの色合いの事。0~360度角度で表現します。
  2. 彩度(saturation)鮮やかさの度合いの事。0~100%で表現します。
  3. 明度・輝度(brightness)明るさの度合いの事。0~100%で表現します。

 

三原色三要素の詳細については、下記を参照してみて下さい。

 

 

色(Color)選択アプリ

では、色(Color)選択アプリを作成していきます。

 

Xcode の上部タブメニューより、File → New → File from Template を選択します。

 

SwiftUI View を選択します。

 

名称は、ColorPickerView を入力してみます。

 

Create ボタンを押して、ColorPickerView.swift を作成します。

 

ContentView:メインメニュー(ランチャー)

前回の記事で作成したメインメニュー(ランチャー)ContentView を確認します。

 


import SwiftUI

struct ContentView: View {

    @State var isPopupView_1 = false

    var body: some View {

        VStack{
            Button {
                self.isPopupView_1.toggle()
            } label: {
                Text("QRCodeView")
                    .font(.title2)
            }
            .fullScreenCover(isPresented: $isPopupView_1, content: {
                QRCodeView(isPopupView_1: $isPopupView_1)
            })
            .padding()
        }
    }
}

#Preview {
    ContentView()
}

 

モーダル表示:sheet()

先程、作成した ColorPickerView を ContentView のメニューに追加します。

 


import SwiftUI

struct ContentView: View {

    @State var isPopupView_1 = false
    @State var isPopupView_2 = false

    var body: some View {
        
        VStack{
            Button {
                self.isPopupView_1.toggle()
            } label: {
                Text("QRCodeView")
                    .font(.title2)
            }
            .fullScreenCover(isPresented: $isPopupView_1, content: {
                QRCodeView(isPopupView_1: $isPopupView_1)
            })
            .padding()

            Button {
                self.isPopupView_2.toggle()
            } label: {
                Text("ColorPickerView")
                    .font(.title2)
            }
            .sheet(isPresented: $isPopupView_2, content: {
                ColorPickerView(isPopupView_2: $isPopupView_2)
            })
            .padding()
        }
    }
}

#Preview {
    ContentView()
}

 

QRCodeView を呼び出す際は、フルモーダル表示をさせる為、fullScreenCover()

指定しましたが、ColorPickerView を呼び出す際は、モーダル表示をさせる sheet()

指定してみます。

 

ColorPickerView:色選択アプリ

 

ソース例:ColorPickerView

次に、ContentView(親画面)から呼び出される ColorPickerView(子画面)

ソースを紹介します。

 


import SwiftUI

struct ColorPickerView: View {

    @Binding var isPopupView_2: Bool
    @State private var color: Color = .white

    var body: some View {
        ZStack {
            Color(red: 1.0, green: 1.0, blue: 0.05, opacity: 0.3)
                .edgesIgnoringSafeArea(.all)

            VStack {
                
                ColorPicker(selection: $color) {
                    Text("ColorPicker")
                        .font(.title2)
                        .foregroundColor(.black)
                }

                HStack {
                    Image(systemName: "cloud.sun.rain.fill")
                        .font(.system(size: 100))
                        .foregroundColor(color)
                        .scaledToFill()
                        .padding()

                    Image(systemName: "figure.outdoor.cycle.circle.fill")
                        .font(.system(size: 100))
                        .foregroundColor(color)
                        .scaledToFill()
                        .padding()
                }

                HStack(alignment: .top){

                    VStack(alignment: .leading){

                        Text("RGB")
                            .font(.title2)
                            .foregroundColor(.purple)
                            .padding()

                        Text("red : \(String(format: "%.1f",color.rgb.red * 255))")
                            .font(.system(size: 19))
                            .foregroundColor(.red)

                        Text("green : \(String(format: "%.1f",color.rgb.green * 255))")
                            .font(.system(size: 19))
                            .foregroundColor(.green)

                        Text("blue : \(String(format: "%.1f",color.rgb.blue * 255))")
                            .font(.system(size: 19))
                            .foregroundColor(.blue)

                        Text("HEX : #\(color.hex)")
                            .font(.system(size: 19))
                            .foregroundColor(.pink)

                    }
                    .padding()

                    VStack(alignment: .leading){

                        Text("HSB")
                            .font(.title2)
                            .foregroundColor(.blue)
                            .padding()

                        Text("hue : \(String(format: "%.1f", color.hsb.hue * 360))" + " 度")
                            .font(.system(size: 19))
                            .foregroundColor(.green)

                        Text("saturation : \(String(format: "%.1f", color.hsb.saturation * 100))" + " %")
                            .font(.system(size: 19))
                            .foregroundColor(.mint)

                        Text("brightness : \(String(format: "%.1f", color.hsb.brightness * 100))" + " %")
                            .font(.system(size: 19))
                            .foregroundColor(.orange)
                    }
                    .padding()
                }
                .padding()

                Button(action: {
                    withAnimation {
                        self.isPopupView_2.toggle()
                    }
                }, label: {
                    Text("Close")
                        .font(.title2)
                        .foregroundColor(.black)
                })
                .padding()
            }
        }
    }
}

#Preview {
    ColorPickerView(isPopupView_2: .constant(false))
}

 

ColorPicker

SwiftUIUIKitでも、ColorPicker というを選択出来る部品が提供されていますので、

こちらを利用してみましょう。

 


    var body: some View {
        ZStack {
            Color(red: 1.0, green: 1.0, blue: 0.05, opacity: 0.3)
                .edgesIgnoringSafeArea(.all)

            VStack {

                ColorPicker(selection: $color) {
                    Text("ColorPicker")
                        .font(.title2)
                        .foregroundColor(.black)
                }
  • ZStack {Color(red: 1.0, green: 1.0, blue: 0.05, opacity: 0.3)メインメニューから呼び出されて、覆い被さるので、メインメニュー区別する為、画面の土台となる部分にクリーム色を設定しています。
  • ColorPicker(selection: $color) {Text(“ColorPicker”)ColorPicker部品を配置しています。名称をTextにする事で、フォントのサイズの設定が出来ます。選んだは、$color に渡しています。

ColorPicker の設定に、Library pane(パーツ選択画面)を利用してみましょう。

ColorPicker を設定したい位置にカーソルを移動した後、shift + command + L

同時に押してみて下さい。

 

上記の画面のように、パーツ選択するボタン無い場合が有ります。

この場合は、Xcode の上部タブメニューより、Editor → Canvas確認してみて下さい。

 

Canvas に、チェックが入っていないと考えられます。

Editor → Canvas選択してみて下さい。

 

Canvas に、チェックが入った事を確認出来ました。

再度、ColorPicker を設定したい位置にカーソルを移動した後、shift + command + L

同時に押してみて下さい。

 

今度は、パーツ選択するボタン左端に有りますので、ボタンを押して、

ColorPicker選択して下さい。

Library pane(パーツ選択画面)を利用せず、直接、ColorPi… をタイピングして

設定する方が早い方は、そちらを選んで下さい、

 


                HStack {
                    Image(systemName: "cloud.sun.rain.fill")
                        .font(.system(size: 100))
                        .foregroundColor(color)
                        .scaledToFill()
                        .padding()

                    Image(systemName: "figure.outdoor.cycle.circle.fill")
                        .font(.system(size: 100))
                        .foregroundColor(color)
                        .scaledToFill()
                        .padding()
                }
  • Image(systemName: “cloud.sun.rain.fill“):システムシンボル(SF Symbols)より、晴れのち曇り時々雨アイコンを設定しています。
  • Image(systemName: “figure.outdoor.cycle.circle.fill“):システムシンボル(SF Symbols)より、自転車レースアイコンを設定しています。
  • .foregroundColor(color):アイコンが変わるように、設定しています。

 

こちらは、SF Symbols で、cloud.sun.rain.fill アイコンを表示した画面です。

 

こちらは、SF Symbols で、figure.outdoor.cycle.circle.fill アイコンを表示した画面です。

 

フォーマット(format)

 


                    VStack(alignment: .leading){
                        
                        Text("RGB")
                            .font(.title2)
                            .foregroundColor(.purple)
                            .padding()

                        Text("red : \(String(format: "%.1f",color.rgb.red * 255))")
                            .font(.system(size: 19))
                            .foregroundColor(.red)

                        Text("green : \(String(format: "%.1f",color.rgb.green * 255))")
                            .font(.system(size: 19))
                            .foregroundColor(.green)

                        Text("blue : \(String(format: "%.1f",color.rgb.blue * 255))")
                            .font(.system(size: 19))
                            .foregroundColor(.blue)

                        Text("HEX : #\(color.hex)")
                            .font(.system(size: 19))
                            .foregroundColor(.pink)

                    }
                    .padding()
  • Text(“red : \(String(format: “%.1f“,color.rgb.red * 255))”):ColorExtensions から、color.rgb.red を取得して、format: “%.1f” で、小数点第1位までの数値文字列に整形しています。
  • Text(“green : \(String(format: “%.1f“,color.rgb.green * 255))”):ColorExtensions から、color.rgb.greenを取得して、format: “%.1f“で、小数点第1位までの数値文字列に整形しています。
  • Text(“blue : \(String(format: “%.1f“,color.rgb.blue * 255))”):ColorExtensions から、color.rgb.blueを取得して、format: “%.1f“で、小数点第1位までの数値文字列に整形しています。
  • Text(“HEX : #\(color.hex)”):ColorExtensions から、color.hex を取得しています。

 


                    VStack(alignment: .leading){
                        
                        Text("HSB")
                            .font(.title2)
                            .foregroundColor(.blue)
                            .padding()

                        Text("hue : \(String(format: "%.1f", color.hsb.hue * 360))" + " 度")
                            .font(.system(size: 19))
                            .foregroundColor(.green)

                        Text("saturation : \(String(format: "%.1f", color.hsb.saturation * 100))" + " %")
                            .font(.system(size: 19))
                            .foregroundColor(.mint)

                        Text("brightness : \(String(format: "%.1f", color.hsb.brightness * 100))" + " %")
                            .font(.system(size: 19))
                            .foregroundColor(.orange)
                    }
                    .padding()
  • Text(“hue : \(String(format: “%.1f”, color.hsb.hue * 360))” + ” “):ColorExtensions から、color.hsb.hue を取得して、format: “%.1f” で、小数点第1位までの数値文字列に整形しています。
  • Text(“saturation : \(String(format: “%.1f“, color.hsb.saturation * 100))” + ” %“):ColorExtensions から、color.hsb.saturation を取得して、format: “%.1f” で、小数点第1位までの数値文字列に整形しています。
  • Text(“brightness : \(String(format: “%.1f“, color.hsb.brightness * 100))” + ” %“):ColorExtensions から、color.hsb.brightnessを取得して、format: “%.1f” で、小数点第1位までの数値文字列に整形しています。

 

ColorExtensions

Color で、RGB16進数(HEX)表現HSBの値を返すメソッドを拡張していきます。

 

extension:Colorの拡張

Color を拡張していきます。

Xcode の上部タブメニューより、File → New → File from Template を選択します。

 

Swift File を選択します。

 

名称は、ColorExtensions を入力してみます。

 

Create ボタンを押して、ColorExtensions.swift を作成します。

 

上記のように、白紙コードが生成されたと思います。

ここに、Color で、RGB16進数(HEX)表現や、HSBの値を返すメソッドソースを

追記していきます。

 

ソース例:ColorExtensions

ColorExtensions.swift のソースを紹介します。


import SwiftUI

struct HSB {
    var hue: CGFloat // 色相:0~360度
    var saturation: CGFloat // 彩度:0~100%
    var brightness: CGFloat // 輝度:0~100%
}

struct RGB {
    var red: CGFloat // Red
    var green: CGFloat // Green
    var blue: CGFloat // Blue
}

extension Color {
    var rgb: RGB {
        let uiColor = UIColor(self)
        var rgb_red: CGFloat = 0
        var rgb_green: CGFloat = 0
        var rgb_blue: CGFloat = 0
        var rgb_alpha: CGFloat = 0
        uiColor.getRed(&rgb_red, green: &rgb_green, blue: &rgb_blue, alpha: &rgb_alpha)

        return RGB(red: rgb_red, green: rgb_green, blue: rgb_blue)
    }

    var hex: String {
        let hex_red = Int(round(self.rgb.red * 255))
        let hex_green = Int(round(self.rgb.green * 255))
        let hex_blue = Int(round(self.rgb.blue * 255))

        return String(format: "%02X%02X%02X", hex_red, hex_green, hex_blue)
    }

    var hsb: HSB {
        let uiColor = UIColor(self)
        var hsb_hue: CGFloat = 0
        var hsb_saturation: CGFloat = 0
        var hsb_brightness: CGFloat = 0
        var hsb_alpha: CGFloat = 0
        uiColor.getHue(&hsb_hue, saturation: &hsb_saturation, brightness: &hsb_brightness, alpha: &hsb_alpha)

        return HSB(hue: hsb_hue, saturation: hsb_saturation, brightness: hsb_brightness)
    }
}

 

ソースを説明します。


struct HSB {
    var hue: CGFloat // 色相:0~360度
    var saturation: CGFloat // 彩度:0~100%
    var brightness: CGFloat // 輝度:0~100%
}

struct RGB {
    var red: CGFloat // Red
    var green: CGFloat // Green
    var blue: CGFloat // Blue
}
  • struct HSB {:HSBの構造体を宣言しています。変数には、CGFloat:浮動小数点を設定しています。
  • struct RGB {:RGBの構造体を宣言しています。変数には、CGFloat:浮動小数点を設定しています。

 


extension Color {
    var rgb: RGB {
        let uiColor = UIColor(self)
        var rgb_red: CGFloat = 0
        var rgb_green: CGFloat = 0
        var rgb_blue: CGFloat = 0
        var rgb_alpha: CGFloat = 0
        uiColor.getRed(&rgb_red, green: &rgb_green, blue: &rgb_blue, alpha: &rgb_alpha)

        return RGB(red: rgb_red, green: rgb_green, blue: rgb_blue)
    }
  • extension Color {var rgb: RGB {Color拡張を宣言しています。
  • let uiColor = UIColor(self)UIColor(self) を定数に代入しsています。
  • var rgb_red: CGFloat = 0:変数の rgb_red に、初期値:0を代入しています。
  • var rgb_green: CGFloat = 0:変数の rgb_green に、初期値:0を代入しています。
  • var rgb_blue: CGFloat = 0:変数の rgb_blue に、初期値:0を代入しています。
  • var rgb_alpha: CGFloat = 0:変数の rgb_alpha に、初期値:0を代入しています。
  • uiColor.getRed(…)uiColor.getRed() で、RGBを取得しています。
  • return RGB(…):取得したを、呼び出し元返却しています。

 


    var hex: String {
        let hex_red = Int(round(self.rgb.red * 255))
        let hex_green = Int(round(self.rgb.green * 255))
        let hex_blue = Int(round(self.rgb.blue * 255))

        return String(format: "%02X%02X%02X", hex_red, hex_green, hex_blue)
    }
  • let hex_red = Int(round(self.rgb.red * 255)):定数 hex_red に、self.rgb.red で取得した値に255倍した整数(四捨五入)を代入しています。
  • let hex_green = Int(round(self.rgb.green * 255)):定数 hex_green に、self.rgb.green で取得した値に255倍した整数(四捨五入)を代入しています。
  • let hex_blue = Int(round(self.rgb.blue * 255)):定数 hex_blue に、self.rgb.blue で取得した値に255倍した整数(四捨五入)を代入しています。
  • return String(format: “%02X%02X%02X“, hex_red, hex_green, hex_blue):hex_red, hex_green, hex_blue の並びで、8桁の16進数(英数大文字)に整形して、呼び出し元返却しています。

 

var hsb: HSB {:は、var rgb: RGB { に類似しているので、説明は省略します。

 

ColorExtensions については、下記を参考にしています。

 

 

 

アプリ実行:シミュレータの起動

では、実際にアプリを実行してみます。

Xcode の上部タブメニューより、Product →  Run を選択します。

 

エラーが無ければ、iPhoneシミュレータが起動します。

 

ContentView(メインメニュー)に追加した、ColorPickerViewボタンが表示されている事が

確認出来ました。

 

ColorPickerView:起動画面

 

では、ColorPickerViewボタン押してみます(タップします)

 

ContentView(メインメニュー)の上に、ColorPickerView(色選択アプリ)

重なって、表示された事が確認出来たと思います。

 

モーダル表示:sheet()

 

ContentView(メインメニュー)から、ColorPickerView(色選択アプリ)

呼び出しましたが、画面の上部(赤枠)ContentView(メインメニュー)

一部が見えている事が分かると思います。

QRCodeView(QRコード生成アプリ)フルモーダル表示とは異なりますね。

 


struct ColorPickerView: View {

    @Binding var isPopupView_2: Bool
    @State private var color: Color = .white

    var body: some View {
        ZStack {
            Color(red: 1.0, green: 1.0, blue: 0.05, opacity: 0.3)
                .edgesIgnoringSafeArea(.all)

            VStack {
                
                ColorPicker(selection: $color) {
                    Text("ColorPicker")
                        .font(.title2)
                        .foregroundColor(.black)
                }

 

上記のソースで、@State private var color: Color = .white color の初期値に

設定していましたので、ColorPicker 数値が反映されている状態が分かります。

<RGB>

red:255.0 green:255.0 blue:255.0 HEX:#FFFFFF

<HSB>

hue:0.0度 saturation:0.0% brightness:100.0%

 

ColorPicker:グリッド機能

ColorPickerView(色選択アプリ)の左上に、ColorPicker の文字が見えると思います。

ColorPicker の文字の右端に、白〇印が見えますが、こちらを押す(タップする)と、

ColorPicker が開きます。

では、グリッド機能で、別の色を選択してみます。(ColorPicker 左側のタブ)

 

こちらは、紫色を選択した例です。

ColorPicker の右上の×印押してColorPickerView(色選択アプリ)

戻ってみます。

ColorPicker 〇印アイコン数値が、紫色に変更された事が確認出来ます。

<RGB>

red:190.0 green:56.0 blue:243.0 HEX:#BE38F3

<HSB>

hue:283.0度 saturation:77.0% brightness:95.3%

 

ColorPicker:スペクトラム機能

今度は、スペクトラム機能を利用してみます。(ColorPicker 中央のタブ)

 

 

次に、スペクトラム機能で、別の色を選択してみます。

こちらは、黄緑色を選択した例です。

ColorPicker の右上の×印押してColorPickerView(色選択アプリ)

戻ってみます。

 

ColorPicker 〇印アイコン数値が、黄緑色に変更された事が確認出来ます。

<RGB>

red:0.0 green:254.3 blue:1.5 HEX:#00FE02

<HSB>

hue:120.4度 saturation:100.0% brightness:99.7%

 

ColorPicker:スライダ機能

最後に、スライダ機能を利用してみます。(ColorPicker 右側のタブ)

 

 

スライダ機能で、別の色を調整してみます。

こちらは、薄紅色を選択した例です。

ColorPicker の右上の×印押してColorPickerView(色選択アプリ)

戻ってみます。

 

ColorPicker 〇印アイコン数値が、薄紅色に変更された事が確認出来ます。

<RGB>

red:235.1 green:26.8 blue:71.3 HEX:#EB1B47

<HSB>

hue:347.2度 saturation:88.6% brightness:92.2%

 

 

まとめ

今回は、SwiftUIで、ColorPicker を利用して、色(カラー)を選択するアプリケーション

開発する記事を紹介しました。

 

次回は、SwiftUIで、Slider を利用して、色(カラー)を選択するアプリケーションを開発する

記事を紹介しようと思います。

 

コメント

タイトルとURLをコピーしました