SwiftUI簡單使用

SwiftUI入門教程
SwiftUI寫一個(gè)簡單的頁面
上面github鏈接教程寫的很詳細(xì),但有的api可能有點(diǎn)出入,最好還是clone項(xiàng)目,自己跑起來研究下。

廢話有點(diǎn)多,介意的直接看 正題三

寫在前面

這段時(shí)間公司業(yè)務(wù)不是很忙,我們一直處于新技術(shù)探究階段。前段時(shí)間學(xué)過flutter,總體來說還是很不錯(cuò),不管是集成三方包,還是vscode新api學(xué)習(xí)成本,又或狀態(tài)管理和路由管理的三方框架(如GetX) ,使用起來都特別順手方便。之前因?yàn)闃I(yè)務(wù)需求,一直用的都是熟悉的oc,對SwiftUI也只是聽聽,沒有怎么入手研究過??赡軐]有接觸過的人,對SwiftUI來說聽的最多的詞 應(yīng)該就是聲明式語言,UI庫,一統(tǒng)蘋果所有終端設(shè)備的新框架庫等等。通過這兩天的學(xué)習(xí)接觸 SwiftUI確實(shí)是很棒。不啰嗦啦,進(jìn)入正題~

@[TOC]

一、簡潔高效的@State

二、好用的全局環(huán)境變量@EnvironmentObject

1、優(yōu)點(diǎn)

2、代碼使用

三、SwiftUI調(diào)用舊vc

1、創(chuàng)建wrapper并實(shí)現(xiàn)UIViewControllerRepresentable協(xié)議

2、SwiftUI中調(diào)用TestViewController

四、ViewController里調(diào)用SwiftUI頁面

一、簡潔高效的@State
在flutter中若改變某個(gè)值需更新界面的話,需要setState,顯得很麻煩。但SwiftUI里面只要聲明一個(gè)@State變量就好,真的是太好用。例如下面代碼就是動態(tài)顯示slider滑動的值,binding也很簡潔,直接通過$加相應(yīng)的變量即可。這種binding在TextField真的是特別好用。oc那種delegate回調(diào)方式根本沒法比。

import SwiftUI
import Combine

struct SliderPage : View {
    
    @State var rating = 0.5

    var body: some View {
        VStack {
            Text("Slider Value: \(self.rating)")
            Slider(value: $rating)
                .padding(30)
            
        }.navigationBarTitle(Text("Slider"))
    }
}

二、好用的全局環(huán)境變量@EnvironmentObject

1、優(yōu)點(diǎn):整個(gè)app能全局共享該數(shù)據(jù),且一旦數(shù)據(jù)更新,用到該數(shù)據(jù)的地方都會相應(yīng)的更新。

2、代碼使用

全局order變量

import SwiftUI

@main
struct iDineApp: App {
    @StateObject var order = Order()

    var body: some Scene {
        WindowGroup {
            MainView()
                .environmentObject(order)
        }
    }
}

存儲信息的Order 模型

import SwiftUI

class Order: ObservableObject {
    @Published var items = [MenuItem]()

    var total: Int {
        if items.count > 0 {
            return items.reduce(0) { $0 + $1.price }
        } else {
            return 0
        }
    }

    func add(item: MenuItem) {
        items.append(item)
    }

    func remove(item: MenuItem) {
        if let index = items.firstIndex(of: item) {
            items.remove(at: index)
        }
    }
}

使用全局Order

import SwiftUI

struct OrderView: View {
    @EnvironmentObject var order: Order

    var body: some View {
        NavigationView {
            List {
                Section {
                    ForEach(order.items) { item in
                        HStack {
                            Text(item.name)
                            Spacer()
                            Text("$\(item.price)")
                        }
                    }
                    .onDelete(perform: deleteItems)
                }

                Section {
                    NavigationLink(destination: CheckoutView()) {
                        Text("Place Order")
                    }
                }
                .disabled(order.items.isEmpty)
            }
            .navigationTitle("Order")
            .listStyle(InsetGroupedListStyle())
            .toolbar {
                EditButton()
            }
        }
    }

    func deleteItems(at offsets: IndexSet) {
        order.items.remove(atOffsets: offsets)
    }
}

以上代碼來自github上iDine項(xiàng)目。


三、SwiftUI調(diào)用舊vc
SwiftUI如何調(diào)用項(xiàng)目中原來就有的ViewController?
思路:創(chuàng)建一個(gè)wrapper,實(shí)現(xiàn)UIViewControllerRepresentable協(xié)議,做相應(yīng)的映射。例如,現(xiàn)在有個(gè)TestViewController,我們?nèi)绾卧赟wiftUI點(diǎn)擊某個(gè)link跳轉(zhuǎn)到該頁面。

1、創(chuàng)建wrapper并實(shí)現(xiàn)UIViewControllerRepresentable協(xié)議

import UIKit
import SwiftUI

// 這里只能用struct,不能用class
struct BFOViewControllerWrapper<T : UIViewController>: UIViewControllerRepresentable {
    typealias UIViewControllerType = T

        func makeUIViewController(context: UIViewControllerRepresentableContext<BFOViewControllerWrapper>) -> BFOViewControllerWrapper.UIViewControllerType {
          return BFOViewControllerWrapper.UIViewControllerType()

        }

        func updateUIViewController(_ uiViewController: BFOViewControllerWrapper.UIViewControllerType, context: UIViewControllerRepresentableContext<BFOViewControllerWrapper>) {
            //
        }
}

2、SwiftUI中調(diào)用TestViewController

NavigationLink(
                        destination: BFOViewControllerWrapper<TestViewController>()) {
                        Text("跳轉(zhuǎn)到TestViewController頁面")
                    }

細(xì)心的網(wǎng)友,肯定注意到了上面的一個(gè)亮點(diǎn),對 就是泛型的使用。這樣使用雖然調(diào)用的時(shí)候感覺寫的字母多了點(diǎn),復(fù)雜了點(diǎn),但BFOViewControllerWrapper卻可以統(tǒng)一重復(fù)的使用,不但功能清晰,后續(xù)維護(hù)也很高效。


四、ViewController里調(diào)用SwiftUI頁面
將SwiftUI頁面放到一個(gè)UIHostingController里面,之后再正常跳轉(zhuǎn)。如下某個(gè)vc點(diǎn)擊按鈕跳轉(zhuǎn)到一個(gè)SwfitUI頁面

import UIKit
import SwiftUI

class TestViewController: UIViewController {
    lazy var lb: UILabel = {
        let lb = UILabel(frame: CGRect(x: 50, y: 100, width: 200, height: 50));
        lb.text = "我是UIViewController的文案"
        lb.textColor = .red
        lb.font = UIFont.systemFont(ofSize: 14)
        return lb
    }()
    
    lazy var btn: UIButton = {
        let btn = UIButton(frame: CGRect(x: 50, y: 200, width: 200, height: 50))
        btn.setTitle("點(diǎn)我展示SwiftUI頁面", for: .normal)
        btn.setTitleColor(.blue, for: .normal)
        btn.setTitleShadowColor(.red, for: .normal)
        btn.backgroundColor = .green
        btn.titleLabel?.font = UIFont.systemFont(ofSize: 14)
        btn.layer.cornerRadius = 10
        btn.layer.masksToBounds = true
        btn.addTarget(self, action: #selector(clickBtn(button:)), for: .touchUpInside)
        return btn
    }()
    // 點(diǎn)擊按鈕跳轉(zhuǎn)到SwiftUI頁面
    @objc func clickBtn(button: UIButton){
        print("you click btn")
        if #available(iOS 13, *) {
            let testSwiftUIView = UIHostingController(rootView: TextPage())
            navigationController?.pushViewController(testSwiftUIView, animated: true)
        }
    }
    override func viewDidLoad() {
        super.viewDidLoad()

        view.addSubview(lb);
        view.addSubview(btn)
    }

}

附:Swift高階函數(shù)map,filter,reduce簡單使用
map用于映射,可將一個(gè)列表轉(zhuǎn)化成另一個(gè)列表,例如下面將數(shù)字列表轉(zhuǎn)成字符串列表

//$0代表數(shù)組的元素
let array = [1, 2, 3, 4, 5 , 6, 7]
let result = array.map {
  String($0)
}

filter 用于過濾,可以對數(shù)組中的元素按照某種規(guī)則進(jìn)行過濾,例如下面輸出大于5的元素

let array = [1, 2, 3, 4, 5 , 6, 7]
let result = array.filter {
          $0 > 5
}
print("result: \(result)");

reduce用于計(jì)算或合并

//計(jì)算數(shù)組array元素的和
//在這里$0和$1的意義不同,$0代表元素計(jì)算后的結(jié)果,$1代表元素
//10代表初始化值,在這里可以理解為 $0初始值 = 10
let result3 = array.reduce(10){  
  $0 + $1
}

合并

let result4 = array.reduce(""){$0 + "\($1)"}// 轉(zhuǎn)換為字符串并拼接
print("result4:",result4);

參考鏈接,感謝分享??

end

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容