在没有以前 NavigationLink 的 SwiftUI NavigationView 上显示系统后退按钮

Posted

技术标签:

【中文标题】在没有以前 NavigationLink 的 SwiftUI NavigationView 上显示系统后退按钮【英文标题】:Display system back button on SwiftUI NavigationView with no previous NavigationLink 【发布时间】:2020-09-03 09:27:44 【问题描述】:

我有一个自定义的 SwiftUI 标题视图,它由几个 Texts 和一个 Image 组成(为了简化,省略了 Image)。带有标题视图的 SwiftUI 视图是从 UIViewController 呈现的,因此我需要一个自定义的后退按钮,它可以从 View(正在显示在 UIHostingController 中)导航到之前呈现它的 UIViewController .

我希望这个自定义后退按钮看起来与系统后退按钮完全一样,但是我找不到适合它的系统映像。我试过 Image(systemName: "chevron.left")Text("❮")(以及几乎所有其他系统图像和 unicode 箭头字符),但这些都没有提供系统后退按钮的外观。

有什么方法可以匹配 SwiftUI 中系统后退按钮的外观吗?

这是系统后退按钮的样子(尾随按钮是 Unicode 左箭头,前导按钮是系统后退按钮):

还有我的自定义后退按钮(如您所见,它比系统按钮小得多):

TitleView.swift:

class TitleViewModel: ObservableObject 
    let backAction: () -> ()
    @Published var name: String
    @Published var subtitle: String?

    init(name: String, subtitle: String?, backAction: @escaping () -> ()) 
        self.name = name
        self.subtitle = subtitle
        self.backAction = backAction
    


struct TitleView: ViewModifier 
    @ObservedObject var viewModel: TitleViewModel

    func body(content: Content) -> some View 
        ZStack(alignment: .top) 
            NavigationView 
                VStack 
                    content
                        .navigationBarTitle("", displayMode: .inline)
                        .navigationBarItems(leading: backButton)
                    NavigationLink(destination: Text("Destination").navigationBarItems(trailing: Text("❮")), label:  Text("Next")
                    )
                
            
            titleView
        
    

    private var backButton: some View 
        Button(action: viewModel.backAction)  Image(systemName: "chevron.left") 
    

    private var titleView: some View 
        VStack 
            Text(viewModel.name)
            Text(viewModel.subtitle ?? "")
        
    


extension View 
    func titleView(_ viewModel: TitleViewModel) -> some View 
        modifier(TitleView(viewModel: viewModel))
    

DetailsView.swift

public struct DetailsView: View 
    public var backAction: () -> ()

    public var body: some View 
        Text("Text")
            .titleView(TitleViewModel(name: "Title", subtitle: "SubTitle", backAction: backAction))
    


public class DetailsViewController: UIHostingController<DetailsView> 
    public override func viewWillAppear(_ animated: Bool) 
        super.viewWillAppear(animated)
        navigationController?.setNavigationBarHidden(true, animated: false)
    


public struct RootView: View 
    public var next: () -> ()

    public var body: some View 
        VStack 
            Text("Root")
            Button(action: next, label:  Text("Next") )
        
    

SceneDelegate 中,设置UINavigationController,将UIHostingController 显示为rootViewController

func instantiateRootViewController() -> UIViewController 
    let navigationController = UINavigationController()
    let detailsView = DetailsView(backAction:  navigationController.popViewController(animated: true) )
    let presentDetailsView =  navigationController.pushViewController(DetailsViewController(rootView: detailsView), animated: true) 
    let rootViewController = UIHostingController(rootView: RootView(next: presentDetailsView))
    navigationController.pushViewController(rootViewController, animated: true)
    return navigationController


func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) 
    if let windowScene = scene as? UIWindowScene 
        let window = UIWindow(windowScene: windowScene)
        let rootViewController = instantiateRootViewController()
        window.rootViewController = rootViewController
        self.window = window
        window.makeKeyAndVisible()
    

【问题讨论】:

【参考方案1】:

您可以尝试以下方法:

private var backButton: some View 
    Button(action: ) 
        Image(systemName: "chevron.left")
            .scaleEffect(0.83)
            .font(Font.title.weight(.medium))
    

您也可以选择使用.offset,但这可能无法正确适应更大的辅助字体大小:

.offset(x: -7, y: 0)

【讨论】:

谢谢,这仍然有点偏离系统设计,但我会尝试使用.font 尝试更紧密地匹配它。我没有意识到您也可以将Font 修饰符应用于Image,很高兴知道。 @DávidPásztor 不客气,如果您找到更接近的匹配项,请告诉我。 Weight 更改为 .medium 就我所知,它仍然不是 100%,但我想说非常接近,以至于用户不会注意到差异,除非他们正在同时查看系统后退按钮和自定义后退按钮:)

以上是关于在没有以前 NavigationLink 的 SwiftUI NavigationView 上显示系统后退按钮的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法向 NavigationLink 添加额外的功能? SwiftUI

创建没有后退按钮 SwiftUI 的 NavigationLink

如何在 SwiftUI 列表中设置 NavigationLink

如何在不更改 UI 的情况下添加 NavigationLink?

SwiftUI 中的 NavigationLink 不接受参数

SwiftUI:NavigationLink 内的水平 ScrollView 会中断导航