preface

Since getting into Flutter and understanding the modern Web framework, looking back on iOS’s native imperative UI capacity is pretty low, it’s like riding a bike and racing a car.

What’s the problem?

  1. No response, nosetState()This can be done with the binding of RxSwift.
  2. Without declarative, the code and effects of traditional imperative UIs don’t match.
  3. Without JIT, compilation takes a lot of time.

Imperative issues are not a silver bullet in Tao wen’s object orientation, nor is DDD, and are discussed in more depth in TypeScript:

Many states are concurrently/Parallel. Either way, it is more complex than sequential. Well, I’ve got a Long range of causality

SwiftUI?

SwiftUI is beautiful, and even supports Hot Reload, but it can’t be far away. The minimum threshold of iOS 13+ blocks most domestic apps, just like the previous UIStackView, out of reach in a few years.

UIStackView?

Last year, the App was finally upgraded to iOS 9 with minimum support, so Amway released a wave of UIStackView. It does implement a lot of FlexBox features, but is StackView really a statement?

headerStackView.axis = .horizontal
headerStackView.addArrangedSubviews([headerLeftLine,
                                    headerLabel,
                                    headerRightLine])
headerStackView.alignment = .center
headerStackView.snp.makeConstraints {
    $0.centerX.equalToSuperview()
}
Copy the code

I can only say a little declarative.

Decide to encapsulate yourself

UIStackView is powerful enough. The problem is that the call layer is not friendly enough. If it had a Flutter/Dart face, it would have survived.

Introduce DeclarativeSugar

Look directly at the effect

Contrast with the grammar of Flutter

Develop quickly with Playground

What does it encapsulate?

  • Declarative UI
  • Hides the complexity and terminology of UIStackView
  • Supports flexible nesting of UIStackView
  • In support of Flutterbuild()Entry and update methodsrebuild()
  • supportRow/Column.Spacer (sizedBox in Flutter)
  • Support listListView (UITableView in UIKit)
  • Support constraintPadding Center SizedBox
  • Support gesturesGestureDetector

Minimum version: iOS 9 Dependency: UIKit

It is recommended to use Then for initialization syntactic sugar. Another goal of this package is to reduce or eliminate situations where constraints are directly used

The code structure

The installation

DeclarativeViewController or DeclarativeView inheritance

class ViewController: DeclarativeViewController {... }Copy the code

Rewrite build() to return your UI, just like Flutter. This View is going to be added to the View of the ViewController, and it’s going to be full-screen.

override func build(a) -> DZWidget {
    return. }Copy the code

function

1. Row

Horizontal layout with Flutter Row

DZRow(
    mainAxisAlignment: ... // UIStackView.Distribution
    crossAxisAlignment: ... // UIStackView.Alignmentchildren: [ ... ] )Copy the code

2. Column

The vertical layout of the Flutter Column

DZColumn(
    mainAxisAlignment: ... // UIStackView.Distribution
    crossAxisAlignment: ... // UIStackView.Alignmentchildren: [ ... ] )Copy the code

3. Padding

Inner Padding with Flutter Padding

3.1 only

 DZPadding(
    edgeInsets: DZEdgeInsets.only(left: 10, top: 8.right: 10, bottom: 8),
    child: UILabel().then { $0.text = "hello world"}),Copy the code

3.2 symmetric

 DZPadding(
    edgeInsets: DZEdgeInsets.symmetric(vertical: 10, horizontal: 20),
    child: UILabel().then { $0.text = "hello world"}),Copy the code

3.3 all

 DZPadding(
    edgeInsets: DZEdgeInsets.all(16),
    child: UILabel().then { $0.text = "hello world"}),Copy the code

4. Center

CenterX and centerY at Autolayout

DZCenter(
    child: UILabel().then { $0.text = "hello world"})Copy the code

5. SizedBox

Wide high constraint

DZSizedBox(
    width: 50, 
    height: 50, 
    child: UIImageView(image: UIImage(named: "icon")))Copy the code

6. Spacer

Parking space

For Row: Set width with the SizedBox of the Flutter.

DZRow(
    children: [
        ...
        DZSpacer(20), 
        ...
    ]
)
Copy the code

Set height for Column: with the SizedBox of the Flutter.

DZColumn(
    children: [
        ...
        DZSpacer(20), 
        ...
    ]
)
Copy the code

7. ListView

The list of

Hide the delegate/datasource and UITableViewCell concepts

Static form

 DZListView(
    tableView: UITableView().then { $0.separatorStyle = .singleLine },
    sections: [
        DZSection(
            cells: [
                DZCell(
                    widget: ...,
                DZCell(
                    widget: ...,
            ]),
        DZSection(
            cells: [
                DZCell(widget: ...)
            ])
    ])
Copy the code

The dynamic form

return DZListView(
    tableView: UITableView(),
    cells: ["a"."b"."c"."d"."e"].map { model in 
        DZCell(widget: UILabel().then { $0.text = model })
    }
)
Copy the code

8. Stack

The Flutter stack, not the UIStackView, handles the superposition of two pages

DZStack(
    edgeInsets: DZEdgeInsets.only(bottom: 40), 
    direction: .horizontal, // center direction
    base: YourViewBelow,
    target: YourViewAbove
)
Copy the code

9. Gesture

Support for click events (Child is UIView call TapGesture, UIButton call touchUpInside) support for recursive lookup, that is, the passed child can be a DZWidget with many layers nested

DZGestureDetector(
    onTap: { print("label tapped") },
    child: UILabel().then { $0.text = "Darren"})DZGestureDetector(
    onTap: { print("button tapped") },
    child: UIButton().then {
        $0.setTitle("button".for: UIControl.State.normal)
        $0.setTitleColor(UIColor.red, for: UIControl.State.normal)
}),
Copy the code

10. AppBar

Support setting navigation bar, this control is just a configuration class

DZAppBar(
    title: "App Bar Title",
    child: ... 
)
Copy the code

The refresh

Heavy brush

self.rebuild {
    self.hide = !self.hide
}
Copy the code

Incremental refresh

UIView.animate(withDuration: 0.5) {
    // incremental reload
    self.hide = !self.hide
    self.context.setSpacing(self.hide ? 50 : 10.for: self.spacer) // Support changing interval distance
    self.context.setHidden(self.hide, for: self.label) // Support hiding
}
Copy the code

conclusion

This lightweight package has reduced the cognitive burden of daily UI writing and increased productivity. (Programmers will do anything to be lazy.)

Although this can’t be done with Flutter widgets or Element Tree optimizations, it can be done with relatively static pages where the layout doesn’t change much. (Just a Fancy UITableView/UIStackView)

If you also feel useful, welcome to improve together.

GitHub address: DeclarativeSugar