From 69c1980e0edb2583c05eb107632ce85a544c4a6d Mon Sep 17 00:00:00 2001 From: Kishikawa Katsumi Date: Sat, 16 Sep 2017 02:46:29 +0900 Subject: [PATCH] Improve testability --- Framework/Sources/LayoutEngine.swift | 232 ++++++++++++++---- .../Sources/SpreadsheetView+Layout.swift | 69 ++++-- Framework/Sources/SpreadsheetView.swift | 6 + .../SpreadsheetView.xcodeproj/project.pbxproj | 4 + Framework/Tests/LayoutTests.swift | 126 ++++++++++ 5 files changed, 373 insertions(+), 64 deletions(-) create mode 100644 Framework/Tests/LayoutTests.swift diff --git a/Framework/Sources/LayoutEngine.swift b/Framework/Sources/LayoutEngine.swift index d3c9a3a0..4aff7cbd 100644 --- a/Framework/Sources/LayoutEngine.swift +++ b/Framework/Sources/LayoutEngine.swift @@ -9,36 +9,25 @@ import UIKit final class LayoutEngine { - private let spreadsheetView: SpreadsheetView - private let scrollView: ScrollView + struct Layouter: ViewLayouter { + let scrollView: ScrollView - private let intercellSpacing: CGSize - private let defaultGridStyle: GridStyle - private let circularScrollingOptions: CircularScrolling.Configuration.Options - private let blankCellReuseIdentifier: String - private let highlightedIndexPaths: Set - private let selectedIndexPaths: Set + func layout(cell: Cell) { + scrollView.insertSubview(cell, at: 0) + } + } + var layouter: ViewLayouter - private let frozenColumns: Int - private let frozenRows: Int + private let spreadsheetView: SpreadsheetView + private let scrollView: ScrollView - private let columnWidthCache: [CGFloat] - private let rowHeightCache: [CGFloat] + private let spreadsheetViewConfiguration: SpreadsheetViewConfiguration + private let dataSourceSnapshot: DataSourceSnapshot + private let scrollViewConfiguration: ScrollViewConfiguration private let visibleRect: CGRect private var cellOrigin: CGPoint - private let startColumn: Int - private let startRow: Int - private let numberOfColumns: Int - private let numberOfRows: Int - private let columnCount: Int - private let rowCount: Int - private let insets: CGPoint - - private let columnRecords: [CGFloat] - private let rowRecords: [CGFloat] - private var mergedCellAddresses = Set
() private var mergedCellRects = [Address: CGRect]() @@ -54,41 +43,133 @@ final class LayoutEngine { init(spreadsheetView: SpreadsheetView, scrollView: ScrollView) { self.spreadsheetView = spreadsheetView self.scrollView = scrollView - - intercellSpacing = spreadsheetView.intercellSpacing - defaultGridStyle = spreadsheetView.gridStyle - circularScrollingOptions = spreadsheetView.circularScrollingOptions - blankCellReuseIdentifier = spreadsheetView.blankCellReuseIdentifier - highlightedIndexPaths = spreadsheetView.highlightedIndexPaths - selectedIndexPaths = spreadsheetView.selectedIndexPaths - - frozenColumns = spreadsheetView.layoutProperties.frozenColumns - frozenRows = spreadsheetView.layoutProperties.frozenRows - columnWidthCache = spreadsheetView.layoutProperties.columnWidthCache - rowHeightCache = spreadsheetView.layoutProperties.rowHeightCache + self.layouter = Layouter(scrollView: scrollView) + + spreadsheetViewConfiguration = SpreadsheetViewConfiguration(intercellSpacing: spreadsheetView.intercellSpacing, + defaultGridStyle: spreadsheetView.gridStyle, + circularScrollingOptions: spreadsheetView.circularScrollingOptions, + circularScrollScalingFactor: spreadsheetView.circularScrollScalingFactor, + blankCellReuseIdentifier: spreadsheetView.blankCellReuseIdentifier, + highlightedIndexPaths: spreadsheetView.highlightedIndexPaths, + selectedIndexPaths: spreadsheetView.selectedIndexPaths) + dataSourceSnapshot = DataSourceSnapshot(frozenColumns: spreadsheetView.layoutProperties.frozenColumns, frozenRows: spreadsheetView.layoutProperties.frozenRows, + columnWidthCache: spreadsheetView.layoutProperties.columnWidthCache, rowHeightCache: spreadsheetView.layoutProperties.rowHeightCache) + + scrollViewConfiguration = ScrollViewConfiguration(startColumn: scrollView.layoutAttributes.startColumn, startRow: scrollView.layoutAttributes.startRow, + numberOfColumns: scrollView.layoutAttributes.numberOfColumns, numberOfRows: scrollView.layoutAttributes.numberOfRows, + columnCount: scrollView.layoutAttributes.columnCount, rowCount: scrollView.layoutAttributes.rowCount, + insets: scrollView.layoutAttributes.insets, + columnRecords: scrollView.columnRecords, rowRecords: scrollView.rowRecords) visibleRect = CGRect(origin: scrollView.state.contentOffset, size: scrollView.state.frame.size) cellOrigin = .zero + } - startColumn = scrollView.layoutAttributes.startColumn - startRow = scrollView.layoutAttributes.startRow - numberOfColumns = scrollView.layoutAttributes.numberOfColumns - numberOfRows = scrollView.layoutAttributes.numberOfRows - columnCount = scrollView.layoutAttributes.columnCount - rowCount = scrollView.layoutAttributes.rowCount - insets = scrollView.layoutAttributes.insets + init(spreadsheetViewConfiguration: SpreadsheetViewConfiguration, dataSourceSnapshot: DataSourceSnapshot, scrollViewConfiguration: ScrollViewConfiguration, scrollViewState: ScrollView.State) { + class DataSource: SpreadsheetViewDataSource { + func numberOfColumns(in spreadsheetView: SpreadsheetView) -> Int { + return 0 + } + + func numberOfRows(in spreadsheetView: SpreadsheetView) -> Int { + return 0 + } - columnRecords = scrollView.columnRecords - rowRecords = scrollView.rowRecords + func spreadsheetView(_ spreadsheetView: SpreadsheetView, widthForColumn column: Int) -> CGFloat { + return 0 + } + + func spreadsheetView(_ spreadsheetView: SpreadsheetView, heightForRow column: Int) -> CGFloat { + return 0 + } + } + spreadsheetView = SpreadsheetView() + scrollView = ScrollView() + struct CellInfo { + let frame: CGRect + let indexPath: IndexPath + } + + struct DebugLayouter: ViewLayouter, CustomStringConvertible { + let dataSource = DataSource() + var cells = [CellInfo]() + + mutating func layout(cell: Cell) { + cells.append(CellInfo(frame: cell.frame, indexPath: cell.indexPath)) + } + + var description: String { + let sortedCells = cells.sorted { (lhs, rhs) -> Bool in + if lhs.indexPath.row < rhs.indexPath.row { + return true + } + if lhs.indexPath.row > rhs.indexPath.row { + return false + } + return lhs.indexPath.column < rhs.indexPath.column + } + var string = "" + var previousRow = 0 + if sortedCells.count > 0 { + previousRow = sortedCells[0].indexPath.row + } + for cell in sortedCells { + let indexPath = cell.indexPath + if previousRow != indexPath.row { + string += "|\n" + previousRow = indexPath.row + } + string += "|" + let location = "R\(indexPath.row)C\(indexPath.column)" + string += String(repeating: " ", count: 6 - location.characters.count) + string += location + let frame = "\(cell.frame)" + string += String(repeating: " ", count: 27 - frame.characters.count) + string += frame + } + string += "|\n" + return string + } + } + let debugLayouter = DebugLayouter() + layouter = debugLayouter + spreadsheetView.dataSource = debugLayouter.dataSource + + self.spreadsheetViewConfiguration = SpreadsheetViewConfiguration(intercellSpacing: spreadsheetViewConfiguration.intercellSpacing, + defaultGridStyle: spreadsheetViewConfiguration.defaultGridStyle, + circularScrollingOptions: spreadsheetViewConfiguration.circularScrollingOptions, + circularScrollScalingFactor: spreadsheetView.circularScrollScalingFactor, + blankCellReuseIdentifier: spreadsheetView.blankCellReuseIdentifier, + highlightedIndexPaths: spreadsheetViewConfiguration.highlightedIndexPaths, + selectedIndexPaths: spreadsheetViewConfiguration.selectedIndexPaths) + self.dataSourceSnapshot = dataSourceSnapshot + self.scrollViewConfiguration = scrollViewConfiguration + + visibleRect = CGRect(origin: scrollViewState.contentOffset, size: scrollViewState.frame.size) + cellOrigin = .zero } func layout() { + let startColumn = scrollViewConfiguration.startColumn + let startRow = scrollViewConfiguration.startRow + let numberOfRows = scrollViewConfiguration.numberOfRows + let columnCount = scrollViewConfiguration.columnCount + let rowCount = scrollViewConfiguration.rowCount + let insets = scrollViewConfiguration.insets + + let rowRecords = scrollViewConfiguration.rowRecords + guard startColumn != columnCount && startRow != rowCount else { return } - let startRowIndex = spreadsheetView.findIndex(in: scrollView.rowRecords, for: visibleRect.origin.y - insets.y) - cellOrigin.y = insets.y + scrollView.rowRecords[startRowIndex] + intercellSpacing.height + let intercellSpacing = spreadsheetViewConfiguration.intercellSpacing + let circularScrollingOptions = spreadsheetViewConfiguration.circularScrollingOptions + let frozenRows = dataSourceSnapshot.frozenRows + let rowHeightCache = dataSourceSnapshot.rowHeightCache + + let startRowIndex = spreadsheetView.findIndex(in: rowRecords, for: visibleRect.origin.y - insets.y) + cellOrigin.y = insets.y + rowRecords[startRowIndex] + intercellSpacing.height for rowIndex in (startRowIndex + startRow).. Bool { + let intercellSpacing = spreadsheetViewConfiguration.intercellSpacing + let circularScrollingOptions = spreadsheetViewConfiguration.circularScrollingOptions + let frozenColumns = dataSourceSnapshot.frozenColumns + let columnWidthCache = dataSourceSnapshot.columnWidthCache + let rowHeightCache = dataSourceSnapshot.rowHeightCache + + let startColumn = scrollViewConfiguration.startColumn + let startRow = scrollViewConfiguration.startRow + let numberOfColumns = scrollViewConfiguration.numberOfColumns + let columnCount = scrollViewConfiguration.columnCount + let insets = scrollViewConfiguration.insets + let columnRecords = scrollViewConfiguration.columnRecords + let rowRecords = scrollViewConfiguration.rowRecords + let startColumnIndex = spreadsheetView.findIndex(in: columnRecords, for: visibleRect.origin.x - insets.x) cellOrigin.x = insets.x + columnRecords[startColumnIndex] + intercellSpacing.width @@ -264,6 +359,10 @@ final class LayoutEngine { return } + let blankCellReuseIdentifier = spreadsheetViewConfiguration.blankCellReuseIdentifier + let highlightedIndexPaths = spreadsheetViewConfiguration.highlightedIndexPaths + let selectedIndexPaths = spreadsheetViewConfiguration.selectedIndexPaths + let gridlines: Gridlines? let border: (borders: Borders?, hasBorders: Bool) @@ -291,7 +390,7 @@ final class LayoutEngine { gridlines = cell.gridlines border = (cell.borders, cell.hasBorder) - scrollView.insertSubview(cell, at: 0) + layouter.layout(cell: cell) scrollView.visibleCells[address] = cell } @@ -350,6 +449,8 @@ final class LayoutEngine { } private func renderHorizontalGridlines() { + let intercellSpacing = spreadsheetViewConfiguration.intercellSpacing + for (address, gridLayout) in horizontalGridLayouts { var frame = CGRect.zero frame.origin = gridLayout.origin @@ -385,6 +486,8 @@ final class LayoutEngine { } private func renderVerticalGridlines() { + let intercellSpacing = spreadsheetViewConfiguration.intercellSpacing + for (address, gridLayout) in verticalGridLayouts { var frame = CGRect.zero frame.origin = gridLayout.origin @@ -440,6 +543,8 @@ final class LayoutEngine { } private func extractGridStyle(style: GridStyle) -> (width: CGFloat, color: UIColor, priority: CGFloat) { + let defaultGridStyle = spreadsheetViewConfiguration.defaultGridStyle + let gridWidth: CGFloat let gridColor: UIColor let priority: CGFloat @@ -512,6 +617,35 @@ final class LayoutEngine { } } +struct SpreadsheetViewConfiguration { + let intercellSpacing: CGSize + let defaultGridStyle: GridStyle + let circularScrollingOptions: CircularScrolling.Configuration.Options + var circularScrollScalingFactor: (horizontal: Int, vertical: Int) + let blankCellReuseIdentifier: String + let highlightedIndexPaths: Set + let selectedIndexPaths: Set +} + +struct DataSourceSnapshot { + let frozenColumns: Int + let frozenRows: Int + let columnWidthCache: [CGFloat] + let rowHeightCache: [CGFloat] +} + +struct ScrollViewConfiguration { + let startColumn: Int + let startRow: Int + let numberOfColumns: Int + let numberOfRows: Int + let columnCount: Int + let rowCount: Int + let insets: CGPoint + let columnRecords: [CGFloat] + let rowRecords: [CGFloat] +} + struct LayoutProperties { let numberOfColumns: Int let numberOfRows: Int @@ -574,3 +708,7 @@ struct GridLayout { let edge: RectEdge let priority: CGFloat } + +protocol ViewLayouter { + mutating func layout(cell: Cell) +} diff --git a/Framework/Sources/SpreadsheetView+Layout.swift b/Framework/Sources/SpreadsheetView+Layout.swift index e9e96ff9..d9974fe3 100644 --- a/Framework/Sources/SpreadsheetView+Layout.swift +++ b/Framework/Sources/SpreadsheetView+Layout.swift @@ -105,17 +105,28 @@ extension SpreadsheetView { } func layoutAttributeForCornerView() -> LayoutAttributes { + return SpreadsheetView.layoutAttributeForCornerView(spreadsheetViewConfiguration, layoutProperties) + } + + static func layoutAttributeForCornerView(_ spreadsheetViewConfiguration: SpreadsheetViewConfiguration, _ layoutProperties: LayoutProperties) -> LayoutAttributes { return LayoutAttributes(startColumn: 0, startRow: 0, - numberOfColumns: frozenColumns, - numberOfRows: frozenRows, - columnCount: frozenColumns, - rowCount: frozenRows, + numberOfColumns: layoutProperties.frozenColumns, + numberOfRows: layoutProperties.frozenRows, + columnCount: layoutProperties.frozenColumns, + rowCount: layoutProperties.frozenRows, insets: .zero) } func layoutAttributeForColumnHeaderView() -> LayoutAttributes { - let insets = circularScrollingOptions.headerStyle == .columnHeaderStartsFirstRow ? CGPoint(x: 0, y: layoutProperties.rowHeightCache.prefix(upTo: frozenRows).reduce(0) { $0 + $1 } + intercellSpacing.height * CGFloat(layoutProperties.frozenRows)) : .zero + return SpreadsheetView.layoutAttributeForColumnHeaderView(spreadsheetViewConfiguration , layoutProperties) + } + + static func layoutAttributeForColumnHeaderView(_ spreadsheetViewConfiguration: SpreadsheetViewConfiguration, _ layoutProperties: LayoutProperties) -> LayoutAttributes { + let intercellSpacing = spreadsheetViewConfiguration.intercellSpacing + let circularScrollingOptions = spreadsheetViewConfiguration.circularScrollingOptions + let circularScrollScalingFactor = spreadsheetViewConfiguration.circularScrollScalingFactor + let insets = circularScrollingOptions.headerStyle == .columnHeaderStartsFirstRow ? CGPoint(x: 0, y: layoutProperties.rowHeightCache.prefix(upTo: layoutProperties.frozenRows).reduce(0) { $0 + $1 } + intercellSpacing.height * CGFloat(layoutProperties.frozenRows)) : .zero return LayoutAttributes(startColumn: 0, startRow: layoutProperties.frozenRows, numberOfColumns: layoutProperties.frozenColumns, @@ -126,7 +137,14 @@ extension SpreadsheetView { } func layoutAttributeForRowHeaderView() -> LayoutAttributes { - let insets = circularScrollingOptions.headerStyle == .rowHeaderStartsFirstColumn ? CGPoint(x: layoutProperties.columnWidthCache.prefix(upTo: frozenColumns).reduce(0) { $0 + $1 } + intercellSpacing.width * CGFloat(layoutProperties.frozenColumns), y: 0) : .zero + return SpreadsheetView.layoutAttributeForRowHeaderView(spreadsheetViewConfiguration , layoutProperties) + } + + static func layoutAttributeForRowHeaderView(_ spreadsheetViewConfiguration: SpreadsheetViewConfiguration, _ layoutProperties: LayoutProperties) -> LayoutAttributes { + let intercellSpacing = spreadsheetViewConfiguration.intercellSpacing + let circularScrollingOptions = spreadsheetViewConfiguration.circularScrollingOptions + let circularScrollScalingFactor = spreadsheetViewConfiguration.circularScrollScalingFactor + let insets = circularScrollingOptions.headerStyle == .rowHeaderStartsFirstColumn ? CGPoint(x: layoutProperties.columnWidthCache.prefix(upTo: layoutProperties.frozenColumns).reduce(0) { $0 + $1 } + intercellSpacing.width * CGFloat(layoutProperties.frozenColumns), y: 0) : .zero return LayoutAttributes(startColumn: layoutProperties.frozenColumns, startRow: 0, numberOfColumns: layoutProperties.numberOfColumns, @@ -137,6 +155,11 @@ extension SpreadsheetView { } func layoutAttributeForTableView() -> LayoutAttributes { + return SpreadsheetView.layoutAttributeForTableView(spreadsheetViewConfiguration , layoutProperties) + } + + static func layoutAttributeForTableView(_ spreadsheetViewConfiguration: SpreadsheetViewConfiguration, _ layoutProperties: LayoutProperties) -> LayoutAttributes { + let circularScrollScalingFactor = spreadsheetViewConfiguration.circularScrollScalingFactor return LayoutAttributes(startColumn: layoutProperties.frozenColumns, startRow: layoutProperties.frozenRows, numberOfColumns: layoutProperties.numberOfColumns, @@ -150,12 +173,15 @@ extension SpreadsheetView { guard let dataSource = dataSource else { return LayoutProperties() } + return SpreadsheetView.resetLayoutProperties(dataSource, self) + } - let numberOfColumns = dataSource.numberOfColumns(in: self) - let numberOfRows = dataSource.numberOfRows(in: self) + static func resetLayoutProperties(_ dataSource: SpreadsheetViewDataSource, _ spreadsheetView: SpreadsheetView) -> LayoutProperties { + let numberOfColumns = dataSource.numberOfColumns(in: spreadsheetView) + let numberOfRows = dataSource.numberOfRows(in: spreadsheetView) - let frozenColumns = dataSource.frozenColumns(in: self) - let frozenRows = dataSource.frozenRows(in: self) + let frozenColumns = dataSource.frozenColumns(in: spreadsheetView) + let frozenRows = dataSource.frozenRows(in: spreadsheetView) guard numberOfColumns >= 0 else { fatalError("`numberOfColumns(in:)` must return a value greater than or equal to 0") @@ -170,7 +196,7 @@ extension SpreadsheetView { fatalError("`frozenRows(in:) must return a value less than or equal to `numberOfRows(in:)`") } - let mergedCells = dataSource.mergedCells(in: self) + let mergedCells = dataSource.mergedCells(in: spreadsheetView) let mergedCellLayouts: [Location: CellRange] = { () in var layouts = [Location: CellRange]() for mergedCell in mergedCells { @@ -205,13 +231,13 @@ extension SpreadsheetView { var columnWidthCache = [CGFloat]() var frozenColumnWidth: CGFloat = 0 for column in 0..= startColumn { width += layoutProperties.columnWidthCache[index] + intercellSpacing.width } @@ -264,7 +299,7 @@ extension SpreadsheetView { var height: CGFloat = 0 for row in startRow..= startRow { height += layoutProperties.rowHeightCache[index] + intercellSpacing.height } diff --git a/Framework/Sources/SpreadsheetView.swift b/Framework/Sources/SpreadsheetView.swift index b072f40d..8cc31d8a 100644 --- a/Framework/Sources/SpreadsheetView.swift +++ b/Framework/Sources/SpreadsheetView.swift @@ -314,6 +314,12 @@ public class SpreadsheetView: UIView { return overlayView } + var spreadsheetViewConfiguration: SpreadsheetViewConfiguration { + return SpreadsheetViewConfiguration(intercellSpacing: intercellSpacing, defaultGridStyle: gridStyle, + circularScrollingOptions: circularScrollingOptions, circularScrollScalingFactor: circularScrollScalingFactor, + blankCellReuseIdentifier: blankCellReuseIdentifier, + highlightedIndexPaths: highlightedIndexPaths, selectedIndexPaths: selectedIndexPaths) + } var layoutProperties = LayoutProperties() let rootView = UIScrollView() diff --git a/Framework/SpreadsheetView.xcodeproj/project.pbxproj b/Framework/SpreadsheetView.xcodeproj/project.pbxproj index a228320a..cad1c987 100644 --- a/Framework/SpreadsheetView.xcodeproj/project.pbxproj +++ b/Framework/SpreadsheetView.xcodeproj/project.pbxproj @@ -21,6 +21,7 @@ 1451A0721ECEC2AF00C048DF /* SpreadsheetView+UIViewHierarchy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1451A0711ECEC2AF00C048DF /* SpreadsheetView+UIViewHierarchy.swift */; }; 1478491F1EC38F8D0020C938 /* ConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1478491E1EC38F8B0020C938 /* ConfigurationTests.swift */; }; 147898E31ECB607E004BB0A1 /* CellTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 147898E21ECB607E004BB0A1 /* CellTests.swift */; }; + 14892A5F1F6BA05C000852E2 /* LayoutTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14892A5E1F6BA05C000852E2 /* LayoutTests.swift */; }; 149E24001EBD4D620049E172 /* CircularScrolling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 149E23FF1EBD4D620049E172 /* CircularScrolling.swift */; }; 149E24021EBECDFB0049E172 /* DataSourceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 149E24011EBECDFB0049E172 /* DataSourceTests.swift */; }; 149E24071EBF05A10049E172 /* LayoutEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 149E24061EBF05A00049E172 /* LayoutEngine.swift */; }; @@ -103,6 +104,7 @@ 1451A0711ECEC2AF00C048DF /* SpreadsheetView+UIViewHierarchy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SpreadsheetView+UIViewHierarchy.swift"; sourceTree = ""; }; 1478491E1EC38F8B0020C938 /* ConfigurationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigurationTests.swift; sourceTree = ""; }; 147898E21ECB607E004BB0A1 /* CellTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CellTests.swift; sourceTree = ""; }; + 14892A5E1F6BA05C000852E2 /* LayoutTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayoutTests.swift; sourceTree = ""; }; 149E23FF1EBD4D620049E172 /* CircularScrolling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircularScrolling.swift; sourceTree = ""; }; 149E24011EBECDFB0049E172 /* DataSourceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataSourceTests.swift; sourceTree = ""; }; 149E24061EBF05A00049E172 /* LayoutEngine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayoutEngine.swift; sourceTree = ""; }; @@ -258,6 +260,7 @@ 14CBB7EF1EC8AF22005BEEB3 /* CellRangeTests.swift */, 1478491E1EC38F8B0020C938 /* ConfigurationTests.swift */, 143664C41EB6201800321E5E /* PerformanceTests.swift */, + 14892A5E1F6BA05C000852E2 /* LayoutTests.swift */, 143664C01EB5A07300321E5E /* HelperObjects.swift */, 143664BE1EB5A01500321E5E /* HelperFunctions.swift */, 149E6AA41EADE19F000D851D /* HostApp */, @@ -465,6 +468,7 @@ 147898E31ECB607E004BB0A1 /* CellTests.swift in Sources */, 143664BF1EB5A01600321E5E /* HelperFunctions.swift in Sources */, 143664C31EB61FE900321E5E /* SelectionTests.swift in Sources */, + 14892A5F1F6BA05C000852E2 /* LayoutTests.swift in Sources */, 149E24021EBECDFB0049E172 /* DataSourceTests.swift in Sources */, 14AE25761EBF1F8C0003D1F8 /* MergedCellTests.swift in Sources */, ); diff --git a/Framework/Tests/LayoutTests.swift b/Framework/Tests/LayoutTests.swift new file mode 100644 index 00000000..f97e5b35 --- /dev/null +++ b/Framework/Tests/LayoutTests.swift @@ -0,0 +1,126 @@ +// +// LayoutTests.swift +// SpreadsheetViewTests +// +// Created by Kishikawa Katsumi on 2017/09/15. +// Copyright © 2017 Kishikawa Katsumi. All rights reserved. +// + +import XCTest +@testable import SpreadsheetView + +class DataSource: SpreadsheetViewDataSource { + var spreadsheetViewConfiguration: SpreadsheetViewConfiguration + var dataSourceSnapshot: DataSourceSnapshot + + init(spreadsheetViewConfiguration: SpreadsheetViewConfiguration, dataSourceSnapshot: DataSourceSnapshot) { + self.spreadsheetViewConfiguration = spreadsheetViewConfiguration + self.dataSourceSnapshot = dataSourceSnapshot + } + + func numberOfColumns(in spreadsheetView: SpreadsheetView) -> Int { + return dataSourceSnapshot.columnWidthCache.count + } + + func numberOfRows(in spreadsheetView: SpreadsheetView) -> Int { + return dataSourceSnapshot.columnWidthCache.count + } + + func spreadsheetView(_ spreadsheetView: SpreadsheetView, widthForColumn column: Int) -> CGFloat { + return dataSourceSnapshot.columnWidthCache[column] + } + + func spreadsheetView(_ spreadsheetView: SpreadsheetView, heightForRow row: Int) -> CGFloat { + return dataSourceSnapshot.rowHeightCache[row] + } + + func spreadsheetView(_ spreadsheetView: SpreadsheetView, cellForItemAt indexPath: IndexPath) -> Cell? { + return nil + } + + func mergedCells(in spreadsheetView: SpreadsheetView) -> [CellRange] { + return [] + } + + func frozenColumns(in spreadsheetView: SpreadsheetView) -> Int { + return dataSourceSnapshot.frozenColumns + } + + func frozenRows(in spreadsheetView: SpreadsheetView) -> Int { + return dataSourceSnapshot.frozenRows + } +} + +class LayoutTests: XCTestCase { + override func setUp() { + super.setUp() + } + + override func tearDown() { + super.tearDown() + } + + func testSimpleLayout() { + let spreadsheetViewConfiguration = SpreadsheetViewConfiguration(intercellSpacing: CGSize(width: 4, height: 4), + defaultGridStyle: .none, + circularScrollingOptions: CircularScrolling.Configuration.none.options, + circularScrollScalingFactor: (1, 1), + blankCellReuseIdentifier: "", + highlightedIndexPaths: [], + selectedIndexPaths: []) + let dataSourceSnapshot = DataSourceSnapshot(frozenColumns: 0, frozenRows: 0, + columnWidthCache: [CGFloat](repeating: 60, count: 200), + rowHeightCache: [CGFloat](repeating: 40, count: 200)) + let dataSource = DataSource(spreadsheetViewConfiguration: spreadsheetViewConfiguration, dataSourceSnapshot: dataSourceSnapshot) + + let spreadsheetView = SpreadsheetView() + spreadsheetView.dataSource = dataSource + let layoutProperties = SpreadsheetView.resetLayoutProperties(dataSource, spreadsheetView) + let layoutAttribute = SpreadsheetView.layoutAttributeForTableView(spreadsheetViewConfiguration, layoutProperties) + + let scrollView = ScrollView(frame: CGRect(x: 0, y: 0, width: 320, height: 567)) + scrollView.layoutAttributes = layoutAttribute + SpreadsheetView.initializeScrollView(scrollView: scrollView, spreadsheetViewConfiguration: spreadsheetViewConfiguration, layoutProperties: layoutProperties) + + let scrollViewConfiguration = ScrollViewConfiguration(startColumn: layoutAttribute.startColumn, startRow: layoutAttribute.startRow, + numberOfColumns: layoutAttribute.numberOfColumns, numberOfRows: layoutAttribute.numberOfRows, + columnCount: layoutAttribute.columnCount, rowCount: layoutAttribute.rowCount, + insets: layoutAttribute.insets, + columnRecords: scrollView.columnRecords, rowRecords: scrollView.rowRecords) + + + do { + let contentOffset = CGPoint(x: 0, y: 0) + let scrollViewState = ScrollView.State(frame: scrollView.frame, contentSize: scrollView.contentSize, contentOffset: contentOffset) + + let layoutEngine = LayoutEngine(spreadsheetViewConfiguration: spreadsheetViewConfiguration, + dataSourceSnapshot: dataSourceSnapshot, + scrollViewConfiguration: scrollViewConfiguration, + scrollViewState: scrollViewState) + layoutEngine.layout() + print(layoutEngine.layouter) + } + do { + let contentOffset = CGPoint(x: 80, y: 0) + let scrollViewState = ScrollView.State(frame: scrollView.frame, contentSize: scrollView.contentSize, contentOffset: contentOffset) + + let layoutEngine = LayoutEngine(spreadsheetViewConfiguration: spreadsheetViewConfiguration, + dataSourceSnapshot: dataSourceSnapshot, + scrollViewConfiguration: scrollViewConfiguration, + scrollViewState: scrollViewState) + layoutEngine.layout() + print(layoutEngine.layouter) + } + do { + let contentOffset = CGPoint(x: 80, y: 60) + let scrollViewState = ScrollView.State(frame: scrollView.frame, contentSize: scrollView.contentSize, contentOffset: contentOffset) + + let layoutEngine = LayoutEngine(spreadsheetViewConfiguration: spreadsheetViewConfiguration, + dataSourceSnapshot: dataSourceSnapshot, + scrollViewConfiguration: scrollViewConfiguration, + scrollViewState: scrollViewState) + layoutEngine.layout() + print(layoutEngine.layouter) + } + } +}