SwiftDataProvider 3.0.0

SwiftDataProvider 3.0.0

Martin Eberl 维护。



  • 作者:
  • Martin Eberl

SwiftDataProvider

CI Status Version License Platform

示例

对于 TableViews 和动画更新的模板代码已不再需要。现在您可以设计带有 Models 的 TableView,而不是追踪所有 IndexPaths 和 IndexSets,简单方便。

要运行示例项目,首先克隆源码库,然后在 Example 目录中运行 pod install

要求

iOS 8.0 XCode 10.2 Swift 5.0

安装

SwiftDataProvider 通过 CocoaPods 提供使用。要安装,只需将以下行添加到您的 Podfile 中

pod 'SwiftDataProvider'

作者

Martin Eberl, [email protected]

许可证

SwiftDataProvider遵循MIT许可证。有关更多信息,请参阅LICENSE文件。

用法

1) 实现UIKit中的UITableViewController或UITableView并遵循RecyclerView协议

2) 保持对SwiftDataProvider的强引用

    private var swiftDataProvider: SwiftDataProvider?

3) 创建SwiftDataProvider实例(例如在viewDidLoad中)并将其分配为UITableView的UITableViewDataSource

override func viewDidLoad() {
    super.viewDidLoad()
    
    //do assign to the tableviews delegate ALWAY BEFORE creating and assigning
    //the SwiftDataProvider to the UITableView or UITableViewController, otherwhise
    //the section header and footer view won't appear, when you handle them within the SwiftDataProvider
    self.tableViewDelegate = self 
    
    self.swiftDataProvider = SwiftDataProvider(recyclerView: self)

    //step 4
}

4) 注册单元格以实现复用并映射到所需内容,例如以下初始化SwiftDataProvider后。请确保为您的数据模型使用唯一的名称!

    swiftDataProvider?.register(cell: UITableViewCell.self, for: String.self) { cell, content in
        cell.textLabel?.text = content
    }

    swiftDataProvider?.register(cell: UITableViewCell.self, for: /*Your data model*/.self) { cell, content in
        cell.textLabel?.text = content.formattedDate
    }

    swiftDataProvider?.register(cellReuseIdentifier: "TestCell", as: TestCell.self, for: TestCell.Content.self) { cell, content in
        cell.content = content
    }

//step 5

5) 分配内容适配器。示例中使用的是 MVVM 模式,但您也可以在 ViewController 中实现 ContentAdapter。

    swiftDataProvider?.contentAdapter = viewModel.contentAdapter

6) a) 使用 ContentProviderAdapter 以自我控制内容并添加部分和行或更新部分标题和页脚

// in the ViewModel

struct ViewModel {
    let contentAdapter = ContentProviderAdapter()
    let section = Section()
    ...

    init() {
        //Use a string or a model, the string uses the default header view, the
        //model requires you to provide a section header view
        section.set(header: "") 
        contentAdapter.add(section: section)
        
        //use automatically update if you'd like the table view 
        //to be updated every time, something is being inserted, deleted or triggered a reload.
        //Default is false, so you can do multiple updates at a time
        //contentAdapter.isAutoCommitEnabled = true
    }

    func addContent() {
        section.add(row: /*Your data model*/)
        // .. insert, remove models, cells ..
        
        //find a specific instance of a model in the section
        let content: <Model Type> = section.content {
            //return true or false
        }
        
        //if you didn't enable the autocommit, you'll have to trigger the update manually
        contentAdapter.commit()
    }
    
    func uödate
}

6) b) 或者使用 DynamicContentProviderAdapter 以自动控制内容

// in the ViewModel

struct ViewModel {
    let contentAdapter = DynamicContentProviderAdapter</*Your data model*/>()

    ...

    init() {
        contentAdapter.sort = { $0 < $1 }
        contentAdapter.sectionContentUpdate = { section , context in
            //Update sectin content whenever a new row has been added
            //use string to show the default section header view or a model, to use a custom view
            section.set(header: "\(section.rows.count) Items")
            
            //action to be used after a section update has performed (.none or .reload)
            return .reload 
        }
        
        //use section sorter, to sort the sections by your given algorythm
        contentAdapter.sortSections = { firstSection, secondSection
            guard let first = firstSection.rows.first(where: {firstSection is TimeModel}) as? TimeModel,
                let second = secondSection.rows.first(where: {firstSection is TimeModel}) as? TimeModel else {
                    return firstSection.rows.contains(where: { firstSection is TimeModel })
            }
            return first.date > second.date
        }
        
        //use automatically update if you'd like the table view 
        //to be updated every time, something is being inserted, deleted or triggered a reload.
        //Default is false, so you can do multiple updates at a time
        //contentAdapter.isAutoCommitEnabled = true
        
        contentAdapter.sectionInitializer = { section in
            //Initialize sectin content the first time, a new Section has been created
            //use string to show the default section header view or a model, to use a custom view
            section.set(header: "\(section.rows.count) Items")
        }
        
        contentAdapter.contentSectionizer = { content, sections in
            //Sectionize the content
            //return .new or .use(index of the section) to create a new section or use the given section
            
            let context = [Section.Keys.predicate: NSPredicate(format: "...")] //you can specify a predicate here, so you can easily categorize the      content to the correct session
            guard let last = sections?.last else {
                return .new(context)
            }
            
            //Here i'm filtering the row
            //if the model to be added into a section meets the given predicate of a section
            (see *let context = [Section.Keys.predicate: NSPredicate(format: "...")]*) 
            if let index = sections.firstIndex(where: { section in
                return section.meetsPredicate(content: content) ?? false
            }) {
                return .use(index)
            }
            return .new(context)
        }
    }

    func addContent() {
        contentAdapter.add(/*Your data model*/)
        
        //if you didn't enable the autocommit, you'll have to trigger the update manually
        contentAdapter.commit()
    }
}

什么是 ContentProviderAdapter 和 DynamicContentProviderAdapter 之间的区别?

ContentProviderAdapter 是一个类,其中您可以控制部分和的部分中的行。这主要用于知道内容结构应如何看起来。因此,您可以向部分添加多个部分和行。

DynamicContentProviderAdapter 是一个仅提供内容并基于提供的逻辑将内容排序到某个区域的类。然而,由于 DynamicContentProviderAdapter 继承自 ContentProviderAdapter,您也可以提供自定义区域。