iOS-项目实战Swift

SwiftUI教程一:搭建一个简单的应用

2020-07-08  本文已影响0人  狂奔的胖蜗牛

1 目的

使用SwiftUI搭建一个应用,从这个应用中,先熟悉SwiftUI如何使用,以及部分与UIKit的区别。

2 搭建

2.1 新建一个SwiftUI的项目

打开Xcode -> Create a new Xcode project -> iOS -> Single View App


image.png

Language选择swift,User Interface选择SwiftUI,输入相关信息,选择Next创建新项目。

点击预览界面Resume,即可查看预览。


image.png

初始项目预览如下:


image.png

2.2 创建出一个列表

先看一下左侧的导航栏


image.png

和UIKit项目类似,但是没有了ViewController,也没有storyboard,点开AppDelegate和SceneDelegate,查看,发现在SceneDelegate里有如下代码:

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {

        let contentView = ContentView()
        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            window.rootViewController = UIHostingController(rootView: contentView)
            self.window = window
            window.makeKeyAndVisible()
        }
    }
@available(iOS 13.0, tvOS 13.0, *)
@available(OSX, unavailable)
@available(watchOS, unavailable)
open class UIHostingController<Content> : UIViewController where Content : View {
    public init(rootView: Content)

    public init?(coder aDecoder: NSCoder, rootView: Content)

    @objc required dynamic public init?(coder aDecoder: NSCoder)

    @objc override dynamic open func viewWillAppear(_ animated: Bool)

    public var rootView: Content

    public func sizeThatFits(in size: CGSize) -> CGSize

    @objc override dynamic open var preferredStatusBarStyle: UIStatusBarStyle { get }

    @objc override dynamic open var prefersStatusBarHidden: Bool { get }

    @objc override dynamic open var preferredStatusBarUpdateAnimation: UIStatusBarAnimation { get }

    @objc override dynamic public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?)
}

可以得出很多信息:
1.该类适用iOS 13+,tvOS 13+,而OSX、watchOS不能使用。
2.该类继承自UIViewController。
3.rootView是View。
4.该类的方法能看出,该类可以控制顶部状态栏状态、显隐等。
可以得出结论,该类是控制SwiftUI显示的VC,SwiftUI的内容需要通过该类来显示,作用同UIKite的VC。

接下来看看ContentView的内容:

import SwiftUI

struct ContentView: View {
    var body: some View {
        Text("Hello, World!")
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
public protocol View {
    associatedtype Body : View
    var body: Self.Body { get }
}

可以看到,View是一个协议,其中有一个泛型属性Body,在重写body属性时,SwiftUI会自己判断出Body的类型,还有一个属性body,重写该属性get方法,在get方法内,控制界面的显示与动作等。

接下来,创建出一个列表,内容包含5条Hello World!。代码如下:

struct ContentView: View {
    var body: some View {
        List {
            Text("Hello World!")
            Text("Hello World!")
            Text("Hello World!")
            Text("Hello World!")
            Text("Hello World!")
        }
    }
}

预览如下:


image.png
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
public struct List<SelectionValue, Content> : View where SelectionValue : Hashable, Content : View {
    @available(watchOS, unavailable)
    public init(selection: Binding<Set<SelectionValue>>?, @ViewBuilder content: () -> Content)
    @available(watchOS, unavailable)
    public init(selection: Binding<SelectionValue?>?, @ViewBuilder content: () -> Content)
    public var body: some View { get }
    public typealias Body = some View
}

1.List继承自View,说明是SwiftUI的内容。
2.List是一个容器,能够排列显示单行内容,效果类似于UIKit的UITableView。

extension Text {
//设置文字颜色
    public func foregroundColor(_ color: Color?) -> Text
//设置文字字体
    public func font(_ font: Font?) -> Text
//设置文字宽度
    public func fontWeight(_ weight: Font.Weight?) -> Text
//设置文字粗细
    public func bold() -> Text
//设置文字斜体
    public func italic() -> Text
//设置文字删除线
    public func strikethrough(_ active: Bool = true, color: Color? = nil) -> Text
//设置文字下划线
    public func underline(_ active: Bool = true, color: Color? = nil) -> Text
//设置文字字距
    public func kerning(_ kerning: CGFloat) -> Text
//设置单词间隔
    public func tracking(_ tracking: CGFloat) -> Text
//设置基准线偏移
    public func baselineOffset(_ baselineOffset: CGFloat) -> Text
}

Text继承自View,说明是SwiftUI的内容。作用类似于UIKit的UILabel。

2.3 创建导航栏

如下代码即可创建出导航栏

struct ContentView: View {
    var body: some View {
        NavigationView {
            List {
                Text("Hello World!")
                Text("Hello World!")
                Text("Hello World!")
                Text("Hello World!")
                Text("Hello World!")
            }
        }
    }
}

预览图:


image.png

接下来设置标题,由于是给NavigationView包含着List,所以标题应该是由List来设置的。

struct ContentView: View {
    var body: some View {
        NavigationView {
            List {
                Text("Hello World!")
                Text("Hello World!")
                Text("Hello World!")
                Text("Hello World!")
                Text("Hello World!")
            }.navigationBarTitle(Text("Hello World!"))
        }
    }
}

预览图:


image.png
public struct NavigationView<Content> : View where Content : View {

    public init(@ViewBuilder content: () -> Content)
    public typealias Body = Never
}

可以看出是SwiftUI特有的,作用类似于UIKit的UINavigationVontroller。管理界面跳转等做用。

public func navigationBarTitle(_ title: Text) -> some View

可以看到,该方法需要传入一个Text,然后将它在顶部导航栏上显示出来。

2.4 显示图片名称列表

我们拖4张图片到项目中,然后将图片名字在列表中显示出来。


image.png

创建出数据对象

import Combine

class DataSource: ObservableObject {
    let didChange = PassthroughSubject<Void, Never>()
    var picture = [String]()
    init() {
        let fm = FileManager.default
        if let path = Bundle.main.resourcePath, let items = try? fm.contentsOfDirectory(atPath: path) {
            items.forEach {
                if $0.hasSuffix("jpg") {
                    picture.append($0)
                }
            }
        }
        didChange.send()
    }
}

将数据与界面进行绑定

struct ContentView: View {
    @ObservedObject var dataSource = DataSource()
    var body: some View {
        NavigationView {
            List(dataSource.picture, id: \.self) {
                Text($0)
            }.navigationBarTitle(Text("Hello World!"))
        }
    }
}

预览:


image.png

2.5 跳转图片查看页面

新建一个查看页View

struct DetailView: View {
    var iamgeName: String
    var body: some View {
        let image = UIImage(named: iamgeName)
        return Image(uiImage: image!)
            .resizable()
            .aspectRatio(1024/768,contentMode: .fit)
            .navigationBarTitle(Text(iamgeName), displayMode: .inline)
    }
}

Image在SwiftUI中是图片控件,等同于UIKit的UIImageView。
resizable方法,使Image能够进行改变,不调用该方法,则Image大小固定。
aspectRatio方法,设置Image内图片的缩放方法。

增加跳转代码

struct ContentView: View {
    @ObservedObject var dataSource = DataSource()
    var body: some View {
        NavigationView {
            List(dataSource.picture, id: \.self) {
                NavigationLink($0, destination: DetailView(iamgeName: $0))
            }.navigationBarTitle(Text("Hello World!"))
        }
    }
}

使用NavigationLink即可,初始化的时候指定跳转到DetailView。


2.6 给图片增加点击事件

struct DetailView: View {
    var iamgeName: String
    @State var hideTitle = false
    var body: some View {
        let image = UIImage(named: iamgeName)
        return Image(uiImage: image!)
            .resizable()
            .aspectRatio(1024/768,contentMode: .fit)
            .navigationBarTitle(Text(iamgeName), displayMode: .inline)
            .navigationBarHidden(hideTitle)
            .onTapGesture {
                self.hideTitle.toggle()
            }
    }
}

添加一个hideTitle属性,使用@State属性装饰器修饰,表示该值能够与View进行绑定。
hideTitle.toggle()对hideTitle进行修改。


image.png

点击图片,则上方title消失。

3 全部代码

import SwiftUI
import Combine

class DataSource: ObservableObject {
    let willChange = PassthroughSubject<Void, Never>()
    var picture = [String]()
    init() {
        let fm = FileManager.default
        if let path = Bundle.main.resourcePath, let items = try? fm.contentsOfDirectory(atPath: path) {
            items.forEach {
                if $0.hasSuffix("jpg") {
                    picture.append($0)
                }
            }
        }
        willChange.send()
    }
}

struct ContentView: View {
    @ObservedObject var dataSource = DataSource()
    var body: some View {
        NavigationView {
            List(dataSource.picture, id: \.self) {
                NavigationLink($0, destination: DetailView(iamgeName: $0))
            }.navigationBarTitle(Text("Hello World!"))
        }
    }
}

struct DetailView: View {
    var iamgeName: String
    @State var hideTitle = false
    var body: some View {
        let image = UIImage(named: iamgeName)
        return Image(uiImage: image!)
            .resizable()
            .aspectRatio(1024/768,contentMode: .fit)
            .navigationBarTitle(Text(iamgeName), displayMode: .inline)
            .navigationBarHidden(hideTitle)
            .onTapGesture {
                self.hideTitle.toggle()
            }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
上一篇下一篇

猜你喜欢

热点阅读