2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

SwiftUIでメソッドチェーンによるイベントハンドリングを行う

Last updated at Posted at 2023-02-12

のっけから宣伝になりますが、個人的にアプリをリリースしております。

渾沌より

Apple Musicの1億曲のライブラリー全てからランダムで音楽を再生するというアプリです。

UIはSwiftUIで実装しており、基本的な音楽プレイヤーの機能は一通り備えています。

このうちシークバーの部分は自前で実装しています。

IMG_0435.jpg

Slider | Apple Developer Documentation

SwiftUIには標準でスライダーバーが用意されていますが、デザインのカスタマイズが今ひとつ不自由だったので自前の実装にしました。


シークバーは当初以下のように実装していました。

struct SeekBar<V>: View where V: BinaryFloatingPoint, V.Stride: BinaryFloatingPoint {
    // 〜中略〜

    /// 初期化
    /// - Parameters:
    ///   - value: 値
    ///   - bounds: 範囲
    ///   - onEditingChanged: ドラッグ中のイベント
    init(value: Binding<V>, in bounds: Binding<ClosedRange<V>>, onEditingChanged: ((Bool) -> Void)?) {

    // 〜中略〜

    /// ドラッグのハンドラ
     private var drag: some Gesture {
         DragGesture()
             .onChanged {
                onEditingChanged?(dragHandler($0))
             }
             .onEnded {
                onEditingChanged?(false)
             }
     }

使う際は以下のようになります。

SeekBar(value: $playbackTime, in: $playbackRange) {
    // ドラッグ中のイベント
}

これはSwiftUI標準のスライダーバーに合わせたものです。

init(value: in:onEditingChanged:) | Apple Developer Documentation

スライダーをいじっている時のイベントハンドリングはクロージャ(onEditingChanged:)で行うようになっています。

ただ、ふと、DragGesture().onChangedのように、メソッドチェーンでのイベントハンドリングを実装したことがない、というのが気になりました。

公式がクロージャだし、今の実装で事足りるのですが、気になってしまったので試してみることにします。


真っ先に思いついたのはViewModifierですが、func body(content: Self.Content) -> Self.Bodyを実装する必要があり、クロージャを格納すれば事足りる今回の用途では少し大袈裟です。

またcontentがイミュータブルのため、プロパティーの変更ができません。

@Stateなども試しましたが、クロージャの状態を管理する必要は全くないので、少し違う気がします。

そんなふうに色々試し、色々調べた結果、結論を言ってしまえば、以下のページに答えがありました。

func myCustomTapHandler(onAction: @escaping () -> Void) -> Self {
    var view = self
    view.action = onAction
    return view
}

自身をミュータブルコピーして、プロパティーを変更し、コピーを返す。

・・・なるほど・・・。

自分の頭の中では、ビューそのものを操作しないといけないと思い込んでいたのですが、SwiftUIはstructベースで、ビューの再作成が繰り返される前提のフレームワークなので、元のビューを返す必要がないんですね。

@Bindingとかはどうなるんだろうと思い、調べてみましたが、

上記ページの「@State@Bindingの違い」の項を見る限り、問題なさそうです。


今回の結果を受けて作り直したシークバーが以下になります。

以前はかなり決めうちでデザインを設定していたのですが、イベントハンドラの件に合わせて、デザインもメソッドチェーンで変更できるようにしました。

複数のビューに共通の変更が必要でない限りは、ViewModifierを使う必要はないですね。

これで使いまわせるようになったと思います。

2
2
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
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?