优雅的使用UIStackView
2020-08-05 本文已影响0人
啧啧同学
UIStackView是iOS9苹果在UIKit框架中引入了一个新的视图类,开发者仅需设置很少,甚者不需要设置任何的约束就可以快速地实现子视图的均匀布局
值得注意的是,UIStackView虽然继承自UIView,但是并不参与屏幕的渲染,重写drawRect:方法也是无效的。
UIStackView的特有属性四个:
- Axis
- Distribution
- Alignment
- spacing
添加子视图的方式
UIStackView使用arrangedSubviews数组来管理子视图。需要注意的是这个数组是一个readonly的属性,我们需要调用方法对arrangedSubviews数组进行操作。
UIStackView的应用--封装一个文件工具操作类
枚举 + UIScrollView + UIStackView 配合使用
1.先提前设计该工具类创建及调用的方式
let view = FCFileToolView(categorys: [.deleted, .copy]) { (category) in
switch category {
case .deleted:
delete()
case .copy: break
copy()
default:
other()
}
}
根据调用方的需求, 定义枚举FCFileToolsCategory:此处是文件操作,定义 全选、删除、分享、下载、复制、文件转移六种操作;并根据ui,枚举内定义各种操作对应的title及icon 属性(个人觉得这是 swift enum中最帅的特性)
enum FCFileToolsCategory {
case selectedAll(Bool)//全选
case deleted//删除
case share//分享
case download//下载
case copy//复制
case move(String)// 文件转移
//展示title
var displayTitle: String {
switch self {
case .selectedAll(let isSelected):
return isSelected ? "取消全选".local() : "全选".local()
case .deleted:
return "删除".local()
case .share:
return "分享".local()
case .download:
return "保存至相簿".local()
case .copy:
return "拷贝照片".local()
case .move(_):
return "移动文件".local()
}
}
// 展示用的图标
var displayIcon: String {
switch self {
case .selectedAll(_):
return "icon_file_edit"
case .deleted:
return "icon_file_delete"
case .share:
return "icon_file_shared"
case .download:
return "icon_file_download"
case .copy:
return "icon_file_copy"
case .move(_):
return "icon_file_move"
}
}
}
2.封装加载用的ItemView及对应的viewModel
class FCFileToolsViewModel {
var category: FCFileToolsCategory
var closure: (() -> ())?
init(category: FCFileToolsCategory) {
self.category = category
}
}
class FCFileToolsView: UIView {
init(_ model: FCFileToolsViewModel) {
self.model = model
super.init(frame: .zero)
setupSubViews()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupSubViews() {
addSubview(icon)
addSubview(titleLabel)
addSubview(bgBtn)
icon.snp.makeConstraints { (make) in
make.top.equalToSuperview()
make.width.equalTo(16.0)
make.height.equalTo(18.0)
make.left.right.equalToSuperview().inset(10.0)
}
titleLabel.snp.makeConstraints { (make) in
make.top.equalTo(icon.snp.bottom).offset(2.0)
make.left.right.equalToSuperview().inset(2.0)
make.bottom.equalToSuperview()
}
bgBtn.snp.makeConstraints { (make) in
make.edges.equalToSuperview()
}
icon.image = UIImage(named: model.category.displayIcon)
titleLabel.text = model.category.displayTitle
themeConfig { (v, t) in
guard let view = v as? FCFileToolsView, let theme = t as? FCThemeColor else { return }
view.backgroundColor = .clear
view.titleLabel.textColor = theme.textColorSubTitle
}
}
@objc func onBgClickEvent() {
switch model.category {
case .selectedAll(let isSelected):
model.category = .selectedAll(!isSelected)
titleLabel.text = model.category.displayTitle
default: break
}
model.closure?()
}
//MARK: - Property
var model: FCFileToolsViewModel
lazy var icon: UIImageView = {
let imgV = UIImageView()
imgV.contentMode = .scaleAspectFit
return imgV
}()
lazy var titleLabel: UILabel = {
let label = UILabel()
label.textAlignment = .center
label.font = UIFont.medium(10.0)
label.numberOfLines = 0
label.adjustsFontSizeToFitWidth = true
return label
}()
lazy var bgBtn: UIButton = {
let btn = UIButton()
btn.backgroundColor = .clear
btn.addTarget(self, action: #selector(onBgClickEvent), for: .touchUpInside)
return btn
}()
}
3.根据需求,创建好类及对应的viewModel
//可读性,closure使用别名
typealias FCFileToolClosure = (FCFileToolsCategory) -> ()
class FCFileToolViewModel {
init(categorys: [FCFileToolsCategory], closure: @escaping FCFileToolClosure) {
self.categorys = categorys
self.closure = closure
}
//MARK: Property
let categorys: [FCFileToolsCategory]
let closure: FCFileToolClosure
}
class FCFileToolView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
setupSubViews()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupSubViews() {
addSubview(scrollView)
scrollView.addSubview(listView)
scrollView.snp.makeConstraints { (make) in
make.edges.equalToSuperview()
}
listView.snp.makeConstraints { (make) in
make.edges.equalToSuperview()
}
}
func refreshUI(_ model: FCFileToolViewModel) {
// 刷新前需要移除上次加载的item
listView.subviews.forEach { $0.removeFromSuperview() }
let toolViews: [FCFileToolsView] = model.categorys.compactMap { (category) -> FCFileToolsView in
let subModel = FCFileToolsViewModel(category: category)
subModel.closure = {
model.closure(category)
}
let subView = FCFileToolsView(subModel)
return subView
}
toolViews.forEach {
listView.addArrangedSubview($0)
}
}
//MARK: Property
lazy var scrollView: UIScrollView = {
let view = UIScrollView(frame: .zero)
view.backgroundColor = .clear
view.showsHorizontalScrollIndicator = false
view.showsVerticalScrollIndicator = false
view.bounces = false
return view
}()
lazy var listView: UIStackView = {
let view = UIStackView()
view.distribution = .equalCentering
view.alignment = .center
view.backgroundColor = .clear
view.spacing = 40.0
view.axis = .horizontal
return view
}()
}
-
使用方式
let listModel = FCFileToolViewModel(categorys: [.copy, .deleted, .move("")]) { (category) in //doMethod with category } let view = FCFileToolView() view.refreshUI(listModel)
//categorys 数量及顺序均可随意切换,超过限制宽度,可滑动
效果图如下:
向右滑动后
IMG_0907.PNG