🤷‍♂️

SwiftUIのFormで.formStyle(.columns)に対してDatePickerのラベルを表示させるとやばい

2023/06/26に公開

概要

SwiftUIにはiOS 13からFormのViewがあり、iOS 16からモディファイア.formStyle()でその見た目を変更できる。

https://developer.apple.com/documentation/swiftui/formstyle

しかし、見た目を.formStyle(.columns)に変更しDatePickerのラベルを表示すると(私の)想定を超えたレンダリングをされる。解決方法はラベルを表示しないことだ。

実例

Xcode 14.3で試した(Xcode 15ベータでも結果は同じ)。

まず想定内の例

struct ScanFormView_Previews: PreviewProvider {
    static var previews: some View {
        @State var date = Date()

        Form {
            Section(header: Text("Sectionだよ")) {
                Divider()

                DatePicker(
                    "賞味期限",
                    selection: $date,
                    displayedComponents: [.date]
                )
                .labelsHidden()

                Divider()

                Text("テキストだよ")
            }
            .padding()
        }
        .formStyle(.columns)
    }
}

想定を超えてくる例

.labelsHidden()を取り除くだけ、つまりラベルを表示してしまうと想定を超えてくる。念のためコードも示す。

struct ScanFormView_Previews: PreviewProvider {
    static var previews: some View {
        @State var date = Date()

        Form {
            Section(header: Text("Sectionだよ")) {
                Divider()

                DatePicker(
                    "賞味期限",
                    selection: $date,
                    displayedComponents: [.date]
                )
//                .labelsHidden() !!!!!ここをコメントアウトしてみる

                Divider()

                Text("テキストだよ")
            }
            .padding()
        }
        .formStyle(.columns)
    }
}

DatePickerのラベルが同列のDividerとさらに親のSectionのレンダリングにも影響を与える。

これ、Dividerを置いてるからわかりやすくなってると思う。Dividerがないと何がなんだかわからない。このDividerを見る限り、予想だがUITableViewのCellでセパレーターがinsetを自動で設定している状態のように見える。ただそれにしたってSectionを押し出してるのもひどいけども。

formStyleをgroupedにする

ぶっこわれた例だけみても意味がわからない人もいると思うので、.formStyle(.columns)から.formStyle(.grouped)にし、Dividerを消して使った例を示しておく。

struct ScanFormView_Previews: PreviewProvider {
    static var previews: some View {
        @State var date = Date()

        Form {
            Section(header: Text("Sectionだよ")) {

                DatePicker(
                    "賞味期限",
                    selection: $date,
                    displayedComponents: [.date]
                )
//                .labelsHidden()

                Text("テキストだよ")
            }
            .padding()
        }
        .formStyle(.grouped)
    }
}

まとめ

何が何だかわからないのでまとめておく

  • FormにはformStyleで見た目を変える機能がある(iOS16以降)
    • formStyle(.columns)
      • DatePickerでラベルを表示するとすごい見た目になる
        • 解決方法はラベルを非表示にする
        • Xcode 14.3でもそうだしXcode 15ベータでも同じ
    • fromStyle(.grouped)
      • DatePickerでラベルを表示してもまあ普通
      • ここでは書いてないがTextFieldでフォーカスが当たった際にFormがスクロールするがスクロール量が異常でTextFieldのすぐ下までスクロールされて非常にきつい
        • Xcode 14.3でもXcode 15でも同じ

感想

  • SwiftUIは中身のコンテンツの設定によってネストされた親Viewの挙動を変える
    • そのせいでテストされていない組み合わせだらけだろう
      • SwiftUIは伸び代がありますねえ...
        • Appleにフィードバック出そうと思う

Discussion