First impressions of SwiftUI

#Mở đầu

Tại sự kiện WWDC 2019, Apple đã giới thiệu một thay đổi lớn đối với các lập trình viên iOS đó là SwiftUI - bộ toolkit cho phép các nhà phát triển thiết kế các ứng dụng declarative UI (thay vì imperative UI như trước đây - dùng oultet, storyboard.. ) trên cả iOS, MacOS, TvOS .

#SwiftUI

Trước khi tìm hiểu SwiftUI mình xin lưu ý vớ các bạn về ImperativeDeclarative programming:

  • Imperative programming: telling the “machine” how to do something, and as a result what you want to happen will happen.
  • Declarative programming: telling the “machine” what you would like to happen, and let the computer figure out how to do it.

Sự khác nhau ở đây là "how" và "what" , với imperative programming chúng ta sẽ chỉ ra các bước, cách thức thực hiện để cho ra input như mong muốn, còn declarative chúng ta chỉ cần nói input mong muốn còn lại mọi việc machine sẽ xử lý. Liên tưởng đến việc nhờ đứa em lấy giúp quyển sách:

  • Imperative programming: bước xuống giường, xuống cầu thang, quẹo phải, mở tủ sách, lấy sách tên...
  • Declarative programming: lấy giúp tao quyển sách đê =))

SwiftUI là một frameworks giúp tạo ra các declarative UI, tức là deveoloper chỉ cần định nghĩa ra giao diện mong muốn, mọi việc resize, scale, self-sizing... SwiftUI sẽ xử lý ✌️

Một số ưu điểm của SwiftUI:

  • Sử dụng declarative syntax rất "hiện đại", quen thuộc với các bạn đã từng làm Flutter hoặc React.
  • Support Self-sizing.
  • Code ngắn gọn dễ hiểu.
  • Có thể tổ chức view kiểu component nên dễ dàng reuse.
  • Tự động update UI khi data state thay đổi.
  • Hỗ trợ dynamic type và dark mode.

#Basic View

Trong bài viết này mình sẽ giới thiệu với các bạn một số đối tượng View cơ bản trong SwiftUI:

Text

Text("SwiftUI")
    .color(.orange)
    .bold()
    .font(.system(.largeTitle))
    .fontWeight(.medium)
    .italic()
    .shadow(color: .black, radius: 1, x: 0, y: 2)

Example:

TextField - SecureField


TextField(self.$name, placeholder: self.nameText, 
onEditingChanged: { changed in
    print("onEditing: \(changed)")
}) {
    print("userName: \(self.name)")
    self.endEditing(true)
}}
.padding(10)
.frame(height: 50)
.textFieldStyle(.roundedBorder)
.padding(EdgeInsets(top: 0, leading: 20, bottom: 0, trailing: 20))

Example:

WebImage

var body: some View {
        Image(uiImage: self.uiImage ?? placeholderImage)
            .resizable()
            .onAppear(perform: downloadWebImage)
            .frame(width: Length(80),
                   height: Length(80),
                   alignment: .center)
            .tapAction {
                print("Tap ")
        }
    }

Example:

Button

Button(action: {
    print("Tap")
}) {
   Text("I'm a Button")
}

Example:

Picker

Picker(selection: $leftIndex, label: Text("Picker")) {
    ForEach(0..<leftSource.count) {
        Text(self.leftSource[$0]).tag($0)
    }
 }.frame(width: UIScreen.main.bounds.width/2)

Example:

DatePicker

DatePicker(
    $server.date,
    minimumDate: Calendar.current.date(byAdding: .year,
                                       value: -1,
                                       to: server.date),
    maximumDate: Calendar.current.date(byAdding: .year,
                                       value: 1,
                                       to: server.date),
    displayedComponents: .date
)

Example:

Slider

    Slider(value: $data.rating)

Example:

Stepper

Stepper(value: $value, step: 2, onEditingChanged: { c in
    print(c)
}) {
    Text("Stepper Value: \(self.value)")
}.padding(50)

Example:

SegmentedControl

SegmentedControl(selection: $currentIndex) {
    ForEach(0..<items.count) { index in
        Text(self.items[index]).tag(index)
    }
    }.tapAction {
        print("currentIndex: \(self.currentIndex)")
}

Example:

WebView

struct WebViewPage : UIViewRepresentable {
    func makeUIView(context: Context) -> WKWebView  {
        return WKWebView()
    }
    
    func updateUIView(_ uiView: WKWebView, context: Context) {
        let req = URLRequest(url: URL(string: "https://www.apple.com")!)
        uiView.load(req)
    }
}

Example:

List

List(0..<5) { item in
    Text("Hello World !")
}.navigationBarTitle(Text("List"), displayMode: .large)

Example:

NavigationView

NavigationView {
    Text("🧚‍♂️🧚‍♀️🧜‍♂️🧜‍♀️🧞‍♂️🧞‍♀️").blur(radius: 5)
    Text("Swifter Swifter").bold().color(.orange).font(.largeTitle)
}.navigationBarTitle(Text("NavigationView"))

Example:

TabBar

TabbedView(selection: $index) {
    ForEach(0 ..< imgs.count) { item in
        TabItemPage(index: item)
            .tabItemLabel(Image(self.imgs[item]))
            .tag(item)
    }
}

Example:

Alert

presentation($showsAlert,
        alert: {
                Alert(title: Text("Hello"))
       })

Example:

ActionSheet

ActionSheet(title: Text("Title"),
            message: Text("Message"),
            buttons:
    [.default(Text("Default"), onTrigger: {
        print("Default")
        self.showSheet = false
    }),.destructive(Text("destructive"), onTrigger: {
        print("destructive")
        self.showSheet = false
    }),.cancel({
        print("Cancel")
        self.showSheet = false
    })])

Example:

#Kết

Trên đây là bài giới thiệu cơ bản về SwiftUI, dễ dàng nhận thấy SwiftUI sẽ mang đến cho chúng ta một phong cách thiết kế ứng dụng khác với trước đây, việc xây dựng giao diện sẽ nhanh chóng và ngắn gọn hơn, việc binding dữ liệu cũng trở nên nhẹ nhàng hơn trước. Tuy nhiên vì chỉ hoạt động trên iOS 13 trở về sau nên việc áp dụng SwiftUI trong các project sẽ còn phải đợi 1 - 2 năm nửa, nhưng chúng ta nên đầu tư từ bây giờ để sau này khỏi phải bỡ ngỡ, chắc chắn SwiftUI sẽ là một cái gì đó rất là này nọ để giúp cho việc phát triển các ứng dụng iOS trở nên "trong sáng" và dễ dàng hơn.

Ở phần sau mình sẽ giới thiệu với các bạn về cách layout với SwiftUI, hẹn gặp lại .

Link tham khảo: https://github.com/Jinxiansen/SwiftUI