LeeGo 是一个轻量级的 Swift 框架,它帮助您将 UI 组件解耦并模块化成小块的乐高风格积木,以便使 UI 开发更具声明性、可配置性和高度可复用性。
理性背后的原因
我们都知道 MVC 模式在处理复杂的 iOS 项目时存在一些严重问题。幸运的是,也有许多目的在于解决问题的方法,其中大多数主要针对的是 Controller
部分,比如 MVP、MVVM、MVSM 或 VIPER。但是几乎没有任何东西解决了 View
部分。这是否意味着我们在 View
部分已经没有问题可解决了?我觉得答案是否定的,尤其是当我们需要我们的应用完全响应时。
我在 dotSwift 的演讲 中谈到了这个想法,也在我的博客文章中提到了
请查看更多详情。
LeeGo 替换了 MVC 中的 View
部分,替换为 Brick
。
特性
LeeGo 可以帮助您的有哪些?
- 描述您的整个 UI 为小块的乐高风格积木。让您在任何时候、任何地点都可以配置您的视图。
- 不再需要处理大量自定义 UIView 子类。相反,您只需处理不同类型的
Brick
,它们是 轻量级 和 纯值类型。 - 设计成 UIKit 友好 和 无侵入性。无需从其他基类继承。
- 可以通过JSON负载远程更新几乎所有内容。
- 内置简便方法,让UIStackView布局无忧。
- 内置自适应性机制,自动计算单元格高度。
- 方法链表达式。
- 利用Swift的枚举,让您将整个UI放入单个枚举文件中。
与Facebook ComponentKit进行比较
两者
- 为iOS带来声明式、可配置和可重用的UI开发。
优点
- 用Swift编写的,专为Swift创建。没有更多的Obj-C++组件。
- 轻量级并且与UIKit友好。没有继承,直接处理标准的UIView和Auto Layout。
- 只整合一小部分即可开始,也可以随时全部丢弃而不会产生任何副作用。
- 通过JSON负载,可以远程更新由LeeGo支持的UI任何部分。
- 由您可能已经熟悉的标准的Auto Layout提供支持。
缺点
- 目前缺少高级功能。例如,内置的可配置视图控制器、视图动画、Auto Layout动画或UIControl组件动作的支持。
- 由标准的Auto Layout提供支持,在某些情况下可能存在潜在的性能问题。
- 仍需要标准的Auto Layout和可视化格式语言的基础知识。
完整文档
用法
基础组件
创建一个名为"title"的UILabel实例,默认文本为"展示",灰色背景颜色
import LeeGo
let titleBrick: Brick = "title".build(UILabel).style([.text("Showcase"), .backgroundColor(.lightGrayColor())])
配置一个UILabel实例,就像标题砖一样
let titleLabel = UILabel()
titleLabel.lg_configureAs(titleBrick)
let titleBrick = "title".build(UILabel).style([.numberOfLines(0), .text("title")])
let subtitleBrick = "subtitle".build(UILabel).style([.textColor(.lightGrayColor()), .numberOfLines(0), .font(.systemFontOfSize(14)), .text("subtitle")])
let imageBrick = "image".build(UIImageView).style([.ratio(1.5), .backgroundColor(.blueColor())]).width(68)
/// Create a brick stand for `UIView` which contains a `title`,
/// a `subtitle` and an `image` inside, layout them with
/// standard auto layout VFL.
let brickName = "cell"
let cellBrick = brickName.build().bricks(titleBrick, subtitleBrick, imageBrick) {
title, subtitle, image in
return Layout([
"H:|-left-[\(image)]-spaceH-[\(title)]-right-|",
"H:[\(image)]-spaceH-[\(subtitle)]-right-|",
"V:|-top-[\(title)]-spaceV-[\(subtitle)]-(>=bottom)-|",
"V:|-top-[\(image)]-(>=bottom)-|"], metrics: LayoutMetrics(20, 20, 20, 20, 10, 10))
}
从标准的UICollectionViewCell实例中 deque,然后将其配置为cell砖块,数据源为element
let cell = collectionView.dequeueCell…
cell.lg_configureAs(cellBrick, dataSource: element[indexPath.item])
受UIStackView启发的布局
创建一个包含3块砖(红色、绿色和蓝色方块)的UIView
砖架,然后使用受UIStackView
启发的布局辅助方法排列它们。
let bricks = ["red".build().style(Style.redBlockStyle).height(50),
"green".build().style(Style.greenBlockStyle).height(80),
"blue".build().style(Style.blueBlockStyle).height(30)]
let layout = Layout(bricks: bricks, axis: .Horizontal, align: .Top, distribution: .FillEqually, metrics: LayoutMetrics(10, 10, 10, 10, 10, 10))
let viewBrick = "view".build().style(Style.blocksStyle).bricks(bricks, layout: layout).height(100)
配置一个UIView
实例,就像砖一样。
view.lg_configureAs(viewBrick)
let viewBrick = Brick.union("brickName", bricks: [
title,
subtitle,
Brick.union("blocks", bricks: [
redBlock.height(50),
greenBlock.height(80),
blueBlock.height(30)], axis: .Horizontal, align: .Top, distribution: .FillEqually, metrics: LayoutMetrics(10, 10, 10, 10, 10, 10)).style([.backgroundColor(.yellowColor())])
], axis: .Vertical, align: .Fill, distribution: .Flow(3), metrics: LayoutMetrics(20, 20, 20, 20, 10, 10))
配置一个UIView
实例,就像砖一样。
view.lg_configureAs(viewBrick)
import LeeGo
enum TwitterBrickSet: BrickBuilderType {
// leaf bricks
case username, account, avatar, tweetText, tweetImage, date, replyButton, retweetButton, retweetCount, likeButton, likeCount
// complex bricks
case retweetView, likeView
case accountHeader, toolbarFooter, retweetHeader
// root bricks
case standardTweet
static let brickClass: [Twitter: AnyClass] = [username: UILabel.self, account: UILabel.self, avatar: UIImageView.self, tweetText: UITextView.self]
func brick() -> Brick {
switch self {
case .username:
return build().style([.font(.boldSystemFontOfSize(14))])
case .account:
return build().style([.font(.systemFontOfSize(14))])
case .avatar:
return build().style([.ratio(1), .backgroundColor(.lightGrayColor()), .cornerRadius(3)]).width(50)
case .tweetText:
return build().style([.scrollEnabled(false)])
…
case .standardTweet:
return build().style([.backgroundColor(.whiteColor())])
.bricks(
avatar.brick(),
accountHeader.brick(),
tweetText.brick(),
tweetImage.brick(),
toolbarFooter.brick()
) { (avatar, accountHeader, tweetText, image, toolbarFooter) in
Layout(["H:|-10-[\(avatar)]-10-[\(tweetText)]-10-|",
"H:[\(avatar)]-10-[\(accountHeader)]-10-|",
"H:[\(avatar)]-10-[\(image)]-10-|",
"H:[\(avatar)]-10-[\(toolbarFooter)]-10-|",
"V:|-10-[\(avatar)]-(>=10)-|",
"V:|-10-[\(accountHeader)]-10-[\(tweetText)]-10-[\(image)]-10-[\(toolbarFooter)]-(>=10)-|"])
}
}
}
}
/// Configure your cell
let cell = collectionView.dequeueCell…
cell.lg_configureAs(TwitterBrickSet.standardTweet.brick(), dataSource: element[indexPath.item])
最佳实践
有关最佳实践和更多设计细节,请查阅 更多设计细节
安装
CocoaPods
LeeGo可以通过CocoaPods获得。要安装它,只需将以下行添加到您的Podfile:
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
use_frameworks!
pod "LeeGo"
Carthage
要使用Carthage将LeeGo集成到Xcode项目中,请将其指定在您的Cartfile中。
github "wangshengjia/LeeGo"
然后,运行以下命令构建LeeGo框架
$ carthage update
最后,您需要手动设置Xcode项目以添加LeeGo框架。
贡献
如果您喜欢LeeGo并愿意让它变得更好,您欢迎为以下内容发送pull request:
- 提议新功能。
- 回答问题。
- 改善文档。
- 审核Pull请求。
- 发现、报告或修复错误。
请注意,该项目以贡献者行为准则发布。参与此项目即表示您同意遵守[其条款](Docs/Code of Conduct.md)。
嗯...
如果您有任何想告诉我的事情,请在Twitter、Weibo上 ping 我,或者直接提交 issue。
我要感谢每一位帮助过我、启发我并鼓励我的人。还要感谢我在Le Monde的团队,特别是 Vincent 和 Blaise。
祝好~