iOS常用iOS

优雅的使用UIStackView

2020-08-05  本文已影响0人  啧啧同学

UIStackView是iOS9苹果在UIKit框架中引入了一个新的视图类,开发者仅需设置很少,甚者不需要设置任何的约束就可以快速地实现子视图的均匀布局

值得注意的是,UIStackView虽然继承自UIView,但是并不参与屏幕的渲染,重写drawRect:方法也是无效的。

UIStackView的特有属性四个:

添加子视图的方式

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
    }()
}

  1. 使用方式

    let listModel = FCFileToolViewModel(categorys: [.copy, .deleted, .move("")]) { (category) in
        
             //doMethod with category
    }
    
    let view = FCFileToolView()
    view.refreshUI(listModel)
    

//categorys 数量及顺序均可随意切换,超过限制宽度,可滑动
效果图如下:

IMG_0906.PNG

向右滑动后


IMG_0907.PNG
上一篇下一篇

猜你喜欢

热点阅读