![](/img/trans.png)
[英]Dynamically change NavigationBar Back Button Text from presented ViewController
[英]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:
// 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
}
}
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.