【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))

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

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


【SwiftUI】TextField の角を丸くして背景色を付けるもっとも簡単な方法は

これ簡単に作る方法ありませんかね。

角の丸い背景に色を付けた TextField。

なんか簡単にできないんですが、

いい方法ありませんか。

 

🧑‍💻 やってみる

「角を丸く」

「背景色を黄色に」

が同時にできません。


TextField("Search", text: $text)
  .frame(width: 200)
  .background(.yellow)

TextField("Search", text: $text)
  .frame(width: 200)
  .textFieldStyle(.roundedBorder)
  .background(.yellow) // NG
  .backgroundStyle(.yellow) // NG
  .tint(.yellow) // NG

👉 roundedBorder | Apple Developer Documentation hatena-bookmark

 

🧑‍💻 Chain Modifiers

一度、スタイルを plain にして、

padding を付けて、

背景に黄色い角丸四角を置きます。


// chain view modifiers
TextField("Search", text: $text)
  .textFieldStyle(.plain)
  .padding(6)
  .background(.yellow, in: .rect(cornerRadius: 6))
  .frame(width: 200)

しかし、数行続くと View 全体の見通しが悪くなるのがいやだ。

 

🧑‍💻 Create TextFieldStyle

TextField 専用のスタイルを作ってそれを適用します。


struct RoundedBordertFieldStyle: TextFieldStyle {
  var cornerRadius: CGFloat
  var color: Color

  func _body(configuration: TextField<Self._Label>) -> some View {
    configuration
      .textFieldStyle(.plain) // macOS
      .padding(cornerRadius)
      .background(color, in: .rect(cornerRadius: cornerRadius))
  }
}

extension TextFieldStyle where Self == RoundedBordertFieldStyle {
  static var roundedBorderYellow: Self {
    Self(cornerRadius: 6, color: .yellow)
  }
}


TextField("Search", text: $text)
  .textFieldStyle(RoundedBordertFieldStyle(cornerRadius: 6, color: .yellow)) // OK
  //.textFieldStyle(.roundedBorderYellow) // OK
  .frame(width: 200)

しかし、いちいちここまで書くのがいやだ。

_ (アンダースコア) もなんかいや。

👉 TextFieldStyle Protocol "makeBody" method hidden | Apple Developer Forums hatena-bookmark

 

🧑‍💻 Create View extension

ViewModifier を作ろうかと思ったが、

View の extension まででいいですよね。


extension View {
  func roundedBorder(cornerRadius: CGFloat, color: Color) -> some View {
    self
      .textFieldStyle(.plain)
      .padding(cornerRadius)
      .background(color, in: .rect(cornerRadius: cornerRadius))
  }
}


// create view extension (or view modifier)
TextField("Search", text: $text)
  .roundedBorder(cornerRadius: 6, color: .yellow)
  .frame(width: 200)

これぐらいがいいのかな。

 

🧑‍💻 Create Child View

新しく View を作って、それに押し込んじゃいます。


struct RoundedBorderTextField: View {
  var label: String
  @Binding var text: String
  var cornerRadius: CGFloat
  var color: Color

  var body: some View {
    TextField(label, text: $text)
      .textFieldStyle(.plain)
      .padding(cornerRadius)
      .background(color, in: .rect(cornerRadius: cornerRadius))
  }
}


// create child view
RoundedBorderTextField(label: "Search", text: $text, cornerRadius: 6, color: .yellow)
  .frame(width: 200)

最初からこれで良かったのでは。

 

🧑‍💻 まとめ

どれが一番いいんすかね。

macOS に切り替えなが思ったのは、

実際、TextField って、

「フォーカス」とかも

取り扱ってますよね。

それを考えると、

「@State を考慮してるやつ」

のがいいのかもしれません。

👉 【SwiftUI】市松模様を背景にする - Checkered Pattern Background 🏁 hatena-bookmark
👉 【SwiftUI】枠線付き角丸ボタンを簡単に作りたい hatena-bookmark