WKStackUIKit 0.0.36

WKStackUIKit 0.0.36

Calvin 维护。



  • CalvinChina

StackUI

中文文档

像 SwiftUI 一样使用 UIStackView

使用 @propertyWrapper@resultBuilder、链式语法和其他在 SwiftUI 中使用的功能,使 UIStackView 更易于使用。对于类如 LabelButtonImageView,仍然按照 UIKit 的方式使用,但使用链式语法进行了封装。

由于 SwiftUI 需要iOS13+ 系统,因此在实际项目中几乎不可能使用 SwiftUI。但 SwiftUI 的功能确实非常吸引人,因此 StackUI 是在 UIStackView 范围内实现 SwiftUI 的。您可以在 StackUI 中体验一些 SwiftUI 的功能,这样您就可以更早地学习新功能。

如果您厌倦了配置 UIKit 的约束,那么 StackUI 将是您的得力助手。声明式布局使世界更美好。

功能

  • 类似于 SwiftUI 的声明式语法;
  • 数据驱动的 UI,数据更新后 UI 自动更新;
  • 支持 HScrollStackVScrollStack,当内容超出堆叠的宽度和高度时,滚动将自动启用;
  • 链式语法配置 UIKit;
  • 可以灵活扩展自定义类以支持 StackUI

需求

  • iOS 9.0+
  • XCode 13.0+
  • Swift 5.4+

安装

CocoaPods

target'<Your Target Name>' do
    pod'StackUI'
    //If you want to use RxSwift
    pod'StackUI/RxSwift'
end

先执行 pod repo update,然后执行 pod install

SPM

  • 文件> Swift Packages> 添加包依赖
  • 添加 https://github.com/CalvinChina/StackUI.git
  • 选择 "Up to Next Major" 并设置为 "0.0.5"
  • 如果需要使用 RxSwift 特性,请选择 StackUISwithRxSwift 产品

示例

HStack

    HStack(alignment: .center, spacing: 5) {
        ImageView().image(UIImage(named: "avatar")).size(width: 40, height: 40)
        Label("user nickname").font(.systemFont(ofSize: 18, weight: .medium))
    }

VStack

    VStack {
        Label("user nickname").font(.systemFont(ofSize: 18, weight: .medium))
        Label().text("The user is lazy, nothing left!").font(.systemFont(ofSize: 12)).textColor(.gray)
    }

HScrollStackForIn

    var users = [UserModel]()
    for index in 0...25 {
        let model = UserModel(avatar: "avatar", name: "user\(index)", desc: "user description\(index)")
        users.append(model)
    }
    HScrollStack() {
        for model in users {
            HStack(alignment: .center, spacing: 5) {
                Spacer(spacing: 12)
                ImageView().image(UIImage(named: model.avatar)).size(width: 80, height: 80)
                VStack {
                    Label(model.name).font(.systemFont(ofSize: 18, weight: .medium))
                    Label().text(model.desc).font(.systemFont(ofSize: 12)).textColor(.gray)
                }
                Divider()
            }.size(width: 300)
        }
    }

@Live

在属性前添加 @Live,使用时加上 $ 符号前缀。更新属性时,关联的 UIKit 将自动更新界面。

    //definition
    @Live var nickName: String? = "User nickname"
    @Live var desc: String? = "The user is lazy, and nothing is left!"
    
    //use
    HStack(distribution: .equalCentering, alignment: .center) {
        HStack(alignment: .center, spacing: 5) {
            ImageView().image(UIImage(named: "avatar")).size(width: 40, height: 40)
            VStack {
                Label($nickName).font(.systemFont(ofSize: 18, weight: .medium))
                Label().text($desc).font(.systemFont(ofSize: 12)).textColor(.gray)
            }
        }
        ImageView().image(UIImage(named: "arrow_right"))
    }
    
    //update
    nickName = "Jay Chou"
    desc = "Ouch, not bad ❤️"

RxSwiftDriver

    //definition
    var nickName = PublishSubject<String?>()
    var desc = PublishSubject<String?>()
    
    //use
    HStack(distribution: .equalCentering, alignment: .center) {
        HStack(alignment: .center, spacing: 5) {
            ImageView().image(UIImage(named: "avatar")).size(width: 40, height: 40)
            VStack {
                Label(nickName.asDriver(onErrorJustReturn: nil)).font(.systemFont(ofSize: 18, weight: .medium))
                Label().text(desc.asDriver(onErrorJustReturn: nil)).font(.systemFont(ofSize: 12)).textColor(.gray)
            }
        }
        ImageView().image(UIImage(named: "arrow_right"))
    }
    
    //update
    nickName.onNext("Jay Chou")
    desc.onNext("Ouch, not bad ❤️")

自定义视图支持 StackUI

您可以自定义父类

ViewLabel 等继承,然后扩展自定义属性。

class CustomView: View {
    var customColor: UIColor = .black
    
    func customColor(_ customColor: UIColor) -> Self {
        self.customColor = customColor
        self.backgroundColor = customColor
        return self
    }
}
class CustomLabel: Label {
    var customColor: UIColor = .black
    
    func customColor(_ customColor: UIColor) -> Self {
        self.customColor = customColor
        self.textColor = customColor
        return self
    }
}

条件语句

     var isShowInfo: Bool = false
     HStack(distribution: .equalCentering, alignment: .center) {
         HStack(alignment: .center, spacing: 5) {
             ImageView().image(UIImage(named: "avatar")).size(width: 40, height: 40)
             if self.isShowInfo == true {
                 VStack {
                     Label("User nickname").font(.systemFont(ofSize: 18, weight: .medium))
                     Label().text("The user is lazy, nothing left!").font(.systemFont(ofSize: 12)).textColor(.gray)
                 }
             }else {
                 Label("No Information")
             }
         }
         ImageView().image(UIImage(named: "arrow_right"))
     }

父类不能修改,必须遵循协议

遵循如 StackUIViewStackUILabel 的协议,然后扩展自定义属性。

class CustomViewFromProtocol: UIView, StackUIView {
    var customColor: UIColor = .black
    
    func customColor(_ customColor: UIColor) -> Self {
        self.customColor = customColor
        self.backgroundColor = customColor
        return self
    }
}
class CustomLabelFromProtocol: UILabel, StackUILabel {
    var customColor: UIColor = .black
    
    func customColor(_ customColor: UIColor) -> Self {
        self.customColor = customColor
        self.textColor = customColor
        return self
    }
}

尚不支持链式语法进行属性配置

通过apply closure进行统一配置

HStack(alignment: .center, spacing: 5) {
     Label().text(model.desc).apply {label in
         //If there are attributes that are not defined by the chain syntax, they can be configured in the apply closure, or they can be submitted to Issue for support.
         label.font = UIFont.systemFont(ofSize: 10)
         label.textColor = .gray
     }
}

ViewBox 使用

有时视图需要边距。此时,您可以先将视图放入ViewBox中,然后再设置内边距,这样可以间接设置视图的上、下、左、右边距。如下代码所示:标签的上、左、下、右边距分别为top: 10, left: 20, bottom: 10, right: 20

ViewBox(paddings: .init(top: 10, left: 20, bottom: 10, right: 20)) {
     Label("Hobbies: writing code;").font(. systemFont(ofSize: 15)).numberOfLines(0)
}.backgroundColor(.lightGray)

当前支持的类

  • Layer的相关属性在View类中进行配置
  • View
  • ImageView
  • Control
  • Label
  • Button
  • TextField
  • TextView
  • Stepper
  • SwitchUI
  • PageControl
  • Slider
  • Spacer
  • Divider
  • ActivityIndicatorView
  • ScrollView
  • TableView
  • CollectionView

如果有其他需要支持的类和属性,请提交Issue或Pull Request。