作ったもの
長押ししたときにボタンの表示を切り替えたいみたいなことがあった時のメモ
今回は以下のようなものを作る手順を紹介します
通常時は😌&背景が緑、
長押し中は🤢&背景が赤になるようなボタンです
やり方
下記みたいなButtonがあったとします
struct SampleButton: View {
@State var isPressed: Bool = false
let buttonSize: CGFloat = 76
var body: some View {
Button {
// 処理
} label: {
ZStack {
Circle()
.frame(width: buttonSize)
.foregroundColor(isPressed ? .red : .green)
.opacity(0.3)
Circle()
.frame(width: buttonSize - 5)
.foregroundColor(.Background)
Circle()
.frame(width: buttonSize - 10)
.foregroundColor(isPressed ? .red : .green)
.opacity(0.3)
Text(isPressed ? "🤢" : "😌")
.font(.system(size: 26, weight: .light))
.foregroundColor(.white)
}
}
}
}
見え方はこんな感じです
長押し中のopacityがボタン全体に重なる上に、Stateを更新する処理を書いていないので当然ですが見た目も変更できていないです。
isPressedはButtonStyleで取得できますが、SampleButton側でも検知できるようにします。
ButtonStyleを作る
前述の通りSampleButtonのisPressedをButtonStyleに渡して長押しを検知できるようにします。
configuration.label
はViewプロトコルに準拠した構造体なので、configuration.isPressed
の変化を検知し、バインドした値を変更するように実装します。
private struct SampleButtonStyle: ButtonStyle {
@Binding var isPressed: Bool
func makeBody(configuration: Self.Configuration) -> some View {
configuration.label.onChange(of: configuration.isPressed) { _isPressed in
isPressed = _isPressed
}
}
}
SampleButton側の変更
SampleButtonに先ほどのSampleButtonStyleを適用します。
完成したViewコンポーネントの全体は以下のようになります。
これで、最初に紹介したようにisPressedで長押しを検知して表示を切り替えることが可能になります。
struct SampleButton: View {
@State var isPressed: Bool = false
let buttonSize: CGFloat = 76
var body: some View {
Button {
// 処理
} label: {
ZStack {
Circle()
.frame(width: buttonSize)
.foregroundColor(isPressed ? .red : .green)
.opacity(0.3)
Circle()
.frame(width: buttonSize - 5)
.foregroundColor(.Background)
Circle()
.frame(width: buttonSize - 10)
.foregroundColor(isPressed ? .red : .green)
.opacity(0.3)
Text(isPressed ? "🤢" : "😌")
.font(.system(size: 26, weight: .light))
.foregroundColor(.white)
}
}
.buttonStyle(SampleButtonStyle(isPressed: $isPressed))
}
}