From 4bb0383907f95fd30bbef02693afc97a0ad46a60 Mon Sep 17 00:00:00 2001 From: James Tang Date: Sun, 19 Jul 2015 16:03:31 +0800 Subject: [PATCH] CSStickyHeaderLayoutGuide, introducing a testable object --- Classes/CSStickyHeaderLayoutGuide.h | 54 +++++++++++++++++++ Classes/CSStickyHeaderLayoutGuide.m | 25 +++++++++ .../project.pbxproj | 18 +++++-- .../CSStickyHeaderFlowLayoutDemoTests.m | 5 -- .../CSStickyHeaderFlowLayoutTests.swift | 36 ------------- .../CSStickyHeaderLayoutGuideTests.m | 50 +++++++++++++++++ 6 files changed, 143 insertions(+), 45 deletions(-) create mode 100644 Classes/CSStickyHeaderLayoutGuide.h create mode 100644 Classes/CSStickyHeaderLayoutGuide.m delete mode 100644 Project/CSStickyHeaderFlowLayoutTests/CSStickyHeaderFlowLayoutTests.swift create mode 100644 Project/CSStickyHeaderFlowLayoutTests/CSStickyHeaderLayoutGuideTests.m diff --git a/Classes/CSStickyHeaderLayoutGuide.h b/Classes/CSStickyHeaderLayoutGuide.h new file mode 100644 index 0000000..1e414e5 --- /dev/null +++ b/Classes/CSStickyHeaderLayoutGuide.h @@ -0,0 +1,54 @@ +// +// CSStickyHeaderLayoutGuide.h +// CSStickyHeaderFlowLayoutDemo +// +// Created by James Tang on 19/7/15. +// Copyright (c) 2015 Jamz Tang. All rights reserved. +// +// Testable object behind CSStickyHeaderFlowLayout + +#import +@import QuartzCore; + + +typedef NS_ENUM(NSInteger, CSStickyHeaderLayoutDirection) { + CSStickyHeaderLayoutDirectionVertical, +}; + +typedef struct CSEdgeInsets { + CGFloat top, left, bottom, right; // specify amount to inset (positive) for each of the edges. values can be negative to 'outset' +} CSEdgeInsets; + +static inline NSString * __nonnull NSStringFromCSEdgeInsets(CSEdgeInsets insets) { + return [NSString stringWithFormat:@"{%@, %@, %@, %@}", @(insets.top), @(insets.left), @(insets.bottom), @(insets.right)]; +} + +typedef CGSize(^CSStickyHeaderLayoutSizeHandler)(void); + +@interface CSStickyHeaderLayoutItem : NSObject + +@property (nonatomic, copy, nullable) CSStickyHeaderLayoutSizeHandler sizeHandler; + ++ (nonnull instancetype)itemWithSizeHandler:(__nullable CSStickyHeaderLayoutSizeHandler)handler; + +@end + + +@interface CSStickyHeaderLayoutGuide : NSObject + +@property (nonatomic) CGFloat minimumLineSpacing; +@property (nonatomic) CGFloat minimumInteritemSpacing; +@property (nonatomic) CGSize itemSize; // If items.size is specified, then itemSize will be ignored +@property (nonatomic) CSStickyHeaderLayoutDirection scrollDirection; // default is CSStickyHeaderLayoutDirectionVertical +@property (nonatomic) CGSize headerReferenceSize; +@property (nonatomic) CGSize footerReferenceSize; +@property (nonatomic) CSEdgeInsets sectionInset; + +@property (nonatomic) CGSize parallaxHeaderReferenceSize; +@property (nonatomic) CGSize parallaxHeaderMinimumReferenceSize; +@property (nonatomic) BOOL parallaxHeaderAlwaysOnTop; +@property (nonatomic) BOOL disableStickyHeaders; + +@property (nonatomic, copy, nonnull) NSArray *items; + +@end diff --git a/Classes/CSStickyHeaderLayoutGuide.m b/Classes/CSStickyHeaderLayoutGuide.m new file mode 100644 index 0000000..f7c49e2 --- /dev/null +++ b/Classes/CSStickyHeaderLayoutGuide.m @@ -0,0 +1,25 @@ +// +// CSStickyHeaderLayoutGuide.m +// CSStickyHeaderFlowLayoutDemo +// +// Created by James Tang on 19/7/15. +// Copyright (c) 2015 Jamz Tang. All rights reserved. +// + +#import "CSStickyHeaderLayoutGuide.h" + +@implementation CSStickyHeaderLayoutGuide + +- (instancetype)init +{ + self = [super init]; + if (self) { + self.minimumLineSpacing = 10; + self.minimumInteritemSpacing = 10; + self.itemSize = CGSizeMake(50, 50); + self.items = @[]; + } + return self; +} + +@end diff --git a/Project/CSStickyHeaderFlowLayoutDemo.xcodeproj/project.pbxproj b/Project/CSStickyHeaderFlowLayoutDemo.xcodeproj/project.pbxproj index 0cbd084..f44b160 100644 --- a/Project/CSStickyHeaderFlowLayoutDemo.xcodeproj/project.pbxproj +++ b/Project/CSStickyHeaderFlowLayoutDemo.xcodeproj/project.pbxproj @@ -15,7 +15,6 @@ 1A18AE5518F18764003DC8CF /* CSAlwaysOnTopHeader.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1A18AE5418F18764003DC8CF /* CSAlwaysOnTopHeader.xib */; }; 1A18AE5818F1947B003DC8CF /* CSAlwaysOnTopHeader.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A18AE5718F1947B003DC8CF /* CSAlwaysOnTopHeader.m */; }; 1A4B2F601B56C539007F67CC /* CSStickyHeaderFlowLayout.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A4B2F551B56C539007F67CC /* CSStickyHeaderFlowLayout.framework */; }; - 1A4B2F691B56C539007F67CC /* CSStickyHeaderFlowLayoutTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A4B2F681B56C539007F67CC /* CSStickyHeaderFlowLayoutTests.swift */; }; 1A4B2F791B56C5A6007F67CC /* CSStickyHeaderFlowLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A4B2F751B56C5A6007F67CC /* CSStickyHeaderFlowLayout.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1A4B2F7A1B56C5A6007F67CC /* CSStickyHeaderFlowLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A4B2F761B56C5A6007F67CC /* CSStickyHeaderFlowLayout.m */; }; 1A4B2F7B1B56C5A6007F67CC /* CSStickyHeaderFlowLayoutAttributes.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A4B2F771B56C5A6007F67CC /* CSStickyHeaderFlowLayoutAttributes.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -25,6 +24,9 @@ 1AC0D88918AA3AF80072B3F1 /* CSSearchBarHeader.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1AC0D88818AA3AF80072B3F1 /* CSSearchBarHeader.xib */; }; 1AC0D88C18AA3B300072B3F1 /* CSLockedHeaderViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AC0D88B18AA3B300072B3F1 /* CSLockedHeaderViewController.m */; }; 1AC67D171B5AC27F0091AFCD /* MyPulling.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AC67D161B5AC27F0091AFCD /* MyPulling.m */; }; + 1AF379091B5B8694003BD1CD /* CSStickyHeaderLayoutGuide.h in Headers */ = {isa = PBXBuildFile; fileRef = 1AF379071B5B8694003BD1CD /* CSStickyHeaderLayoutGuide.h */; }; + 1AF3790A1B5B8694003BD1CD /* CSStickyHeaderLayoutGuide.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AF379081B5B8694003BD1CD /* CSStickyHeaderLayoutGuide.m */; }; + 1AF3790C1B5B87C7003BD1CD /* CSStickyHeaderLayoutGuideTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AF3790B1B5B87C7003BD1CD /* CSStickyHeaderLayoutGuideTests.m */; }; 1AFE0956187D677000CA880A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1AFE0955187D677000CA880A /* Foundation.framework */; }; 1AFE0958187D677000CA880A /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1AFE0957187D677000CA880A /* CoreGraphics.framework */; }; 1AFE095A187D677000CA880A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1AFE0959187D677000CA880A /* UIKit.framework */; }; @@ -96,7 +98,6 @@ 1A4B2F581B56C539007F67CC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 1A4B2F5F1B56C539007F67CC /* CSStickyHeaderFlowLayoutTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CSStickyHeaderFlowLayoutTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 1A4B2F671B56C539007F67CC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 1A4B2F681B56C539007F67CC /* CSStickyHeaderFlowLayoutTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CSStickyHeaderFlowLayoutTests.swift; sourceTree = ""; }; 1A4B2F751B56C5A6007F67CC /* CSStickyHeaderFlowLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSStickyHeaderFlowLayout.h; path = ../../Classes/CSStickyHeaderFlowLayout.h; sourceTree = ""; }; 1A4B2F761B56C5A6007F67CC /* CSStickyHeaderFlowLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CSStickyHeaderFlowLayout.m; path = ../../Classes/CSStickyHeaderFlowLayout.m; sourceTree = ""; }; 1A4B2F771B56C5A6007F67CC /* CSStickyHeaderFlowLayoutAttributes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSStickyHeaderFlowLayoutAttributes.h; path = ../../Classes/CSStickyHeaderFlowLayoutAttributes.h; sourceTree = ""; }; @@ -108,6 +109,9 @@ 1AC0D88B18AA3B300072B3F1 /* CSLockedHeaderViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSLockedHeaderViewController.m; sourceTree = ""; }; 1AC67D151B5AC27F0091AFCD /* MyPulling.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MyPulling.h; sourceTree = ""; }; 1AC67D161B5AC27F0091AFCD /* MyPulling.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MyPulling.m; sourceTree = ""; }; + 1AF379071B5B8694003BD1CD /* CSStickyHeaderLayoutGuide.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSStickyHeaderLayoutGuide.h; path = ../../Classes/CSStickyHeaderLayoutGuide.h; sourceTree = ""; }; + 1AF379081B5B8694003BD1CD /* CSStickyHeaderLayoutGuide.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CSStickyHeaderLayoutGuide.m; path = ../../Classes/CSStickyHeaderLayoutGuide.m; sourceTree = ""; }; + 1AF3790B1B5B87C7003BD1CD /* CSStickyHeaderLayoutGuideTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSStickyHeaderLayoutGuideTests.m; sourceTree = ""; }; 1AFE0952187D677000CA880A /* CSStickyHeaderFlowLayoutDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CSStickyHeaderFlowLayoutDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 1AFE0955187D677000CA880A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 1AFE0957187D677000CA880A /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; @@ -190,6 +194,8 @@ children = ( 1A4B2F751B56C5A6007F67CC /* CSStickyHeaderFlowLayout.h */, 1A4B2F761B56C5A6007F67CC /* CSStickyHeaderFlowLayout.m */, + 1AF379071B5B8694003BD1CD /* CSStickyHeaderLayoutGuide.h */, + 1AF379081B5B8694003BD1CD /* CSStickyHeaderLayoutGuide.m */, 1A4B2F771B56C5A6007F67CC /* CSStickyHeaderFlowLayoutAttributes.h */, 1A4B2F781B56C5A6007F67CC /* CSStickyHeaderFlowLayoutAttributes.m */, 1A4B2F571B56C539007F67CC /* Supporting Files */, @@ -208,8 +214,8 @@ 1A4B2F651B56C539007F67CC /* CSStickyHeaderFlowLayoutTests */ = { isa = PBXGroup; children = ( - 1A4B2F681B56C539007F67CC /* CSStickyHeaderFlowLayoutTests.swift */, 1A4B2F661B56C539007F67CC /* Supporting Files */, + 1AF3790B1B5B87C7003BD1CD /* CSStickyHeaderLayoutGuideTests.m */, ); path = CSStickyHeaderFlowLayoutTests; sourceTree = ""; @@ -346,6 +352,7 @@ files = ( 1A4B2F791B56C5A6007F67CC /* CSStickyHeaderFlowLayout.h in Headers */, 1A4B2F7B1B56C5A6007F67CC /* CSStickyHeaderFlowLayoutAttributes.h in Headers */, + 1AF379091B5B8694003BD1CD /* CSStickyHeaderLayoutGuide.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -550,6 +557,7 @@ files = ( 1A4B2F7C1B56C5A6007F67CC /* CSStickyHeaderFlowLayoutAttributes.m in Sources */, 1A4B2F7A1B56C5A6007F67CC /* CSStickyHeaderFlowLayout.m in Sources */, + 1AF3790A1B5B8694003BD1CD /* CSStickyHeaderLayoutGuide.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -557,7 +565,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 1A4B2F691B56C539007F67CC /* CSStickyHeaderFlowLayoutTests.swift in Sources */, + 1AF3790C1B5B87C7003BD1CD /* CSStickyHeaderLayoutGuideTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -637,6 +645,7 @@ 1A4B2F6F1B56C539007F67CC /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_MODULES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; @@ -669,6 +678,7 @@ 1A4B2F701B56C539007F67CC /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_MODULES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; diff --git a/Project/CSStickyHeaderFlowLayoutDemoTests/CSStickyHeaderFlowLayoutDemoTests.m b/Project/CSStickyHeaderFlowLayoutDemoTests/CSStickyHeaderFlowLayoutDemoTests.m index 4fc774f..500b0b7 100644 --- a/Project/CSStickyHeaderFlowLayoutDemoTests/CSStickyHeaderFlowLayoutDemoTests.m +++ b/Project/CSStickyHeaderFlowLayoutDemoTests/CSStickyHeaderFlowLayoutDemoTests.m @@ -26,9 +26,4 @@ - (void)tearDown [super tearDown]; } -- (void)testExample -{ - XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); -} - @end diff --git a/Project/CSStickyHeaderFlowLayoutTests/CSStickyHeaderFlowLayoutTests.swift b/Project/CSStickyHeaderFlowLayoutTests/CSStickyHeaderFlowLayoutTests.swift deleted file mode 100644 index 7bd858e..0000000 --- a/Project/CSStickyHeaderFlowLayoutTests/CSStickyHeaderFlowLayoutTests.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// CSStickyHeaderFlowLayoutTests.swift -// CSStickyHeaderFlowLayoutTests -// -// Created by James Tang on 16/7/15. -// Copyright (c) 2015 Jamz Tang. All rights reserved. -// - -import UIKit -import XCTest - -class CSStickyHeaderFlowLayoutTests: XCTestCase { - - override func setUp() { - super.setUp() - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - super.tearDown() - } - - func testExample() { - // This is an example of a functional test case. - XCTAssert(true, "Pass") - } - - func testPerformanceExample() { - // This is an example of a performance test case. - self.measureBlock() { - // Put the code you want to measure the time of here. - } - } - -} diff --git a/Project/CSStickyHeaderFlowLayoutTests/CSStickyHeaderLayoutGuideTests.m b/Project/CSStickyHeaderFlowLayoutTests/CSStickyHeaderLayoutGuideTests.m new file mode 100644 index 0000000..2ec6dbe --- /dev/null +++ b/Project/CSStickyHeaderFlowLayoutTests/CSStickyHeaderLayoutGuideTests.m @@ -0,0 +1,50 @@ +// +// CSStickyHeaderLayoutGuideTests.m +// CSStickyHeaderFlowLayoutDemo +// +// Created by James Tang on 19/7/15. +// Copyright (c) 2015 Jamz Tang. All rights reserved. +// + +#import +#import +#import "CSStickyHeaderLayoutGuide.h" + +@interface CSStickyHeaderLayoutGuideTests : XCTestCase + +@property (nonatomic, strong) CSStickyHeaderLayoutGuide *guide; + +@end + +@implementation CSStickyHeaderLayoutGuideTests + +- (void)setUp { + [super setUp]; + + self.guide = [[CSStickyHeaderLayoutGuide alloc] init]; +} + +- (void)tearDown { + + self.guide = nil; + [super tearDown]; +} + +- (void)testDefaults { + XCTAssertEqual(self.guide.minimumLineSpacing, 10); + XCTAssertEqual(self.guide.minimumInteritemSpacing, 10); + XCTAssertEqualObjects(NSStringFromCGSize(self.guide.itemSize), @"{50, 50}"); + XCTAssertEqual(self.guide.scrollDirection, CSStickyHeaderLayoutDirectionVertical); + XCTAssertEqualObjects(NSStringFromCGSize(self.guide.headerReferenceSize), @"{0, 0}"); + XCTAssertEqualObjects(NSStringFromCGSize(self.guide.footerReferenceSize), @"{0, 0}"); + XCTAssertEqualObjects(NSStringFromCGSize(self.guide.headerReferenceSize), @"{0, 0}"); + XCTAssertEqualObjects(NSStringFromCSEdgeInsets(self.guide.sectionInset), @"{0, 0, 0, 0}"); + XCTAssertEqualObjects(NSStringFromCGSize(self.guide.parallaxHeaderReferenceSize), @"{0, 0}"); + XCTAssertEqualObjects(NSStringFromCGSize(self.guide.parallaxHeaderMinimumReferenceSize), @"{0, 0}"); + XCTAssertEqual(self.guide.parallaxHeaderAlwaysOnTop, NO); + XCTAssertEqual(self.guide.disableStickyHeaders, NO); + XCTAssertEqualObjects(self.guide.items, @[]); +} + + +@end