SwiftUI x iOS26 でメニューを閉じた後にレイアウトが崩れる事象の対処法
背景
iOS26のUIで導入されたLiquid Glassでは、メニュー(UIKit.UIMenuやSwiftUI.Menu)を表示する際、表示元のボタンがメニューに変形するアニメーションが行われるようになった。
iOS26 SDKへの対応を行った際、SwiftUIで実装したメニューのうち、一部だけメニューを閉じる(ボタンに戻る)アニメーションの後にレイアウトが一瞬崩れる事象が確認された。
この事象は1秒程度待てば解消されて正しいレイアウトになる。
が、あまりにも分かりやすい残念体験なので改修を行った。

アニメーションによる残念なレイアウト崩れ。少し待つと解消されるのがなおさら残念感を誘う
結論
Q. メニューを閉じた後にレイアウトが崩れる事象の対処法は?
- A. ボタンを
.frame()による固定サイズ指定でレイアウトしない
修正の具体例
1. 塗りつぶしボタンの場合
修正前のコード
冒頭に挙げたボタンおよびメニューは、以下のように実装していた。
// 記事の内容に直接関わらない、メニュー自体の定義やフォント、色等の指定に関する記述は省略
Menu {
// menuの定義
} label: {
VStack(spacing: 0) {
Text("新規ステップの追加")
.font(…)
.frame(maxWidth: .infinity, minHeight: 42)
.background(…)
.foregroundColor(…)
.cornerRadius(4)
}.frame(height: 75)
}
.disabled(…)
.opacity(…)
修正後のコード
上記は歴史的経緯もありいささか冗長な記述もあるが、レイアウト崩れを回避するポイントは先に挙げた通り frame()による固定サイズ指定を行わない点だ。
具体的には以下のように修正した。
Menu {
// menuの定義
} label: {
Text("新規ステップの追加")
.font(…)
.padding(.vertical, 12.0) // 変更点1
.frame(maxWidth: .infinity) // 変更点2-1
.background(…)
.foregroundColor(…)
.cornerRadius(4)
.padding(16.0) // 変更点2-2
}
.disabled(…)
.opacity(…)
frameによる固定サイズ指定の回避は、以下のような変更により実現した。
- 変更点1: 高さの指定は
frame()ではなくpadding()により間接的に行う - 変更点2: 幅の指定は
maxWidthとpadding()により行う
変更点2について少し補足する。
frame()は使わない、と言いつつ、変更点2-1ではしっかり使用している。
ただし、プロパティの指定は maxWidth: .infinity なので、単にビュー幅いっぱいまで広げるものである。これであればレイアウト崩れの要因にはならない模様。
また、変更点2-1だけでは左右の余白が無くなってしまうので、変更点2-2の指定により余白を保つようにしている。
2. アイコンボタンの場合
アイコンだけのボタンにおいても、frame()でサイズを指定した箇所に限り、同様のレイアウト崩れが発生していた。
この場合は以下のように修正した。
Menu {
// menuの定義
} label: {
- Image("my_icon")
- .frame(width: 32)
+ Image(systemName: "ellipsis.circle")
+ .font(.system(size: 32.0, weight: .thin))
}
このボタンのアイコンは黒丸が3つ並んだ、いわゆるミートボールメニューである。
変更前はアセットカタログ内の画像を使用しており、古くから存在するファイルをframe()でサイズ調整をしてしのいでいた。
修正にあたり、frame()使用の回避および自前素材の削減を行うため、SFSymbolの ellipsis.circle(外周を丸く囲ったミートボールメニューのアイコン)に置き換え、サイズ指定はフォントサイズの指定により行うこととした。
※ フォントサイズはSwiftUI.Font.titleなどを使えば文字サイズ変更にも対応できるが、この画面は文字サイズ変更に非対応なので、.system(size:, weight:) により固定値を用いた。
〆
SwiftUI x iOS26で発生するレイアウト崩れのとりあえずの対処法を紹介した。
今回は修正を急ぎたかったので原因の詳細な調査までは行っていない。
画面遷移直後やアニメーション終了後しばらくすると想定通りの位置に表示されることから、メニューからボタンに再変形する際のレイアウト計算に限り、固定サイズの値が適切に考慮されていないように見える。
(OS側が、しかもアップデートにより追加で行うようになったアニメーションであれば、きちんとやってほしいというのが本音ではあるが…)
幸い、レイアウト崩れの回避を行ったことで、SwiftUIのコードもいくらかスッキリさせられたので、人間にとっても易しいコードを維持できれば、この手の問題にも堅牢なUIになると思う。
Discussion