如何在SwiftUI中将NavigationLink显示为按钮

如何在SwiftUI中将NavigationLink显示为按钮,navigation,swiftui,Navigation,Swiftui,我在这里读了很多关于SwiftUI导航的文章,并尝试了一些方法,但都没有达到预期效果 基本上,我有一个包含训练列表的视图,您可以通过单击一行来显示单个训练。这与使用NavigationView和NavigationLink时的预期效果一样 现在,我想在“详细信息”视图上单击一个按钮开始训练。这将打开一个带有计时器的视图。该视图应显示与细节视图相同的动画,并在导航栏中用后退按钮显示训练名称 我可以通过详细信息页面上的NavigationLink视图来实现这一点,但该链接始终显示为一个全宽行,箭头位

我在这里读了很多关于SwiftUI导航的文章,并尝试了一些方法,但都没有达到预期效果

基本上,我有一个包含训练列表的视图,您可以通过单击一行来显示单个训练。这与使用NavigationView和NavigationLink时的预期效果一样

现在,我想在“详细信息”视图上单击一个按钮开始训练。这将打开一个带有计时器的视图。该视图应显示与细节视图相同的动画,并在导航栏中用后退按钮显示训练名称

我可以通过详细信息页面上的NavigationLink视图来实现这一点,但该链接始终显示为一个全宽行,箭头位于右侧。我希望这是一个按钮,而不是,但导航链接似乎是抵制样式

struct WorkoutDetail: View {
    var workout: Workout

    var body: some View {
        VStack {
            NavigationLink(destination: TimerView()) {
                Text("Starten")
            }.navigationBarTitle(Text(workout.title))
        }
    }
}

struct WorkoutList: View {
    var workoutCollection: WorkoutCollection

    var body: some View {
        NavigationView {
            List(workoutCollection.workouts) { workout in
                NavigationLink(destination: WorkoutDetail(workout: workout)) {
                    WorkoutRow(workout: workout)
                }
            }.navigationBarTitle(Text("Workouts"))
        }
    }
}
更新:这里有一个屏幕截图来说明我的意思:


我自己已经玩了几天了。我想这就是你要找的

struct WorkoutDetail: View {
var workout: Workout

var body: some View {
    NavigationView {
       VStack {
           NavigationLink(destination: TimerView()) {
               ButtonView()
           }.navigationBarTitle(Text(workout.title))
        }
    }
}
并创建要在NavigationLink中显示的视图

struct ButtonView: View {
var body: some View {
    Text("Starten")
        .frame(width: 200, height: 100, alignment: .center)
        .background(Color.yellow)
        .foregroundColor(Color.red)
}

注意:导航视图上方的任何内容都会显示在导航中的所有页面上,从而使导航视图在链接中的大小变小。

您不需要将视图包装在
导航链接中,以使其在按下时触发导航

我们可以用
NavigationLink
绑定一个属性,无论执行什么操作,只要更改该属性,我们的导航就会触发。例如:

struct SwiftUI: View {
    @State private var action: Int? = 0
    
    var body: some View {
        
        NavigationView {
            VStack {
                NavigationLink(destination: Text("Destination_1"), tag: 1, selection: $action) {
                    EmptyView()
                }
                NavigationLink(destination: Text("Destination_2"), tag: 2, selection: $action) {
                    EmptyView()
                }
                
                Text("Your Custom View 1")
                    .onTapGesture {
                        //perform some tasks if needed before opening Destination view
                        self.action = 1
                    }
                Text("Your Custom View 2")
                    .onTapGesture {
                        //perform some tasks if needed before opening Destination view
                        self.action = 2
                    }
            }
        }
    }
}
无论何时更改
可绑定属性的值(即操作)
导航链接
都会将其
标记的预定义值与绑定属性
操作
进行比较,前提是两者相等

因此,您可以以任何方式创建视图,也可以从任何视图触发导航,而不必考虑任何操作,只需使用
NavigationLink
绑定的属性即可


谢谢,希望有帮助。

使用按钮标签内的导航链接

Button(action: {
    print("Floating Button Click")
}, label: {
    NavigationLink(destination: AddItemView()) {
         Text("Open View")
     }
})

例如,我认为准确的方法是使用
按钮样式

NavigationLink(destination: WorkoutDetail(workout: workout)) {
  WorkoutRow(workout: workout)
}
.buttonStyle(ButtonStyle3D(background: Color.yellow))

您可以将NavigationLink as按钮与ZStack一起使用:

@State var tag:Int? = nil
ZStack {
  NavigationLink(destination: MyModal(), tag: 1, selection: $tag) {
    EmptyView()
  }

  Button(action: {
    self.tag = 1
  }, label: {
    Text("show view tag 1")
  })
}
希望能有所帮助。

与的解决方案非常相似,但删除了ZStack:

struct ContentView: View {
    @State var selectedTag: String?

    var body: some View {
        Button(action: {
            self.selectedTag = "xx"
        }, label: {
            Image(systemName: "plus")
        })
        .background(
            NavigationLink(
                destination: Text("XX"),
                tag: "xx",
                selection: $selectedTag,
                label: { EmptyView() }
            )
        )
    }
}

等待没有状态的更简洁的解决方案。您呢?

您可以将导航链接直接添加到按钮,如下所示:

    @State var tag:Int? = nil

    ...

    NavigationLink(destination: Text("Full List"), tag: 1, selection: $tag) {
        MyButton(buttonText: "Full list") {
            self.tag = 1
        }
    }

我不知道为什么所有这些答案都让事情变得如此复杂。在Swiftui2.0中,您只需在导航链接中添加按钮

NavigationLink(destination: TimerView()) {
    Text("Starten")
}

您可以对
文本
对象应用SwiftUI样式,就像对任何其他元素应用样式一样。

如何填充
训练
?每件事背后都有模型(通常是某种形式的
@ObjectBinding
)吗?换句话说,你是如何获得应用程序的
训练状态的?我已经更新了帖子以显示列表视图以显示训练是如何填充的。workoutCollection已加载并移交给SceneDelegate类中的列表视图。谢谢,但不幸的是,这并不是我的问题。我用截图更新了我的问题。问题是,我得到一行链接,文本左对齐,箭头右对齐。但我想要的是一个普通的按钮。我还不确定答案,但现在我还要寻找解决方案。如果您从一个视图开始并转到一个新视图(总共两个视图),上面的代码可以正常工作,就像您希望的那样。如果您从带有导航链接的列表视图开始,然后转到workoutDetail视图,然后是timer视图,它将放入>(总共3个视图)。用上面的代码尝试一个测试项目,你就会明白我的意思。是的,它的工作原理和我想要的完全一样,现在唯一的问题是按钮的外观。在你的WorkoutList中,将“List”更改为“ForEach”。这就消除了所有的>。可能不是最终的解决方案,但可能会让您更接近。谢谢-我已经寻找了一段时间。这是一个有趣的解决方案,我们不应该在Swift中遇到这个问题。当我在Swift 5.2中实现此功能时,偶尔会出现错误:SwiftUI在推送aNavigationLink时遇到问题。请提交一个bug。使用标签是一个危险的解决方案,因为可能存在另一个组件,您可以在其中获得混合行为或不同的方法,不建议这样做,而是创建一个包装器,允许您使用外部任何人都无法复制的特定IDit@Kross不了解这里的风险。在app store上有2个使用这种方法的复杂应用程序,并且从未在任何地方遇到过任何混合行为。标记是在组件内创建的,并与同一组件的NavigationLink连接,因此无法从任何其他组件访问该组件。因此,外部组件可以自由复制标记并附加其导航链接,这不会影响当前组件的行为和导航。如果这不是您提到的风险,请发布您的解决方案,它将有助于更好地理解。rbaldwin我在几个案例中尝试过,我甚至将更多组件放入其中,并且它正常工作。也许你可以上传那部分代码,这样我就能帮你了。这正是我想要的。没有意识到可以将按钮样式添加到Navigationlinks。哇!要简化这么多代码!同意。这是目前SwiftUI 2Best的最佳答案。我们可以为按钮实现自定义样式,因此这是对我来说最简单、最干净的解决方案。因为这是一个SwiftUI 1.0问题。因为即使在SwiftUI 2.0中,您也可以使用您的方法获得附件箭头