[SwiftUI] アクセシビリティ設定の「ボタンの形」を有効にした際にボタンのUIが崩れた場合の解消法

# はじめに
ボタンを複数配置した画面にて、アクセシビリティー設定の「ボタンの形」を有効にした場合、UI崩れが発生しました。解決方法を簡単にまとめます

# 環境
Xcode 15.2

## 発生したUI崩れ
設定画面より、アクセシビリティー設定の「ボタンの形」を有効にして前後のUIを比較する

<img width="200" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631585/f581a6a7-292c-a017-e834-e05493ada97b.png"> → <img width="200" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631585/0ab16a8d-1159-5048-f950-1744d84b8402.png"> → <img width="200" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631585/20b4c255-ec18-c99c-be64-a0a29616c68d.png"> → <img width="200" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631585/c49da2a0-d22c-fa3d-3f8f-4f7ce7ef3ed4.png"> → <img width="200" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631585/a3eeb60d-7507-9997-7659-1b5ac55899f5.png">


## NavigationLink実装部分
ボタンを複数配置した画面の実装は以下の通りです。

```swift
struct HomeView: View {
    @State private var path: [Screen] = []

    var buttonSize: CGFloat {
        guard let window = UIApplication.shared.connectedScenes.first as? UIWindowScene else {
            return 140
        }
        return window.screen.bounds.width / 3
    }

    var body: some View {
        NavigationStack(path: $path) {
            VStack(spacing: 20) {
                HStack(spacing: 20) {
                    NavigationLink(value: Screen.gameSetting) {
                        MenuButtonImage(
                            image: "btn_game_setting",
                            size: buttonSize
                        )
                    }
                    NavigationLink(value: Screen.gameRecord) {
                        MenuButtonImage(
                            image: "btn_game_record",
                            size: buttonSize
                        )
                    }
                }
                HStack(spacing: 20) {
                    NavigationLink(value: Screen.gameStart) {
                        MenuButtonImage(
                            image: "btn_game_start",
                            size: buttonSize
                        )
                    }
                    NavigationLink(value: Screen.randomNumber) {
                        MenuButtonImage(
                            image: "btn_randomNumber_table",
                            size: buttonSize
                        )
                    }
                }
                HStack(spacing: 20) {
                    NavigationLink(value: Screen.uses) {
                        MenuButtonImage(
                            image: "btn_uses",
                            size: buttonSize
                        )
                    }
                    NavigationLink(value: Screen.mainSetting) {
                        MenuButtonImage(
                            image: "btn_mainSetting",
                            size: buttonSize
                        )
                    }
                }
            }
            .padding(20)
            .navigationDestination(for: Screen.self) { screen in
                switch screen {
                    // 省略
                }
            }
        }
        .tint(Color.appNavBarButtonColor)
    }

    private struct MenuButtonImage: View {
        var image: String
        var size: CGFloat

        var body: some View {
            Image(image)
                .resizable()
                .frame(width: size, height: size)
                .background(Color.white)
                .cornerRadius(16)
                .padding(20)
        }
    }
}
```

ちなみに`NavigationLink`を使わず`Button`にしたとしても同じでした。

```swift

Button {
    //
} label: {
    Image("btn_game_setting")
        .resizable()
        .frame(width: buttonSize, height: buttonSize)
        .background(Color.white)
        .cornerRadius(16)
        .padding(20)
}
```

## UIが崩れた原因と対策①
アクセシビリティー設定の「ボタンの形」を設定すると、ButtonStyle`BorderedButtonStyle`になるようです。実装の中で`buttonStyle(_:)`の指定をしておらず`.automatic`が適用されていたことで変わってしまったようです。

https://developer.apple.com/documentation/swiftui/primitivebuttonstyle/bordered

適当な位置に`.buttonStyle(.plain)`を追加することでボタンのスタイルが変わらなくなりました。

## UIが崩れた原因と対策②
ボタンの実装も悪さしている部分がありました。
Imageに対して`.padding(20)`をしていたことでスタイルが`.bordered`に変わった際にボーダーの幅が多く取られておりました。
`.padding(20)`を消すことでアクセシビリティーを維持したままUI崩れも直せました。


```diff_swift
    private struct MenuButtonImage: View {
        var image: String
        var size: CGFloat

        var body: some View {
            Image(image)
                .resizable()
                .frame(width: size, height: size)
                .background(Color.white)
                .cornerRadius(16)
-               .padding(20)
        }
    }
```

<img width="200" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631585/e18d9c84-f943-d6de-fe36-10309ee54683.png">

# おわりに
アクセシビリティー設定の「ボタンの形」を選択するとボタンのスタイルが変わるということを今回初めて知りました。
ボタンのスタイルを固定とすることで思わぬUI崩れは防げると思いますが、アクセシビリティー観点では必要に応じて`.bordered`に変わるべき?とも思いました。

そもそも今回の事象がUI崩れというべきか、ボタンとしては機能するし許容できるのでは？という観点もあると思いますが、ユーザーの設定次第でボタンのスタイルが変わることは覚えておき、大きなリリース前にはUIのチェックも念の為しておきたいなと思いました。