LoginSignup
1
1
Qiita×Findy記事投稿キャンペーン 「自分のエンジニアとしてのキャリアを振り返ろう!」

【SwiftUI】Button長押しを検知してButton自身の表示を切り替える

Posted at

作ったもの

長押ししたときにボタンの表示を切り替えたいみたいなことがあった時のメモ
今回は以下のようなものを作る手順を紹介します

画面収録-2024-03-13-22.03.21.gif

通常時は😌&背景が緑、
長押し中は🤢&背景が赤になるようなボタンです

やり方

下記みたいな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)
            }
        }
    }
}

見え方はこんな感じです

画面収録-2024-03-13-22.02.38.gif

長押し中の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))
    }
}
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1