35
18

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でListの上にButtonを置く場合List自体にイベントを奪われないようにする

Last updated at Posted at 2021-04-10

はじめに結論

SwiftUIでListの上にButtonを置くと、タップイベントがListのほうで実行されてしまう。そのため、ButtonのスタイルをBorderlessButtonStylePlainButtonStyleにする必要がある。

(この記事はXcode 12.4でのSwiftUIでの話です)

本題

解決方法

ButtonにBorderlessButtonStylePlainButtonStyleのスタイルを設定する

//: A UIKit based Playground for presenting user interface
  
import UIKit
import SwiftUI
import PlaygroundSupport

struct ContentView: View {
    var body: some View {
        List {
            HStack {
                Text("Cell 1")

                Spacer()

                Button(action: {
                    print("B_1押したね")
                }, label: {
                    Text("Border")
                })
                .buttonStyle(BorderlessButtonStyle())

                Button(action: {
                    print("P_1押したね")
                }, label: {
                    Text("Plain")
                })
                .buttonStyle(PlainButtonStyle())
            }
        }
    }
}

PlaygroundPage.current.liveView = UIHostingController(rootView: ContentView())

これで解決。タップイベントはListではなくボタンで反応するようになった。

デザイン的なものはButtonでなく内部のTextに適用していけばいい。

蛇足: なぜButtonのスタイルで判断するのかを考える

  • 予想
    • AppleはListをUITableViewのように動作させたい場合をデフォルトと考えているのではないかと思う。
  • 実験してなんとなくわかること
    • SwiftUIはListの要素のモディファイアではonTapGestureでタップしたときにUITableViewのようにList自体を変更することはやりたくない
    • SwiftUIのListのなかにButtonがあるときはそれが要素なのでUITableViewのように振る舞わうことを制御できる
      • もしその挙動を変更したければButton側で変更できるようにしている

以下は実験

全てのスタイルを適用してみる

他にもDefaultButtonStyleというのがあるのでそれも適用してみる。結果はListがタップできるようになってしまう。つまりこれがデフォルトか。

//: A UIKit based Playground for presenting user interface
  
import UIKit
import SwiftUI
import PlaygroundSupport

struct ContentView: View {
    var body: some View {
        List {
            HStack {
                Text("Cell 1")

                Spacer()

                Button(action: {
                    print("B_1押したね")
                }, label: {
                    Text("Border")
                })
                .buttonStyle(BorderlessButtonStyle())

                Button(action: {
                    print("P_1押したね")
                }, label: {
                    Text("Plain")
                })
                .buttonStyle(PlainButtonStyle())

                Button(action: {
                    print("D_1押したね")
                }, label: {
                    Text("Default")
                })
                .buttonStyle(DefaultButtonStyle())
            }
        }
    }
}

PlaygroundPage.current.liveView = UIHostingController(rootView: ContentView())

なぜButtonのスタイルで判断するのか

  • Listには複数のSectionやView(Cell/Item)が必要なためListのスタイルで統一的に指定しづらい
    • 1行目とか指定する形にしてしまえばできるとは思うがそれも複雑でどうかと思う
      • 内部のViewの状態で判断しようとしている

具体的にはListが2行になっている場合、1行目はCellにはタップできないが、2行目はCellにもタップできる。

//: A UIKit based Playground for presenting user interface
  
import UIKit
import SwiftUI
import PlaygroundSupport

struct ContentView: View {
    var body: some View {
        List {
            HStack {
                Text("Cell 1")

                Spacer()

                Button(action: {
                    print("B_1押したね")
                }, label: {
                    Text("Border")
                })
                .buttonStyle(BorderlessButtonStyle())

                Button(action: {
                    print("P_1押したね")
                }, label: {
                    Text("Plain")
                })
                .buttonStyle(PlainButtonStyle())
            }

            HStack {
                Text("Cell 2")

                Spacer()

                Button(action: {
                    print("D_2押したね")
                }, label: {
                    Text("Default")
                })
                .buttonStyle(DefaultButtonStyle())
            }
        }
    }
}

PlaygroundPage.current.liveView = UIHostingController(rootView: ContentView())

スクリーンショット 2021-04-10 16.16.30.png

上記の予想はあくまで身勝手な予想なので、何かコメントあればコメント欄にお願いします。

35
18
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
35
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?