Skip to content

Commit

Permalink
Separated section (#17)
Browse files Browse the repository at this point in the history
* add separated section +  example
* add init using custom view for separated section + more examples
* fix typos
* add isEqualToDiffable implementation to separated cell
  • Loading branch information
heinzl authored and mbuchetics committed Sep 18, 2018
1 parent e855400 commit 09c633a
Show file tree
Hide file tree
Showing 13 changed files with 703 additions and 8 deletions.
46 changes: 42 additions & 4 deletions DataSource.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@
39E9E3AC1E659D6C00A3C300 /* TextFieldCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39E9E3AB1E659D6C00A3C300 /* TextFieldCell.swift */; };
39E9E3AE1E659D7D00A3C300 /* SwitchCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39E9E3AD1E659D7D00A3C300 /* SwitchCell.swift */; };
39EBE0671E717FBE006B7E62 /* UIColor+Interpolation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39EBE0661E717FBE006B7E62 /* UIColor+Interpolation.swift */; };
4C6076D821490B00002E8BD1 /* SeparatedSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C6076D721490B00002E8BD1 /* SeparatedSection.swift */; };
4C6076DC21490B4D002E8BD1 /* SeparatorLineCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C6076DA21490B4D002E8BD1 /* SeparatorLineCell.swift */; };
4C6076DF21490C80002E8BD1 /* SeparatedSectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C6076DE21490C80002E8BD1 /* SeparatedSectionViewController.swift */; };
4C6076E121490FF3002E8BD1 /* SeparatorLineCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C6076E021490FF3002E8BD1 /* SeparatorLineCell.xib */; };
4CA65F60214F952E004F2F19 /* UIView+AutoLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA65F5F214F952E004F2F19 /* UIView+AutoLayout.swift */; };
5C61C91820AF0AB0003A08B8 /* SwipeActionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C61C91720AF0AB0003A08B8 /* SwipeActionViewController.swift */; };
/* End PBXBuildFile section */

Expand Down Expand Up @@ -141,6 +146,11 @@
39E9E3AB1E659D6C00A3C300 /* TextFieldCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldCell.swift; sourceTree = "<group>"; };
39E9E3AD1E659D7D00A3C300 /* SwitchCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwitchCell.swift; sourceTree = "<group>"; };
39EBE0661E717FBE006B7E62 /* UIColor+Interpolation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Interpolation.swift"; sourceTree = "<group>"; };
4C6076D721490B00002E8BD1 /* SeparatedSection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SeparatedSection.swift; sourceTree = "<group>"; };
4C6076DA21490B4D002E8BD1 /* SeparatorLineCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SeparatorLineCell.swift; sourceTree = "<group>"; };
4C6076DE21490C80002E8BD1 /* SeparatedSectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeparatedSectionViewController.swift; sourceTree = "<group>"; };
4C6076E021490FF3002E8BD1 /* SeparatorLineCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SeparatorLineCell.xib; sourceTree = "<group>"; };
4CA65F5F214F952E004F2F19 /* UIView+AutoLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+AutoLayout.swift"; sourceTree = "<group>"; };
5C61C91720AF0AB0003A08B8 /* SwipeActionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwipeActionViewController.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

Expand Down Expand Up @@ -225,6 +235,8 @@
398248CC1E5CA9C600F802D1 /* DataSource+UITableViewDelegate.swift */,
398248C61E5C7CCA00F802D1 /* DataSource+Diff.swift */,
398248CA1E5CA74A00F802D1 /* UITableViewExtensions.swift */,
4CA65F5E214F951C004F2F19 /* Utilities */,
4C6076D921490B34002E8BD1 /* SeparatedSection */,
395D14A61B90612D00658680 /* DataSource.h */,
395D14A81B90612D00658680 /* Info.plist */,
);
Expand All @@ -240,6 +252,7 @@
3968B90D1E7C103400EE876F /* RandomPersonsViewController.swift */,
396E02DF20A1B0090072291F /* SwipeToDeleteViewController.swift */,
5C61C91720AF0AB0003A08B8 /* SwipeActionViewController.swift */,
4C6076DE21490C80002E8BD1 /* SeparatedSectionViewController.swift */,
);
name = Examples;
sourceTree = "<group>";
Expand Down Expand Up @@ -302,6 +315,24 @@
path = Cells;
sourceTree = "<group>";
};
4C6076D921490B34002E8BD1 /* SeparatedSection */ = {
isa = PBXGroup;
children = (
4C6076D721490B00002E8BD1 /* SeparatedSection.swift */,
4C6076DA21490B4D002E8BD1 /* SeparatorLineCell.swift */,
4C6076E021490FF3002E8BD1 /* SeparatorLineCell.xib */,
);
path = SeparatedSection;
sourceTree = "<group>";
};
4CA65F5E214F951C004F2F19 /* Utilities */ = {
isa = PBXGroup;
children = (
4CA65F5F214F952E004F2F19 /* UIView+AutoLayout.swift */,
);
path = Utilities;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXHeadersBuildPhase section */
Expand Down Expand Up @@ -400,6 +431,8 @@
};
395D14A31B90612D00658680 = {
CreatedOnToolsVersion = 7.0;
DevelopmentTeam = M8F9QH57A6;
LastSwiftMigration = 0930;
DevelopmentTeam = PRXJBCN9SJ;
LastSwiftMigration = 1000;
ProvisioningStyle = Automatic;
Expand Down Expand Up @@ -449,6 +482,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
4C6076E121490FF3002E8BD1 /* SeparatorLineCell.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -496,6 +530,7 @@
395D14801B90610A00658680 /* AppDelegate.swift in Sources */,
398248A31E5C6D9900F802D1 /* StartViewController.swift in Sources */,
39EBE0671E717FBE006B7E62 /* UIColor+Interpolation.swift in Sources */,
4C6076DF21490C80002E8BD1 /* SeparatedSectionViewController.swift in Sources */,
3968B9121E7C103400EE876F /* FormViewController.swift in Sources */,
3968B9131E7C103400EE876F /* DiffViewController.swift in Sources */,
39E9E3AC1E659D6C00A3C300 /* TextFieldCell.swift in Sources */,
Expand All @@ -509,14 +544,17 @@
398248CB1E5CA74A00F802D1 /* UITableViewExtensions.swift in Sources */,
398248CD1E5CA9C600F802D1 /* DataSource+UITableViewDelegate.swift in Sources */,
398248C51E5C7A5600F802D1 /* CellDescriptor.swift in Sources */,
4CA65F60214F952E004F2F19 /* UIView+AutoLayout.swift in Sources */,
398248C31E5C7A4000F802D1 /* Section.swift in Sources */,
398248C71E5C7CCA00F802D1 /* DataSource+Diff.swift in Sources */,
398248C11E5C7A3500F802D1 /* Row.swift in Sources */,
390CAF1C1E79AA560024E3E6 /* SectionDescriptor.swift in Sources */,
3968B9091E7BFDF800EE876F /* Diffable.swift in Sources */,
398248C91E5CA06600F802D1 /* DataSource+UITableViewDataSource.swift in Sources */,
398248AF1E5C6EFB00F802D1 /* DataSource.swift in Sources */,
4C6076DC21490B4D002E8BD1 /* SeparatorLineCell.swift in Sources */,
39B621801E6D757000BE18EE /* DataSource+UITableViewDataSourcePrefetching.swift in Sources */,
4C6076D821490B00002E8BD1 /* SeparatedSection.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -675,7 +713,7 @@
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
DEVELOPMENT_TEAM = PRXJBCN9SJ;
DEVELOPMENT_TEAM = M8F9QH57A6;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Carthage/Build/iOS",
Expand All @@ -696,7 +734,7 @@
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
DEVELOPMENT_TEAM = PRXJBCN9SJ;
DEVELOPMENT_TEAM = M8F9QH57A6;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Carthage/Build/iOS",
Expand All @@ -721,7 +759,7 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = PRXJBCN9SJ;
DEVELOPMENT_TEAM = M8F9QH57A6;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
Expand Down Expand Up @@ -753,7 +791,7 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = PRXJBCN9SJ;
DEVELOPMENT_TEAM = M8F9QH57A6;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
Expand Down
5 changes: 5 additions & 0 deletions DataSource/DataSource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,11 @@ public class DataSource: NSObject {
self.cellDescriptors[d.rowIdentifier] = d
}

let separator = SeparatorLineCell.descriptor
if self.cellDescriptors[separator.rowIdentifier] == nil {
self.cellDescriptors[separator.rowIdentifier] = separator
}

let defaultSectionDescriptors: [SectionDescriptorType] = [
SectionDescriptor<Void>(),
SectionDescriptor<String>()
Expand Down
6 changes: 3 additions & 3 deletions DataSource/Section.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ public protocol SectionType {

// MARK: - Section

public class Section: SectionType {
open class Section: SectionType {

public let identifier: String
public let content: Any?

public private(set) var rows: [RowType] = []
public private(set) var visibleRows: [RowType] = []
public internal(set) var rows: [RowType] = []
public internal(set) var visibleRows: [RowType] = []

public init(_ content: Any? = nil, rows: [RowType], visibleRows: [RowType]? = nil, identifier: String? = nil) {
if let identifier = identifier {
Expand Down
126 changes: 126 additions & 0 deletions DataSource/SeparatedSection/SeparatedSection.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
//
// SeparatedSection.swift
// DataSource
//
// Created by Michael Heinzl on 11.09.18.
// Copyright © 2018 aaa - all about apps GmbH. All rights reserved.
//

import UIKit

public struct Transition {
public let from: Any?
public let to: Any?

public init(from: Any?, to: Any?) {
self.from = from
self.to = to
}

public var isFirst: Bool {
return from == nil && to != nil
}

public var isLast: Bool {
return from != nil && to == nil
}

}

open class SeparatedSection: Section {

public typealias StyleConfigureClosure = (Transition) -> SeparatorStyle
public typealias ViewConfigureClosure = (Transition) -> UIView?

let styleConfigureClosure: StyleConfigureClosure?
let viewConfigureClosure: ViewConfigureClosure?

public static let defaultStyleConfigureClosure: StyleConfigureClosure = { (transition) in
if transition.isFirst || transition.isLast {
return SeparatorStyle(leftInset: 0.0)
} else {
return SeparatorStyle(leftInset: 16.0)
}
}

// inits using SeparatorStyle configure closure

public init(_ content: Any?, rows: [RowType], visibleRows: [RowType]?, identifier: String?, styleConfigureClosure: @escaping StyleConfigureClosure = SeparatedSection.defaultStyleConfigureClosure) {
self.styleConfigureClosure = styleConfigureClosure
self.viewConfigureClosure = nil
super.init(content, rows: rows, visibleRows: visibleRows, identifier: identifier)
}

public convenience init(_ content: Any? = nil, items: [Any], rowIdentifier: String? = nil, sectionIdentifier: String? = nil, styleConfigureClosure: @escaping StyleConfigureClosure = SeparatedSection.defaultStyleConfigureClosure) {
let rows = items.map { Row($0, identifier: rowIdentifier) as RowType }
self.init(content, rows: rows, visibleRows: rows, identifier: sectionIdentifier, styleConfigureClosure: styleConfigureClosure)
}

// inits using UIView configure closure

public init(_ content: Any?, rows: [RowType], visibleRows: [RowType]?, identifier: String?, viewConfigureClosure: @escaping ViewConfigureClosure) {
self.styleConfigureClosure = nil
self.viewConfigureClosure = viewConfigureClosure
super.init(content, rows: rows, visibleRows: visibleRows, identifier: identifier)
}

public convenience init(_ content: Any? = nil, items: [Any], rowIdentifier: String? = nil, sectionIdentifier: String? = nil, viewConfigureClosure: @escaping ViewConfigureClosure) {
let rows = items.map { Row($0, identifier: rowIdentifier) as RowType }
self.init(content, rows: rows, visibleRows: rows, identifier: sectionIdentifier, viewConfigureClosure: viewConfigureClosure)
}

override public func updateVisibility(sectionIndex: Int, dataSource: DataSource) {
guard !rows.isEmpty else {
self.visibleRows = []
return
}
var visibleRows = [RowType]()

var separatorViewModel = separatorLineViewModel(diffIdentifier: "separator-\(rows[0].diffableItem?.diffIdentifier ?? "")-first",
transition: Transition(from: nil, to: rows.first!.item))
visibleRows.append(separatorViewModel.row)

for (rowIndex, row) in rows.enumerated() {
let cellDescriptor = dataSource.cellDescriptors[row.identifier]
let indexPath = IndexPath(row: rowIndex, section: sectionIndex)
let isHidden = cellDescriptor?.isHiddenClosure?(row, indexPath) ?? dataSource.isRowHidden?(row, indexPath) ?? false

if !isHidden {
visibleRows.append(row)

let separatorId: String
// Use diffIdentifier of row and identifier of section for diffIdentifier of separator
// this prevents unintentional reordering of rows
if let diffableRow = row.item as? Diffable {
separatorId = "separator-\(identifier)-\(diffableRow.diffIdentifier)"
} else {
separatorId = "separator-\(UUID().uuidString)"
}

let nextRow: RowType?
if rows.indices.contains(rowIndex + 1) {
nextRow = rows[rowIndex + 1]
} else {
nextRow = nil
}

separatorViewModel = separatorLineViewModel(diffIdentifier: separatorId,
transition: Transition(from: row.item, to: nextRow?.item))
visibleRows.append(separatorViewModel.row)
}
}

self.visibleRows = visibleRows
}

private func separatorLineViewModel(diffIdentifier: String, transition: Transition) -> SeparatorLineViewModel {
if let styleConfigureClosure = styleConfigureClosure {
return SeparatorLineViewModel(diffIdentifier: diffIdentifier, style: styleConfigureClosure(transition))
} else if let viewConfigureClosure = viewConfigureClosure {
return SeparatorLineViewModel(diffIdentifier: diffIdentifier, customView: viewConfigureClosure(transition))
} else {
return SeparatorLineViewModel(diffIdentifier: diffIdentifier, style: SeparatedSection.defaultStyleConfigureClosure(transition))
}
}

}
Loading

0 comments on commit 09c633a

Please sign in to comment.