SwiftUIでカラーピッカーを作る連載記事です。今回は前回までに作成したRGB各チャネルのスライダーで選択した値を元に色をプレビュー表示する処理を実装します。
また、現在値のフォーマットが小数点以下1桁になっているため、数値指定する場合の精度が低すぎます。文字列化のフォーマットも修正します。
現在値の文字列化フォーマット変更
ColorPickerChannelModel
クラスのfieldText
プロパティを修正します。次のように文字列化フォーマットを%.1f
から%g
に変更します。
/// 入力中のテキストのバインディング
var fieldText: Binding<String> {
Binding {
self.fieldTextStore ?? String(format: "%g", self.currentValue)
} set: {
self.fieldTextStore = $0
if let value = Double($0) {
self.changeCurrentValue(value)
}
}
}

色のプレビューの表示
選択された色をプレビュー表示する処理を実装します。
ColorPickerPreviewの実装
プレビューを表示するビューを実装します。プレビューはシンプルに次のような処理にします。
- 選択色で塗りつぶす
- 4pixel程度の枠を付ける
次のようなコードになります。
import SwiftUI
struct ColorPickerPreview: View {
@Binding var color: Color
var body: some View {
GeometryReader { geometry in
Path { path in
path.addRect(CGRect(x: 0, y: 0, width: geometry.size.width, height: geometry.size.height))
}
.fill(color)
Path { path in
path.addRect(CGRect(x: 0, y: 0, width: geometry.size.width, height: geometry.size.height))
}
.stroke(lineWidth: 4)
}
}
}
struct ColorPickerPreview_Previews: PreviewProvider {
static var previews: some View {
ColorPickerPreview(color: .constant(.blue))
}
}

ColorPickerへの追加
ColorPicker
にColorPickerPreview
を配置します。配置場所は3つのPickerGradationView
の下に縦横50pixel程度で配置します。
ColorPickerPreview.color
プロパティに渡すバインディングを作ります。redChannel.currentValue
, greenChannel.currentValue
, blueChannel.currentValue
からColor
を作って、Binding<Color>
で返すプロパティを追加します。
var color: Binding<Color> {
Binding {
Color(red: redChannel.currentValue,
green: greenChannel.currentValue,
blue: blueChannel.currentValue)
} set: { _ in
}
}
ColorPickerPreview
をビューに置きます。分かりやすいようにパッディングやラベルも一緒に置きます。
import SwiftUI
struct ColorPicker: View {
@StateObject var redChannel: ColorPickerChannelModel = ColorPickerChannelModel(channelName: "Red")
@StateObject var redGradation: ColorPickerGradationModel = .red
@StateObject var greenChannel: ColorPickerChannelModel = ColorPickerChannelModel(channelName: "Green")
@StateObject var greenGradation: ColorPickerGradationModel = .green
@StateObject var blueChannel: ColorPickerChannelModel = ColorPickerChannelModel(channelName: "Blue")
@StateObject var blueGradation: ColorPickerGradationModel = .blue
var color: Binding<Color> {
Binding {
Color(red: redChannel.currentValue,
green: greenChannel.currentValue,
blue: blueChannel.currentValue)
} set: { _ in
}
}
var body: some View {
VStack {
ColorPickerSubView(channel: redChannel, gradation: redGradation)
ColorPickerSubView(channel: greenChannel, gradation: greenGradation)
ColorPickerSubView(channel: blueChannel, gradation: blueGradation)
VStack {
Text("Preview")
ColorPickerPreview(color: color)
.frame(width: 100, height: 100)
}
.padding()
}
.padding()
}
}
struct ColorPicker_Previews: PreviewProvider {
static var previews: some View {
ColorPicker()
.previewInterfaceOrientation(.portrait)
}
}

コードのダウンロード
今回の記事で作成したコードのダウンロードはこちらです。