- IRCollectionTableViewModel-swift is a powerful MVVM Tableview/CollectionView for iOS, which is flexible and can easy to handle and reuse.
- The Objc version IRCollectionTableViewModel.
- MVVM structure.
- Flexible, Reusable.
- Git clone this project.
- Copy this project into your own project.
- Add the .xcodeproj into you project and link it as embed framework.
- You can remove the
demo
andScreenShots
folder.
- Add
pod 'IRCollectionTableViewModel-swift'
in thePodfile
pod install
- Model--view--viewmodel (MVVM) is a software architectural pattern.
- It has advantages more than the tranditional MVC architectural. Can improve the whole code strurcture.
- More detail can see the MVVM wikipedia. MVVM
- Create a new class
TableViewViewModel
extendsTableViewBasicViewModel
andUITableViewDataSource
, and ImportIRCollectionTableViewModel-swift
import IRCollectionTableViewModel_swift
class TableViewViewModel: TableViewBasicViewModel, UITableViewDataSource {
...
}
- You can add your init method and register the cell inside
init(tableView: UITableView) {
super.init()
items = []
tableView.register(UINib.init(nibName: TableViewCell.identifier(), bundle: nil), forCellReuseIdentifier: TableViewCell.identifier())
}
- Add
update
method
func update() {
items.removeAll()
self.setupRows()
}
- For setup
items
, other words, setup the sections/rows you want to show. CreateTableViewSectionItem
andTableViewRowItem
,DemoSectionType
,DemoRowType
enum TableViewSectionType: NSInteger {
case DemoSection
}
internal enum ProfileRowType : NSInteger {
case RowType_DemoRow
}
class TableViewRowItem: RowBasicModelItem {
var newType: ProfileRowType = .RowType_DemoRow
override public var type: ProfileRowType.RawValue {
set {
self.newType = ProfileRowType(rawValue: newValue)!
}
get {
return newType.rawValue
}
}
override init(type: RowType, title: String) {
super.init(type: type, title: title)
}
}
class TableViewSectionItem: SectionBasicModelItem {
private var _sectionTitle: String?
private var _type: TableViewSectionType = .DemoSection
override init(rowCount: UInt) {
super.init(rowCount: rowCount)
}
override func sectionTitle() -> String? {
return self._sectionTitle
}
open func sectionTitle(_ sectionTitle: String) {
self._sectionTitle = sectionTitle
}
override func type() -> SectionType {
return self._type.rawValue
}
open func type(_ type: TableViewSectionType) {
self._type = type
}
}
- Setup
items
func setupRows() {
var rowItems: [RowBasicModelItem] = []
rowItems.append(TableViewRowItem.init(type: ProfileRowType.RowType_DemoRow.rawValue, title: "Demo Row"))
rowItems.append(TableViewRowItem.init(type: ProfileRowType.RowType_DemoRow.rawValue, title: "Demo Row"))
editedTexts = []
for _ in rowItems {
editedTexts.append("")
}
let item = TableViewSectionItem.init(rowCount: UInt(rowItems.count))
item.type(.DemoSection)
item.sectionTitle("Demo Section")
item.rows = rowItems
self.items.append(item)
}
- Override
UITableViewDataSource
// MARK: - UITableViewDataSource
func numberOfSections(in tableView: UITableView) -> Int {
return items.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items[section].rowCount()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let item = items[indexPath.section]
let row = item.rows[indexPath.row]
switch row.type {
case ProfileRowType.RowType_DemoRow.rawValue:
do {
let cell: TableViewCell = tableView.dequeueReusableCell(withIdentifier: TableViewCell.identifier(), for: indexPath) as! TableViewCell
cell.titleLabel.text = String.init(format: "%@%ld", row.title!, row.tagRange.location)
cell.editTextField.text = self.editedTexts[indexPath.row] as String
cell.editTextField.tag = row.tagRange.location
cell.editTextField.delegate = self
return cell
}
default:
break
}
return UITableViewCell.init()
}
- Use your view model
TableViewViewModel
var viewModel: TableViewViewModel?
self.tableView.register(UINib.init(nibName: TableViewHeaderView.identifier(), bundle: nil), forHeaderFooterViewReuseIdentifier: TableViewHeaderView.identifier())
viewModel = TableViewViewModel.init(tableView: self.tableView)
self.tableView.dataSource = viewModel
viewModel!.update()
-
Just the same way of
TableViewViewModel
. Create a new classCustomCollectionViewModel
extendsTableViewBasicViewModel
andUICollectionViewDataSource
. -
You can add your init method and register the cell inside.
-
For setup
items
, other words, setup the sections/rows you want to show. CreateCustomCollectionSectionItem
andCustomCollectionRowItem
,CustomCollectionSectionType
. -
Override
UICollectionViewDataSource
.
TableViewBasicViewModel
provides some usage methods
// MARK: - Public
public func getRowTypeWith(type: SectionType, row: NSInteger) -> NSInteger
public func getSectionTitleinSection(section: NSInteger) -> String?
public func getSectionLeftIconinSection(section: NSInteger) -> UIImage?
public func getSectionTypeinSection(section: NSInteger) -> SectionType
public func hideRows(hide: Bool, inSection section: NSInteger)
public func hiddenRowsinSection(section: NSInteger) -> Bool
public func getIndexSetWithSectionType(sectionType: SectionType) -> NSIndexSet?
public func getIndexPathWithSectionType(sectionType: SectionType, rowType: RowType) -> NSIndexPath?
public func setupRowTag()
public func getIndexPathFromRowTag(rowTag: NSInteger) -> NSIndexPath
-
Because the cells have reuse feature, somtimes we need to tag the cell/componenst if want to recognize the specific cell/components, thus
IRCollectionTableViewModel
provides a tag feature -
Setup tags by
setupRowTag
, it save the tag information in thetagRange
which is in theRowBasicModelItem
- (void)setupRows {
...
self.setupRowTag()
}
- Get tag
let row = item.rows[indexPath.row]
let tag = row.tagRange.location
- Get indexPath by tag
public func getIndexPathFromRowTag(rowTag: NSInteger) -> NSIndexPath
- Sometimes you want to tag the UI components like
UITextField
, usesetTagRangeLength
var row = TableViewRowItem.init(type: ProfileRowType.RowType_DemoRow.rawValue, title: "Demo Row")
row.setTagRangeLength(2)
...
self.setupRowTag()
- Then get tags
let row = item.rows[indexPath.row]
let tag1 = row.tagRange.location
let tag2 = row.tagRange.location + 1
cell.textField1.tag = tag1
cell.textField2.tag = tag2
- If you wnat to check the tags are mapping to the same index path
self.getIndexPathFromRowTag(tag1) == self.getIndexPathFromRowTag(tag2)
Now, you can easy to tag anyhing you want.
- Get row type
self.getRowTypeWith(type: 0, row: 0)
- Get section title which set in the
SectionBasicModelItem
self.getSectionTitleinSection(section: 0)
- Get section icon which set in the
SectionBasicModelItem
self.getSectionLeftIconinSection(section: 0)
- Get section type by section index
self.getSectionTypeinSection(section: 0)
- Hide rows for specific setion by
public func hideRows(hide: Bool, inSection section: NSInteger)
- Check hidden status by
public func hiddenRowsinSection(section: NSInteger) -> Bool
if self.hiddenRowsinSection(section: 0) {
self.hideRows(hide: false, inSection: 0)
}
- Get index of section by section type
self.getIndexSetWithSectionType(sectionType: .DemoSection)
- Get index path by section type and row type
self.getIndexPathWithSectionType(sectionType: .DemoSection, rowType: .RowType_DemoRow)
TableView | CollectionView |
---|---|