从 SwiftUI 的导航栏中删除后退按钮文本
Remove back button text from navigationbar in SwiftUI
我最近开始使用 SwiftUI,得出的结论是使用导航还不是很好。我想要实现的是以下内容。我终于设法在没有使应用程序崩溃的情况下摆脱了 t运行slucent 背景,但现在我 运行 进入下一期。我怎样才能摆脱 navbaritem 中的 "back" 文本?
我通过像这样在 SceneDelegate.swift
文件中设置默认外观 运行ce 来实现上面的视图。
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) 正如本期的创建者已经说过的那样,在您覆盖后返回手势停止工作导航栏项目。有了这个,我也想知道如何设置后退按钮的 foregroundColor 。它现在具有默认的蓝色,但是我想用另一种颜色覆盖它。
标准后退按钮标题取自上一屏幕的导航栏标题。
有可能通过以下方法获得所需的效果:
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" : "")
}
}
}
所以我实际上得到了以下实际有效的解决方案。我正在像这样覆盖导航栏项目
.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 会成熟一点,这样可以更容易地完成。
我找到了一种仅使用 SwiftUI 删除后退按钮文本并保留原始人字形的简单方法。
添加了拖动手势来模仿经典的导航后退按钮
当用户想通过向右滑动返回时。
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()
}
}
)
}
}
其实很简单。下面的解决方案是我做的最快最干净的。
例如,将其放在 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
}
}
自定义 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)
}
}
}
使用 Introspect 框架,您可以轻松访问底层导航项并将 backButtonDisplayMode
设置为最小。
以下是您可以如何在推送的视图中使用它
var body: some View {
Text("Your body here")
.introspectNavigationController { navController in
navController.navigationBar.topItem?.backButtonDisplayMode = .minimal
}
}
我通过在推送详细信息屏幕之前更改主屏幕的标题然后在它 re-appears 时将其设置回原位来实现此目的。唯一需要注意的是,当您返回主屏幕时,标题的 re-appearance 有点明显。
总结:
在主视图上添加状态变量(例如 isDetailShowing)以存储详细信息屏幕是否显示
在主视图上使用 navigationTitle 修饰符根据 isDetailShowing 的当前值设置标题
在主视图上使用 onAppear 修饰符将 isDetailShowing 的值设置为 false
在主屏幕的 NavigationLink 上使用 simultaneousGesture 修饰符将 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")
}
}
我最近开始使用 SwiftUI,得出的结论是使用导航还不是很好。我想要实现的是以下内容。我终于设法在没有使应用程序崩溃的情况下摆脱了 t运行slucent 背景,但现在我 运行 进入下一期。我怎样才能摆脱 navbaritem 中的 "back" 文本?
我通过像这样在 SceneDelegate.swift
文件中设置默认外观 运行ce 来实现上面的视图。
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) 正如本期的创建者已经说过的那样,在您覆盖后返回手势停止工作导航栏项目。有了这个,我也想知道如何设置后退按钮的 foregroundColor 。它现在具有默认的蓝色,但是我想用另一种颜色覆盖它。
标准后退按钮标题取自上一屏幕的导航栏标题。
有可能通过以下方法获得所需的效果:
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" : "")
}
}
}
所以我实际上得到了以下实际有效的解决方案。我正在像这样覆盖导航栏项目
.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 会成熟一点,这样可以更容易地完成。
我找到了一种仅使用 SwiftUI 删除后退按钮文本并保留原始人字形的简单方法。
添加了拖动手势来模仿经典的导航后退按钮 当用户想通过向右滑动返回时。
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()
}
}
)
}
}
其实很简单。下面的解决方案是我做的最快最干净的。
例如,将其放在 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
}
}
自定义 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)
}
}
}
使用 Introspect 框架,您可以轻松访问底层导航项并将 backButtonDisplayMode
设置为最小。
以下是您可以如何在推送的视图中使用它
var body: some View {
Text("Your body here")
.introspectNavigationController { navController in
navController.navigationBar.topItem?.backButtonDisplayMode = .minimal
}
}
我通过在推送详细信息屏幕之前更改主屏幕的标题然后在它 re-appears 时将其设置回原位来实现此目的。唯一需要注意的是,当您返回主屏幕时,标题的 re-appearance 有点明显。
总结:
在主视图上添加状态变量(例如 isDetailShowing)以存储详细信息屏幕是否显示
在主视图上使用 navigationTitle 修饰符根据 isDetailShowing 的当前值设置标题
在主视图上使用 onAppear 修饰符将 isDetailShowing 的值设置为 false
在主屏幕的 NavigationLink 上使用 simultaneousGesture 修饰符将 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") } }