From d9083c1237cb821002d098db1f5540274f7b2692 Mon Sep 17 00:00:00 2001 From: Ling Wang Date: Wed, 26 Jun 2013 09:55:45 -0500 Subject: [PATCH] Reborn as a standalone project. --- .../project.pbxproj | 360 ++++++ WLPageViewController/AppDelegate.h | 15 + WLPageViewController/AppDelegate.m | 52 + WLPageViewController/DataViewController.h | 14 + WLPageViewController/DataViewController.m | 37 + WLPageViewController/DataViewController.xib | 236 ++++ WLPageViewController/Default-568h@2x.png | Bin 0 -> 18594 bytes WLPageViewController/Default.png | Bin 0 -> 6540 bytes WLPageViewController/Default@2x.png | Bin 0 -> 16107 bytes WLPageViewController/ModelController.h | 17 + WLPageViewController/ModelController.m | 89 ++ WLPageViewController/PageViewController.h | 16 + WLPageViewController/PageViewController.m | 68 + WLPageViewController/PageViewController.xib | 133 ++ .../WLPageViewController-Info.plist | 45 + .../WLPageViewController-Prefix.pch | 29 + WLPageViewController/WLPageViewController.h | 48 + WLPageViewController/WLPageViewController.m | 1098 +++++++++++++++++ WLPageViewController/damping.m | 53 + .../en.lproj/InfoPlist.strings | 2 + WLPageViewController/main.m | 18 + 21 files changed, 2330 insertions(+) create mode 100644 WLPageViewController.xcodeproj/project.pbxproj create mode 100644 WLPageViewController/AppDelegate.h create mode 100644 WLPageViewController/AppDelegate.m create mode 100644 WLPageViewController/DataViewController.h create mode 100644 WLPageViewController/DataViewController.m create mode 100644 WLPageViewController/DataViewController.xib create mode 100644 WLPageViewController/Default-568h@2x.png create mode 100644 WLPageViewController/Default.png create mode 100644 WLPageViewController/Default@2x.png create mode 100644 WLPageViewController/ModelController.h create mode 100644 WLPageViewController/ModelController.m create mode 100644 WLPageViewController/PageViewController.h create mode 100644 WLPageViewController/PageViewController.m create mode 100644 WLPageViewController/PageViewController.xib create mode 100644 WLPageViewController/WLPageViewController-Info.plist create mode 100644 WLPageViewController/WLPageViewController-Prefix.pch create mode 100644 WLPageViewController/WLPageViewController.h create mode 100644 WLPageViewController/WLPageViewController.m create mode 100644 WLPageViewController/damping.m create mode 100644 WLPageViewController/en.lproj/InfoPlist.strings create mode 100644 WLPageViewController/main.m diff --git a/WLPageViewController.xcodeproj/project.pbxproj b/WLPageViewController.xcodeproj/project.pbxproj new file mode 100644 index 0000000..69b188b --- /dev/null +++ b/WLPageViewController.xcodeproj/project.pbxproj @@ -0,0 +1,360 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + C952C46817626F490021A0BA /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C952C46717626F490021A0BA /* UIKit.framework */; }; + C952C46A17626F490021A0BA /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C952C46917626F490021A0BA /* Foundation.framework */; }; + C952C46C17626F490021A0BA /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C952C46B17626F490021A0BA /* CoreGraphics.framework */; }; + C952C47217626F490021A0BA /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = C952C47017626F490021A0BA /* InfoPlist.strings */; }; + C952C47417626F490021A0BA /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C952C47317626F490021A0BA /* main.m */; }; + C952C47817626F490021A0BA /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = C952C47717626F490021A0BA /* AppDelegate.m */; }; + C952C47A17626F490021A0BA /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = C952C47917626F490021A0BA /* Default.png */; }; + C952C47C17626F490021A0BA /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C952C47B17626F490021A0BA /* Default@2x.png */; }; + C952C47E17626F490021A0BA /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C952C47D17626F490021A0BA /* Default-568h@2x.png */; }; + C952C48717626F620021A0BA /* WLPageViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C952C48617626F620021A0BA /* WLPageViewController.m */; }; + C952C4951762709C0021A0BA /* PageViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C952C48E1762709C0021A0BA /* PageViewController.m */; }; + C952C4961762709C0021A0BA /* DataViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C952C4901762709C0021A0BA /* DataViewController.m */; }; + C952C4971762709C0021A0BA /* ModelController.m in Sources */ = {isa = PBXBuildFile; fileRef = C952C4921762709C0021A0BA /* ModelController.m */; }; + C952C4981762709C0021A0BA /* PageViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = C952C4931762709C0021A0BA /* PageViewController.xib */; }; + C952C4991762709C0021A0BA /* DataViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = C952C4941762709C0021A0BA /* DataViewController.xib */; }; + C952C4D417629FFB0021A0BA /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C952C4D317629FFB0021A0BA /* QuartzCore.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + C952C46417626F490021A0BA /* WLPageViewController.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WLPageViewController.app; sourceTree = BUILT_PRODUCTS_DIR; }; + C952C46717626F490021A0BA /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + C952C46917626F490021A0BA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + C952C46B17626F490021A0BA /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + C952C46F17626F490021A0BA /* WLPageViewController-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "WLPageViewController-Info.plist"; sourceTree = ""; }; + C952C47117626F490021A0BA /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + C952C47317626F490021A0BA /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + C952C47517626F490021A0BA /* WLPageViewController-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "WLPageViewController-Prefix.pch"; sourceTree = ""; }; + C952C47617626F490021A0BA /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + C952C47717626F490021A0BA /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + C952C47917626F490021A0BA /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = ""; }; + C952C47B17626F490021A0BA /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = ""; }; + C952C47D17626F490021A0BA /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; + C952C48517626F620021A0BA /* WLPageViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WLPageViewController.h; sourceTree = ""; }; + C952C48617626F620021A0BA /* WLPageViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WLPageViewController.m; sourceTree = ""; }; + C952C48D1762709C0021A0BA /* PageViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PageViewController.h; sourceTree = ""; }; + C952C48E1762709C0021A0BA /* PageViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PageViewController.m; sourceTree = ""; }; + C952C48F1762709C0021A0BA /* DataViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataViewController.h; sourceTree = ""; }; + C952C4901762709C0021A0BA /* DataViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DataViewController.m; sourceTree = ""; }; + C952C4911762709C0021A0BA /* ModelController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModelController.h; sourceTree = ""; }; + C952C4921762709C0021A0BA /* ModelController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ModelController.m; sourceTree = ""; }; + C952C4931762709C0021A0BA /* PageViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PageViewController.xib; sourceTree = ""; }; + C952C4941762709C0021A0BA /* DataViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DataViewController.xib; sourceTree = ""; }; + C952C4D317629FFB0021A0BA /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + C952C46117626F490021A0BA /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C952C4D417629FFB0021A0BA /* QuartzCore.framework in Frameworks */, + C952C46817626F490021A0BA /* UIKit.framework in Frameworks */, + C952C46A17626F490021A0BA /* Foundation.framework in Frameworks */, + C952C46C17626F490021A0BA /* CoreGraphics.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + C952C45B17626F490021A0BA = { + isa = PBXGroup; + children = ( + C952C46D17626F490021A0BA /* WLPageViewController */, + C952C48417626F4E0021A0BA /* Demo */, + C952C46617626F490021A0BA /* Frameworks */, + C952C46517626F490021A0BA /* Products */, + ); + sourceTree = ""; + }; + C952C46517626F490021A0BA /* Products */ = { + isa = PBXGroup; + children = ( + C952C46417626F490021A0BA /* WLPageViewController.app */, + ); + name = Products; + sourceTree = ""; + }; + C952C46617626F490021A0BA /* Frameworks */ = { + isa = PBXGroup; + children = ( + C952C46717626F490021A0BA /* UIKit.framework */, + C952C46917626F490021A0BA /* Foundation.framework */, + C952C46B17626F490021A0BA /* CoreGraphics.framework */, + C952C4D317629FFB0021A0BA /* QuartzCore.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + C952C46D17626F490021A0BA /* WLPageViewController */ = { + isa = PBXGroup; + children = ( + C952C48C17626FD60021A0BA /* Dependence */, + C952C48517626F620021A0BA /* WLPageViewController.h */, + C952C48617626F620021A0BA /* WLPageViewController.m */, + ); + path = WLPageViewController; + sourceTree = ""; + }; + C952C46E17626F490021A0BA /* Supporting Files */ = { + isa = PBXGroup; + children = ( + C952C46F17626F490021A0BA /* WLPageViewController-Info.plist */, + C952C47017626F490021A0BA /* InfoPlist.strings */, + C952C47317626F490021A0BA /* main.m */, + C952C47517626F490021A0BA /* WLPageViewController-Prefix.pch */, + C952C47917626F490021A0BA /* Default.png */, + C952C47B17626F490021A0BA /* Default@2x.png */, + C952C47D17626F490021A0BA /* Default-568h@2x.png */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + C952C48417626F4E0021A0BA /* Demo */ = { + isa = PBXGroup; + children = ( + C952C47617626F490021A0BA /* AppDelegate.h */, + C952C47717626F490021A0BA /* AppDelegate.m */, + C952C48D1762709C0021A0BA /* PageViewController.h */, + C952C48E1762709C0021A0BA /* PageViewController.m */, + C952C48F1762709C0021A0BA /* DataViewController.h */, + C952C4901762709C0021A0BA /* DataViewController.m */, + C952C4911762709C0021A0BA /* ModelController.h */, + C952C4921762709C0021A0BA /* ModelController.m */, + C952C4931762709C0021A0BA /* PageViewController.xib */, + C952C4941762709C0021A0BA /* DataViewController.xib */, + C952C46E17626F490021A0BA /* Supporting Files */, + ); + name = Demo; + path = WLPageViewController; + sourceTree = ""; + }; + C952C48C17626FD60021A0BA /* Dependence */ = { + isa = PBXGroup; + children = ( + C9F06006177A4F7900978AF2 /* WLContainerControllers */, + ); + name = Dependence; + sourceTree = ""; + }; + C9F06006177A4F7900978AF2 /* WLContainerControllers */ = { + isa = PBXGroup; + children = ( + ); + name = WLContainerControllers; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + C952C46317626F490021A0BA /* WLPageViewController */ = { + isa = PBXNativeTarget; + buildConfigurationList = C952C48117626F490021A0BA /* Build configuration list for PBXNativeTarget "WLPageViewController" */; + buildPhases = ( + C952C46017626F490021A0BA /* Sources */, + C952C46117626F490021A0BA /* Frameworks */, + C952C46217626F490021A0BA /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = WLPageViewController; + productName = WLPageViewController; + productReference = C952C46417626F490021A0BA /* WLPageViewController.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + C952C45C17626F490021A0BA /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0460; + ORGANIZATIONNAME = Moke; + }; + buildConfigurationList = C952C45F17626F490021A0BA /* Build configuration list for PBXProject "WLPageViewController" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = C952C45B17626F490021A0BA; + productRefGroup = C952C46517626F490021A0BA /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + C952C46317626F490021A0BA /* WLPageViewController */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + C952C46217626F490021A0BA /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C952C47217626F490021A0BA /* InfoPlist.strings in Resources */, + C952C47A17626F490021A0BA /* Default.png in Resources */, + C952C47C17626F490021A0BA /* Default@2x.png in Resources */, + C952C47E17626F490021A0BA /* Default-568h@2x.png in Resources */, + C952C4981762709C0021A0BA /* PageViewController.xib in Resources */, + C952C4991762709C0021A0BA /* DataViewController.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + C952C46017626F490021A0BA /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C952C47417626F490021A0BA /* main.m in Sources */, + C952C47817626F490021A0BA /* AppDelegate.m in Sources */, + C952C48717626F620021A0BA /* WLPageViewController.m in Sources */, + C952C4951762709C0021A0BA /* PageViewController.m in Sources */, + C952C4961762709C0021A0BA /* DataViewController.m in Sources */, + C952C4971762709C0021A0BA /* ModelController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + C952C47017626F490021A0BA /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + C952C47117626F490021A0BA /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + C952C47F17626F490021A0BA /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES; + CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; + CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_STRICT_SELECTOR_MATCH = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + IPHONEOS_DEPLOYMENT_TARGET = 6.1; + ONLY_ACTIVE_ARCH = YES; + OTHER_CFLAGS = ( + "-Wall", + "-Wextra", + "-Wno-unused-parameter", + ); + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + C952C48017626F490021A0BA /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES; + CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; + CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_STRICT_SELECTOR_MATCH = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + IPHONEOS_DEPLOYMENT_TARGET = 6.1; + OTHER_CFLAGS = ( + "-Wall", + "-Wextra", + "-Wno-unused-parameter", + ); + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + C952C48217626F490021A0BA /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "WLPageViewController/WLPageViewController-Prefix.pch"; + INFOPLIST_FILE = "WLPageViewController/WLPageViewController-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + C952C48317626F490021A0BA /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "WLPageViewController/WLPageViewController-Prefix.pch"; + INFOPLIST_FILE = "WLPageViewController/WLPageViewController-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + C952C45F17626F490021A0BA /* Build configuration list for PBXProject "WLPageViewController" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C952C47F17626F490021A0BA /* Debug */, + C952C48017626F490021A0BA /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C952C48117626F490021A0BA /* Build configuration list for PBXNativeTarget "WLPageViewController" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C952C48217626F490021A0BA /* Debug */, + C952C48317626F490021A0BA /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = C952C45C17626F490021A0BA /* Project object */; +} diff --git a/WLPageViewController/AppDelegate.h b/WLPageViewController/AppDelegate.h new file mode 100644 index 0000000..7a81efa --- /dev/null +++ b/WLPageViewController/AppDelegate.h @@ -0,0 +1,15 @@ +// +// AppDelegate.h +// WLPageViewController +// +// Created by Ling Wang on 6/7/13. +// Copyright (c) 2013 Moke. All rights reserved. +// + +#import + +@interface AppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + +@end diff --git a/WLPageViewController/AppDelegate.m b/WLPageViewController/AppDelegate.m new file mode 100644 index 0000000..4630742 --- /dev/null +++ b/WLPageViewController/AppDelegate.m @@ -0,0 +1,52 @@ +// +// AppDelegate.m +// WLPageViewController +// +// Created by Ling Wang on 6/7/13. +// Copyright (c) 2013 Moke. All rights reserved. +// + +#import "AppDelegate.h" +#import "PageViewController.h" + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + PageViewController *papeViewController = [PageViewController new]; + + self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + self.window.backgroundColor = [UIColor whiteColor]; + self.window.rootViewController = papeViewController; + [self.window makeKeyAndVisible]; + return YES; +} + +- (void)applicationWillResignActive:(UIApplication *)application +{ + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. +} + +- (void)applicationDidEnterBackground:(UIApplication *)application +{ + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. +} + +- (void)applicationWillEnterForeground:(UIApplication *)application +{ + // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. +} + +- (void)applicationDidBecomeActive:(UIApplication *)application +{ + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. +} + +- (void)applicationWillTerminate:(UIApplication *)application +{ + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. +} + +@end diff --git a/WLPageViewController/DataViewController.h b/WLPageViewController/DataViewController.h new file mode 100644 index 0000000..ef45920 --- /dev/null +++ b/WLPageViewController/DataViewController.h @@ -0,0 +1,14 @@ +// +// DataViewController.h +// WLPageViewController +// +// Created by Ling Wang on 7/7/11. +// Copyright 2011 __MyCompanyName__. All rights reserved. +// + +#import + +@interface DataViewController : UIViewController +@property (strong, nonatomic) IBOutlet UILabel *dataLabel; +@property (strong, nonatomic) id dataObject; +@end diff --git a/WLPageViewController/DataViewController.m b/WLPageViewController/DataViewController.m new file mode 100644 index 0000000..c6ee799 --- /dev/null +++ b/WLPageViewController/DataViewController.m @@ -0,0 +1,37 @@ +// +// DataViewController.m +// WLPageViewController +// +// Created by Ling Wang on 7/7/11. +// Copyright 2011 __MyCompanyName__. All rights reserved. +// + +#import "DataViewController.h" + +@implementation DataViewController + +@synthesize dataLabel = _dataLabel; +@synthesize dataObject = _dataObject; + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Release any cached data, images, etc that aren't in use. +} + +#pragma mark - View lifecycle + +- (void)viewDidLoad +{ + [super viewDidLoad]; + // Do any additional setup after loading the view, typically from a nib. + self.title = [self.dataObject description]; +} + +- (void)viewWillAppear:(BOOL)animated +{ + [super viewWillAppear:animated]; + self.dataLabel.text = [self.dataObject description]; +} + +@end diff --git a/WLPageViewController/DataViewController.xib b/WLPageViewController/DataViewController.xib new file mode 100644 index 0000000..27ae642 --- /dev/null +++ b/WLPageViewController/DataViewController.xib @@ -0,0 +1,236 @@ + + + + 1280 + 10J869 + 1845 + 1038.35 + 461.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 845 + + + YES + IBProxyObject + IBUIView + IBUILabel + + + YES + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + YES + + YES + + + + + YES + + IBFilesOwner + IBCocoaTouchFramework + + + IBFirstResponder + IBCocoaTouchFramework + + + + 274 + + YES + + + 274 + {{8, 37}, {304, 415}} + + + + + 3 + MQA + + 2 + + + IBCocoaTouchFramework + + + + 290 + {{8, 8}, {304, 21}} + + + + NO + YES + 7 + NO + IBCocoaTouchFramework + Label + + 1 + MCAwIDAAA + + + 1 + 10 + 1 + + 1 + 4 + + + Helvetica-Light + 14 + 16 + + + + {{0, 20}, {320, 460}} + + + + + 1 + MC45NzgyNjA4Njk2IDAuOTE4NDgxMzEwOCAwLjczOTE0MjYzNDQAA + + + IBCocoaTouchFramework + + + + + YES + + + view + + + + 3 + + + + dataLabel + + + + 6 + + + + + YES + + 0 + + + + + + 1 + + + YES + + + + + + + -1 + + + File's Owner + + + -2 + + + + + 4 + + + + + 5 + + + + + + + YES + + YES + -1.CustomClassName + -2.CustomClassName + 1.IBEditorWindowLastContentRect + 1.IBPluginDependency + 4.IBPluginDependency + 5.IBPluginDependency + + + YES + DataViewController + UIResponder + {{354, 412}, {320, 480}} + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + YES + + + + + + YES + + + + + 6 + + + + YES + + DataViewController + UIViewController + + dataLabel + UILabel + + + dataLabel + + dataLabel + UILabel + + + + IBProjectSource + ./Classes/DataViewController.h + + + + + 0 + IBCocoaTouchFramework + + com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 + + + YES + 3 + 845 + + diff --git a/WLPageViewController/Default-568h@2x.png b/WLPageViewController/Default-568h@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0891b7aabfcf3422423b109c8beed2bab838c607 GIT binary patch literal 18594 zcmeI4X;f257Jx&9fS`ixvS;&$x8J@slQFSel)6zJN=?13FB7H(lQjRkSy8x_-S~tvu2gzn1oS+dLcF#eqtq$ z%tf9TTvX?`)R@}3uBI;jzS-=ZR-Td&MHaS&;!0?Ni*#$#`n*~CcQK)Q9vAQ~TUpnI!j)a2biYK^R)M~A5wUDZhx?ULMX z3x1P&qt=trOY6P2U67L=m=U?F|5#Uj(eCueNTZaHs_ceWiHeET+j+tp3Jt9g(ekqP z2WOvfR{qV+9r+o4J5?qK>7;;^+I7tGv-i)es$X_D=EoKF+S?zsyj^oRFElP}c}JT< zd8SUs-?O?}2YD#ngKbnHgzHBcboxK_2r9l(?eNCl-pEzkJm}fY?WC*jnS?VBE4EpY zO$fEejz6fU;W2Kl>JeQBZBl-%Irg`obSlg*@4QB;Dd1H7^Oi5wvt4d{RZ!8Og?^aE z)k0$1g+V3fd(gdQ3d&q2q-FL*uy#}|bc^=VhFsl0jBgUGJ+-s3U8MK9A!YJJMxpci z5hJ%|{DwV48fZn0{n5l$N_KcSb#NKE4plB`9I6Zt=Z!~-zw0{9tg$L&Ju1F0X)Cy8 zKF;(&lJ>x)Jw(=;p~sF(Sd9VWGwFE2rnyS9!f^DZ8+aCLq zQ};>lcJ1GDLqjm6Hd>|Eabno@P`~Bn(~6^aD_#yoEH(a?Nm1S<;S+hSxI5d16^<1lEM3NPFi zkqPrpL)+ zgnseFikg`gJVBha1&7C4;O6>h=dt~`ND+;Zd?W(4v2JIb7Pt>Td42%M-Ju-XAH#Pns762L}K3 zDhvsRqN0Ni(1UrishD2YvV?4*h2iFj$+&N||Fn$4n|^NSU+o?~jq`0jVQt8T9l{7b zXiwwODFh2V!Q6sqP9S>WH$oOf$N~=d0-bqTlD61!=`&0eAP-F>XN?*|gtOXX{ zQVTWyYo4ZK0GAw!GHf|pz9`D;-bbb*5LBX*{bnz|+)$@&P9|ORM2o?95{;ejvo&r- zq8cBhTN6nn)7~W>54U)%-F_-b?YKdfk5I8MHcuzBD5)!;yv#Z&R&^y=@=>VTIMy#r zX&U<=BsPkdqcMe<_}2+>H%XKyrr5ZR8_KVe>ZqYN z^=^~TFD};;rHJ$U;{~w^hYojl4hRI@SH$^K{YEo=sg)WY87r!*7blQK&qnpDo0`Vn zkl)9u9g=mCh&ZCJS(L4yN3k0kQ zuvg$h2KEEk51T+O0JQ+r0`R>g{jvqM0Mr6d3qUOZwE!?PI7HY@CE|dr sfw?Q;rAv?G4&^^8-z_>&sWXMxvD*gPOU4CBe-*@OtE+wfmVJNyHv)PfH~;_u literal 0 HcmV?d00001 diff --git a/WLPageViewController/Default.png b/WLPageViewController/Default.png new file mode 100644 index 0000000000000000000000000000000000000000..4c8ca6f693f96d511e9113c0eb59eec552354e42 GIT binary patch literal 6540 zcmeAS@N?(olHy`uVBq!ia0y~yU~~ZD2OMlbkt;o0To@QwR5G2N13aCb6#|O#(=u~X z85k@CTSM>X-wqM6>&y>YB4)1;;ojbLbbV-W^iFB1wa3^zCog^LCAReC4K0-?R_2{6 zrP*)4+_uWUy3w5N52M3PW_}MFMP9a~>YLvVZ1D_k*IMQ2QT^fwzoOb(*3gH$%aYWC zkHmcab=va2<#X%jakpJ;<1@F;k__#bwtC&%^D0v(FBh9K&$sK+<}2RJS609D)17$w ztdQP8(eLM8Ka}m_IQ@3wyMKP)l=oM4-?`YS_*P?4V_ORLPxsj&7Ju#kH;>6^Kp?T7~ zl+q?{UOOqV==?+d{=)5s|M~T1mwtH@+Z^$G&eEO9JNP^AX@3jZ*J*!!>lc|1-W%fA z@AOQpXZ_Lt>rxFXrGp*zLPiW@uo_c7C{As>j zWeX)wi+LTp_)@KYZCX{j;H?|1yXT4DnlS(Fr8gyP5|uaX_gLvaW0ScZdnG7o+u{T6 zFI-%d{ls*WuCDa5UJ@|RXv&ejZe}*BMkiWY51&pnRPw(hlykSzvj6e%mYz-GdvzBD zF10?szF_~!jS=?2HyQuPCvARXAe}C}WP|yQ*>5~~=*Nxq8+HHW1~FMDRCP^TcacKuk$ z(U#REVv)D!PhJ*ecH-ELFUrfyV&*)Z)>UCOuS?yd^L@Afk>ihynYPc{^CRwu+JHX+#$@YsC4c|l0tGigsn@jy) zXD($Ouk>H+V(Mr6NQT0S9BFM~V6nkj;1OBOz`zY;a|<&v%$g$sEJPk;hD4M^`1)8S z=jZArrsOB3>Q&?x097+E*i={nnYpPYi3%0DIeEoa6}C!X6;?ntNLXJ<0j#7X+g2&U zH$cHTzbI9~RL@Y)NXd>%K|#T$C?(A*$i)q+9mum)$|xx*u+rBrFE7_CH`dE9O4m2E zw6xSWFw!?N(gmu}Ew0QfNvzP#D^`XW0yD=YwK%ybv!En1KTiQ3|)OBHVcpi zp&D%TL4k-AsNfg_g$9~9p}$+4Ynr|VULLgiakg&)DD)EWO!OHC@snXr}UI${nVUP zpr1>Mf#G6^ng~;pt%^&NvQm>vU@-wn)!_JWN=(;B61LIDR86%A1?G9U(@`={MPdPF zbOKdd`R1o&rd7HmmZaJl85kPr8kp-EnTHsfS{ayIfdU*&4N@e5WSomq6HD@oLh|!- z?7;Dr3*ssm=^5w&a}>G?yzvAH17L|`#|6|0E4}QvA~xC{V_*wu2^AHZU}H9f($4F$btFf{}TLQXUhF5fht1@YV$^ z9BUdFV+73^nIsvRXRM40U}6b7z_6}kHbY}i1LK(xT@6Mi?F5GKBfbp|ZU-3BR*6kv zXcRSQ(0-)mprD+wTr)o_4I;(%zOu)+jEgNB)_SXCVoSa}|F?cfwR!69+L=W3IX z!UiU`0@ph%94Rb33Cpq^IY*r_8XBW%V>G9XmK&p`=xCiXTEmXEH%41uqixaAmicH0 zVYIt6!aI*K%s=kP-v##6IXGZ2Cama>{@)81;C?K-P&M2k<0!GL}5+H~XTq*@SQi|Ft z2*0X`$`8S!qO#)xBeJRkf?;t189=ZB6Imw-h=`q;FP(2UpWZvmJ@=k-@45M(dtb7r zyVEiaLk$=Vw#>zu;st}j6Jf9=m1+nXCFe!$1PrEZ%5Ze_ba8YX_9-*rJujiLuQmJo&2v+Cxes}ec zU|qeux&7*yz#W=X_|wGQskL7*OHNjwFs@sEC+64Hb$Z(#H21Gh$Pe2WzOubdr6fzg z{l{!k%OD?N5Z7j33SoK?YdV6Scm>})U+MIQLNRgIvkZQEc^mP9XBPg%y|S$~Br|;N zk?-!-(Qqh_mQ|6WINQ{hHAjBRV#O#!FkAJ+oxy`L#f8V45*VvWMJFBB5m zG6vOLtDvgoDjHlSq-*h5xM56O>Jjau2f2IxKItIb@coX4XTyf$^{LZG&lI|D95wN1 z!fo0)q>WV7-V;q|A?HR!*bgozJw%j98-~gwBKVV0;=hZIF>7oJSr2YjOWO*rSxz#& z;KXnDrJVZp;Yduiy1-H%s$ZFz6Q=x@$V_B@Tqwl?>6e;EHt|MiK<(#hXQMuj@Jseeh&eN{FxsQ$iw>D1aX1HMMlUbh?Z zmhY4eHffn5&LUbL_}o8|$JYz&$WFiLWmEg0ZPX+;W>@CxQz-%{E5+P7dH9&ey_y$R z@Zzje>2B%z!i!7Brqi{t5Y)~5>vpqRs~2aXD8DVE8vKl=`k(`duI1-k@?!pJ^HA6S zS;3WpuhjQHyoC>X>Xf8gze%_8^#+^RTV>V9&YPAWMjd~%xpSg?ON?kK^X*Pb(o8jR zz;DmaOWMMr6=M~K?MFx4_xDkARTxLJ@W@ohAx z5RD0jGgk?QL@H`VubD2k4}?VtB8@g`%hHBA$2pJ(gK5g1HMNysXEF_BNu-p!&+Qa8_APgopHWnRgg=TZZF*sXWTMQPD z!Q(Au5|+F;7M~`tWbsU98~NA{h0Y7%GB|t&n}w9OOABU4^X*V5xuN;rY(M#ouuqm) zyt!e?28fY!FgP?8GvBsMl_aM^UUVKiGFsleFN?t^<46kO#pF-cX0;sIOb(aM z)^jQgX^Z6pKA9mC@N)_aiHj9HxD2|?A@Y9B_h}(*v3%ek8CXc1Qy^jFPF&zrMa1OZ zSVaF{&ZY|(|H0XE&X>-XQz1`=fF2n@VKC_|h3jlKVM&-jmyMavllcYr`6LVtfq2ou zd+8zkkCB+2)rxq0Lkq_&Ad@g(O8;pAm96>tu79?81T@Z<;gm^3ZtPG-SR94Mr<3tm z9NrR3u*4I5aMlo(09g@8m_;%Rf+XiSa_KZao9n}7N0JrsV#;5Ucr+F*TTzQ8{%f3O zeIUy?WDS|-$LvMc@Z7320)tr}bfIka5hx9H;8H|%our=C+Do0CSFRWue14o5#r8v2 zw=|&r4*eMX%lgCV(ka?*j%H^UuP4LmBC(ON`)&7>NF-|PDRU{-7o`CU0HNbd&c~))@yl9IKu_ zXA+A-!khpP_yx=f#qt2_0ptmgBf4gF!{Y)MW6R$cC1d7@$Yb?+_j zYwfE^5_e`vhT zX=u3r>4$fsxP&apbm@Rcbyuc2T=giqZiMo9@9=oua6#YH0hO-1ak9^rJTPMM qY4Yr5Cu^v99p{E9VdroUHKlRW;M8#BJ^AOQE?e9wSHJo8(7yq;BYKSh literal 0 HcmV?d00001 diff --git a/WLPageViewController/ModelController.h b/WLPageViewController/ModelController.h new file mode 100644 index 0000000..d64bd3f --- /dev/null +++ b/WLPageViewController/ModelController.h @@ -0,0 +1,17 @@ +// +// ModelController.h +// WLPageViewController +// +// Created by Ling Wang on 7/7/11. +// Copyright 2011 __MyCompanyName__. All rights reserved. +// + +#import +#import "WLPageViewController.h" + +@class DataViewController; + +@interface ModelController : NSObject +- (DataViewController *)viewControllerAtIndex:(NSUInteger)index; +- (NSUInteger)indexOfViewController:(DataViewController *)viewController; +@end diff --git a/WLPageViewController/ModelController.m b/WLPageViewController/ModelController.m new file mode 100644 index 0000000..4570801 --- /dev/null +++ b/WLPageViewController/ModelController.m @@ -0,0 +1,89 @@ +// +// ModelController.m +// WLPageViewController +// +// Created by Ling Wang on 7/7/11. +// Copyright 2011 __MyCompanyName__. All rights reserved. +// + +#import "ModelController.h" + +#import "DataViewController.h" + +/* + A controller object that manages a simple model -- a collection of month names. + + The controller serves as the data source for the page view controller; it therefore implements pageViewController:viewControllerBeforeViewController: and pageViewController:viewControllerAfterViewController:. + It also implements a custom method, viewControllerAtIndex: which is useful in the implementation of the data source methods, and in the initial configuration of the application. + + There is no need to actually create view controllers for each page in advance -- indeed doing so incurs unnecessary overhead. Given the data model, these methods create, configure, and return a new view controller on demand. + */ + +@interface ModelController() +@property (readonly, strong, nonatomic) NSArray *pageData; +@end + +@implementation ModelController + +@synthesize pageData = _pageData; + +- (id)init +{ + self = [super init]; + if (self) { + // Create the data model. + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + _pageData = [[dateFormatter monthSymbols] copy]; + } + return self; +} + +- (DataViewController *)viewControllerAtIndex:(NSUInteger)index +{ + // Return the data view controller for the given index. + if (([self.pageData count] == 0) || (index >= [self.pageData count])) { + return nil; + } + + // Create a new view controller and pass suitable data. + DataViewController *dataViewController = [[DataViewController alloc] initWithNibName:@"DataViewController" bundle:nil]; + dataViewController.dataObject = [self.pageData objectAtIndex:index]; + return dataViewController; +} + +- (NSUInteger)indexOfViewController:(DataViewController *)viewController +{ + /* + Return the index of the given data view controller. + For simplicity, this implementation uses a static array of model objects and the view controller stores the model object; you can therefore use the model object to identify the index. + */ + return [self.pageData indexOfObject:viewController.dataObject]; +} + +#pragma mark - Page View Controller Data Source + +- (UIViewController *)pageViewController:(WLPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController +{ + NSUInteger index = [self indexOfViewController:(DataViewController *)viewController]; + if (index == NSNotFound) { + return nil; + } +// NSUInteger count = [self.pageData count]; +// index = (index - 1 + count) % count; + if (index == 0) return nil; + return [self viewControllerAtIndex:index - 1]; +} + +- (UIViewController *)pageViewController:(WLPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController +{ + NSUInteger index = [self indexOfViewController:(DataViewController *)viewController]; + if (index == NSNotFound) { + return nil; + } + +// index = (index + 1) % [self.pageData count]; + if (index == [self.pageData count] - 1) return nil; + return [self viewControllerAtIndex:index + 1]; +} + +@end diff --git a/WLPageViewController/PageViewController.h b/WLPageViewController/PageViewController.h new file mode 100644 index 0000000..89f4c5a --- /dev/null +++ b/WLPageViewController/PageViewController.h @@ -0,0 +1,16 @@ +// +// PageViewController.h +// WLPageViewController +// +// Created by Ling Wang on 7/7/11. +// Copyright 2011 __MyCompanyName__. All rights reserved. +// + +#import +#import "WLPageViewController.h" + +@interface PageViewController : UIViewController + +@property (strong, nonatomic) WLPageViewController *pageViewController; + +@end diff --git a/WLPageViewController/PageViewController.m b/WLPageViewController/PageViewController.m new file mode 100644 index 0000000..3a34f56 --- /dev/null +++ b/WLPageViewController/PageViewController.m @@ -0,0 +1,68 @@ +// +// PageViewController.m +// WLPageViewController +// +// Created by Ling Wang on 7/7/11. +// Copyright 2011 __MyCompanyName__. All rights reserved. +// + +#import "PageViewController.h" + +#import "ModelController.h" + +#import "DataViewController.h" + +@interface PageViewController () +@property (readonly, strong, nonatomic) ModelController *modelController; +@end + +@implementation PageViewController + +@synthesize pageViewController = _pageViewController; +@synthesize modelController = _modelController; + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Release any cached data, images, etc that aren't in use. +} + +#pragma mark - View lifecycle + +- (void)viewDidLoad +{ + [super viewDidLoad]; + // Configure the page view controller and add it as a child view controller. + DataViewController *startingViewController = [self.modelController viewControllerAtIndex:0]; + self.pageViewController = [[WLPageViewController alloc] initWithViewController:startingViewController]; +// self.pageViewController.enableTapPageTurning = YES; + self.pageViewController.dataSource = self.modelController; + self.pageViewController.delegate = self; + + [self addChildViewController:self.pageViewController]; + [self.view addSubview:self.pageViewController.view]; + + // Set the page view controller's bounds using an inset rect so that self's view is visible around the edges of the pages. + CGRect pageViewRect = self.view.bounds; + self.pageViewController.view.frame = pageViewRect; + + [self.pageViewController didMoveToParentViewController:self]; + + // Add the page view controller's gesture recognizers to the book view controller's view so that the gestures are started more easily. +// self.view.gestureRecognizers = self.pageViewController.gestureRecognizers; +} + +- (ModelController *)modelController +{ + /* + Return the model controller object, creating it if necessary. + In more complex implementations, the model controller may be passed to the view controller. + */ + if (!_modelController) { + _modelController = [[ModelController alloc] init]; + } + return _modelController; +} + + +@end diff --git a/WLPageViewController/PageViewController.xib b/WLPageViewController/PageViewController.xib new file mode 100644 index 0000000..7c443ec --- /dev/null +++ b/WLPageViewController/PageViewController.xib @@ -0,0 +1,133 @@ + + + + 1536 + 12C60 + 2843 + 1187.34 + 625.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 1929 + + + YES + IBProxyObject + IBUIView + + + YES + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + PluginDependencyRecalculationVersion + + + + YES + + IBFilesOwner + IBCocoaTouchFramework + + + IBFirstResponder + IBCocoaTouchFramework + + + + 274 + {{0, 20}, {320, 460}} + + 1 + MC42MDAwMDAwMjM4IDAuNDAwMDAwMDA2IDAuMjAwMDAwMDAzAA + + + IBCocoaTouchFramework + + + + + YES + + + view + + + + 6 + + + + + YES + + 0 + + YES + + + + + + 1 + + + + + -1 + + + File's Owner + + + -2 + + + + + + + YES + + YES + -1.CustomClassName + -1.IBPluginDependency + -2.CustomClassName + -2.IBPluginDependency + 1.IBPluginDependency + + + YES + PageViewController + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + UIResponder + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + YES + + + + + + YES + + + + + 6 + + + 0 + IBCocoaTouchFramework + + com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 + + + YES + 3 + 1929 + + diff --git a/WLPageViewController/WLPageViewController-Info.plist b/WLPageViewController/WLPageViewController-Info.plist new file mode 100644 index 0000000..aa1ec6a --- /dev/null +++ b/WLPageViewController/WLPageViewController-Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + com.moke.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/WLPageViewController/WLPageViewController-Prefix.pch b/WLPageViewController/WLPageViewController-Prefix.pch new file mode 100644 index 0000000..0cab1c0 --- /dev/null +++ b/WLPageViewController/WLPageViewController-Prefix.pch @@ -0,0 +1,29 @@ +// +// Prefix header for all source files of the 'WLPageViewController' target in the 'WLPageViewController' project +// + +#import + +#ifndef __IPHONE_3_0 +#warning "This project uses features only available in iOS SDK 3.0 and later." +#endif + +#ifdef __OBJC__ + #import + #import +#endif + +// DLog is almost a drop-in replacement for NSLog +// DLog(); +// DLog(@"here"); +// DLog(@"value: %d", x); +#ifdef DEBUG +#define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); +#else +#define DLog(...) +#endif + +#define DDLogError DLog + +// ALog always displays output regardless of the DEBUG setting +#define ALog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); diff --git a/WLPageViewController/WLPageViewController.h b/WLPageViewController/WLPageViewController.h new file mode 100644 index 0000000..d3c3e14 --- /dev/null +++ b/WLPageViewController/WLPageViewController.h @@ -0,0 +1,48 @@ +// +// WLPageViewController.h +// WLPageViewController +// +// Created by Ling Wang on 7/8/11. +// Copyright 2011 __MyCompanyName__. All rights reserved. +// + +#import "WLContainerController.h" + +@protocol WLPageViewControllerDataSource; +@protocol WLPageViewControllerDelegate; + + +@interface WLPageViewController : WLContainerController + +#pragma mark Creating Page View Controllers +- (id)initWithViewController:(UIViewController *)viewController; +- (void)turnForward; +- (void)turnBackward; + +@property(nonatomic, weak) id dataSource; +@property(nonatomic, weak) id delegate; + +#pragma mark Configuration +@property(nonatomic, assign) BOOL enableTapPageTurning; + +#pragma mark Customizing Appearance +@property(nonatomic, copy) NSDictionary *titleTextAttributes; + +@end + + +@protocol WLPageViewControllerDataSource + +- (UIViewController *)pageViewController:(WLPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController; +- (UIViewController *)pageViewController:(WLPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController; + +@end + + +@protocol WLPageViewControllerDelegate +@optional +- (void)pageViewController:(WLPageViewController *)pageViewController willBeginPagingViewController:(UIViewController *)viewController; +- (void)pageViewController:(WLPageViewController *)pageViewController didEndPagingViewController:(UIViewController *)viewController; + +@end + diff --git a/WLPageViewController/WLPageViewController.m b/WLPageViewController/WLPageViewController.m new file mode 100644 index 0000000..efc5c1d --- /dev/null +++ b/WLPageViewController/WLPageViewController.m @@ -0,0 +1,1098 @@ +// +// WLPageViewController.m +// WLPageViewController +// +// Created by Ling Wang on 7/8/11. +// Copyright 2011 __MyCompanyName__. All rights reserved. +// + +#import "WLPageViewController.h" +#import + +#define kPagingAnimationDuration 0.4 + +@interface WLPageViewController () { +@private + UITapGestureRecognizer *_tapGestureRecognizer; + UIViewController *_nextViewController; + UIViewController *_previousViewController; + UIViewController *_nnextViewController; + UIViewController *_ppreviousViewController; + UIView *_titleView; + UIView *_previousTitleView; + UIView *_nextTitleView; + UIView *_ppreviousTitleView; + UIView *_nnextTitleView; + BOOL _arePagingAnimationsCancelled; + NSUInteger _pagingAnimationCount; +} +- (IBAction)pan:(UIPanGestureRecognizer *)gestureRecognizer; +- (IBAction)turnPage:(UITapGestureRecognizer *)gestureRecognizer; +@end + + + + +@implementation WLPageViewController + +@synthesize dataSource = _dataSource; +@synthesize delegate = _delegate; +@synthesize enableTapPageTurning = _enableTapPageTurning; +@synthesize titleTextAttributes = _titleTextAttributes; + + +- (id)initWithViewController:(UIViewController *)viewController { + self = [super init]; + if (self) { + self.contentController = viewController; + } + return self; +} + + +#pragma mark - View lifecycle + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + // Pan gesture recognizer. + UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)]; + [self.view addGestureRecognizer:panGestureRecognizer]; + + // Tap gesture recognizer. + _tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(turnPage:)]; + _tapGestureRecognizer.enabled = _enableTapPageTurning; + [self.view addGestureRecognizer:_tapGestureRecognizer]; + + // Init navigation bar title view. + self.navigationItem.titleView = [[UIView alloc] init]; + [_titleView removeFromSuperview]; + _titleView = [self setupSubTitleViewWith:_contentController]; + self.navigationItem.titleView.bounds = _titleView.frame; + [self.navigationItem.titleView addSubview:_titleView]; +} + +- (void)didReceiveMemoryWarning { + [self unloadInvisiblePages]; + if (self.isViewLoaded && self.view.window == nil) { + _titleView = nil; + _previousTitleView = nil; + _nextTitleView = nil; + _ppreviousTitleView = nil; + _nnextTitleView = nil; + } + [super didReceiveMemoryWarning]; +} + + +#pragma mark - Providing Content + +- (void)setContentController:(UIViewController *)contentController { + if (_contentController == contentController) return; + + [self unregisterKVOForNavigationBar]; + [self unregisterKVOForToolbar]; + + if (self.isViewLoaded) { + [self updateNavigationBarFrom:contentController]; + [self updateToolbarFrom:contentController]; + } + + [self addChildViewController:contentController]; + if (self.isViewLoaded) { + if (contentController.view.superview != self.view) { + [self.view addSubview:contentController.view]; + } + } + [contentController didMoveToParentViewController:self]; + + _contentController = contentController; + + if (self.isViewLoaded) { + // !!!: Unloading invisible pages is not only for saving memory but is also necessary for scroll-to-top of content scroll view to work because if there are more than one sub scroll views tapping on status bar does not trigger scroll-to-top. + [self unloadInvisiblePages]; + } +} + +- (UIViewController *)loadPreviousPage { + UIViewController *previousViewController = [_dataSource pageViewController:self viewControllerBeforeViewController:_contentController]; + if (previousViewController == nil) return nil; + + BOOL isNewlyAdded = ![self.childViewControllers containsObject:previousViewController]; + if (isNewlyAdded) { + [self addChildViewController:previousViewController]; + } + CGRect previousFrame = _contentController.view.frame; + previousFrame.origin.x -= self.view.bounds.size.width; + previousViewController.view.frame = previousFrame; + [self.view addSubview:previousViewController.view]; + if (isNewlyAdded) { + [previousViewController didMoveToParentViewController:self]; + } + + [_previousTitleView removeFromSuperview]; + _previousTitleView = [self setupSubTitleViewWith:previousViewController]; + // Center title view. + _previousTitleView.center = _titleView.center; + [self.navigationItem.titleView addSubview:_previousTitleView]; + + return previousViewController; +} + +- (UIViewController *)loadNextPage { + UIViewController *nextViewController = [_dataSource pageViewController:self viewControllerAfterViewController:_contentController]; + if (nextViewController == nil) return nil; + + BOOL isNewlyAdded = ![self.childViewControllers containsObject:nextViewController]; + if (isNewlyAdded) { + [self addChildViewController:nextViewController]; + } + CGRect nextFrame = _contentController.view.frame; + nextFrame.origin.x += self.view.bounds.size.width; + nextViewController.view.frame = nextFrame; + [self.view addSubview:nextViewController.view]; + if (isNewlyAdded) { + [nextViewController didMoveToParentViewController:self]; + } + + [_nextTitleView removeFromSuperview]; + _nextTitleView = [self setupSubTitleViewWith:nextViewController]; + // Center title view. + _nextTitleView.center = _titleView.center; + [self.navigationItem.titleView addSubview:_nextTitleView]; + + return nextViewController; +} + +- (UIViewController *)loadPPreviousPage { + UIViewController *ppreviousViewController = [_dataSource pageViewController:self viewControllerBeforeViewController:_previousViewController]; + if (ppreviousViewController == nil) return nil; + + BOOL isNewlyAdded = ![self.childViewControllers containsObject:ppreviousViewController]; + if (isNewlyAdded) { + [self addChildViewController:ppreviousViewController]; + } + CGRect previousFrame = _previousViewController.view.frame; + previousFrame.origin.x -= self.view.bounds.size.width; + ppreviousViewController.view.frame = previousFrame; + [self.view addSubview:ppreviousViewController.view]; + if (isNewlyAdded) { + [ppreviousViewController didMoveToParentViewController:self]; + } + + [_ppreviousTitleView removeFromSuperview]; + _ppreviousTitleView = [self setupSubTitleViewWith:ppreviousViewController]; + // Center title view. + _ppreviousTitleView.center = _titleView.center; + [self.navigationItem.titleView addSubview:_ppreviousTitleView]; + + return ppreviousViewController; +} + +- (UIViewController *)loadNNextPage { + UIViewController *nnextViewController = [_dataSource pageViewController:self viewControllerAfterViewController:_nextViewController]; + if (nnextViewController == nil) return nil; + + BOOL isNewlyAdded = ![self.childViewControllers containsObject:nnextViewController]; + if (isNewlyAdded) { + [self addChildViewController:nnextViewController]; + } + CGRect nextFrame = _nextViewController.view.frame; + nextFrame.origin.x += self.view.bounds.size.width; + nnextViewController.view.frame = nextFrame; + [self.view addSubview:nnextViewController.view]; + if (isNewlyAdded) { + [nnextViewController didMoveToParentViewController:self]; + } + + [_nnextTitleView removeFromSuperview]; + _nnextTitleView = [self setupSubTitleViewWith:nnextViewController]; + // Center title view. + _nnextTitleView.center = _titleView.center; + [self.navigationItem.titleView addSubview:_nnextTitleView]; + + return nnextViewController; +} + +- (void)unloadInvisiblePages { + CGRect bounds = self.view.bounds; + NSMutableArray *vcToUnload = [NSMutableArray arrayWithCapacity:self.childViewControllers.count]; + for (UIViewController *vc in self.childViewControllers) { + UIView *v = vc.view; + if (!CGRectIntersectsRect(bounds, v.frame)) { + [vcToUnload addObject:vc]; + } + } + for (UIViewController *vc in vcToUnload) { + if (vc == _previousViewController) { + _previousViewController = nil; + [_ppreviousTitleView removeFromSuperview]; + _ppreviousTitleView = nil; + } else if (vc == _nextViewController) { + _nextViewController = nil; + [_nextTitleView removeFromSuperview]; + _nextTitleView = nil; + } + + if (vc == _ppreviousViewController) { + _ppreviousViewController = nil; + [_ppreviousTitleView removeFromSuperview]; + _ppreviousTitleView = nil; + } else if (vc == _nnextViewController) { + _nnextViewController = nil; + [_nnextTitleView removeFromSuperview]; + _nnextTitleView = nil; + } + UIView *v = vc.view; + [vc willMoveToParentViewController:nil]; + [v removeFromSuperview]; + [vc removeFromParentViewController]; + } +} + +- (void)layoutContentView:(UIView *)contentView { + [super layoutContentView:contentView]; + // Maintain the invariant relationships among previous view, content view and next view. + CGFloat pageWidth = self.view.bounds.size.width; + if (_previousViewController) { + _previousViewController.view.frame = CGRectOffset(_contentController.view.frame, -pageWidth, 0.f); + } + if (_nextViewController) { + _nextViewController.view.frame = CGRectOffset(_contentController.view.frame, pageWidth, 0.f); + } + if (_ppreviousViewController) { + _ppreviousViewController.view.frame = CGRectOffset(_previousViewController.view.frame, -pageWidth, 0.f); + } + if (_nnextViewController) { + _nnextViewController.view.frame = CGRectOffset(_nextViewController.view.frame, pageWidth, 0.f); + } +} + + + + +#pragma mark - Configuration + +- (void)setEnableTapPageTurning:(BOOL)enableTapPageTurning { + _enableTapPageTurning = enableTapPageTurning; + _tapGestureRecognizer.enabled = _enableTapPageTurning; +} + + +#pragma mark - Navigation bar and toolbar configuration + +- (UIView *)setupSubTitleViewWith:(UIViewController *)viewController { + UIView *subTitleView = nil; + CGRect titleViewBounds = self.navigationItem.titleView.bounds; + if (viewController.navigationItem.titleView) { + subTitleView = viewController.navigationItem.titleView; + subTitleView.frame = titleViewBounds; + } else { + UILabel *titleLabel = [[UILabel alloc] initWithFrame:titleViewBounds]; + UIFont *font = [_titleTextAttributes objectForKey:UITextAttributeFont]; + if (!font) font = [UIFont boldSystemFontOfSize:20]; + titleLabel.font = font; + UIColor *textColor = [_titleTextAttributes objectForKey:UITextAttributeTextColor]; + if (!textColor) textColor = [UIColor whiteColor]; + titleLabel.textColor = textColor; + UIColor *shadowColor= [_titleTextAttributes objectForKey:UITextAttributeTextShadowColor]; + if (shadowColor) titleLabel.shadowColor = shadowColor; + NSValue *shadowOffset = [_titleTextAttributes objectForKey:UITextAttributeTextShadowOffset]; + if (shadowOffset) titleLabel.shadowOffset = [shadowOffset CGSizeValue]; + titleLabel.text = viewController.navigationItem.title; + titleLabel.textAlignment = NSTextAlignmentCenter; + titleLabel.backgroundColor = [UIColor clearColor]; + subTitleView = titleLabel; + } + [subTitleView sizeToFit]; + return subTitleView; +} + + + + +#pragma mark - Paging + +- (IBAction)pan:(UIPanGestureRecognizer *)gestureRecognizer { + _isTransitioningContentView = YES; + + const CGRect bounds = self.view.bounds; + CGPoint translation = [gestureRecognizer translationInView:self.view]; + const CGPoint boundsCenter = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds)); + CGPoint center = _contentController.view.center; + const CGFloat pageWidth = bounds.size.width; + + if (gestureRecognizer.state == UIGestureRecognizerStateBegan) { + [CATransaction setDisableActions:YES]; + if ([_contentController.view.layer animationForKey:@"position.x"]) { + _contentController.view.layer.position = ((CALayer *)_contentController.view.layer.presentationLayer).position; + [_contentController.view.layer removeAnimationForKey:@"position.x"]; + } + if ([_previousViewController.view.layer animationForKey:@"position.x"]) { + CGPoint position = _contentController.view.layer.position; + position.x -= pageWidth; + _previousViewController.view.layer.position = position; + [_previousViewController.view.layer removeAnimationForKey:@"position.x"]; + } + if ([_ppreviousViewController.view.layer animationForKey:@"position.x"]) { + CGPoint position = _ppreviousViewController.view.layer.position; + position.x -= pageWidth; + _ppreviousViewController.view.layer.position = position; + [_ppreviousViewController.view.layer removeAnimationForKey:@"position.x"]; + } + if ([_nextViewController.view.layer animationForKey:@"position.x"]) { + CGPoint position = _contentController.view.layer.position; + position.x += pageWidth; + _nextViewController.view.layer.position = position; + [_nextViewController.view.layer removeAnimationForKey:@"position.x"]; + } + if ([_nnextViewController.view.layer animationForKey:@"position.x"]) { + CGPoint position = _nnextViewController.view.layer.position; + position.x += pageWidth; + _nnextViewController.view.layer.position = position; + [_nnextViewController.view.layer removeAnimationForKey:@"position.x"]; + } + if ([_titleView.layer animationForKey:@"opacity"]) { + _titleView.layer.opacity = ((CALayer *)_titleView.layer.presentationLayer).opacity; + [_titleView.layer removeAnimationForKey:@"opacity"]; + } + if ([_previousTitleView.layer animationForKey:@"opacity"]) { + _previousTitleView.layer.opacity = ((CALayer *)_previousTitleView.layer.presentationLayer).opacity; + [_previousTitleView.layer removeAnimationForKey:@"opacity"]; + } + if ([_ppreviousTitleView.layer animationForKey:@"opacity"]) { + _ppreviousTitleView.layer.opacity = ((CALayer *)_ppreviousTitleView.layer.presentationLayer).opacity; + [_ppreviousTitleView.layer removeAnimationForKey:@"opacity"]; + } + if ([_nextTitleView.layer animationForKey:@"opacity"]) { + _nextTitleView.layer.opacity = ((CALayer *)_nextTitleView.layer.presentationLayer).opacity; + [_nextTitleView.layer removeAnimationForKey:@"opacity"]; + } + if ([_nnextTitleView.layer animationForKey:@"opacity"]) { + _nnextTitleView.layer.opacity = ((CALayer *)_nnextTitleView.layer.presentationLayer).opacity; + [_nnextTitleView.layer removeAnimationForKey:@"opacity"]; + } + [CATransaction setDisableActions:NO]; + + if ([_delegate respondsToSelector:@selector(pageViewController:willBeginPagingViewController:)]) { + [_delegate pageViewController:self willBeginPagingViewController:_contentController]; + } + } else if (gestureRecognizer.state == UIGestureRecognizerStateChanged) { + if (center.x < boundsCenter.x) { + if (_nextViewController == nil) { + // The end. Add some damping. + translation.x /= 2.f; + } + } else if (center.x > boundsCenter.x) { + if (_previousViewController == nil) { + // The end. Add some damping. + translation.x /= 2.f; + } + } + + center.x += translation.x; + const CGFloat pageOffset = center.x - boundsCenter.x; + + if (center.x < boundsCenter.x) { + if (_nextViewController == nil) { + _nextViewController = [self loadNextPage]; + } + // Title transition. + if (_nextViewController) { + _titleView.alpha = 1 - fabsf(pageOffset) / pageWidth; + _nextTitleView.alpha = 1 - _titleView.alpha; + } + } else if (center.x > boundsCenter.x) { + if (_previousViewController == nil) { + _previousViewController = [self loadPreviousPage]; + } + // Title transition. + if (_previousViewController) { + _titleView.alpha = 1 - fabsf(pageOffset) / pageWidth; + _previousTitleView.alpha = 1 - _titleView.alpha; + } + } + + _contentController.view.center = center; + CGPoint previousViewCenter = center; + previousViewCenter.x -= pageWidth; + _previousViewController.view.center = previousViewCenter; + CGPoint nextViewCenter = center; + nextViewCenter.x += pageWidth; + _nextViewController.view.center = nextViewCenter; + + // Reset translation: I'm use incremental translation not accumulative translation. + [gestureRecognizer setTranslation:CGPointZero inView:gestureRecognizer.view]; + } else if (gestureRecognizer.state == UIGestureRecognizerStateEnded || gestureRecognizer.state == UIGestureRecognizerStateCancelled) { + const CGFloat pageOffset = center.x - boundsCenter.x; + // Elastic paging and bouncing modeled with damping. + CGFloat w_0 = 0.7f; // natural frequency + CGFloat zeta = 0.8f; // damping ratio for under-damping + CGFloat w_d = w_0 * sqrtf(1.f - zeta * zeta); // damped frequency + CGFloat x_0 = pageOffset; + + CGPoint velocity = [gestureRecognizer velocityInView:self.view]; + // Scale velocity down. + velocity.x /= 20.f; + velocity.y /= 20.f; + + // Use critical damping to calculate the max displacement: x(t) = (A + B * t) * e^(-w_0 * t) + // Use x(t)' = 0 to get the max x(t) — amplitude. + // x(t)' = [B - w_0 * (A + B * t)] * e^(-w_0 * t) + // x(t)' = 0 => t = 1 / w_0 - A / B. + // x_max = (v_0 / w_0 + x_0) * e^[-v_0 / (v_0 + w_0 * x_0)] + CGFloat A = x_0; + CGFloat B = velocity.x + w_0 * x_0; + CGFloat t_max = 1 / w_0 - A / B; + CGFloat x_max = powf((CGFloat)M_E, -w_0 * t_max) * (A + B * t_max); +// DLog(@"v_0 = %f, x_0 = %f, t_max = %f, x_max = %f", velocity.x, x_0, t_max, x_max); + + BOOL turnToPreviousPage = NO; + BOOL turnToNextPage = NO; + if (x_max >= 0.5 * pageWidth || velocity.x > 40.f) { + if (_previousViewController == nil) { + _previousViewController = [self loadPreviousPage]; + } + if (_previousViewController) { + turnToPreviousPage = YES; + } + } else if (x_max <= -0.5 * pageWidth || velocity.x < -40.f) { + if (_nextViewController == nil) { + _nextViewController = [self loadNextPage]; + } + if (_nextViewController) { + turnToNextPage = YES; + } + } + + if (turnToPreviousPage) { + // Turn to previous page. + CGPoint previousViewCenter = _previousViewController.view.center; + CGPoint newPreviousViewCenter = boundsCenter; + CGPoint newCenter = CGPointMake(newPreviousViewCenter.x + pageWidth, newPreviousViewCenter.y); + + [CATransaction begin]; + [CATransaction setAnimationDuration:kPagingAnimationDuration]; + + // Equilibrium postion is differenct, initial replacement is different. + x_0 = previousViewCenter.x - newPreviousViewCenter.x; + + BOOL underDamping = NO; + + // Try critical damping first. + // Limit x_max so that no more than 1 page is scrolled in one direction in one paging. + // When v_0 is large, x_max can be approximated by (v_0 / w_0 + x_0) / e. + const CGFloat X_MAX_LIMIT = 0; + const CGFloat VELOCITY_MAX_LIMIT = w_0 * (X_MAX_LIMIT * (CGFloat)M_E - x_0); + if (velocity.x > VELOCITY_MAX_LIMIT) { + underDamping = YES; + velocity.x /= 1.5f; + } + + if (underDamping) { +// DLog(@"Under-damping"); + // Limit x_max so that no more than 1 page is scrolled in one direction in one paging. + const CGFloat VELOCITY_MAX_LIMIT = 180.f; + if (velocity.x > VELOCITY_MAX_LIMIT) { + velocity.x = VELOCITY_MAX_LIMIT; + } + A = x_0; + B = (zeta * x_0 + velocity.x) / w_d; + CGFloat a = B * w_d - A * zeta * w_0; + CGFloat b = A * w_d + B * zeta * w_0; + CGFloat sin_max = sqrtf(a * a / (a * a + b * b)); + CGFloat theta_max; + if (a * b > 0) { + theta_max = asinf(sin_max); + } else { + theta_max = (CGFloat)M_PI - asinf(sin_max); + } + t_max = theta_max / w_d; + if (t_max > 0.f) { + x_max = powf((CGFloat)M_E, -zeta * w_0 * t_max) * (A * cosf(w_d * t_max) + B * sinf(w_d * t_max)); +// DLog(@"v_0 = %f, x_0 = %f, t_max = %f, x_max = %f", velocity.x, x_0, t_max, x_max); + if (x_max > 0.f) { + // Part of pre-previous view will be shown temporarily. + _ppreviousViewController = [self loadPPreviousPage]; + } + } + } else { +// DLog(@"Critical damping"); + A = x_0; + B = velocity.x + w_0 * x_0; + } + + // Current view. + CAKeyframeAnimation *pageAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position.x"]; + pageAnimation.delegate = self; + pageAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; + NSUInteger steps = 100; + NSMutableArray *pageAnimationValues = [NSMutableArray arrayWithCapacity:steps]; + CGFloat value; + for (NSUInteger step = 0; step < steps; ++step) { + CGFloat t = 0.1f * step; + if (underDamping) { + value = powf((CGFloat)M_E, -zeta * w_0 * t) * (A * cosf(w_d * t) + B * sinf(w_d * t)) + newCenter.x; + } else { + value = powf((CGFloat)M_E, -w_0 * t) * (A + B * t) + newCenter.x; + } + [pageAnimationValues addObject:@(value)]; + } + pageAnimation.values = pageAnimationValues; + [_contentController.view.layer addAnimation:pageAnimation forKey:pageAnimation.keyPath]; + _pagingAnimationCount++; + [CATransaction setDisableActions:YES]; + _contentController.view.layer.position = newCenter; + [CATransaction setDisableActions:NO]; + + CAKeyframeAnimation *titleAnimation = [CAKeyframeAnimation animationWithKeyPath:@"opacity"]; + titleAnimation.delegate = self; + titleAnimation.timingFunction = pageAnimation.timingFunction; + NSMutableArray *titleAnimationValues = [NSMutableArray arrayWithCapacity:steps]; + for (NSUInteger step = 0; step < steps; ++step) { + value = 1.f - fabsf([pageAnimationValues[step] floatValue] - boundsCenter.x) / pageWidth; + [titleAnimationValues addObject:@(value)]; + } + titleAnimation.values = titleAnimationValues; + [_titleView.layer addAnimation:titleAnimation forKey:titleAnimation.keyPath]; + _pagingAnimationCount++; + [CATransaction setDisableActions:YES]; + _titleView.layer.opacity = 0.f; + [CATransaction setDisableActions:NO]; + + // Previous view. + [pageAnimationValues removeAllObjects]; + for (NSUInteger step = 0; step < steps; ++step) { + CGFloat t = 0.1f * step; + if (underDamping) { + value = powf((CGFloat)M_E, -zeta * w_0 * t) * (A * cosf(w_d * t) + B * sinf(w_d * t)) + newPreviousViewCenter.x; + } else { + value = powf((CGFloat)M_E, -w_0 * t) * (A + B * t) + newPreviousViewCenter.x; + } + [pageAnimationValues addObject:@(value)]; + } + pageAnimation.values = pageAnimationValues; + [_previousViewController.view.layer addAnimation:pageAnimation forKey:pageAnimation.keyPath]; + _pagingAnimationCount++; + [CATransaction setDisableActions:YES]; + _previousViewController.view.layer.position = newPreviousViewCenter; + [CATransaction setDisableActions:NO]; + + [titleAnimationValues removeAllObjects]; + for (NSUInteger step = 0; step < steps; ++step) { + value = 1.f - fabsf([pageAnimationValues[step] floatValue] - boundsCenter.x) / pageWidth; + [titleAnimationValues addObject:@(value)]; + } + titleAnimation.values = titleAnimationValues; + [_previousTitleView.layer addAnimation:titleAnimation forKey:titleAnimation.keyPath]; + _pagingAnimationCount++; + [CATransaction setDisableActions:YES]; + _previousTitleView.layer.opacity = 1.f; + [CATransaction setDisableActions:NO]; + + if (_ppreviousViewController) { + CGPoint newPPreviousViewCenter = CGPointMake(newPreviousViewCenter.x - pageWidth, newPreviousViewCenter.y); + [pageAnimationValues removeAllObjects]; + for (NSUInteger step = 0; step < steps; ++step) { + CGFloat t = 0.1f * step; + if (underDamping) { + value = powf((CGFloat)M_E, -zeta * w_0 * t) * (A * cosf(w_d * t) + B * sinf(w_d * t)) + newPPreviousViewCenter.x; + } else { + value = powf((CGFloat)M_E, -w_0 * t) * (A + B * t) + newPPreviousViewCenter.x; + } + [pageAnimationValues addObject:@(value)]; + } + pageAnimation.values = pageAnimationValues; + [_ppreviousViewController.view.layer addAnimation:pageAnimation forKey:pageAnimation.keyPath]; + _pagingAnimationCount++; + [CATransaction setDisableActions:YES]; + _ppreviousViewController.view.layer.position = newPPreviousViewCenter; + [CATransaction setDisableActions:NO]; + + [titleAnimationValues removeAllObjects]; + for (NSUInteger step = 0; step < steps; ++step) { + value = 1.f - fabsf([pageAnimationValues[step] floatValue] - boundsCenter.x) / pageWidth; + [titleAnimationValues addObject:@(value)]; + } + titleAnimation.values = titleAnimationValues; + [_ppreviousTitleView.layer addAnimation:titleAnimation forKey:titleAnimation.keyPath]; + _pagingAnimationCount++; + [CATransaction setDisableActions:YES]; + _ppreviousTitleView.layer.opacity = 0.f; + [CATransaction setDisableActions:NO]; + } + + // Next view. + if (_nextViewController) { + if (_nextViewController != _ppreviousViewController) { + CGPoint newNextViewCenter = CGPointMake(newCenter.x + pageWidth, newCenter.y); + [pageAnimationValues removeAllObjects]; + for (NSUInteger step = 0; step < steps; ++step) { + CGFloat t = 0.1f * step; + if (underDamping) { + value = powf((CGFloat)M_E, -zeta * w_0 * t) * (A * cosf(w_d * t) + B * sinf(w_d * t)) + newNextViewCenter.x; + } else { + value = powf((CGFloat)M_E, -w_0 * t) * (A + B * t) + newNextViewCenter.x; + } + [pageAnimationValues addObject:@(value)]; + } + pageAnimation.values = pageAnimationValues; + [_nextViewController.view.layer addAnimation:pageAnimation forKey:pageAnimation.keyPath]; + _pagingAnimationCount++; + [CATransaction setDisableActions:YES]; + _nextViewController.view.layer.position = newNextViewCenter; + [CATransaction setDisableActions:NO]; + } + + if (_nextTitleView != _ppreviousTitleView) { + [titleAnimationValues removeAllObjects]; + for (NSUInteger step = 0; step < steps; ++step) { + value = 1.f - fabsf([pageAnimationValues[step] floatValue] - boundsCenter.x) / pageWidth; + [titleAnimationValues addObject:@(value)]; + } + titleAnimation.values = titleAnimationValues; + [_nextTitleView.layer addAnimation:titleAnimation forKey:titleAnimation.keyPath]; + _pagingAnimationCount++; + [CATransaction setDisableActions:YES]; + _nextTitleView.layer.opacity = 0.f; + [CATransaction setDisableActions:NO]; + } + } + + [CATransaction commit]; + } else if (turnToNextPage) { + // Turn to next page. + CGPoint nextViewCenter = _nextViewController.view.center; + CGPoint newNextViewCenter = boundsCenter; + CGPoint newCenter = CGPointMake(newNextViewCenter.x - pageWidth, newNextViewCenter.y); + + [CATransaction begin]; + [CATransaction setAnimationDuration:kPagingAnimationDuration]; + + // Equilibrium postion is differenct, initial replacement is different. + x_0 = nextViewCenter.x - newNextViewCenter.x; + + BOOL underDamping = NO; + + // Try critical damping first. + // Limit x_max so that no more than 1 page is scrolled in one direction in one paging. + // When v_0 is large, x_max can be approximated by (v_0 / w_0 + x_0) / e. + const CGFloat X_MIN_LIMIT = 0; + const CGFloat VELOCITY_MIN_LIMIT = w_0 * (X_MIN_LIMIT * (CGFloat)M_E - x_0); + if (velocity.x < VELOCITY_MIN_LIMIT) { + underDamping = YES; + velocity.x /= 1.5f; + } + + if (underDamping) { +// DLog(@"Under-damping"); + // Limit x_max so that no more than 1 page is scrolled in one direction in one paging. + const CGFloat VELOCITY_MAX_LIMIT = 180.f; + if (velocity.x < -VELOCITY_MAX_LIMIT) { + velocity.x = -VELOCITY_MAX_LIMIT; + } + A = x_0; + B = (zeta * x_0 + velocity.x) / w_d; + CGFloat a = B * w_d - A * zeta * w_0; + CGFloat b = A * w_d + B * zeta * w_0; + CGFloat sin_max = sqrtf(a * a / (a * a + b * b)); + CGFloat theta_max; + if (a * b > 0) { + theta_max = asinf(sin_max); + } else { + theta_max = (CGFloat)M_PI - asinf(sin_max); + } + t_max = theta_max / w_d; + if (t_max > 0.f) { + x_max = powf((CGFloat)M_E, -zeta * w_0 * t_max) * (A * cosf(w_d * t_max) + B * sinf(w_d * t_max)); +// DLog(@"v_0 = %f, x_0 = %f, t_max = %f, x_max = %f", velocity.x, x_0, t_max, x_max); + if (x_max < 0.f) { + // Part of next-next view will be shown temporarily. + _nnextViewController = [self loadNNextPage]; + } + } + } else { +// DLog(@"Critical damping"); + A = x_0; + B = velocity.x + w_0 * x_0; + } + + // Current view. + CAKeyframeAnimation *pageAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position.x"]; + pageAnimation.delegate = self; + pageAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; + NSUInteger steps = 100; + NSMutableArray *pageAnimationValues = [NSMutableArray arrayWithCapacity:steps]; + CGFloat value; + for (NSUInteger step = 0; step < steps; ++step) { + CGFloat t = 0.1f * step; + if (underDamping) { + value = powf((CGFloat)M_E, -zeta * w_0 * t) * (A * cosf(w_d * t) + B * sinf(w_d * t)) + newCenter.x; + } else { + value = powf((CGFloat)M_E, -w_0 * t) * (A + B * t) + newCenter.x; + } + [pageAnimationValues addObject:@(value)]; + } + pageAnimation.values = pageAnimationValues; + [_contentController.view.layer addAnimation:pageAnimation forKey:pageAnimation.keyPath]; + _pagingAnimationCount++; + [CATransaction setDisableActions:YES]; + _contentController.view.layer.position = newCenter; + [CATransaction setDisableActions:NO]; + + CAKeyframeAnimation *titleAnimation = [CAKeyframeAnimation animationWithKeyPath:@"opacity"]; + titleAnimation.delegate = self; + titleAnimation.timingFunction = pageAnimation.timingFunction; + NSMutableArray *titleAnimationValues = [NSMutableArray arrayWithCapacity:steps]; + for (NSUInteger step = 0; step < steps; ++step) { + value = 1.f - fabsf([pageAnimationValues[step] floatValue] - boundsCenter.x) / pageWidth; + [titleAnimationValues addObject:@(value)]; + } + titleAnimation.values = titleAnimationValues; + [_titleView.layer addAnimation:titleAnimation forKey:titleAnimation.keyPath]; + _pagingAnimationCount++; + [CATransaction setDisableActions:YES]; + _titleView.layer.opacity = 0.f; + [CATransaction setDisableActions:NO]; + + // Previous view. + if (_previousViewController) { + if (_previousViewController != _nnextViewController) { + CGPoint newPreviousViewCenter = CGPointMake(newCenter.x - pageWidth, newCenter.y); + [pageAnimationValues removeAllObjects]; + for (NSUInteger step = 0; step < steps; ++step) { + CGFloat t = 0.1f * step; + if (underDamping) { + value = powf((CGFloat)M_E, -zeta * w_0 * t) * (A * cosf(w_d * t) + B * sinf(w_d * t)) + newPreviousViewCenter.x; + } else { + value = powf((CGFloat)M_E, -w_0 * t) * (A + B * t) + newPreviousViewCenter.x; + } + [pageAnimationValues addObject:@(value)]; + } + pageAnimation.values = pageAnimationValues; + [_previousViewController.view.layer addAnimation:pageAnimation forKey:pageAnimation.keyPath]; + _pagingAnimationCount++; + [CATransaction setDisableActions:YES]; + _previousViewController.view.layer.position = newPreviousViewCenter; + [CATransaction setDisableActions:NO]; + } + + if (_previousTitleView != _nnextTitleView) { + [titleAnimationValues removeAllObjects]; + for (NSUInteger step = 0; step < steps; ++step) { + value = 1.f - fabsf([pageAnimationValues[step] floatValue] - boundsCenter.x) / pageWidth; + [titleAnimationValues addObject:@(value)]; + } + titleAnimation.values = titleAnimationValues; + [_previousTitleView.layer addAnimation:titleAnimation forKey:titleAnimation.keyPath]; + _pagingAnimationCount++; + [CATransaction setDisableActions:YES]; + _previousTitleView.layer.opacity = 0.f; + [CATransaction setDisableActions:NO]; + } + } + + // Next view. + [pageAnimationValues removeAllObjects]; + for (NSUInteger step = 0; step < steps; ++step) { + CGFloat t = 0.1f * step; + if (underDamping) { + value = powf((CGFloat)M_E, -zeta * w_0 * t) * (A * cosf(w_d * t) + B * sinf(w_d * t)) + newNextViewCenter.x; + } else { + value = powf((CGFloat)M_E, -w_0 * t) * (A + B * t) + newNextViewCenter.x; + } + [pageAnimationValues addObject:@(value)]; + } + pageAnimation.values = pageAnimationValues; + [_nextViewController.view.layer addAnimation:pageAnimation forKey:pageAnimation.keyPath]; + _pagingAnimationCount++; + [CATransaction setDisableActions:YES]; + _nextViewController.view.layer.position = newNextViewCenter; + [CATransaction setDisableActions:NO]; + + [titleAnimationValues removeAllObjects]; + for (NSUInteger step = 0; step < steps; ++step) { + value = 1.f - fabsf([pageAnimationValues[step] floatValue] - boundsCenter.x) / pageWidth; + [titleAnimationValues addObject:@(value)]; + } + titleAnimation.values = titleAnimationValues; + [_nextTitleView.layer addAnimation:titleAnimation forKey:titleAnimation.keyPath]; + _pagingAnimationCount++; + [CATransaction setDisableActions:YES]; + _nextTitleView.layer.opacity = 1.f; + [CATransaction setDisableActions:NO]; + + if (_nnextViewController) { + CGPoint newNNextViewCenter = CGPointMake(newNextViewCenter.x + pageWidth, newNextViewCenter.y); + [pageAnimationValues removeAllObjects]; + for (NSUInteger step = 0; step < steps; ++step) { + CGFloat t = 0.1f * step; + if (underDamping) { + value = powf((CGFloat)M_E, -zeta * w_0 * t) * (A * cosf(w_d * t) + B * sinf(w_d * t)) + newNNextViewCenter.x; + } else { + value = powf((CGFloat)M_E, -w_0 * t) * (A + B * t) + newNNextViewCenter.x; + } + [pageAnimationValues addObject:@(value)]; + } + pageAnimation.values = pageAnimationValues; + [_nnextViewController.view.layer addAnimation:pageAnimation forKey:pageAnimation.keyPath]; + _pagingAnimationCount++; + [CATransaction setDisableActions:YES]; + _nnextViewController.view.layer.position = newNNextViewCenter; + [CATransaction setDisableActions:NO]; + + [titleAnimationValues removeAllObjects]; + for (NSUInteger step = 0; step < steps; ++step) { + value = 1.f - fabsf([pageAnimationValues[step] floatValue] - boundsCenter.x) / pageWidth; + [titleAnimationValues addObject:@(value)]; + } + titleAnimation.values = titleAnimationValues; + [_nnextTitleView.layer addAnimation:titleAnimation forKey:titleAnimation.keyPath]; + _pagingAnimationCount++; + [CATransaction setDisableActions:YES]; + _nnextTitleView.layer.opacity = 0.f; + [CATransaction setDisableActions:NO]; + } + + [CATransaction commit]; + } else { + // Bounce back to restore current page. + [CATransaction begin]; + [CATransaction setAnimationDuration:kPagingAnimationDuration]; + + if (t_max > 0.f) { + if (x_max > 0.f) { + if (_previousViewController == nil) { + _previousViewController = [self loadPreviousPage]; + } + } else if (x_max < 0.f) { + if (_nextViewController == nil) { + _nextViewController = [self loadNextPage]; + } + } + } + + // Current view. + CAKeyframeAnimation *pageAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position.x"]; + pageAnimation.delegate = self; + pageAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; + NSUInteger steps = 100; + NSMutableArray *pageAnimationValues = [NSMutableArray arrayWithCapacity:steps]; + CGFloat value; + for (NSUInteger step = 0; step < steps; ++step) { + CGFloat t = 0.1f * step; + value = powf((CGFloat)M_E, -w_0 * t) * (A + B * t) + boundsCenter.x; + [pageAnimationValues addObject:@(value)]; + } + pageAnimation.values = pageAnimationValues; + [_contentController.view.layer addAnimation:pageAnimation forKey:pageAnimation.keyPath]; + _pagingAnimationCount++; + [CATransaction setDisableActions:YES]; + _contentController.view.layer.position = boundsCenter; + [CATransaction setDisableActions:NO]; + + CAKeyframeAnimation *titleAnimation = [CAKeyframeAnimation animationWithKeyPath:@"opacity"]; + titleAnimation.delegate = self; + titleAnimation.timingFunction = pageAnimation.timingFunction; + NSMutableArray *titleAnimationValues = [NSMutableArray arrayWithCapacity:steps]; + for (NSUInteger step = 0; step < steps; ++step) { + value = 1.f - fabsf([pageAnimationValues[step] floatValue] - boundsCenter.x) / pageWidth; + [titleAnimationValues addObject:@(value)]; + } + titleAnimation.values = titleAnimationValues; + [_titleView.layer addAnimation:titleAnimation forKey:titleAnimation.keyPath]; + _pagingAnimationCount++; + [CATransaction setDisableActions:YES]; + _titleView.layer.opacity = 1.f; + [CATransaction setDisableActions:NO]; + + // Previous view. + if (_previousViewController) { + CGPoint previousViewCenter = CGPointMake(boundsCenter.x - pageWidth, boundsCenter.y); + [pageAnimationValues removeAllObjects]; + for (NSUInteger step = 0; step < steps; ++step) { + CGFloat t = 0.1f * step; + value = powf((CGFloat)M_E, -w_0 * t) * (A + B * t) + previousViewCenter.x; + [pageAnimationValues addObject:@(value)]; + } + pageAnimation.values = pageAnimationValues; + [_previousViewController.view.layer addAnimation:pageAnimation forKey:pageAnimation.keyPath]; + _pagingAnimationCount++; + [CATransaction setDisableActions:YES]; + _previousViewController.view.layer.position = previousViewCenter; + [CATransaction setDisableActions:NO]; + + [titleAnimationValues removeAllObjects]; + for (NSUInteger step = 0; step < steps; ++step) { + value = 1.f - fabsf([pageAnimationValues[step] floatValue] - boundsCenter.x) / pageWidth; + [titleAnimationValues addObject:@(value)]; + } + titleAnimation.values = titleAnimationValues; + [_previousTitleView.layer addAnimation:titleAnimation forKey:titleAnimation.keyPath]; + _pagingAnimationCount++; + [CATransaction setDisableActions:YES]; + _previousTitleView.layer.opacity = 0.f; + [CATransaction setDisableActions:NO]; + } + + // Next view. + if (_nextViewController) { + CGPoint nextViewCenter = CGPointMake(boundsCenter.x + pageWidth, boundsCenter.y); + [pageAnimationValues removeAllObjects]; + for (NSUInteger step = 0; step < steps; ++step) { + CGFloat t = 0.1f * step; + value = powf((CGFloat)M_E, -w_0 * t) * (A + B * t) + nextViewCenter.x; + [pageAnimationValues addObject:@(value)]; + } + pageAnimation.values = pageAnimationValues; + [_nextViewController.view.layer addAnimation:pageAnimation forKey:pageAnimation.keyPath]; + _pagingAnimationCount++; + [CATransaction setDisableActions:YES]; + _nextViewController.view.layer.position = nextViewCenter; + [CATransaction setDisableActions:NO]; + + [titleAnimationValues removeAllObjects]; + for (NSUInteger step = 0; step < steps; ++step) { + value = 1.f - fabsf([pageAnimationValues[step] floatValue] - boundsCenter.x) / pageWidth; + [titleAnimationValues addObject:@(value)]; + } + titleAnimation.values = titleAnimationValues; + [_nextTitleView.layer addAnimation:titleAnimation forKey:titleAnimation.keyPath]; + _pagingAnimationCount++; + [CATransaction setDisableActions:YES]; + _nextTitleView.layer.opacity = 0.f; + [CATransaction setDisableActions:NO]; + } + + [CATransaction commit]; + } + } +} + +- (IBAction)turnPage:(UITapGestureRecognizer *)gestureRecognizer +{ + if (_pagingAnimationCount > 0) return; + + if (gestureRecognizer.state != UIGestureRecognizerStateRecognized) return; + + if ([_delegate respondsToSelector:@selector(pageViewController:willBeginPagingViewController:)]) { + [_delegate pageViewController:self willBeginPagingViewController:_contentController]; + } + + UIView *view = gestureRecognizer.view; + CGPoint location = [gestureRecognizer locationInView:view]; + + static const CGFloat TAP_MARGIN = 40.0; + + // Tap on left margin, turn backward. + if (location.x < CGRectGetMinX(view.bounds) + TAP_MARGIN) { + [self turnBackward]; + } + // Tap on right margin, turn forward. + else if (location.x > CGRectGetMaxX(view.bounds) - TAP_MARGIN) { + [self turnForward]; + } +} + +- (void)turnForward { + _isTransitioningContentView = YES; + + if (_nextViewController == nil) { + _nextViewController = [self loadNextPage];; + } + + if (_nextViewController) { + CGPoint center = _contentController.view.center; + CGPoint nextViewCenter = _nextViewController.view.center; + CGPoint translation = CGPointMake(center.x - nextViewCenter.x, center.y - nextViewCenter.y); + CGPoint newCenter = CGPointMake(center.x + translation.x, center.y + translation.y); + [[UIApplication sharedApplication] beginIgnoringInteractionEvents]; + [UIView animateWithDuration:kPagingAnimationDuration animations:^(void) { + _contentController.view.center = newCenter; + _nextViewController.view.center = center; + _titleView.alpha = 0; + _nextTitleView.alpha = 1; + } completion:^(BOOL finished) { + if (finished) { + [self pagingDidEnd]; + } + [[UIApplication sharedApplication] endIgnoringInteractionEvents]; + }]; + } +} + +- (void)turnBackward { + _isTransitioningContentView = YES; + + if (_previousViewController == nil) { + _previousViewController = [self loadPreviousPage]; + } + + if (_previousViewController) { + CGPoint center = _contentController.view.center; + CGPoint previousViewCenter = _previousViewController.view.center; + CGPoint translation = CGPointMake(center.x - previousViewCenter.x, center.y - previousViewCenter.y); + CGPoint newCenter = CGPointMake(center.x + translation.x, center.y + translation.y); + [[UIApplication sharedApplication] beginIgnoringInteractionEvents]; + [UIView animateWithDuration:kPagingAnimationDuration animations:^(void) { + _contentController.view.center = newCenter; + _previousViewController.view.center = center; + _titleView.alpha = 0; + _previousTitleView.alpha = 1; + } completion:^(BOOL finished) { + if (finished) { + [self pagingDidEnd]; + } + [[UIApplication sharedApplication] endIgnoringInteractionEvents]; + }]; + } +} + +- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag { + if (!flag) { + _arePagingAnimationsCancelled = YES; + } + if (--_pagingAnimationCount == 0) { + [self pagingDidEnd]; + } +} + +- (void)pagingDidEnd +{ + UIViewController *oldContentController = _contentController; + CGPoint center = _contentController.view.center; + CGRect bounds = self.view.bounds; + if (center.x > CGRectGetMaxX(bounds) && _previousViewController != nil) { // Land in the previous page. + _nextViewController = _contentController; + self.contentController = _previousViewController; + _previousViewController = _ppreviousViewController; + _ppreviousViewController = nil; + + _nextTitleView = _titleView; + _titleView = _previousTitleView; + _previousTitleView = _ppreviousTitleView; + _ppreviousTitleView = nil; + self.navigationItem.titleView.bounds = _titleView.frame; + } else if (center.x < CGRectGetMinX(bounds) && _nextViewController != nil) { // Land in the next page. + _previousViewController = _contentController; + self.contentController = _nextViewController; + _nextViewController = _nnextViewController; + _nnextViewController = nil; + + _previousTitleView = _titleView; + _titleView = _nextTitleView; + _nextTitleView = _nnextTitleView; + _nnextTitleView = nil; + self.navigationItem.titleView.bounds = _titleView.frame; + } + + _isTransitioningContentView = NO; + _arePagingAnimationsCancelled = NO; + + if ([_delegate respondsToSelector:@selector(pageViewController:didEndPagingViewController:)]) { + [_delegate pageViewController:self didEndPagingViewController:oldContentController]; + } +} + +@end diff --git a/WLPageViewController/damping.m b/WLPageViewController/damping.m new file mode 100644 index 0000000..58ab13b --- /dev/null +++ b/WLPageViewController/damping.m @@ -0,0 +1,53 @@ +## k = 80 +## m = 125 +## c = 200 + +t = 0:0.1:10; + +## w_0 = sqrt(k / m) +## zeta = c / (2 * sqrt(m * k)) +## zeta_w_0 = c / (2 * m) +w_0 = .7 +zeta = 1 + +if abs(zeta - 1) < 0.001 +# critical damping + printf('Critical damping\n'); + A = x_0 + B = v_0 + w_0 * x_0 + x = (A + B * t) .* power(e, -w_0 * t); + t_max = 1 / w_0 - A / B + x_max = (v_0 + w_0 * x_0) / w_0 * e^(-v_0 / (v_0 + w_0 * x_0)) +elseif zeta < 1 + # under-damping + printf('Under-damping\n'); + w_d = w_0 * sqrt(1 - zeta * zeta) + A = x_0 + B = (zeta * x_0 + v_0) / w_d + x = power(e, -zeta * w_0 * t) .* (A * cos(w_d * t) + B * sin(w_d * t)); + a = B * w_d - A * zeta * w_0 + b = A * w_d + B * zeta * w_0 + sin_max = sqrt(a^2 / (a^2 + b^2)) + if a * b > 0 + theta_max = asin(sin_max) + theta_max = [theta_max, theta_max + pi, theta_max + 2 * pi] + else + theta_max = pi - asin(sin_max) + theta_max = [theta_max, theta_max + pi] + end + t_max = theta_max / w_d + x_max = power(e, -zeta * w_0 * t_max) .* (A * cos(w_d * t_max) + B * sin(w_d * t_max)) +else + # over-damping + printf('Over-damping\n'); + g_b = 2 * zeta * w_0; + g_c = w_0 * w_0; + g_delta = sqrt(g_b * g_b - 4 * g_a * g_c); + gamma_1 = (-g_b + g_delta) / 2; + gamma_2 = (-g_b - g_delta) / 2; + A = x_0 + (gamma_1 * x_0 - v_0) / (gamma_2 - gamma_1); + B = -(gamma_1 * x_0 - v_0) / (gamma_2 - gamma_1); + x = A * power(e, gamma_1 * t) + B * power(e, gamma_2 * t); +end + +plot(t, x) diff --git a/WLPageViewController/en.lproj/InfoPlist.strings b/WLPageViewController/en.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/WLPageViewController/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/WLPageViewController/main.m b/WLPageViewController/main.m new file mode 100644 index 0000000..49ab24c --- /dev/null +++ b/WLPageViewController/main.m @@ -0,0 +1,18 @@ +// +// main.m +// WLPageViewController +// +// Created by Ling Wang on 6/7/13. +// Copyright (c) 2013 Moke. All rights reserved. +// + +#import + +#import "AppDelegate.h" + +int main(int argc, char *argv[]) +{ + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +}