魏名华

不要偷懒,做更好的自己

Nothing


No Welcome Message

SwiftUI 相关

2个问题:1、怎么开发;2、怎么用在现有的项目中?

开发

资源

https://developer.apple.com/tutorials/swiftui:官方教程,有好几个章节,并且有配套的example

https://onevcat.com/2019/06/swift-ui-firstlook/:喵神写的《SwiftUI 的一些初步探索》

SwiftUI app 的启动

教程示例 app 在 AppDelegate 中通过 application(_:configurationForConnecting:options) 返回了一个名为 “Default Configuration” 的 UISceneConfiguration 实例:

func application(
    _ application: UIApplication,
    configurationForConnecting connectingSceneSession: UISceneSession,
    options: UIScene.ConnectionOptions) -> UISceneConfiguration
{
    return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}

这个名字的 Configuration 在 Info.plist 的 “UIApplicationSceneManifest -> UISceneConfigurations” 中进行了定义,指定了 Scene Session Delegate 类为 $(PRODUCT_MODULE_NAME).SceneDelegate。这部分内容是 iOS 13 中新加入的通过 Scene 管理 app 生命周期的方式,以及多窗口支持部分所需要的代码。这部分不是我们今天的话题。在 app 完成启动后,控制权被交接给 SceneDelegate,它的 scene(_:willConnectTo:options:) 将会被调用,进行 UI 的配置:

func scene(
        _ scene: UIScene,
        willConnectTo session: UISceneSession,
        options connectionOptions: UIScene.ConnectionOptions)
    {
        let window = UIWindow(frame: UIScreen.main.bounds)
        window.rootViewController = UIHostingController(rootView: ContentView())
        self.window = window
        window.makeKeyAndVisible()
    }

这部分内容就是标准的 iOS app 启动流程了。UIHostingController 是一个 UIViewController 子类,它将负责接受一个 SwiftUI 的 View 描述并将其用 UIKit 进行渲染 (在 iOS 下的情况)。

UIHostingController 就是一个普通的 UIViewController,因此完全可以做到将 SwiftUI 创建的界面一点点集成到已有的 UIKit app 中,而并不需要从头开始就是基于 SwiftUI 的构建。

  1. 是吗,也就是说,可以在现有项目中,使用UIHostingController,就能使用 SwiftUI ?
  2. UIScene: 需要进一步了解!

关于 some View

some View 这种写法使用了 Swift 5.1 的 Opaque return types 特性。它向编译器作出保证,每次 body 得到的一定是某一个确定的,遵守 View 协议的类型,但是请编译器“网开一面”,不要再细究具体的类型。

具体看喵神的文章,写的一清二楚

UI

搭积木式的开发,参考官方sample

数据流

  1. 在View的内部,可以使用state,跟react很像

@State var showFavoritesOnly = false

  1. 数据绑定BindableObject

仅仅是data肯定是不能绑定ui的,所以RxSwift使用Observable,ui使用的是Observable里面的数据,而不是直接使用data,这样observable变化,ui可以实时绑定更新。BindableObject也是一样的道理。

开始觉得:在Landmarks的代码中,很明显SwiftUI使用的是双向绑定,并不是单向数据流,整个数据流程,跟RxSwift差别还是挺大的,虽然看起来简洁,但是感觉乱糟糟的一团,尤其是LandmarkDetail,传进来一个landmark,还要再从userData里面去获取对应的index,需要去动态改userData里面的landmark,而不是列表点击传进来的landmark

后来觉得:好像SwiftUI某些更简洁,某些时候也很复杂,ui使用BindableObject的数据,都不用订阅,只要BindableObject数据变化,send一下,UI就能刷新,好像是更简洁。但是在detail页面,又要通过index去取BindableObject的数据,有点复杂化了,不知道有没有好办法。

其他

  1. 2种方法来让list所用的数据变成 identifiable
Lists work with identifiable data. You can make your data identifiable in one of two ways: by calling the identified(by:) method with a key path to a property that uniquely identifies each element, or by making your data type conform to the Identifiable protocol.
struct Landmark: Hashable, Codable {
    var id: Int
}

List(landmarkData.identified(by: \.id)) { landmark in

}
struct Landmark: Hashable, Codable, Identifiable {
    var id: Int
}

List(landmarkData) { landmark in

}
  1. vector based 的图片,可以随意修改前景色,不是说有的都可以吗?
Because system images are vector based, you can change their color with the foregroundColor(_:) modifier.
  1. list
// 只显示数据列表
List(landmarkData) { landmark in
    if !self.showFavoritesOnly || landmark.isFavorite {
        NavigationLink(destination: LandmarkDetail(landmark: landmark)) {
            LandmarkRow(landmark: landmark)
        }
    }
}

// 加一些类似headerview,list就不能直接使用landmarkData参数了,而是在闭包里面forEach
List {
    Toggle(isOn: $userData.showFavoritesOnly) {
        Text("Show Favorites Only")
    }
    
    ForEach(userData.landmarks) { landmark in
        if !self.userData.showFavoritesOnly || landmark.isFavorite {
            NavigationButton(
            destination: LandmarkDetail(landmark: landmark)) {
                LandmarkRow(landmark: landmark)
            }
        }
    }
}
  1. Button这里为什么是Label,搞不懂

public init(action: @escaping () -> Void, label: () -> Label)

Button(action: {
    withAnimation {
    	self.showDetail.toggle()
    }
}) {
    Image(systemName: "chevron.right.circle")
        .imageScale(.large)
        .rotationEffect(.degrees(showDetail ? 90 : 0))
        .scaleEffect(showDetail ? 1.5 : 1)
        .padding()
}
  1. 原来SwiftUI的定义在一个文件里面,10000多行,Foundation也是一样,有点意思,为什么

  2. 真个动画这一节不太明白,有空再细细研究

  3. sample都编译不通过,我还玩个球