本文へスキップ
Hironobu Iga

SwiftUI で戻るボタンの文字を消す

navigationBarBackButtonHidden で消すと、スワイプ戻しと長押しのスタック表示まで失われる。UINavigationBar の appearance をいじるほうが安全。

公開日

この記事は別サイトにも掲載しています。 https://iganin.hatenablog.com/entry/2024/02/26/201210

語り尽くされている感があるが、今一度調べたので備忘録的にメモ。

tl;dr;

  • UINavigationBar の Appearance をいじることで達成可能
  • navigationBarBackButtonHidden にして、navigationItem を navigationBarLeading に追加でも対応できるが以下の機能が消える
    • SwipeGesture による元の画面への遷移
    • 戻るボタン長押しによる Stack の表示と選択による画面遷移

環境

以下の環境で確認

  • iOS 17.x
  • Xcode 15.2

UIKit

まず UIKit の場合にどうするかを記述する。 これは非常に簡単に行うことができて、navigationItem.backButtonDisplayModeminimal にしてやれば良い。 iOS 14 以上の制約はあるが、昨今は基本的にはこのサポートバージョンの条件を満たしていると思う。 backButtonDisplayMode | Apple Developer Documentation

SwiftUI

SwiftUI でどうするかを記述する。

UINavigationBar の Appearance をいじる

おそらくこの方法が筋が良いと思う。以下のようにすることで、BackButton のテキストを非表示にすることができる。

appearance.backButtonAppearance.normal.titleTextAttributes = [.foregroundColor: UIColor.clear]

この方法であれば、後述の方法では無効化されてしまうデフォルトの以下の機能も無効化されない。

  • Swipe Gesture による画面遷移
  • 長時間押下による Stack の表示 + 指定した画面への遷移

ToolbarItem(placement: .navigationBarLeading)

navigationBarBackButtonHidden() で BackButton を非表示にして、ToolbarItem(placement: .navigationBarLeading) で独自の戻るボタンを置く方法。 以下のように ViewModifier を作成すると設定がだいぶ楽になる。

struct MinimalNavigationBarBackButton: ViewModifier {
  @Environment(\.dismiss) var dismiss

  public func body(content: Content) -> some View {
    content
      .navigationBarBackButtonHidden(true)
      .toolbar {
        ToolbarItem(placement: .navigationBarLeading) {
            Button {
                dismiss()
            } label: {
                Image(systemName: "chevron.backward")
            }
            .foregroundStyle(Color.black)
        }
      }
  }
}

直感的な方法ではあるが、デフォルトである以下の機能が無効になる。

  • A Swipe による元の画面への画面遷移
  • B 戻るボタンの長時間押下による Stack の表示 + 指定 Stack への遷移

A については UINavigationController をいじることで実装できるが、全体に適用すると BackButton が Hidden でも Swipe で戻れてしまうので制御が必要。 B もおそらく実装できるが手間はかかりそう。

extension UINavigationController: UIGestureRecognizerDelegate {
    override open func viewDidLoad() {
        super.viewDidLoad()
        interactivePopGestureRecognizer?.delegate = self
    }

    public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        return viewControllers.count > 1
    }
}

その他

以下の方法も検討できるが、BackButton 以外の挙動が変わりそうなのでその辺りの考慮が必要そう。

  • 画面遷移と同時に User の navigationTitle を空文字にする
  • toolbarRole に editor を指定

Reference