Skip to main content

SwiftUI专辑004-Button以及跳转

· 预计阅读6分钟

headerimg 本章将介绍如何使用各种Button和如何跳转。

  • Button
  • EditButton
  • PasteButton
  • NavigationView
  • NavigationLink

Getting ready

首先,新建一个ButtonsApp的SwiftUI工程。

How to do it…

  1. 新建文件
  2. 模板选择SwiftUI View
  3. 输入名称ButtonView
  4. 重复上面步骤,创建EditButtonView
  5. 重复上面步骤,创建PasteButtonView
  6. 重复上面步骤,创建MenuButtonView,(MenuButton已经弃用了,使用Menu)
  7. 打开ContentView.swift,在body中添加一个NavigationView
NavigationView {
VStack {
NavigationLink(destination: ButtonView()) {
Text("Buttons").padding()
}
NavigationLink(destination: EditButtonView()) {
Text("EditButtons").padding()
}
NavigationLink(destination: MenuButtonView()) {
Text("MenuButtons").padding()
}
NavigationLink(destination: PasteButtonView()) {
Text("PasteButtons").padding()
}
NavigationLink(destination:
Text("Very long text that should not be displayed in a single line because it is not good design")
.padding()
.navigationBarTitle(Text("Detail"))
) {
Text("details about text").padding()
}
}.navigationBarTitle(Text("Main View"), displayMode:.inline)

最终显示如下:

image-20211222163022220

  1. 打开EditButtonView.swift,添加下面的代码,实现EditButton
struct EditButtonView: View {
@State private var animals = ["Cats", "Dogs", "Goats"]
var body: some View {
NavigationView {
List {
ForEach(animals, id: \.self) { animal in
Text(animal)
}.onDelete(perform: removeAnimal)
}
}.navigationBarItems(trailing: EditButton())
.navigationBarTitle(Text("EditButtonView"), displayMode: .inline)
}

func removeAnimal(at offsets: IndexSet){
animals.remove(atOffsets: offsets)
}
}

最终得到,点击右上角的Edit按钮,List会进入编辑状态。

20211222164221

  1. 打开MenuButtonView.swift, 添加以下代码
var body: some View {
Text("MenuButtons are currently available on MacOS currently")
.padding()
.navigationBarTitle("MenuButtons", displayMode:.inline)

/*
MenuButton("country +") {
Button("USA") { print("Selected USA") }.background(Color.accentColor)
Button("India") { print("Selected India") }
}
*/
}

  1. 打开PasteButtonView.swift,添加以下代码
struct PasteButtonView: View {
var body: some View {
VStack {
Text("PasteButton controls how you paste in macOS but is not available in iOS. For more information, check the \"See also\" section of this recipe")
.padding()
}.navigationBarTitle("PasteButton", displayMode: .inline)
}
}

How it works…

NavigationLink必须放在NavigationView里使用。

NavigationLink 需要两个参数destinationlabeldestination代表点击后跳转的View。label代表显示的内容。

.navigationBarTitlemodifier给ContentView界面添加了个title。第一个参数指定title的内容,第二个参数指定title显示的模式。.inline代表在标准的navigationBar中显示。

其他几个界面也有指定.navigationBarTitle,但是在preview中不会显示,在运行时才会显示。

EditButtonList一起使用,让List可编辑。我们之后再学习List。

MenuButtonsPasteButtons只能在macOS中使用。MenuButtons已被弃用,可以不用看了。

PasteButton可参考官方文档中的例子。

API详情

Button

Creating a Button

// action是点击时触发的方法, label控制显示内容
init(action: @escaping () -> Void, label: () -> Label)
init(_ titleKey: LocalizedStringKey, action: @escaping () -> Void)

Creating a Button with a Role

//多了个ButtonRole,用于描述Button语意,SwiftUI会根据语意添加样式,比如取消,是红色的。
init(role: ButtonRole?, action: @escaping () -> Void, label: () -> Label)

Creating a Button from a Configuration

///通过config初始化
init(_ configuration: PrimitiveButtonStyleConfiguration)

Setting a Border Shape

///设置border样式,
// capsule : 胶囊形状, rounded rectangle: 圆角矩形,可自定义圆角大小
func buttonBorderShape(_ shape: ButtonBorderShape) -> some View

Styling Button Appearance

/// 设置样式,创建自定义样式
func buttonStyle<S>(_ style: S) -> some View where S : ButtonStyle

举个例子

struct RedborderStyle: PrimitiveButtonStyle {
func makeBody(configuration: Configuration) -> some View {
configuration.label.padding().border(Color.red)
}
}

struct ButtonView: View {
var body: some View {
Button("你好") {
print("hello")
}.buttonStyle(RedborderStyle())
}
}

用于创建类似于UINavigationController的导航。

Creating a Navigation View

init(content: () -> Content)

Styling Navigation Views

func navigationViewStyle<S>(_ style: S) -> some View where S : NavigationViewStyle

Adding Titles

//导航栏标题
func navigationTitle(_ titleKey: LocalizedStringKey) -> some View
//subtitle,只有macOS才有
func navigationSubtitle<S>(_ subtitle: S) -> some View where S : StringProtocol
...

Managing Navigation Bars

//隐藏navigationbar
func navigationBarHidden(_ hidden: Bool) -> some View
func navigationBarBackButtonHidden(_ hidesBackButton: Bool) -> some View
///显示模式,inline: 正常大小导航栏居中, large:大的导航栏,居左
func navigationBarTitleDisplayMode(_ displayMode: NavigationBarItem.TitleDisplayMode) -> some View

控制navigation跳转的view。点击后会跳转到destination。当然除了,手动触发,也能够通过代码触发跳转。代码跳转有两种方式,一种是通过isActive,一种是通过tag+selection。

Presenting a Destination View

init(destination: () -> Destination, label: () -> Label)
init<S>(_ title: S, destination: () -> Destination) where S : StringProtocol

Presenting a Destination View with Programmatic Activation

///提供isActive,这样可以通过代码来跳转
init<S>(_ title: S, isActive: Binding<Bool>, destination: () -> Destination) where S : StringProtocol
...

举个例子, 下面的点击两个按钮都能跳转到对应View。

struct ContentView: View {
@State var showEditBtnScreen = false
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: EditButtonView(), isActive: $showEditBtnScreen) {
Text("EditButtons").padding()
}
Button("设置active跳转") {
showEditBtnScreen = true
}
}.navigationBarTitle(Text("Main View"), displayMode: .inline)
}
}
}

Presenting a Selectable Destination View

///通过给每个Link一个tag,然后通过设置selection为对应tag,控制跳转
init<S, V>(_ title: S, tag: V, selection: Binding<V?>, destination: () -> Destination) where S : StringProtocol, V : Hashable
...

举个例子

struct ContentView: View {
enum Screens {
case editButtonScreen
case memuButtonScreen
}
@State var currentScreen: Screens?
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: EditButtonView(), tag: Screens.editButtonScreen, selection: $currentScreen) {
Text("EditButtons").padding()
}
NavigationLink(destination: MenuButtonView(), tag: Screens.memuButtonScreen, selection: $currentScreen) {
Text("MenuButtons").padding()
}
Button("设置selection跳转") {
currentScreen = .memuButtonScreen
}
}.navigationBarTitle(Text("Main View"), displayMode: .inline)
}
}
}