簡體   English   中英

從 SwiftUI 中的導航欄中刪除后退按鈕文本

[英]Remove back button text from navigationbar in SwiftUI

我最近開始在 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 NavigationView 的自定義后退按鈕文本)正如本期的創建者已經說過的那樣,在您覆蓋導航欄后后退手勢停止工作項目。 有了這個,我也想知道如何設置后退按鈕的 foregroundColor 。 它現在具有默認的藍色,但是我想用另一種顏色覆蓋它。

這真的很容易。 以下解決方案是我制作的最快和最干凈的解決方案。

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

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

這將從應用程序中的每個 NavigationView (UINavigationController) 中刪除后退按鈕文本。

借助@Pitchbloas 提供的解決方案,此方法僅涉及將backButtonDisplayMode屬性設置為.minimal

extension UINavigationController {

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

}

我找到了一種僅使用 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()
          }
        }
    )
  }
}

所以我實際上最終得到了以下實際可行的解決方案。 我像這樣覆蓋導航欄項目

.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 會成熟一點,這樣可以更容易地完成。

標准后退按鈕標題取自前一屏幕的導航欄標題。

可以通過以下方法獲得所需的效果:

演示

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" : "")
        }
    }
}

使用Introspect框架,您可以輕松訪問底層導航項並將backButtonDisplayMode設置為最小。

這是在推送的視圖中使用它的方法

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

自定義 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)
        }
    }
}

我通過在推送詳細屏幕之前更改主屏幕的標題並在它重新出現時將其設置回來來實現這一點。 唯一需要注意的是,當您返回主屏幕時,標題的重新出現有點明顯。

概括:

  • 在主視圖上添加狀態變量(例如 isDetailShowing)以存儲是否顯示詳細信息屏幕

  • 在主視圖上使用 navigationTitle 修飾符根據 isDetailShowing 的當前值設置標題

  • 在主視圖上使用 onAppear 修飾符將 isDetailShowing 的值設置為 false

  • 在主屏幕的 NavigationLink 上,使用同步手勢修飾符將 isDetailShowing 設置為 true

     struct MasterView: View { @State var isDetailShowing = false var body: some View { VStack { Spacer() .frame(height: 20) Text("Master Screen") .frame(maxWidth: .infinity, alignment: .leading) Spacer() .frame(height: 20) NavigationLink(destination: DetailView()) { Text("Go to detail screen") } .simultaneousGesture(TapGesture().onEnded() { isDetailShowing = true }) } .navigationBarTitleDisplayMode(.inline) .navigationTitle(isDetailShowing ? "" : "Master Screen Title") .onAppear() { isDetailShowing = false } } } struct DetailView: View { var body: some View { Text("This is the detail screen") .navigationBarTitleDisplayMode(.inline) .navigationTitle("Detail Screen Title") } }

如果你想:

  • 在全球范圍內進行
  • 保留標准的后退按鈕(以及自定義行為,例如長按導航幾個屏幕的能力)
  • 避免引入任何第三方框架

您可以通過外觀將后退按鈕文本顏色設置為清除顏色:

let navigationBarAppearance = UINavigationBarAppearance()

let backButtonAppearance = UIBarButtonItemAppearance(style: .plain)
backButtonAppearance.focused.titleTextAttributes = [.foregroundColor: UIColor.clear]
backButtonAppearance.disabled.titleTextAttributes = [.foregroundColor: UIColor.clear]
backButtonAppearance.highlighted.titleTextAttributes = [.foregroundColor: UIColor.clear]
backButtonAppearance.normal.titleTextAttributes = [.foregroundColor: UIColor.clear]

navigationBarAppearance.backButtonAppearance = backButtonAppearance

//Not sure you'll need both of these, but feel free to adjust to your needs.
UINavigationBar.appearance().standardAppearance = navigationBarAppearance
UINavigationBar.appearance().scrollEdgeAppearance = navigationBarAppearance

您可以在應用程序啟動時執行一次並忘記它。

一個潛在的缺點(取決於您的偏好)是,當您移動到另一個標題時,當前 window 的標題會向左滑動,從而過渡到清晰的顏色。

您還可以嘗試不同的文本屬性。

演示

適用於 iOS 16

上面的解決方案對我不起作用。 我想對視圖進行特定的更改,而不需要任何全局(外觀或擴展)並且使用最少的樣板代碼。

Since you can update NavigationItem inside the init of the View. You can solve this in 2 steps:

  1. 獲取可見視圖 Controller。
// Get Visible ViewController
extension UIApplication {
    
    static var visibleVC: UIViewController? {
        var currentVC = UIApplication.shared.windows.first { $0.isKeyWindow }?.rootViewController
        while let presentedVC = currentVC?.presentedViewController {
            if let navVC = (presentedVC as? UINavigationController)?.viewControllers.last {
                currentVC = navVC
            } else if let tabVC = (presentedVC as? UITabBarController)?.selectedViewController {
                currentVC = tabVC
            } else {
                currentVC = presentedVC
            }
        }
        return currentVC
    }
    
}
  1. 在視圖的 init 中更新 NavigationItem。
struct YourView: View {
    
    init(hideBackLabel: Bool = true) {
        if hideBackLabel {
            // iOS 14+
            UIApplication.visibleVC?.navigationItem.backButtonDisplayMode = .minimal
            
            // iOS 13-
            let button = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
            UIApplication.visibleVC?.navigationItem.backBarButtonItem = button
        }
    }

}

為什么不使用隱藏默認后退按鈕的自定義后退按鈕

你可以使用任何你喜歡的設計!

適用於 iOS 16

第一個視圖

struct ContentView: View {
var body: some View {
    NavigationView {
        VStack(){
            Spacer()
            NavigationLink(destination: View2()) {
                Text("Navigate")
                    .font(.title)
            }
            Spacer()
        }
    }
}
}

第二視圖

struct View2: View {
@Environment(\.presentationMode) var presentationMode

var body: some View {
    NavigationView {
        ZStack{
            VStack{
                HStack(alignment:.center){
//Any Design You Like
                    Image(systemName: "chevron.left")
                           .font(.title)
                           .foregroundColor(.blue)
                           .onTapGesture {                          
self.presentationMode.wrappedValue.dismiss()
                           }
                           .padding()
                   Spacer()
                }
                Spacer()
            }
        }
    }
    .navigationBarBackButtonHidden(true)
}
}

你可以使用.toolbarRole(.editor)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM