美文网首页iOS常用iOS
优雅的使用UIStackView

优雅的使用UIStackView

作者: 啧啧同学 | 来源:发表于2020-08-05 07:14 被阅读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
        }()
    }
    
    
    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

    相关文章

      网友评论

        本文标题:优雅的使用UIStackView

        本文链接:https://www.haomeiwen.com/subject/mbnyrktx.html