从 SwiftUI 中的导航栏中删除后退按钮文本

Posted

技术标签:

【中文标题】从 SwiftUI 中的导航栏中删除后退按钮文本【英文标题】:Remove back button text from navigationbar in SwiftUI 【发布时间】:2020-06-17 01:21:01 【问题描述】:

我最近开始使用 SwiftUI,得出的结论是使用导航还不是很好。我想要达到的目标如下。我终于设法摆脱了半透明背景而不会导致应用程序崩溃,但现在我遇到了下一个问题。如何摆脱 navbaritem 中的“后退”文本?

我通过像这样在SceneDelegate.swift 文件中设置默认外观来实现上述视图。

let newNavAppearance = UINavigationBarAppearance()
newNavAppearance.configureWithTransparentBackground()
newNavAppearance.setBackIndicatorImage(UIImage(named: "backButton"), transitionMaskImage: UIImage(named: "backButton"))
newNavAppearance.titleTextAttributes = [
    .font: UIFont(name: GTWalsheim.bold.name, size: 18)!,
    .backgroundColor: UIColor.white

]

UINavigationBar.appearance().standardAppearance = newNavAppearance

我可以实现此目的的一种可能方法是覆盖导航栏项目,但是正如此问题的创建者已经说过的那样,这有一个缺点(SwiftUI Custom Back Button Text for NavigationView),在您覆盖导航栏项目后,后退手势停止工作.有了这个,我也想知道如何设置后退按钮的前景颜色。它现在具有默认的蓝色,但是我想用另一种颜色覆盖它。

【问题讨论】:

【参考方案1】:

其实很简单。以下解决方案是我制作的最快和最干净的解决方案。

例如,将其放在 SceneDelegate 的底部。

extension UINavigationController 
    // Remove back button text 
    open override func viewWillLayoutSubviews() 
        navigationBar.topItem?.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
    

这将从您应用中的每个 NavigationView (UINavigationController) 中删除后退按钮文本。

【讨论】:

谢谢!几天来,我一直在寻找像这样的简单解决方案。 这应该是公认的答案。【参考方案2】:

支持@Pitchbloas 提供的解决方案,此方法只需将backButtonDisplayMode 属性设置为.minimal

extension UINavigationController 

  open override func viewWillLayoutSubviews() 
    navigationBar.topItem?.backButtonDisplayMode = .minimal
  


【讨论】:

我不知道'backButtonDisplayMode',谢谢! 这是一个不错的选择!只是提醒其他人它需要 ios 14+。 发现这是一个很好的解决方案,但应该在设置按钮显示模式之前调用super.viewWillLayoutSubviews()【参考方案3】:

我找到了一种直接使用 SwiftUI 删除后退按钮文本并保留原始 V 形的简单方法。

添加了拖动手势以模仿经典的导航返回按钮 当用户想要通过向右滑动返回时。

import SwiftUI

struct ContentView: View 

  @Environment(\.presentationMode) var presentation

  var body: some View 
    ZStack 
      // Your main view code here with a ZStack to have the
      // gesture on all the view.
    
    .navigationBarBackButtonHidden(true)
    .navigationBarItems(
      leading: Button(action:  presentation.wrappedValue.dismiss() ) 
        Image(systemName: "chevron.left")
          .foregroundColor(.blue)
          .imageScale(.large) )
    .contentShape(Rectangle()) // Start of the gesture to dismiss the navigation
    .gesture(
      DragGesture(coordinateSpace: .local)
        .onEnded  value in
          if value.translation.width > .zero
              && value.translation.height > -30
              && value.translation.height < 30 
            presentation.wrappedValue.dismiss()
          
        
    )
  

【讨论】:

这太棒了!我要提一下,presentation.wrappedValue.dismiss 在项目中一直很头疼,有时会在特定情况下导致应用崩溃。【参考方案4】:

所以我实际上最终得到了以下实际可行的解决方案。我正在像这样覆盖导航栏项目

.navigationBarItems(leading:
    Image("backButton")
        .foregroundColor(.blue)
        .onTapGesture 
            self.presentationMode.wrappedValue.dismiss()
    
)

唯一的问题是后退手势不起作用,因此通过实际扩展 UINavigationController 解决了这个问题

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

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

现在它看起来正是我想要的方式,解决方案有点老套......但它现在可以工作,希望 SwiftUI 会成熟一点,这样可以更容易地完成。

【讨论】:

这不会在向后滑动时为您提供重复的导航和返回按钮吗?对我来说就是这样。所以我最终使用工具栏增加了导航标题的宽度。【参考方案5】:

标准返回按钮标题取自前一屏的导航栏标题。

可以通过以下方法获得所需的效果:

struct TestBackButtonTitle: View 
    @State private var hasTitle = true
    var body: some View 
        NavigationView 
            NavigationLink("Go", destination:
                Text("Details")
                    .onAppear 
                        self.hasTitle = false
                    
                    .onDisappear 
                        self.hasTitle = true
                    
            )
            .navigationBarTitle(self.hasTitle ? "Master" : "")
        
    

【讨论】:

好吧,是的,这是一个可能的解决方案,但它真的很讨厌,如果我必须在每个屏幕上都这样做,那会有点烦人和 hacky。我正在寻找一种全局禁用此文本的方法。【参考方案6】:

自定义 navigationBarItems 和 self.presentationMode.wrappedValue.dismiss() 有效,但不允许执行向后滑动

您可以添加以下代码以再次滑动

//perform gesture go back
extension UINavigationController: UIGestureRecognizerDelegate 
    override open func viewDidLoad() 
        super.viewDidLoad()
        interactivePopGestureRecognizer?.delegate = self
    

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

但问题是,有时它会在你滑动半屏然后取消时让你的应用崩溃。

我建议使用另一种方法来删除“后退”文本。 添加 isActive 状态来监控当前屏幕是否处于活动状态。 :)

struct ContentView: View 
    @State var isActive = false

    var body: some View 
        NavigationView() 
            NavigationLink(
                "Next",
                destination: Text("Second Page").navigationBarTitle("Second"),
                isActive: $isActive
            )
                .navigationBarTitle(!isActive ? "Title" : "", displayMode: .inline)
        
    

【讨论】:

在 iOS 15.2 上,此(使用 $isActive 绑定的第二个修复)可以禁用后退按钮文本,但会导致在导航中选择随机项目,并且调试控制台显示错误“遇到 SwiftUI推送导航链接时出现问题。请提交错误。"【参考方案7】:

使用这个:

import UIKit

extension UINavigationController 
    open override func viewWillAppear(_ animated: Bool) 
        super.viewWillAppear(animated)

        navigationBar.topItem?.backButtonDisplayMode = .minimal
    

这比viewWillLayoutSubviews 变体更高效(如果您print viewWillLayoutSubviews 解决方案中的任何内容被打印了很多次,您可以自己检查一下。

【讨论】:

【参考方案8】:

使用Introspect 框架,您可以轻松访问底层导航项并将backButtonDisplayMode 设置为最小。

这是在被推送的视图中使用它的方法

var body: some View 
    Text("Your body here")
        .introspectNavigationController  navController in
            navController.navigationBar.topItem?.backButtonDisplayMode = .minimal
        

【讨论】:

以上是关于从 SwiftUI 中的导航栏中删除后退按钮文本的主要内容,如果未能解决你的问题,请参考以下文章

无法删除 sliver 应用栏中的后退按钮

在 Swift 中使用 hidesBackButton 隐藏导航栏中的后退按钮

隐藏导航栏但保留后退按钮 - SwiftUI

SwiftUI Navigation 多个后退按钮

更改导航栏后退按钮并删除标题以使其看起来像在 ios7 中

标签栏导航栏中的后退按钮