【Swift】Color の RGB + Opacity の数値を求める

カラーピッカーの

スポイドで

色を確認してたけど、

なんか、あやしい。


数値化してスッキリしたい。

 

🎨 Color から赤、緑、青の値を読み取る


struct ContentView: View {
  @Environment(\.self) var environment
  @State private var color = Color.red
  @State private var resolvedColor: Color.Resolved?

  var body: some View {
    VStack {
      ColorPicker("Select your favorite color", selection: $color)

      if let resolvedColor {
        Text("Red: \(resolvedColor.red)")
        Text("Green: \(resolvedColor.green)")
        Text("Blue: \(resolvedColor.blue)")
        Text("Opacity: \(resolvedColor.opacity)")
      }
    }
    .padding()
    .onChange(of: color, initial: true, getColor)
  }

  func getColor() {
    resolvedColor = color.resolve(in: environment)
  }
}

👉 How to read the red, green, and blue values from a Color - a free SwiftUI by Example tutorial hatena-bookmark

ビルトインの ColorPicker で取得した色を数字化して表示していますね。

分かりやすい !

 

🎨 小数点以下3桁に丸める

ついでに、

小数点以下4桁目を丸めて3桁にして、

0で埋める。


String(format:"%.3f", (0.123456 * 1000).rounded() / 1000)
// 0.123

👉 【Swift】2024年5月版 四捨五入と小数点と0埋め hatena-bookmark

てか、String のみで四捨五入できる、とか!

👉 Rounding a double value to x number of decimal places in swift - Stack Overflow hatena-bookmark

 

🎨 まとめ

これらをまとめて整理しておきます。



Light / Dark 共、

数字が同じになりました。

なるほど、

Dynamic System Color というのは、

environment を見ながら色を変化させているのか !

変化させていたのだ !



【SwiftUI】Default background Color in built-in View Component

上は GroupBox を使って、

下は それに似せて Stack系のViewで書く。


GroupBox("Today's Menu 1") {
  VStack(alignment: .leading) {
    Text("🍛 curry and rice")
    Text("🥗 green salad")
  }
}
.frame(width: 300)

VStack {
  HStack {
    Text("Today's Menu 2")
      .bold()
    Spacer()
  }
  VStack(alignment: .leading) {
    Text("🍛 curry and rice")
    Text("🥗 green salad")
  }
}
.padding()
.frame(width: 300)
.background(
  .background, // *
  in: .rect(cornerRadius: 8)
)

背景色が違う !

 

🧑🏻‍💻 意図しない背景色

特に背景色を意識せずに画面を構成していくと、

微妙に色が違うことありません ?

そもそもデフォルトの背景色はどんな色なのですか。

もちろん、Color クラスに定義されてますよね?

簡単に呼び出せますよね ?

Light / Dark の変化に対応してますよね ?

 

🧑🏻‍💻 地道に調べる

Xcode のカラーピッカーで調べます。


Edit

 ↓

Format

 ↓

Show Colors

RGB で opacity 100% で


//       light               dark  
// 0.949 0.949 0.969 | 0.110 0.110 0.118

でした。

 

🧑🏻‍💻 既存の背景色 (Light/Dark 対応)

これ、SwiftUI.Color で定義されてませんよね。

UIColor の定義でそれらしきのものを見つけて、

数値を取ってみます。


//                           opacity 100%          light               dark
Color(.systemBackground)                  // 1.000 1.000 1.000 | 0.000 0.000 0.000
Color(.secondarySystemBackground)         // 0.949 0.949 0.969 | 0.110 0.110 0.118
Color(.tertiarySystemBackground)          // 1.000 1.000 1.000 | 0.173 0.173 0.180
Color(.systemGroupedBackground)           // 0.949 0.949 0.969 | 0.000 0.000 0.000
Color(.secondarySystemGroupedBackground)  // 1.000 1.000 1.000 | 0.110 0.110 0.118
Color(.tertiarySystemGroupedBackground)   // 0.949 0.949 0.969 | 0.173 0.173 0.180

どうやら、GroubBox デフォルト背景色は、


Color(.secondarySystemBackground)

と同じもののようです。

GroupBoxStyle に定義されているのでしょうが、

見つけられませんでした。

 

🧑🏻‍💻 まとめ

こういうの困りません?

なんだか単に「色」といってもかなり深そう。

👉 大解剖!UIColorファミリー by しもとり | トーク | iOSDC Japan 2020 - fortee.jp hatena-bookmark

iOS まわりの激しい変化の歴史を感じます。

👉 【SwiftUI】CardView のような GroupBox は本当に便利なのか hatena-bookmark


【SwiftUI】.contentTransition(.symbolEffect(.replace))



これよく見かけるのでやってみます。


.contentTransition(.symbolEffect(.replace))

まず、Button の Label のアイコンを、

ある値を見ながら切り替えます。

よくあるパターンなので想像はつくでしょう。


@State private var value = false


Button {
  value.toggle()
} label: {
  Label("Favorite", systemImage: value ? "heart.fill" : "heart")
}

次に .symbolVariant() を使います。

挙動は同じだと思われます。


Button {
  value.toggle()
} label: {
  Label("Favorite", systemImage: "heart")
    .symbolVariant(value ? .fill : .none)
}

ここで、

.contentTransition(.symbolEffect(.replace))

付けます。


Button {
  value.toggle()
} label: {
  Label("Favorite", systemImage: "heart")
    .symbolVariant(value ? .fill : .none)
    .contentTransition(.symbolEffect(.replace))
}

Apple 公式サンプルコードでは、

以下のようにさらに細かく調整されていました。


Button {
  value.toggle()
} label: {
  Label("Favorite", systemImage: "heart")
    .symbolVariant(value ? .fill : .none)
    .contentTransition(
      .symbolEffect(value ? .replace.upUp : .replace.downUp)
    )
}

以上4つを並べて確認します。

微妙にエフェクト具合が違うけど、

どれがいいとはいいづらい。

👉 【SwiftUI】市松模様を背景にする - Checkered Pattern Background 🏁 hatena-bookmark

 

🧑🏻‍💻 まとめ

タイトルどおりの


.contentTransition(.symbolEffect(.replace))

ぐらいがシンプルな記述のわりに見栄えが良いように思います。

みんなが良く使ってる意味が分かりました !