Swift 专栏

SwiftUI的注意点

2021-12-01  本文已影响0人  Jiangyouhua

Hi, 大家好,我是姜友华。这两天在适应SwiftUI,SwiftUI较Swift UIKit在构建APP有较大的改变。在这里,我将其中的注意点记录下来。

通常我在学习新的界面类开发框架时,回从以下几个方面着手:页面的构建、页面的跳转、状态的改变、数据的传递及数据的持久化。SwiftUI较Swift UIKit在数据的传递与数据的持久化没有变化,所以这里只说说:页面的构建、页面的跳转、数据的传递。

官网里有有史以来最好的教程,还有最好的说明

一、页面的构建。

  1. View:

2.Layout

二、页面的跳转

  1. 判断渲染
if isShow {
    MyView()
}
  1. Present
struct ContentView: View {
    @State private var showingSheet = false

    var body: some View {
        Button("Show Sheet") {
            showingSheet.toggle()
        }
        .sheet(isPresented: $showingSheet) {
            backFunc()
        } content: {
            MyView()
        }
    }
}
  1. Navigation
NavigationView {
    List {
        NavigationLink("Purple", destination: ColorDetail(color: .purple))
        NavigationLink("Pink", destination: ColorDetail(color: .pink))
        NavigationLink("Orange", destination: ColorDetail(color: .orange))
    }
    .navigationTitle("Colors")

    Text("Select a Color") // A placeholder to show before selection.
}

struct ColorDetail: View {
    var color: Color

    var body: some View {
        color
            .frame(width: 200, height: 200)
            .navigationTitle(color.description.capitalized)
    }
}
  1. TabBar
TabView {
    Text("The First Tab")
        .badge(10)
        .tabItem {
            Image(systemName: "1.square.fill")
            Text("First")
        }
    Text("Another Tab")
        .tabItem {
            Image(systemName: "2.square.fill")
            Text("Second")
        }
    Text("The Last Tab")
        .tabItem {
            Image(systemName: "3.square.fill")
            Text("Third")
        }
}
.font(.headline)

三、状态的改变

  1. @State、@Binding, struct;@StateObject、@Binding Object、@ObservableObject、@EnvironmentObject,class。
@State private var isVisible = true
......
if isVisible == true {
    Text("Hello") // Only rendered when isVisible is true.
}
// 子视图
struct PlayButton: View {
    @Binding var isPlaying: Bool

    var body: some View {
        Button(action: {
            self.isPlaying.toggle()
        }) {
            Image(systemName: isPlaying ? "pause.circle" : "play.circle")
        }
    }
}

// 父视图
struct PlayerView: View {
    var episode: Episode
    @State private var isPlaying: Bool = false

    var body: some View {
        VStack {
            Text(episode.title)
            Text(episode.showTitle)
            PlayButton(isPlaying: $isPlaying)
        }
    }
}
class Contact: ObservableObject {
    @Published var name: String
    @Published var age: Int

    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }

    func haveBirthday() -> Int {
        age += 1
        return age
    }
}

let john = Contact(name: "John Appleseed", age: 24)
cancellable = john.objectWillChange
    .sink { _ in
        print("\(john.age) will change")
}
print(john.haveBirthday())
// Prints "24 will change"
// Prints "25"

objectWillChange是ObservableObject协议的方法。

class User: ObservableObject {
      @Publish var name: String
      @Publish var age: Int
}

struct EditView: View {
    @EnvironmentObject var user: User

    var body: some View {
        TextField("Name", text: $user.name)
    }
}

struct DisplayView: View {
    @EnvironmentObject var user: User

    var body: some View {
        Text(user.name)
    }
}

struct ContentView: View {
    let user = User(name: "Jiang", age)

    var body: some View {
        VStack {
            EditView()
            DisplayView()\
        }.environmentObject(user)
    }
}

2 @Environment、@ FocusState

 @Environment(\.colorScheme) var colorScheme: ColorScheme
......
if colorScheme == .dark { // Checks the wrapped value.
    DarkContent()
} else {
    LightContent()
}
struct LoginForm {
    enum Field: Hashable {
        case username
        case password
    }

    @State private var username = ""
    @State private var password = ""
    @FocusState private var focusedField: Field?

    var body: some View {
        Form {
            TextField("Username", text: $username)
                .focused($focusedField, equals: .username)

            SecureField("Password", text: $password)
                .focused($focusedField, equals: .password)

            Button("Sign In") {
                if username.isEmpty {
                    focusedField = .username
                } else if password.isEmpty {
                    focusedField = .password
                } else {
                    handleLogin(username, password)
                }
            }
        }
    }
}

四、GeometryReader与Path

  1. GeometryReader
GeometryReader { geometry in
    HStack(spacing: 0) {
        Text("Left")
            .font(.largeTitle)
            .foregroundColor(.black)
            .frame(width: geometry.size.width * 0.33)
            .background(Color.yellow)
        Text("Right")
            .font(.largeTitle)
            .foregroundColor(.black)
            .frame(width: geometry.size.width * 0.67)
            .background(Color.orange)
    }
}
.frame(height: 50)
  1. GeometryReader与Path
var body: some View {
       GeometryReader{ geometry in
             Path{ path in 
                path.moveto()
                path.addLine()
            }
      }
}
  1. Shape
struct Triangle: Shape {
    func path(in rect: CGRect) -> Path {
        var path = Path()

        path.move(to: CGPoint(x: rect.midX, y: rect.minY))
        path.addLine(to: CGPoint(x: rect.minX, y: rect.maxY))
        path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
        path.addLine(to: CGPoint(x: rect.midX, y: rect.minY))

        return path
    }
}

五、SwiftUI与UIKit组件互用。

  1. UIKit用SwiftUI
  let swiftUIView = Text("Jiang youhua") 
  let viewCtrl = UIHostingController(rootView: swiftUIView)
  1. UIView转SwiftUI
struct TextView: UIViewRepresentable {
    @Binding var text: NSMutableAttributedString

    func makeUIView(context: Context) -> UITextView {
        UITextView()
    }

    func updateUIView(_ uiView: UITextView, context: Context) {
        uiView.attributedText = text
    }

}
  1. UIViewController转SwiftUI
struct PageViewController<Page: View>: UIViewControllerRepresentable {
    var pages: [Page]

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    func makeUIViewController(context: Context) -> UIPageViewController {
        let pageViewController = UIPageViewController(
            transitionStyle: .scroll,
            navigationOrientation: .horizontal)

        return pageViewController
    }

    func updateUIViewController(_ pageViewController: UIPageViewController, context: Context) {
        pageViewController.setViewControllers(
            [context.coordinator.controllers[0]], direction: .forward, animated: true)
    }

    class Coordinator: NSObject, UIPageViewControllerDataSource {
        var parent: PageViewController
        var controllers = [UIViewController]()

        init(_ pageViewController: PageViewController) {
            parent = pageViewController
            controllers = parent.pages.map { UIHostingController(rootView: $0) }
        }

        func pageViewController(
            _ pageViewController: UIPageViewController,
            viewControllerBefore viewController: UIViewController) -> UIViewController?
        {
            guard let index = controllers.firstIndex(of: viewController) else {
                return nil
            }
            if index == 0 {
                return controllers.last
            }
            return controllers[index - 1]
        }

        func pageViewController(
            _ pageViewController: UIPageViewController,
            viewControllerAfter viewController: UIViewController) -> UIViewController?
        {
            guard let index = controllers.firstIndex(of: viewController) else {
                return nil
            }
            if index + 1 == controllers.count {
                return controllers.first
            }
            return controllers[index + 1]
        }
    }
}

好,我是姜友华,今天就到这里,下次见。

上一篇下一篇

猜你喜欢

热点阅读