├── HyParallaxCurveHeaderViewDemo ├── Assets.xcassets │ ├── Contents.json │ ├── 11381801.imageset │ │ ├── 11381801.png │ │ ├── 11381801@2x.png │ │ ├── 11381801@3x.png │ │ └── Contents.json │ ├── icon_refuse.imageset │ │ ├── icon_refuse@2x.png │ │ └── Contents.json │ └── AppIcon.appiconset │ │ └── Contents.json ├── preview.gif ├── ViewController.h ├── TestViews.h ├── AppDelegate.h ├── main.m ├── HyParallaxCurveHeaderViewClass │ ├── UIImage+ImageEffects.h │ ├── HyParallaxCurveHeaderView.h │ ├── HyParallaxCurveHeaderView.m │ └── UIImage+ImageEffects.m ├── Info.plist ├── Base.lproj │ ├── Main.storyboard │ └── LaunchScreen.storyboard ├── TestViews.m ├── AppDelegate.m ├── ViewController.m └── TestViews.xib ├── HyParallaxCurveHeaderViewDemo.xcodeproj ├── project.xcworkspace │ └── contents.xcworkspacedata ├── xcuserdata │ └── Hy_Mac.xcuserdatad │ │ └── xcschemes │ │ ├── xcschememanagement.plist │ │ └── HyParallaxCurveHeaderViewDemo.xcscheme └── project.pbxproj ├── Podfile ├── HyParallaxCurveHeaderViewClass ├── UIImage+ImageEffects.h ├── HyParallaxCurveHeaderView.h ├── HyParallaxCurveHeaderView.m └── UIImage+ImageEffects.m ├── HyParallaxCurveHeaderViewDemoTests ├── Info.plist └── HyParallaxCurveHeaderViewDemoTests.m ├── HyParallaxCurveHeaderViewDemoUITests ├── Info.plist └── HyParallaxCurveHeaderViewDemoUITests.m ├── README.md └── HyParallaxCurveHeaderView.podspec /HyParallaxCurveHeaderViewDemo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewDemo/preview.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wwdc14yh/HyParallaxCurveHeaderView/HEAD/HyParallaxCurveHeaderViewDemo/preview.gif -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewDemo/Assets.xcassets/11381801.imageset/11381801.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wwdc14yh/HyParallaxCurveHeaderView/HEAD/HyParallaxCurveHeaderViewDemo/Assets.xcassets/11381801.imageset/11381801.png -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewDemo/Assets.xcassets/11381801.imageset/11381801@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wwdc14yh/HyParallaxCurveHeaderView/HEAD/HyParallaxCurveHeaderViewDemo/Assets.xcassets/11381801.imageset/11381801@2x.png -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewDemo/Assets.xcassets/11381801.imageset/11381801@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wwdc14yh/HyParallaxCurveHeaderView/HEAD/HyParallaxCurveHeaderViewDemo/Assets.xcassets/11381801.imageset/11381801@3x.png -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewDemo/Assets.xcassets/icon_refuse.imageset/icon_refuse@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wwdc14yh/HyParallaxCurveHeaderView/HEAD/HyParallaxCurveHeaderViewDemo/Assets.xcassets/icon_refuse.imageset/icon_refuse@2x.png -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewDemo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // HyParallaxCurveHeaderViewDemo 4 | // 5 | // Created by Hy_Mac on 16/8/29. 6 | // Copyright © 2016年 @Hy. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewDemo/TestViews.h: -------------------------------------------------------------------------------- 1 | // 2 | // TestViews.h 3 | // TableViewCurveHeaderView 4 | // 5 | // Created by Hy_Mac on 16/8/26. 6 | // Copyright © 2016年 Hy. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TestViews : UIView 12 | 13 | + (_Nonnull instancetype)loadXib; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // HyParallaxCurveHeaderViewDemo 4 | // 5 | // Created by Hy_Mac on 16/8/29. 6 | // Copyright © 2016年 @Hy. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // HyParallaxCurveHeaderViewDemo 4 | // 5 | // Created by Hy_Mac on 16/8/29. 6 | // Copyright © 2016年 @Hy. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewDemo/Assets.xcassets/icon_refuse.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "icon_refuse@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | platform :ios, ‘7.0’ 3 | inhibit_all_warning! 4 | 5 | 6 | target 'HyParallaxCurveHeaderViewDemo' do 7 | 8 | end 9 | 10 | target 'HyParallaxCurveHeaderViewDemoTests' do 11 | 12 | end 13 | 14 | target 'HyParallaxCurveHeaderViewDemoUITests' do 15 | 16 | end 17 | 18 | pod repo add master https://gitcafe.com/akuandev/Specs.git; 19 | Cloning spec repo `master` from `https://gitcafe.com/akuandev/Specs.git` 20 | -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewDemo/Assets.xcassets/11381801.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "11381801.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "11381801@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "11381801@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewClass/UIImage+ImageEffects.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+ImageEffects.h 3 | // Inkling 4 | // 5 | // Created by Aaron Pang on 3/26/14. 6 | // Copyright (c) 2014 Inkling. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIImage (ImageEffects) 12 | 13 | - (UIImage *)applySubtleEffect; 14 | - (UIImage *)applyLightEffect; 15 | - (UIImage *)applyExtraLightEffect; 16 | - (UIImage *)applyDarkEffect; 17 | - (UIImage *)applyTintEffectWithColor:(UIColor *)tintColor; 18 | - (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewDemo/HyParallaxCurveHeaderViewClass/UIImage+ImageEffects.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+ImageEffects.h 3 | // Inkling 4 | // 5 | // Created by Aaron Pang on 3/26/14. 6 | // Copyright (c) 2014 Inkling. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIImage (ImageEffects) 12 | 13 | - (UIImage *)applySubtleEffect; 14 | - (UIImage *)applyLightEffect; 15 | - (UIImage *)applyExtraLightEffect; 16 | - (UIImage *)applyDarkEffect; 17 | - (UIImage *)applyTintEffectWithColor:(UIColor *)tintColor; 18 | - (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewDemoTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewDemoUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewDemo.xcodeproj/xcuserdata/Hy_Mac.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | HyParallaxCurveHeaderViewDemo.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 7A9FD10A1D7432B200156442 16 | 17 | primary 18 | 19 | 20 | 7A9FD1231D7432B200156442 21 | 22 | primary 23 | 24 | 25 | 7A9FD12E1D7432B200156442 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | } 43 | ], 44 | "info" : { 45 | "version" : 1, 46 | "author" : "xcode" 47 | } 48 | } -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewDemoTests/HyParallaxCurveHeaderViewDemoTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // HyParallaxCurveHeaderViewDemoTests.m 3 | // HyParallaxCurveHeaderViewDemoTests 4 | // 5 | // Created by Hy_Mac on 16/8/29. 6 | // Copyright © 2016年 @Hy. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface HyParallaxCurveHeaderViewDemoTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation HyParallaxCurveHeaderViewDemoTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | // Use XCTAssert and related functions to verify your tests produce the correct results. 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 0.0.1 19 | CFBundleVersion 20 | 0.0.1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewClass/HyParallaxCurveHeaderView.h: -------------------------------------------------------------------------------- 1 | // 2 | // HyParallaxCurveHeaderView.h 3 | // TableViewCurveHeaderView 4 | // 5 | // Created by Hy_Mac on 16/8/29. 6 | // Copyright © 2016年 Hy. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface HyParallaxCurveHeaderView : UIView 12 | 13 | 14 | /** 15 | * 弧度; 16 | 默认 0.7f; 17 | 取值范围(0.0f ~ 1.0f) 18 | */ 19 | @property (nonatomic) CGFloat curveFloat; 20 | 21 | /** 22 | * 是否设置推荐弧度(为YES"curveFloat"属性失效) 23 | 默认 NO 24 | 取值范围(YES ~ NO) 25 | */ 26 | @property (nonatomic) BOOL suggestCurve; 27 | 28 | /** 29 | * 曲面颜色 30 | */ 31 | @property (nonatomic, strong, nonnull) UIColor *curveColor; 32 | 33 | /** 34 | * 背景颜色 35 | */ 36 | @property (nonatomic, strong, nonnull) UIColor *backgroundColor; 37 | 38 | /** 39 | * ... 40 | */ 41 | @property (nonatomic) CGFloat POINT_Y1; 42 | 43 | @property (nonatomic) CGFloat imageWidth; 44 | 45 | @property (nonatomic, nonnull, strong, readonly) UIView *followBottomView; 46 | 47 | @property (nonatomic, nonnull, strong, readonly) UIImageView *imageView; 48 | 49 | @property (nonatomic, strong, nonnull) UIColor *blurTintColor; 50 | 51 | @property (assign, nonatomic) BOOL isShowBlur; 52 | 53 | @property (assign, nonatomic) BOOL isParallax; 54 | 55 | - (void) layoutHeaderViewForScrollViewOffset:(CGPoint)offset; 56 | 57 | + (_Nonnull instancetype)loadHeaderCurveViewWithSize:(CGSize)size; 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewDemo/HyParallaxCurveHeaderViewClass/HyParallaxCurveHeaderView.h: -------------------------------------------------------------------------------- 1 | // 2 | // HyParallaxCurveHeaderView.h 3 | // TableViewCurveHeaderView 4 | // 5 | // Created by Hy_Mac on 16/8/29. 6 | // Copyright © 2016年 Hy. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface HyParallaxCurveHeaderView : UIView 12 | 13 | 14 | /** 15 | * 弧度; 16 | 默认 0.7f; 17 | 取值范围(0.0f ~ 1.0f) 18 | */ 19 | @property (nonatomic) CGFloat curveFloat; 20 | 21 | /** 22 | * 是否设置推荐弧度(为YES"curveFloat"属性失效) 23 | 默认 NO 24 | 取值范围(YES ~ NO) 25 | */ 26 | @property (nonatomic) BOOL suggestCurve; 27 | 28 | /** 29 | * 曲面颜色 30 | */ 31 | @property (nonatomic, strong, nonnull) UIColor *curveColor; 32 | 33 | /** 34 | * 背景颜色 35 | */ 36 | @property (nonatomic, strong, nonnull) UIColor *backgroundColor; 37 | 38 | /** 39 | * ... 40 | */ 41 | @property (nonatomic) CGFloat POINT_Y1; 42 | 43 | @property (nonatomic) CGFloat imageWidth; 44 | 45 | @property (nonatomic, nonnull, strong, readonly) UIView *followBottomView; 46 | 47 | @property (nonatomic, nonnull, strong, readonly) UIImageView *imageView; 48 | 49 | @property (nonatomic, strong, nonnull) UIColor *blurTintColor; 50 | 51 | @property (assign, nonatomic) BOOL isShowBlur; 52 | 53 | @property (assign, nonatomic) BOOL isParallax; 54 | 55 | - (void) layoutHeaderViewForScrollViewOffset:(CGPoint)offset; 56 | 57 | + (_Nonnull instancetype)loadHeaderCurveViewWithSize:(CGSize)size; 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewDemoUITests/HyParallaxCurveHeaderViewDemoUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // HyParallaxCurveHeaderViewDemoUITests.m 3 | // HyParallaxCurveHeaderViewDemoUITests 4 | // 5 | // Created by Hy_Mac on 16/8/29. 6 | // Copyright © 2016年 @Hy. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface HyParallaxCurveHeaderViewDemoUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation HyParallaxCurveHeaderViewDemoUITests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | 22 | // In UI tests it is usually best to stop immediately when a failure occurs. 23 | self.continueAfterFailure = NO; 24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 25 | [[[XCUIApplication alloc] init] launch]; 26 | 27 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 28 | } 29 | 30 | - (void)tearDown { 31 | // Put teardown code here. This method is called after the invocation of each test method in the class. 32 | [super tearDown]; 33 | } 34 | 35 | - (void)testExample { 36 | // Use recording to get started writing UI tests. 37 | // Use XCTAssert and related functions to verify your tests produce the correct results. 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewDemo/TestViews.m: -------------------------------------------------------------------------------- 1 | // 2 | // TestViews.m 3 | // TableViewCurveHeaderView 4 | // 5 | // Created by Hy_Mac on 16/8/26. 6 | // Copyright © 2016年 Hy. All rights reserved. 7 | // 8 | 9 | #import "TestViews.h" 10 | 11 | @interface TestViews () 12 | @property (weak, nonatomic) IBOutlet UIButton *button0; 13 | @property (weak, nonatomic) IBOutlet UIButton *button1; 14 | @property (weak, nonatomic) IBOutlet UIButton *button2; 15 | 16 | @end 17 | 18 | @implementation TestViews 19 | 20 | - (void)awakeFromNib 21 | { 22 | [super awakeFromNib]; 23 | _button0.layer.cornerRadius = 15.f; 24 | _button0.layer.borderColor = [UIColor colorWithRed:62.f/255.f green:177.f/255.f blue:251.f/255.f alpha:1].CGColor; 25 | _button0.layer.borderWidth = 1.f/2.f; 26 | 27 | _button1.layer.cornerRadius = 15.f; 28 | _button1.layer.borderColor = [UIColor colorWithRed:62.f/255.f green:177.f/255.f blue:251.f/255.f alpha:1].CGColor; 29 | _button1.layer.borderWidth = 1.f/2.f; 30 | 31 | _button2.layer.cornerRadius = 15.f; 32 | _button2.layer.borderColor = [UIColor colorWithRed:252.f/255.f green:183.f/255.f blue:66.f/255.f alpha:1].CGColor; 33 | _button2.layer.borderWidth = 1.f; 34 | 35 | } 36 | 37 | + (_Nonnull instancetype)loadXib 38 | { 39 | // Instantiate the nib content without any reference to it. 40 | NSArray *nibContents = [[NSBundle mainBundle] loadNibNamed:@"TestViews" owner:nil options:nil]; 41 | 42 | // Find the view among nib contents (not too hard assuming there is only one view in it). 43 | return [nibContents lastObject]; 44 | } 45 | 46 | /* 47 | // Only override drawRect: if you perform custom drawing. 48 | // An empty implementation adversely affects performance during animation. 49 | - (void)drawRect:(CGRect)rect { 50 | // Drawing code 51 | } 52 | */ 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewDemo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // HyParallaxCurveHeaderViewDemo 4 | // 5 | // Created by Hy_Mac on 16/8/29. 6 | // Copyright © 2016年 @Hy. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // 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. 26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 27 | } 28 | 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // 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. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 38 | } 39 | 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // 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. 43 | } 44 | 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | --- 2 | #HyParallaxCurveHeaderView 3 | ------------- 4 | [![Platform](http://img.shields.io/badge/platform-ios-blue.svg?style=flat 5 | )](https://developer.apple.com/iphone/index.action) 6 | [![Language](http://img.shields.io/badge/language-ObjC-brightgreen.svg?style=flat)](https://developer.apple.com/Objective-C) 7 | [![License](http://img.shields.io/badge/license-MIT-lightgrey.svg?style=flat)](http://mit-license.org) 8 | > 关于**HyParallaxCurveHeaderView**灵感来自于[智联招聘App]() 9 | 10 | ####示例: 11 | 12 | ![image](https://github.com/wwdc14/HyParallaxCurveHeaderViewDemo/blob/master/HyParallaxCurveHeaderViewDemo/preview.gif) 13 | 14 | ###原理说明 15 | 1.采用贝塞尔曲线绘制曲线视图具体看`- (void)drawRect:(CGRect)rect`方法 16 | 17 | 18 | ### 下载安装 19 | 将下载好的项目提取以下类托入项目中 20 | `UIImage+ImageEffects.h/.m` 21 | `HyParallaxCurveHeaderView.h/.m` 22 | 将`HyParallaxCurveHeaderView.h`import 23 | 24 | ### Podfile 25 | 使用`Podfile`进行代码集成,详情看下面 26 | 27 | 打开`Podfile`添加以下代码 28 | 29 | `pod 'HyParallaxCurveHeaderView', :git => 'https://github.com/wwdc14/HyParallaxCurveHeaderView.git'` 30 | 31 | 保存->`pod install` 32 | 33 | ###使用方法 34 | 35 | 实例`HyParallaxCurveHeaderView` 36 | ```obj 37 | HyParallaxCurveHeaderView *curveHeaderView = [HyParallaxCurveHeaderView loadHeaderCurveViewWithSize:CGSizeMake(CGRectGetWidth([UIScreen mainScreen].bounds), 300)]; 38 | _tableView.tableHeaderView = curveHeaderView; 39 | ``` 40 | 41 | ###属性以及方法说明 42 | * 属性 43 | 44 | `@property (nonatomic) CGFloat curveFloat` 曲线弧度取值范围0.0~1.0 45 | 46 | `@property (nonatomic) BOOL suggestCurve` 是否设置推荐弧度(为YES"curveFloat"属性失效) 47 | 48 | `@property (nonatomic, strong, nonnull) UIColor *curveColor` 曲面颜色 49 | 50 | `@property (nonatomic, strong, nonnull) UIColor *backgroundColor` 背景颜色 51 | 52 | `@property (nonatomic) CGFloat imageWidth` imageView宽度 53 | 54 | `@property (nonatomic, nonnull, strong, readonly) UIView *followBottomView` 跟随底部View 55 | 56 | `@property (nonatomic, nonnull, strong, readonly) UIImageView *imageView` imageView 57 | 58 | `@property (nonatomic, strong, nonnull) UIColor *blurTintColor` 模糊颜色 59 | 60 | `@property (assign, nonatomic) BOOL isShowBlur` 是否显示模糊 61 | 62 | `@property (assign, nonatomic) BOOL isParallax` 是否具有视差效果 63 | 64 | * 函数 65 | 66 | `- (void) layoutHeaderViewForScrollViewOffset:(CGPoint)offset` 实现下拉改变曲面重要方法(必须调用) 67 | 68 | `+ (_Nonnull instancetype)loadHeaderCurveViewWithSize:(CGSize)size` 初始化方法 69 | 70 | ### 注意事项 71 | 72 | * 非常感谢[Vinodh-G](https://github.com/Vinodh-G/ParallaxTableViewHeader)开源的`ParallaxTableViewHeader`三方库提供滑动视差效果. 73 | 74 | ### 期待 75 | * 如果在使用过程中遇到BUG,希望你能Issues我 76 | * 如果觉得好用请Star! 77 | 78 | -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewDemo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // HyParallaxCurveHeaderViewDemo 4 | // 5 | // Created by Hy_Mac on 16/8/29. 6 | // Copyright © 2016年 @Hy. All rights reserved. 7 | // 8 | 9 | #import "TestViews.h" 10 | #import "ViewController.h" 11 | #import "HyParallaxCurveHeaderView.h" 12 | 13 | @interface ViewController () 14 | @property (nullable, nonatomic, assign)UITableView *tableView; 15 | @end 16 | 17 | @implementation ViewController 18 | 19 | - (void)viewDidLoad { 20 | [super viewDidLoad]; 21 | // Do any additional setup after loading the view, typically from a nib. 22 | { 23 | UITableView *tableView = [UITableView new]; 24 | _tableView = tableView; 25 | _tableView.frame = [UIScreen mainScreen].bounds; 26 | [self.view addSubview:_tableView]; 27 | _tableView.delegate = self; 28 | _tableView.dataSource = self; 29 | 30 | HyParallaxCurveHeaderView *curveHeaderView = [HyParallaxCurveHeaderView loadHeaderCurveViewWithSize:CGSizeMake(CGRectGetWidth([UIScreen mainScreen].bounds), 300)]; 31 | curveHeaderView.imageView.image = [UIImage imageNamed:@"11381801"]; 32 | curveHeaderView.curveFloat = 140.f/300.f; 33 | curveHeaderView.POINT_Y1 = 160.f/300.f; 34 | curveHeaderView.suggestCurve = false; 35 | curveHeaderView.curveColor = [UIColor whiteColor]; 36 | curveHeaderView.backgroundColor = [UIColor colorWithRed:69.f/255.f green:168.f/255.f blue:244.f/255.f alpha:1]; 37 | curveHeaderView.blurTintColor = [UIColor colorWithRed:69.f/255.f green:168.f/255.f blue:244.f/255.f alpha:0.2f]; 38 | 39 | TestViews *views = [TestViews loadXib]; 40 | views.backgroundColor = [UIColor clearColor]; 41 | views.frame = CGRectMake(0, 0, CGRectGetWidth(curveHeaderView.followBottomView.frame), CGRectGetHeight(curveHeaderView.followBottomView.frame)); 42 | [curveHeaderView.followBottomView addSubview:views]; 43 | _tableView.tableHeaderView = curveHeaderView; 44 | } 45 | } 46 | 47 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 48 | { 49 | return 100; 50 | } 51 | 52 | // Row display. Implementers should *always* try to reuse cells by setting each cell's reuseIdentifier and querying for available reusable cells with dequeueReusableCellWithIdentifier: 53 | // Cell gets various attributes set automatically based on table (separators) and data source (accessory views, editing controls) 54 | 55 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 56 | { 57 | UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"cell"]; 58 | if (!cell) { 59 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"cell"]; 60 | } 61 | cell.textLabel.text = [NSString stringWithFormat:@"%zd",indexPath.row]; 62 | return cell; 63 | } 64 | 65 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView 66 | { 67 | [(HyParallaxCurveHeaderView *)self.tableView.tableHeaderView layoutHeaderViewForScrollViewOffset:scrollView.contentOffset]; 68 | } 69 | 70 | - (BOOL)prefersStatusBarHidden 71 | { 72 | return true; 73 | } 74 | 75 | - (void)didReceiveMemoryWarning { 76 | [super didReceiveMemoryWarning]; 77 | // Dispose of any resources that can be recreated. 78 | } 79 | 80 | 81 | @end 82 | -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewDemo.xcodeproj/xcuserdata/Hy_Mac.xcuserdatad/xcschemes/HyParallaxCurveHeaderViewDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 74 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /HyParallaxCurveHeaderView.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod spec lint HyParallaxCurveHeaderView.podspec' to ensure this is a 3 | # valid spec and to remove all comments including this before submitting the spec. 4 | # 5 | # To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html 6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/ 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | 11 | # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 12 | # 13 | # These will help people to find your library, and whilst it 14 | # can feel like a chore to fill in it's definitely to your advantage. The 15 | # summary should be tweet-length, and the description more in depth. 16 | # 17 | 18 | s.name = "HyParallaxCurveHeaderView" 19 | s.version = "0.0.2" 20 | s.summary = "A short description of HyParallaxCurveHeaderView." 21 | 22 | s.description = <<-DESC 23 | A longer description of HyParallaxCurveHeaderView in Markdown format. 24 | 25 | * Think: Why did you write this? What is the focus? What does it do? 26 | * CocoaPods will be using this to generate tags, and improve search results. 27 | * Try to keep it short, snappy and to the point. 28 | * Finally, don't worry about the indent, CocoaPods strips it! 29 | DESC 30 | 31 | s.homepage = "https://github.com/wwdc14/HyParallaxCurveHeaderView" 32 | # s.screenshots = "www.example.com/screenshots_1.gif", "www.example.com/screenshots_2.gif" 33 | 34 | 35 | # ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 36 | # 37 | # Licensing your code is important. See http://choosealicense.com for more info. 38 | # CocoaPods will detect a license file if there is a named LICENSE* 39 | # Popular ones are 'MIT', 'BSD' and 'Apache License, Version 2.0'. 40 | # 41 | 42 | s.license = "MIT (example)" 43 | # s.license = { :type => "MIT", :file => "FILE_LICENSE" } 44 | 45 | 46 | # ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 47 | # 48 | # Specify the authors of the library, with email addresses. Email addresses 49 | # of the authors are extracted from the SCM log. E.g. $ git log. CocoaPods also 50 | # accepts just a name if you'd rather not provide an email address. 51 | # 52 | # Specify a social_media_url where others can refer to, for example a twitter 53 | # profile URL. 54 | # 55 | 56 | s.author = { "Hy_Mac" => "wwdc14@vip.qq.com" } 57 | # Or just: s.author = "Hy_Mac" 58 | # s.authors = { "Hy_Mac" => "" } 59 | # s.social_media_url = "http://twitter.com/Hy_Mac" 60 | 61 | # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 62 | # 63 | # If this Pod runs only on iOS or OS X, then specify the platform and 64 | # the deployment target. You can optionally include the target after the platform. 65 | # 66 | 67 | #s.platform = :ios 68 | s.platform = :ios, "6.0" 69 | 70 | # When using multiple platforms 71 | s.ios.deployment_target = "6.0" 72 | # s.osx.deployment_target = "10.7" 73 | # s.watchos.deployment_target = "2.0" 74 | 75 | 76 | # ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 77 | # 78 | # Specify the location from where the source should be retrieved. 79 | # Supports git, hg, bzr, svn and HTTP. 80 | # 81 | 82 | s.source = { :git => "https://github.com/wwdc14/HyParallaxCurveHeaderView.git", :tag => "0.0.1" } 83 | 84 | 85 | # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 86 | # 87 | # CocoaPods is smart about how it includes source code. For source files 88 | # giving a folder will include any swift, h, m, mm, c & cpp files. 89 | # For header files it will include any header in the folder. 90 | # Not including the public_header_files will make all headers public. 91 | # 92 | 93 | s.source_files = 'HyParallaxCurveHeaderViewClass/**/*.{h,m}' 94 | #s.exclude_files = "" 95 | 96 | # s.public_header_files = "HyParallaxCurveHeaderViewClass/**/*.h" 97 | 98 | 99 | # ――― Resources ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 100 | # 101 | # A list of resources included with the Pod. These are copied into the 102 | # target bundle with a build phase script. Anything else will be cleaned. 103 | # You can preserve files from being cleaned, please don't preserve 104 | # non-essential files like tests, examples and documentation. 105 | # 106 | 107 | # s.resource = "icon.png" 108 | # s.resources = "Resources/*.png" 109 | 110 | # s.preserve_paths = "FilesToSave", "MoreFilesToSave" 111 | 112 | 113 | # ――― Project Linking ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 114 | # 115 | # Link your library with frameworks, or libraries. Libraries do not include 116 | # the lib prefix of their name. 117 | # 118 | 119 | # s.framework = "SomeFramework" 120 | # s.frameworks = "SomeFramework", "AnotherFramework" 121 | 122 | # s.library = "iconv" 123 | # s.libraries = "iconv", "xml2" 124 | 125 | 126 | # ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 127 | # 128 | # If your library depends on compiler flags you can set them in the xcconfig hash 129 | # where they will only apply to your library. If you depend on other Podspecs 130 | # you can include multiple dependencies to ensure it works. 131 | 132 | # s.requires_arc = true 133 | 134 | # s.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" } 135 | # s.dependency "JSONKit", "~> 1.4" 136 | 137 | end 138 | -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewDemo/TestViews.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 23 | 31 | 41 | 50 | 59 | 68 | 77 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewClass/HyParallaxCurveHeaderView.m: -------------------------------------------------------------------------------- 1 | // 2 | // HyParallaxCurveHeaderView.m 3 | // TableViewCurveHeaderView 4 | // 5 | // Created by Hy_Mac on 16/8/29. 6 | // Copyright © 2016年 Hy. All rights reserved. 7 | // 8 | 9 | #import "HyParallaxCurveHeaderView.h" 10 | #import "UIImage+ImageEffects.h" 11 | 12 | @interface HyHeaderCurveView : UIView 13 | @property (nonatomic) CGFloat POINT_Y1; 14 | @property (nonatomic) BOOL suggestCurve; 15 | @property (nonatomic) CGFloat imageWidth; 16 | @property (nonatomic) CGFloat curveFloat; 17 | @property (nonatomic, strong, nonnull) UIColor *curveColor; 18 | @property (nonatomic, strong, nonnull) UIColor *backgroundColor; 19 | @property (nonatomic, nonnull, strong, readonly) UIView *followBottomView; 20 | @property (nonatomic, nonnull, strong, readonly) UIImageView *imageView; 21 | @property (nonnull, nonatomic, strong) UIBezierPath* rectanglePath; 22 | @property (nonnull, nonatomic, strong) UIBezierPath* bezierPath; 23 | @property (nonnull, nonatomic, strong) CAShapeLayer* shapeLayer; 24 | @end 25 | 26 | #define w [UIScreen mainScreen].bounds.size.width 27 | #define MAX_Y CGRectGetMaxY(self.frame) 28 | #define MARGIN 70 29 | 30 | @implementation HyHeaderCurveView 31 | 32 | - (instancetype) init 33 | { 34 | self = [super init]; 35 | if (self) { 36 | [self initUI]; 37 | } 38 | return self; 39 | } 40 | 41 | - (instancetype) initWithFrame:(CGRect)frame 42 | { 43 | self = [super initWithFrame:frame]; 44 | if (self) { 45 | [self initUI]; 46 | } 47 | return self; 48 | } 49 | 50 | - (void)initUI 51 | { 52 | 53 | _bezierPath = [UIBezierPath bezierPath]; 54 | { 55 | _shapeLayer = [CAShapeLayer layer]; 56 | [self.layer addSublayer:_shapeLayer]; 57 | _shapeLayer.frame = self.frame; 58 | } 59 | _bezierPath = [UIBezierPath bezierPath]; 60 | _curveFloat = 0.48f; 61 | _POINT_Y1 = 0.0f; 62 | _suggestCurve = false; 63 | { 64 | _followBottomView = [self viewWithTag:1000]; 65 | if (!_followBottomView) { 66 | _followBottomView = [UIView new]; 67 | [self addSubview:_followBottomView]; 68 | _followBottomView.tag = 1000; 69 | } 70 | } 71 | 72 | { 73 | _imageWidth = 60; 74 | _imageView = [[UIImageView alloc] init]; 75 | _imageView.tag = 1001; 76 | _imageView.contentMode = UIViewContentModeScaleAspectFill; 77 | [self addSubview:_imageView]; 78 | _imageView.layer.masksToBounds = true; 79 | _imageView.layer.borderWidth = 2.f; 80 | _imageView.layer.borderColor = [UIColor whiteColor].CGColor; 81 | _imageView.layer.cornerRadius = _imageWidth/2; 82 | } 83 | } 84 | 85 | - (void)setImageWidth:(CGFloat)imageWidth 86 | { 87 | _imageWidth = imageWidth; 88 | _imageView.layer.cornerRadius = _imageWidth/2; 89 | _imageView.frame = CGRectMake(_imageView.frame.origin.x, 90 | _imageView.frame.origin.y, 91 | _imageWidth, 92 | _imageWidth); 93 | } 94 | 95 | - (void)setCurveColor:(UIColor *)curveColor 96 | { 97 | _curveColor = curveColor; 98 | _shapeLayer.fillColor = _curveColor.CGColor; 99 | } 100 | 101 | - (void)setBackgroundColor:(UIColor *)backgroundColor 102 | { 103 | _backgroundColor = backgroundColor; 104 | _shapeLayer.backgroundColor = _backgroundColor.CGColor; 105 | } 106 | 107 | - (void) setPOINT_Y1:(CGFloat)POINT_Y1 108 | { 109 | //_POINT_Y1 = POINT_Y1; 110 | _POINT_Y1 = POINT_Y1 * CGRectGetHeight(self.frame); 111 | _followBottomView.frame = CGRectMake(0, 112 | _POINT_Y1, 113 | CGRectGetWidth(self.frame), 114 | CGRectGetHeight(self.frame) - _POINT_Y1); 115 | [self setNeedsDisplay]; 116 | } 117 | 118 | - (void)setSuggestCurve:(BOOL)suggestCurve 119 | { 120 | _suggestCurve = suggestCurve; 121 | if (_suggestCurve) { 122 | [self setPOINT_Y1:(CGRectGetMidY(self.frame)/2)/CGRectGetMidY(self.frame)]; 123 | } 124 | } 125 | 126 | - (void)setFrame:(CGRect)frame 127 | { 128 | [super setFrame:frame]; 129 | _shapeLayer.frame = frame; 130 | [self setNeedsDisplay]; 131 | if (_POINT_Y1 == 0.0f) { 132 | 133 | _POINT_Y1 = CGRectGetMidY(frame); 134 | _followBottomView.frame = CGRectMake(0, 135 | _POINT_Y1, 136 | CGRectGetWidth(self.frame), 137 | CGRectGetHeight(self.frame) - CGRectGetMaxY(_imageView.frame)); 138 | } 139 | [_followBottomView setFrame:CGRectMake(0, 140 | CGRectGetMaxY(self.frame) - CGRectGetHeight(_followBottomView.frame), 141 | w, 142 | CGRectGetHeight(_followBottomView.frame))]; 143 | } 144 | 145 | // Only override drawRect: if you perform custom drawing. 146 | // An empty implementation adversely affects performance during animation. 147 | - (void)drawRect:(CGRect)rect { 148 | [super drawRect:rect]; 149 | CGFloat progress = CGRectGetHeight(rect)/CGRectGetHeight([UIScreen mainScreen].bounds); 150 | progress = MAX(progress - 0.3, 0.0f); 151 | CGFloat centerX = CGRectGetMidX(self.frame); 152 | CGFloat point6X = CGRectGetMaxX(self.frame)-MARGIN; 153 | CGFloat dragY = ((_curveFloat * CGRectGetHeight(self.frame)) - (progress*400)) + (progress*400);//速度差值 154 | if (_suggestCurve) { 155 | dragY = (_POINT_Y1 - 85) + (progress*400); 156 | } 157 | 158 | { 159 | _imageView.frame = CGRectMake(centerX - _imageWidth/2, 160 | dragY - _imageWidth/2, 161 | _imageWidth, 162 | _imageWidth); 163 | } 164 | 165 | NSArray *points = @[[NSValue valueWithCGPoint:CGPointMake(0, _POINT_Y1)], //point0 166 | [NSValue valueWithCGPoint:CGPointMake(0, MAX_Y)], //point1 167 | [NSValue valueWithCGPoint:CGPointMake(w, MAX_Y)], //point2 168 | [NSValue valueWithCGPoint:CGPointMake(w, _POINT_Y1)], //point3 169 | [NSValue valueWithCGPoint:CGPointMake(centerX, dragY)], //point4 170 | [NSValue valueWithCGPoint:CGPointMake(w, _POINT_Y1)], //point5 171 | [NSValue valueWithCGPoint:CGPointMake(point6X, dragY)], //point6 172 | [NSValue valueWithCGPoint:CGPointMake(0, _POINT_Y1)], //point7 173 | [NSValue valueWithCGPoint:CGPointMake(MARGIN, dragY)], //point8 174 | [NSValue valueWithCGPoint:CGPointMake(0, _POINT_Y1)] //point9 175 | ]; 176 | //标记关键点 177 | // for (NSValue * value in points) { 178 | // NSInteger index = [points indexOfObject:value]; 179 | // CGPoint point = [value CGPointValue]; 180 | // UILabel *view = [self viewWithTag:index+100]; 181 | // if (!view) { 182 | // view = [[UILabel alloc] init]; 183 | // view.tag = index+100; 184 | // [self addSubview:view]; 185 | // view.backgroundColor = [UIColor redColor]; 186 | // view.textAlignment = 1; 187 | // view.clipsToBounds = true; 188 | // } 189 | // view.text = [NSString stringWithFormat:@"%zd",index]; 190 | // [view setFrame:CGRectMake(point.x-10/2, point.y-5/2, 10, 10)]; 191 | // view.layer.cornerRadius = 10/2; 192 | // view.font = [UIFont systemFontOfSize:10]; 193 | // view.textColor = [UIColor whiteColor]; 194 | // view.hidden = true; 195 | // } 196 | 197 | // Bezier Drawing 198 | [_bezierPath removeAllPoints]; 199 | [_bezierPath moveToPoint: [[points objectAtIndex:0] CGPointValue]]; 200 | [_bezierPath addLineToPoint: [[points objectAtIndex:1] CGPointValue]]; 201 | [_bezierPath addLineToPoint: [[points objectAtIndex:2] CGPointValue]]; 202 | [_bezierPath addLineToPoint: [[points objectAtIndex:3] CGPointValue]]; 203 | 204 | [_bezierPath addCurveToPoint: [[points objectAtIndex:4] CGPointValue] 205 | controlPoint1: [[points objectAtIndex:5] CGPointValue] 206 | controlPoint2: [[points objectAtIndex:6] CGPointValue]]; 207 | 208 | [_bezierPath addCurveToPoint: [[points objectAtIndex:7] CGPointValue] 209 | controlPoint1: [[points objectAtIndex:8] CGPointValue] 210 | controlPoint2: [[points objectAtIndex:9] CGPointValue]]; 211 | _shapeLayer.path = _bezierPath.CGPath; 212 | points = nil; 213 | } 214 | 215 | @end 216 | 217 | @interface HyParallaxCurveHeaderView () 218 | @property (weak, nonatomic) UIScrollView *scrollView; 219 | @property (weak, nonatomic) HyHeaderCurveView *subView; 220 | @property (nonatomic) UIImageView *bluredImageView; 221 | @property (nonnull, strong, nonatomic) HyHeaderCurveView *curveView; 222 | @end 223 | 224 | #define kDefaultHeaderFrame CGRectMake(0, 0, self.frame.size.width, self.frame.size.height) 225 | static CGFloat kParallaxDeltaFactor = 0.5f; 226 | 227 | @implementation HyParallaxCurveHeaderView 228 | 229 | + (_Nonnull instancetype)loadHeaderCurveViewWithSize:(CGSize)size 230 | { 231 | HyParallaxCurveHeaderView *headerView = [[HyParallaxCurveHeaderView alloc] initWithFrame:(CGRect){CGPointZero,size}]; 232 | HyHeaderCurveView *curveView = [[HyHeaderCurveView alloc] initWithFrame:headerView.frame]; 233 | headerView.isShowBlur = true; 234 | headerView.isParallax = true; 235 | [headerView initialSetupForCustomSubView:curveView]; 236 | return headerView; 237 | } 238 | 239 | - (void)initialSetupForCustomSubView:(HyHeaderCurveView *)subView 240 | { 241 | UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:self.bounds]; 242 | self.scrollView = scrollView; 243 | self.subView = subView; 244 | _followBottomView = _subView.followBottomView; 245 | _imageView = _subView.imageView; 246 | subView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; 247 | [self.scrollView addSubview:subView]; 248 | 249 | self.bluredImageView = [[UIImageView alloc] initWithFrame:subView.frame]; 250 | self.bluredImageView.autoresizingMask = subView.autoresizingMask; 251 | self.bluredImageView.alpha = 0.0f; 252 | [self.scrollView addSubview:self.bluredImageView]; 253 | 254 | [self addSubview:self.scrollView]; 255 | if (_isShowBlur) { 256 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 257 | [self refreshBlurView]; 258 | }); 259 | } 260 | } 261 | 262 | - (void)layoutHeaderViewForScrollViewOffset:(CGPoint)offset 263 | { 264 | CGRect frame = self.scrollView.frame; 265 | if (offset.y > 0) 266 | { 267 | if (_isParallax) { 268 | frame.origin.y = MAX(offset.y *kParallaxDeltaFactor, 0); 269 | } 270 | self.scrollView.frame = frame; 271 | self.bluredImageView.alpha = 1 / kDefaultHeaderFrame.size.height * offset.y * 2; 272 | self.clipsToBounds = YES; 273 | } 274 | else 275 | { 276 | CGFloat delta = 0.0f; 277 | CGRect rect = kDefaultHeaderFrame; 278 | delta = fabs(MIN(0.0f, offset.y)); 279 | rect.origin.y -= delta; 280 | rect.size.height += delta; 281 | self.scrollView.frame = rect; 282 | self.clipsToBounds = NO; 283 | self.bluredImageView.alpha = offset.y/kDefaultHeaderFrame.size.height; 284 | } 285 | } 286 | 287 | - (void)refreshBlurView 288 | { 289 | UIImage *screenShot = [self screenShotOfView:self]; 290 | 291 | UIColor *color = _blurTintColor; 292 | if (!color) { 293 | color = [UIColor colorWithWhite:0.3 alpha:0.4]; 294 | } 295 | 296 | screenShot = [screenShot applyBlurWithRadius:6 tintColor:color saturationDeltaFactor:1.0 maskImage:nil]; 297 | self.bluredImageView.image = screenShot; 298 | } 299 | 300 | - (UIImage *)screenShotOfView:(UIView *)view 301 | { 302 | UIGraphicsBeginImageContextWithOptions(kDefaultHeaderFrame.size, YES, 0.0); 303 | [self drawViewHierarchyInRect:kDefaultHeaderFrame afterScreenUpdates:NO]; 304 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 305 | UIGraphicsEndImageContext(); 306 | 307 | return image; 308 | } 309 | 310 | - (void)setCurveColor:(UIColor *)curveColor 311 | { 312 | _curveColor = curveColor; 313 | _subView.curveColor = curveColor; 314 | } 315 | 316 | - (void)setSuggestCurve:(BOOL)suggestCurve 317 | { 318 | _suggestCurve = suggestCurve; 319 | _subView.suggestCurve = suggestCurve; 320 | } 321 | 322 | - (void)setCurveFloat:(CGFloat)curveFloat 323 | { 324 | _curveFloat = curveFloat; 325 | _subView.curveFloat = curveFloat; 326 | } 327 | 328 | - (void)setBackgroundColor:(UIColor *)backgroundColor 329 | { 330 | _backgroundColor = backgroundColor; 331 | _subView.backgroundColor = backgroundColor; 332 | } 333 | 334 | - (void)setPOINT_Y1:(CGFloat)POINT_Y1 335 | { 336 | _POINT_Y1 = POINT_Y1; 337 | _subView.POINT_Y1 = POINT_Y1; 338 | } 339 | 340 | - (void)setImageWidth:(CGFloat)imageWidth 341 | { 342 | _imageWidth = imageWidth; 343 | _subView.imageWidth = imageWidth; 344 | } 345 | 346 | /* 347 | // Only override drawRect: if you perform custom drawing. 348 | // An empty implementation adversely affects performance during animation. 349 | - (void)drawRect:(CGRect)rect { 350 | // Drawing code 351 | } 352 | */ 353 | 354 | @end 355 | -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewDemo/HyParallaxCurveHeaderViewClass/HyParallaxCurveHeaderView.m: -------------------------------------------------------------------------------- 1 | // 2 | // HyParallaxCurveHeaderView.m 3 | // TableViewCurveHeaderView 4 | // 5 | // Created by Hy_Mac on 16/8/29. 6 | // Copyright © 2016年 Hy. All rights reserved. 7 | // 8 | 9 | #import "HyParallaxCurveHeaderView.h" 10 | #import "UIImage+ImageEffects.h" 11 | 12 | @interface HyHeaderCurveView : UIView 13 | @property (nonatomic) CGFloat POINT_Y1; 14 | @property (nonatomic) BOOL suggestCurve; 15 | @property (nonatomic) CGFloat imageWidth; 16 | @property (nonatomic) CGFloat curveFloat; 17 | @property (nonatomic, strong, nonnull) UIColor *curveColor; 18 | @property (nonatomic, strong, nonnull) UIColor *backgroundColor; 19 | @property (nonatomic, nonnull, strong, readonly) UIView *followBottomView; 20 | @property (nonatomic, nonnull, strong, readonly) UIImageView *imageView; 21 | @property (nonnull, nonatomic, strong) UIBezierPath* rectanglePath; 22 | @property (nonnull, nonatomic, strong) UIBezierPath* bezierPath; 23 | @property (nonnull, nonatomic, strong) CAShapeLayer* shapeLayer; 24 | @end 25 | 26 | #define w [UIScreen mainScreen].bounds.size.width 27 | #define MAX_Y CGRectGetMaxY(self.frame) 28 | #define MARGIN 70 29 | 30 | @implementation HyHeaderCurveView 31 | 32 | - (instancetype) init 33 | { 34 | self = [super init]; 35 | if (self) { 36 | [self initUI]; 37 | } 38 | return self; 39 | } 40 | 41 | - (instancetype) initWithFrame:(CGRect)frame 42 | { 43 | self = [super initWithFrame:frame]; 44 | if (self) { 45 | [self initUI]; 46 | } 47 | return self; 48 | } 49 | 50 | - (void)initUI 51 | { 52 | 53 | _bezierPath = [UIBezierPath bezierPath]; 54 | { 55 | _shapeLayer = [CAShapeLayer layer]; 56 | [self.layer addSublayer:_shapeLayer]; 57 | _shapeLayer.frame = self.frame; 58 | } 59 | _bezierPath = [UIBezierPath bezierPath]; 60 | _curveFloat = 0.48f; 61 | _POINT_Y1 = 0.0f; 62 | _suggestCurve = false; 63 | { 64 | _followBottomView = [self viewWithTag:1000]; 65 | if (!_followBottomView) { 66 | _followBottomView = [UIView new]; 67 | [self addSubview:_followBottomView]; 68 | _followBottomView.tag = 1000; 69 | } 70 | } 71 | 72 | { 73 | _imageWidth = 60; 74 | _imageView = [[UIImageView alloc] init]; 75 | _imageView.tag = 1001; 76 | _imageView.contentMode = UIViewContentModeScaleAspectFill; 77 | [self addSubview:_imageView]; 78 | _imageView.layer.masksToBounds = true; 79 | _imageView.layer.borderWidth = 2.f; 80 | _imageView.layer.borderColor = [UIColor whiteColor].CGColor; 81 | _imageView.layer.cornerRadius = _imageWidth/2; 82 | } 83 | } 84 | 85 | - (void)setImageWidth:(CGFloat)imageWidth 86 | { 87 | _imageWidth = imageWidth; 88 | _imageView.layer.cornerRadius = _imageWidth/2; 89 | _imageView.frame = CGRectMake(_imageView.frame.origin.x, 90 | _imageView.frame.origin.y, 91 | _imageWidth, 92 | _imageWidth); 93 | } 94 | 95 | - (void)setCurveColor:(UIColor *)curveColor 96 | { 97 | _curveColor = curveColor; 98 | _shapeLayer.fillColor = _curveColor.CGColor; 99 | } 100 | 101 | - (void)setBackgroundColor:(UIColor *)backgroundColor 102 | { 103 | _backgroundColor = backgroundColor; 104 | _shapeLayer.backgroundColor = _backgroundColor.CGColor; 105 | } 106 | 107 | - (void) setPOINT_Y1:(CGFloat)POINT_Y1 108 | { 109 | //_POINT_Y1 = POINT_Y1; 110 | _POINT_Y1 = POINT_Y1 * CGRectGetHeight(self.frame); 111 | _followBottomView.frame = CGRectMake(0, 112 | _POINT_Y1, 113 | CGRectGetWidth(self.frame), 114 | CGRectGetHeight(self.frame) - _POINT_Y1); 115 | [self setNeedsDisplay]; 116 | } 117 | 118 | - (void)setSuggestCurve:(BOOL)suggestCurve 119 | { 120 | _suggestCurve = suggestCurve; 121 | if (_suggestCurve) { 122 | [self setPOINT_Y1:(CGRectGetMidY(self.frame)/2)/CGRectGetMidY(self.frame)]; 123 | } 124 | } 125 | 126 | - (void)setFrame:(CGRect)frame 127 | { 128 | [super setFrame:frame]; 129 | _shapeLayer.frame = frame; 130 | [self setNeedsDisplay]; 131 | if (_POINT_Y1 == 0.0f) { 132 | 133 | _POINT_Y1 = CGRectGetMidY(frame); 134 | _followBottomView.frame = CGRectMake(0, 135 | _POINT_Y1, 136 | CGRectGetWidth(self.frame), 137 | CGRectGetHeight(self.frame) - CGRectGetMaxY(_imageView.frame)); 138 | } 139 | [_followBottomView setFrame:CGRectMake(0, 140 | CGRectGetMaxY(self.frame) - CGRectGetHeight(_followBottomView.frame), 141 | w, 142 | CGRectGetHeight(_followBottomView.frame))]; 143 | } 144 | 145 | // Only override drawRect: if you perform custom drawing. 146 | // An empty implementation adversely affects performance during animation. 147 | - (void)drawRect:(CGRect)rect { 148 | [super drawRect:rect]; 149 | CGFloat progress = CGRectGetHeight(rect)/CGRectGetHeight([UIScreen mainScreen].bounds); 150 | progress = MAX(progress - 0.3, 0.0f); 151 | CGFloat centerX = CGRectGetMidX(self.frame); 152 | CGFloat point6X = CGRectGetMaxX(self.frame)-MARGIN; 153 | CGFloat dragY = ((_curveFloat * CGRectGetHeight(self.frame)) - (progress*400)) + (progress*400);//速度差值 154 | if (_suggestCurve) { 155 | dragY = (_POINT_Y1 - 85) + (progress*400); 156 | } 157 | 158 | { 159 | _imageView.frame = CGRectMake(centerX - _imageWidth/2, 160 | dragY - _imageWidth/2, 161 | _imageWidth, 162 | _imageWidth); 163 | } 164 | 165 | NSArray *points = @[[NSValue valueWithCGPoint:CGPointMake(0, _POINT_Y1)], //point0 166 | [NSValue valueWithCGPoint:CGPointMake(0, MAX_Y)], //point1 167 | [NSValue valueWithCGPoint:CGPointMake(w, MAX_Y)], //point2 168 | [NSValue valueWithCGPoint:CGPointMake(w, _POINT_Y1)], //point3 169 | [NSValue valueWithCGPoint:CGPointMake(centerX, dragY)], //point4 170 | [NSValue valueWithCGPoint:CGPointMake(w, _POINT_Y1)], //point5 171 | [NSValue valueWithCGPoint:CGPointMake(point6X, dragY)], //point6 172 | [NSValue valueWithCGPoint:CGPointMake(0, _POINT_Y1)], //point7 173 | [NSValue valueWithCGPoint:CGPointMake(MARGIN, dragY)], //point8 174 | [NSValue valueWithCGPoint:CGPointMake(0, _POINT_Y1)] //point9 175 | ]; 176 | //标记关键点 177 | // for (NSValue * value in points) { 178 | // NSInteger index = [points indexOfObject:value]; 179 | // CGPoint point = [value CGPointValue]; 180 | // UILabel *view = [self viewWithTag:index+100]; 181 | // if (!view) { 182 | // view = [[UILabel alloc] init]; 183 | // view.tag = index+100; 184 | // [self addSubview:view]; 185 | // view.backgroundColor = [UIColor redColor]; 186 | // view.textAlignment = 1; 187 | // view.clipsToBounds = true; 188 | // } 189 | // view.text = [NSString stringWithFormat:@"%zd",index]; 190 | // [view setFrame:CGRectMake(point.x-10/2, point.y-5/2, 10, 10)]; 191 | // view.layer.cornerRadius = 10/2; 192 | // view.font = [UIFont systemFontOfSize:10]; 193 | // view.textColor = [UIColor whiteColor]; 194 | // view.hidden = true; 195 | // } 196 | 197 | // Bezier Drawing 198 | [_bezierPath removeAllPoints]; 199 | [_bezierPath moveToPoint: [[points objectAtIndex:0] CGPointValue]]; 200 | [_bezierPath addLineToPoint: [[points objectAtIndex:1] CGPointValue]]; 201 | [_bezierPath addLineToPoint: [[points objectAtIndex:2] CGPointValue]]; 202 | [_bezierPath addLineToPoint: [[points objectAtIndex:3] CGPointValue]]; 203 | 204 | [_bezierPath addCurveToPoint: [[points objectAtIndex:4] CGPointValue] 205 | controlPoint1: [[points objectAtIndex:5] CGPointValue] 206 | controlPoint2: [[points objectAtIndex:6] CGPointValue]]; 207 | 208 | [_bezierPath addCurveToPoint: [[points objectAtIndex:7] CGPointValue] 209 | controlPoint1: [[points objectAtIndex:8] CGPointValue] 210 | controlPoint2: [[points objectAtIndex:9] CGPointValue]]; 211 | _shapeLayer.path = _bezierPath.CGPath; 212 | points = nil; 213 | } 214 | 215 | @end 216 | 217 | @interface HyParallaxCurveHeaderView () 218 | @property (weak, nonatomic) UIScrollView *scrollView; 219 | @property (weak, nonatomic) HyHeaderCurveView *subView; 220 | @property (nonatomic) UIImageView *bluredImageView; 221 | @property (nonnull, strong, nonatomic) HyHeaderCurveView *curveView; 222 | @end 223 | 224 | #define kDefaultHeaderFrame CGRectMake(0, 0, self.frame.size.width, self.frame.size.height) 225 | static CGFloat kParallaxDeltaFactor = 0.5f; 226 | 227 | @implementation HyParallaxCurveHeaderView 228 | 229 | + (_Nonnull instancetype)loadHeaderCurveViewWithSize:(CGSize)size 230 | { 231 | HyParallaxCurveHeaderView *headerView = [[HyParallaxCurveHeaderView alloc] initWithFrame:(CGRect){CGPointZero,size}]; 232 | HyHeaderCurveView *curveView = [[HyHeaderCurveView alloc] initWithFrame:headerView.frame]; 233 | headerView.isShowBlur = true; 234 | headerView.isParallax = true; 235 | [headerView initialSetupForCustomSubView:curveView]; 236 | return headerView; 237 | } 238 | 239 | - (void)initialSetupForCustomSubView:(HyHeaderCurveView *)subView 240 | { 241 | UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:self.bounds]; 242 | self.scrollView = scrollView; 243 | self.subView = subView; 244 | _followBottomView = _subView.followBottomView; 245 | _imageView = _subView.imageView; 246 | subView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; 247 | [self.scrollView addSubview:subView]; 248 | 249 | self.bluredImageView = [[UIImageView alloc] initWithFrame:subView.frame]; 250 | self.bluredImageView.autoresizingMask = subView.autoresizingMask; 251 | self.bluredImageView.alpha = 0.0f; 252 | [self.scrollView addSubview:self.bluredImageView]; 253 | 254 | [self addSubview:self.scrollView]; 255 | if (_isShowBlur) { 256 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 257 | [self refreshBlurView]; 258 | }); 259 | } 260 | } 261 | 262 | - (void)layoutHeaderViewForScrollViewOffset:(CGPoint)offset 263 | { 264 | CGRect frame = self.scrollView.frame; 265 | if (offset.y > 0) 266 | { 267 | if (_isParallax) { 268 | frame.origin.y = MAX(offset.y *kParallaxDeltaFactor, 0); 269 | } 270 | self.scrollView.frame = frame; 271 | self.bluredImageView.alpha = 1 / kDefaultHeaderFrame.size.height * offset.y * 2; 272 | self.clipsToBounds = YES; 273 | } 274 | else 275 | { 276 | CGFloat delta = 0.0f; 277 | CGRect rect = kDefaultHeaderFrame; 278 | delta = fabs(MIN(0.0f, offset.y)); 279 | rect.origin.y -= delta; 280 | rect.size.height += delta; 281 | self.scrollView.frame = rect; 282 | self.clipsToBounds = NO; 283 | self.bluredImageView.alpha = offset.y/kDefaultHeaderFrame.size.height; 284 | } 285 | } 286 | 287 | - (void)refreshBlurView 288 | { 289 | UIImage *screenShot = [self screenShotOfView:self]; 290 | 291 | UIColor *color = _blurTintColor; 292 | if (!color) { 293 | color = [UIColor colorWithWhite:0.3 alpha:0.4]; 294 | } 295 | 296 | screenShot = [screenShot applyBlurWithRadius:6 tintColor:color saturationDeltaFactor:1.0 maskImage:nil]; 297 | self.bluredImageView.image = screenShot; 298 | } 299 | 300 | - (UIImage *)screenShotOfView:(UIView *)view 301 | { 302 | UIGraphicsBeginImageContextWithOptions(kDefaultHeaderFrame.size, YES, 0.0); 303 | [self drawViewHierarchyInRect:kDefaultHeaderFrame afterScreenUpdates:NO]; 304 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 305 | UIGraphicsEndImageContext(); 306 | 307 | return image; 308 | } 309 | 310 | - (void)setCurveColor:(UIColor *)curveColor 311 | { 312 | _curveColor = curveColor; 313 | _subView.curveColor = curveColor; 314 | } 315 | 316 | - (void)setSuggestCurve:(BOOL)suggestCurve 317 | { 318 | _suggestCurve = suggestCurve; 319 | _subView.suggestCurve = suggestCurve; 320 | } 321 | 322 | - (void)setCurveFloat:(CGFloat)curveFloat 323 | { 324 | _curveFloat = curveFloat; 325 | _subView.curveFloat = curveFloat; 326 | } 327 | 328 | - (void)setBackgroundColor:(UIColor *)backgroundColor 329 | { 330 | _backgroundColor = backgroundColor; 331 | _subView.backgroundColor = backgroundColor; 332 | } 333 | 334 | - (void)setPOINT_Y1:(CGFloat)POINT_Y1 335 | { 336 | _POINT_Y1 = POINT_Y1; 337 | _subView.POINT_Y1 = POINT_Y1; 338 | } 339 | 340 | - (void)setImageWidth:(CGFloat)imageWidth 341 | { 342 | _imageWidth = imageWidth; 343 | _subView.imageWidth = imageWidth; 344 | } 345 | 346 | /* 347 | // Only override drawRect: if you perform custom drawing. 348 | // An empty implementation adversely affects performance during animation. 349 | - (void)drawRect:(CGRect)rect { 350 | // Drawing code 351 | } 352 | */ 353 | 354 | @end 355 | -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewClass/UIImage+ImageEffects.m: -------------------------------------------------------------------------------- 1 | /* 2 | File: UIImage+ImageEffects.m 3 | Abstract: This is a category of UIImage that adds methods to apply blur and tint effects to an image. This is the code you’ll want to look out to find out how to use vImage to efficiently calculate a blur. 4 | Version: 1.0 5 | 6 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple 7 | Inc. ("Apple") in consideration of your agreement to the following 8 | terms, and your use, installation, modification or redistribution of 9 | this Apple software constitutes acceptance of these terms. If you do 10 | not agree with these terms, please do not use, install, modify or 11 | redistribute this Apple software. 12 | 13 | In consideration of your agreement to abide by the following terms, and 14 | subject to these terms, Apple grants you a personal, non-exclusive 15 | license, under Apple's copyrights in this original Apple software (the 16 | "Apple Software"), to use, reproduce, modify and redistribute the Apple 17 | Software, with or without modifications, in source and/or binary forms; 18 | provided that if you redistribute the Apple Software in its entirety and 19 | without modifications, you must retain this notice and the following 20 | text and disclaimers in all such redistributions of the Apple Software. 21 | Neither the name, trademarks, service marks or logos of Apple Inc. may 22 | be used to endorse or promote products derived from the Apple Software 23 | without specific prior written permission from Apple. Except as 24 | expressly stated in this notice, no other rights or licenses, express or 25 | implied, are granted by Apple herein, including but not limited to any 26 | patent rights that may be infringed by your derivative works or by other 27 | works in which the Apple Software may be incorporated. 28 | 29 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE 30 | MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION 31 | THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS 32 | FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND 33 | OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. 34 | 35 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL 36 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 37 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 38 | INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, 39 | MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED 40 | AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), 41 | STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE 42 | POSSIBILITY OF SUCH DAMAGE. 43 | 44 | Copyright (C) 2013 Apple Inc. All Rights Reserved. 45 | 46 | 47 | Copyright © 2013 Apple Inc. All rights reserved. 48 | WWDC 2013 License 49 | 50 | NOTE: This Apple Software was supplied by Apple as part of a WWDC 2013 51 | Session. Please refer to the applicable WWDC 2013 Session for further 52 | information. 53 | 54 | IMPORTANT: This Apple software is supplied to you by Apple Inc. 55 | ("Apple") in consideration of your agreement to the following terms, and 56 | your use, installation, modification or redistribution of this Apple 57 | software constitutes acceptance of these terms. If you do not agree with 58 | these terms, please do not use, install, modify or redistribute this 59 | Apple software. 60 | 61 | In consideration of your agreement to abide by the following terms, and 62 | subject to these terms, Apple grants you a non-exclusive license, under 63 | Apple's copyrights in this original Apple software (the "Apple 64 | Software"), to use, reproduce, modify and redistribute the Apple 65 | Software, with or without modifications, in source and/or binary forms; 66 | provided that if you redistribute the Apple Software in its entirety and 67 | without modifications, you must retain this notice and the following 68 | text and disclaimers in all such redistributions of the Apple Software. 69 | Neither the name, trademarks, service marks or logos of Apple Inc. may 70 | be used to endorse or promote products derived from the Apple Software 71 | without specific prior written permission from Apple. Except as 72 | expressly stated in this notice, no other rights or licenses, express or 73 | implied, are granted by Apple herein, including but not limited to any 74 | patent rights that may be infringed by your derivative works or by other 75 | works in which the Apple Software may be incorporated. 76 | 77 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES 78 | NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE 79 | IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR 80 | A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND 81 | OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. 82 | 83 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL 84 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 85 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 86 | INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, 87 | MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED 88 | AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), 89 | STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE 90 | POSSIBILITY OF SUCH DAMAGE. 91 | 92 | EA1002 93 | 5/3/2013 94 | */ 95 | 96 | #import "UIImage+ImageEffects.h" 97 | #import 98 | #import 99 | 100 | @implementation UIImage (ImageEffects) 101 | 102 | 103 | - (UIImage *)applySubtleEffect 104 | { 105 | UIColor *tintColor = [UIColor colorWithWhite:1.0 alpha:0.3]; 106 | return [self applyBlurWithRadius:3 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil]; 107 | } 108 | 109 | 110 | - (UIImage *)applyLightEffect 111 | { 112 | UIColor *tintColor = [UIColor colorWithWhite:1.0 alpha:0.3]; 113 | return [self applyBlurWithRadius:30 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil]; 114 | } 115 | 116 | 117 | - (UIImage *)applyExtraLightEffect 118 | { 119 | UIColor *tintColor = [UIColor colorWithWhite:0.97 alpha:0.82]; 120 | return [self applyBlurWithRadius:20 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil]; 121 | } 122 | 123 | 124 | - (UIImage *)applyDarkEffect 125 | { 126 | UIColor *tintColor = [UIColor colorWithWhite:0.11 alpha:0.73]; 127 | return [self applyBlurWithRadius:20 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil]; 128 | } 129 | 130 | 131 | - (UIImage *)applyTintEffectWithColor:(UIColor *)tintColor 132 | { 133 | const CGFloat EffectColorAlpha = 0.6; 134 | UIColor *effectColor = tintColor; 135 | int componentCount = CGColorGetNumberOfComponents(tintColor.CGColor); 136 | if (componentCount == 2) { 137 | CGFloat b; 138 | if ([tintColor getWhite:&b alpha:NULL]) { 139 | effectColor = [UIColor colorWithWhite:b alpha:EffectColorAlpha]; 140 | } 141 | } 142 | else { 143 | CGFloat r, g, b; 144 | if ([tintColor getRed:&r green:&g blue:&b alpha:NULL]) { 145 | effectColor = [UIColor colorWithRed:r green:g blue:b alpha:EffectColorAlpha]; 146 | } 147 | } 148 | return [self applyBlurWithRadius:10 tintColor:effectColor saturationDeltaFactor:-1.0 maskImage:nil]; 149 | } 150 | 151 | 152 | - (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage 153 | { 154 | // Check pre-conditions. 155 | if (self.size.width < 1 || self.size.height < 1) { 156 | NSLog (@"*** error: invalid size: (%.2f x %.2f). Both dimensions must be >= 1: %@", self.size.width, self.size.height, self); 157 | return nil; 158 | } 159 | if (!self.CGImage) { 160 | NSLog (@"*** error: image must be backed by a CGImage: %@", self); 161 | return nil; 162 | } 163 | if (maskImage && !maskImage.CGImage) { 164 | NSLog (@"*** error: maskImage must be backed by a CGImage: %@", maskImage); 165 | return nil; 166 | } 167 | 168 | CGRect imageRect = { CGPointZero, self.size }; 169 | UIImage *effectImage = self; 170 | 171 | BOOL hasBlur = blurRadius > __FLT_EPSILON__; 172 | BOOL hasSaturationChange = fabs(saturationDeltaFactor - 1.) > __FLT_EPSILON__; 173 | if (hasBlur || hasSaturationChange) { 174 | UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]); 175 | CGContextRef effectInContext = UIGraphicsGetCurrentContext(); 176 | CGContextScaleCTM(effectInContext, 1.0, -1.0); 177 | CGContextTranslateCTM(effectInContext, 0, -self.size.height); 178 | CGContextDrawImage(effectInContext, imageRect, self.CGImage); 179 | 180 | vImage_Buffer effectInBuffer; 181 | effectInBuffer.data = CGBitmapContextGetData(effectInContext); 182 | effectInBuffer.width = CGBitmapContextGetWidth(effectInContext); 183 | effectInBuffer.height = CGBitmapContextGetHeight(effectInContext); 184 | effectInBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectInContext); 185 | 186 | UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]); 187 | CGContextRef effectOutContext = UIGraphicsGetCurrentContext(); 188 | vImage_Buffer effectOutBuffer; 189 | effectOutBuffer.data = CGBitmapContextGetData(effectOutContext); 190 | effectOutBuffer.width = CGBitmapContextGetWidth(effectOutContext); 191 | effectOutBuffer.height = CGBitmapContextGetHeight(effectOutContext); 192 | effectOutBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectOutContext); 193 | 194 | if (hasBlur) { 195 | // A description of how to compute the box kernel width from the Gaussian 196 | // radius (aka standard deviation) appears in the SVG spec: 197 | // http://www.w3.org/TR/SVG/filters.html#feGaussianBlurElement 198 | // 199 | // For larger values of 's' (s >= 2.0), an approximation can be used: Three 200 | // successive box-blurs build a piece-wise quadratic convolution kernel, which 201 | // approximates the Gaussian kernel to within roughly 3%. 202 | // 203 | // let d = floor(s * 3*sqrt(2*pi)/4 + 0.5) 204 | // 205 | // ... if d is odd, use three box-blurs of size 'd', centered on the output pixel. 206 | // 207 | CGFloat inputRadius = blurRadius * [[UIScreen mainScreen] scale]; 208 | NSUInteger radius = floor(inputRadius * 3. * sqrt(2 * M_PI) / 4 + 0.5); 209 | if (radius % 2 != 1) { 210 | radius += 1; // force radius to be odd so that the three box-blur methodology works. 211 | } 212 | vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend); 213 | vImageBoxConvolve_ARGB8888(&effectOutBuffer, &effectInBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend); 214 | vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend); 215 | } 216 | BOOL effectImageBuffersAreSwapped = NO; 217 | if (hasSaturationChange) { 218 | CGFloat s = saturationDeltaFactor; 219 | CGFloat floatingPointSaturationMatrix[] = { 220 | 0.0722 + 0.9278 * s, 0.0722 - 0.0722 * s, 0.0722 - 0.0722 * s, 0, 221 | 0.7152 - 0.7152 * s, 0.7152 + 0.2848 * s, 0.7152 - 0.7152 * s, 0, 222 | 0.2126 - 0.2126 * s, 0.2126 - 0.2126 * s, 0.2126 + 0.7873 * s, 0, 223 | 0, 0, 0, 1, 224 | }; 225 | const int32_t divisor = 256; 226 | NSUInteger matrixSize = sizeof(floatingPointSaturationMatrix)/sizeof(floatingPointSaturationMatrix[0]); 227 | int16_t saturationMatrix[matrixSize]; 228 | for (NSUInteger i = 0; i < matrixSize; ++i) { 229 | saturationMatrix[i] = (int16_t)roundf(floatingPointSaturationMatrix[i] * divisor); 230 | } 231 | if (hasBlur) { 232 | vImageMatrixMultiply_ARGB8888(&effectOutBuffer, &effectInBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags); 233 | effectImageBuffersAreSwapped = YES; 234 | } 235 | else { 236 | vImageMatrixMultiply_ARGB8888(&effectInBuffer, &effectOutBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags); 237 | } 238 | } 239 | if (!effectImageBuffersAreSwapped) 240 | effectImage = UIGraphicsGetImageFromCurrentImageContext(); 241 | UIGraphicsEndImageContext(); 242 | 243 | if (effectImageBuffersAreSwapped) 244 | effectImage = UIGraphicsGetImageFromCurrentImageContext(); 245 | UIGraphicsEndImageContext(); 246 | } 247 | 248 | // Set up output context. 249 | UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]); 250 | CGContextRef outputContext = UIGraphicsGetCurrentContext(); 251 | CGContextScaleCTM(outputContext, 1.0, -1.0); 252 | CGContextTranslateCTM(outputContext, 0, -self.size.height); 253 | 254 | // Draw base image. 255 | CGContextDrawImage(outputContext, imageRect, self.CGImage); 256 | 257 | // Draw effect image. 258 | if (hasBlur) { 259 | CGContextSaveGState(outputContext); 260 | if (maskImage) { 261 | CGContextClipToMask(outputContext, imageRect, maskImage.CGImage); 262 | } 263 | CGContextDrawImage(outputContext, imageRect, effectImage.CGImage); 264 | CGContextRestoreGState(outputContext); 265 | } 266 | 267 | // Add in color tint. 268 | if (tintColor) { 269 | CGContextSaveGState(outputContext); 270 | CGContextSetFillColorWithColor(outputContext, tintColor.CGColor); 271 | CGContextFillRect(outputContext, imageRect); 272 | CGContextRestoreGState(outputContext); 273 | } 274 | 275 | // Output image is ready. 276 | UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext(); 277 | UIGraphicsEndImageContext(); 278 | 279 | return outputImage; 280 | } 281 | 282 | 283 | @end -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewDemo/HyParallaxCurveHeaderViewClass/UIImage+ImageEffects.m: -------------------------------------------------------------------------------- 1 | /* 2 | File: UIImage+ImageEffects.m 3 | Abstract: This is a category of UIImage that adds methods to apply blur and tint effects to an image. This is the code you’ll want to look out to find out how to use vImage to efficiently calculate a blur. 4 | Version: 1.0 5 | 6 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple 7 | Inc. ("Apple") in consideration of your agreement to the following 8 | terms, and your use, installation, modification or redistribution of 9 | this Apple software constitutes acceptance of these terms. If you do 10 | not agree with these terms, please do not use, install, modify or 11 | redistribute this Apple software. 12 | 13 | In consideration of your agreement to abide by the following terms, and 14 | subject to these terms, Apple grants you a personal, non-exclusive 15 | license, under Apple's copyrights in this original Apple software (the 16 | "Apple Software"), to use, reproduce, modify and redistribute the Apple 17 | Software, with or without modifications, in source and/or binary forms; 18 | provided that if you redistribute the Apple Software in its entirety and 19 | without modifications, you must retain this notice and the following 20 | text and disclaimers in all such redistributions of the Apple Software. 21 | Neither the name, trademarks, service marks or logos of Apple Inc. may 22 | be used to endorse or promote products derived from the Apple Software 23 | without specific prior written permission from Apple. Except as 24 | expressly stated in this notice, no other rights or licenses, express or 25 | implied, are granted by Apple herein, including but not limited to any 26 | patent rights that may be infringed by your derivative works or by other 27 | works in which the Apple Software may be incorporated. 28 | 29 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE 30 | MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION 31 | THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS 32 | FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND 33 | OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. 34 | 35 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL 36 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 37 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 38 | INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, 39 | MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED 40 | AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), 41 | STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE 42 | POSSIBILITY OF SUCH DAMAGE. 43 | 44 | Copyright (C) 2013 Apple Inc. All Rights Reserved. 45 | 46 | 47 | Copyright © 2013 Apple Inc. All rights reserved. 48 | WWDC 2013 License 49 | 50 | NOTE: This Apple Software was supplied by Apple as part of a WWDC 2013 51 | Session. Please refer to the applicable WWDC 2013 Session for further 52 | information. 53 | 54 | IMPORTANT: This Apple software is supplied to you by Apple Inc. 55 | ("Apple") in consideration of your agreement to the following terms, and 56 | your use, installation, modification or redistribution of this Apple 57 | software constitutes acceptance of these terms. If you do not agree with 58 | these terms, please do not use, install, modify or redistribute this 59 | Apple software. 60 | 61 | In consideration of your agreement to abide by the following terms, and 62 | subject to these terms, Apple grants you a non-exclusive license, under 63 | Apple's copyrights in this original Apple software (the "Apple 64 | Software"), to use, reproduce, modify and redistribute the Apple 65 | Software, with or without modifications, in source and/or binary forms; 66 | provided that if you redistribute the Apple Software in its entirety and 67 | without modifications, you must retain this notice and the following 68 | text and disclaimers in all such redistributions of the Apple Software. 69 | Neither the name, trademarks, service marks or logos of Apple Inc. may 70 | be used to endorse or promote products derived from the Apple Software 71 | without specific prior written permission from Apple. Except as 72 | expressly stated in this notice, no other rights or licenses, express or 73 | implied, are granted by Apple herein, including but not limited to any 74 | patent rights that may be infringed by your derivative works or by other 75 | works in which the Apple Software may be incorporated. 76 | 77 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES 78 | NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE 79 | IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR 80 | A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND 81 | OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. 82 | 83 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL 84 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 85 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 86 | INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, 87 | MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED 88 | AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), 89 | STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE 90 | POSSIBILITY OF SUCH DAMAGE. 91 | 92 | EA1002 93 | 5/3/2013 94 | */ 95 | 96 | #import "UIImage+ImageEffects.h" 97 | #import 98 | #import 99 | 100 | @implementation UIImage (ImageEffects) 101 | 102 | 103 | - (UIImage *)applySubtleEffect 104 | { 105 | UIColor *tintColor = [UIColor colorWithWhite:1.0 alpha:0.3]; 106 | return [self applyBlurWithRadius:3 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil]; 107 | } 108 | 109 | 110 | - (UIImage *)applyLightEffect 111 | { 112 | UIColor *tintColor = [UIColor colorWithWhite:1.0 alpha:0.3]; 113 | return [self applyBlurWithRadius:30 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil]; 114 | } 115 | 116 | 117 | - (UIImage *)applyExtraLightEffect 118 | { 119 | UIColor *tintColor = [UIColor colorWithWhite:0.97 alpha:0.82]; 120 | return [self applyBlurWithRadius:20 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil]; 121 | } 122 | 123 | 124 | - (UIImage *)applyDarkEffect 125 | { 126 | UIColor *tintColor = [UIColor colorWithWhite:0.11 alpha:0.73]; 127 | return [self applyBlurWithRadius:20 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil]; 128 | } 129 | 130 | 131 | - (UIImage *)applyTintEffectWithColor:(UIColor *)tintColor 132 | { 133 | const CGFloat EffectColorAlpha = 0.6; 134 | UIColor *effectColor = tintColor; 135 | int componentCount = CGColorGetNumberOfComponents(tintColor.CGColor); 136 | if (componentCount == 2) { 137 | CGFloat b; 138 | if ([tintColor getWhite:&b alpha:NULL]) { 139 | effectColor = [UIColor colorWithWhite:b alpha:EffectColorAlpha]; 140 | } 141 | } 142 | else { 143 | CGFloat r, g, b; 144 | if ([tintColor getRed:&r green:&g blue:&b alpha:NULL]) { 145 | effectColor = [UIColor colorWithRed:r green:g blue:b alpha:EffectColorAlpha]; 146 | } 147 | } 148 | return [self applyBlurWithRadius:10 tintColor:effectColor saturationDeltaFactor:-1.0 maskImage:nil]; 149 | } 150 | 151 | 152 | - (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage 153 | { 154 | // Check pre-conditions. 155 | if (self.size.width < 1 || self.size.height < 1) { 156 | NSLog (@"*** error: invalid size: (%.2f x %.2f). Both dimensions must be >= 1: %@", self.size.width, self.size.height, self); 157 | return nil; 158 | } 159 | if (!self.CGImage) { 160 | NSLog (@"*** error: image must be backed by a CGImage: %@", self); 161 | return nil; 162 | } 163 | if (maskImage && !maskImage.CGImage) { 164 | NSLog (@"*** error: maskImage must be backed by a CGImage: %@", maskImage); 165 | return nil; 166 | } 167 | 168 | CGRect imageRect = { CGPointZero, self.size }; 169 | UIImage *effectImage = self; 170 | 171 | BOOL hasBlur = blurRadius > __FLT_EPSILON__; 172 | BOOL hasSaturationChange = fabs(saturationDeltaFactor - 1.) > __FLT_EPSILON__; 173 | if (hasBlur || hasSaturationChange) { 174 | UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]); 175 | CGContextRef effectInContext = UIGraphicsGetCurrentContext(); 176 | CGContextScaleCTM(effectInContext, 1.0, -1.0); 177 | CGContextTranslateCTM(effectInContext, 0, -self.size.height); 178 | CGContextDrawImage(effectInContext, imageRect, self.CGImage); 179 | 180 | vImage_Buffer effectInBuffer; 181 | effectInBuffer.data = CGBitmapContextGetData(effectInContext); 182 | effectInBuffer.width = CGBitmapContextGetWidth(effectInContext); 183 | effectInBuffer.height = CGBitmapContextGetHeight(effectInContext); 184 | effectInBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectInContext); 185 | 186 | UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]); 187 | CGContextRef effectOutContext = UIGraphicsGetCurrentContext(); 188 | vImage_Buffer effectOutBuffer; 189 | effectOutBuffer.data = CGBitmapContextGetData(effectOutContext); 190 | effectOutBuffer.width = CGBitmapContextGetWidth(effectOutContext); 191 | effectOutBuffer.height = CGBitmapContextGetHeight(effectOutContext); 192 | effectOutBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectOutContext); 193 | 194 | if (hasBlur) { 195 | // A description of how to compute the box kernel width from the Gaussian 196 | // radius (aka standard deviation) appears in the SVG spec: 197 | // http://www.w3.org/TR/SVG/filters.html#feGaussianBlurElement 198 | // 199 | // For larger values of 's' (s >= 2.0), an approximation can be used: Three 200 | // successive box-blurs build a piece-wise quadratic convolution kernel, which 201 | // approximates the Gaussian kernel to within roughly 3%. 202 | // 203 | // let d = floor(s * 3*sqrt(2*pi)/4 + 0.5) 204 | // 205 | // ... if d is odd, use three box-blurs of size 'd', centered on the output pixel. 206 | // 207 | CGFloat inputRadius = blurRadius * [[UIScreen mainScreen] scale]; 208 | NSUInteger radius = floor(inputRadius * 3. * sqrt(2 * M_PI) / 4 + 0.5); 209 | if (radius % 2 != 1) { 210 | radius += 1; // force radius to be odd so that the three box-blur methodology works. 211 | } 212 | vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend); 213 | vImageBoxConvolve_ARGB8888(&effectOutBuffer, &effectInBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend); 214 | vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend); 215 | } 216 | BOOL effectImageBuffersAreSwapped = NO; 217 | if (hasSaturationChange) { 218 | CGFloat s = saturationDeltaFactor; 219 | CGFloat floatingPointSaturationMatrix[] = { 220 | 0.0722 + 0.9278 * s, 0.0722 - 0.0722 * s, 0.0722 - 0.0722 * s, 0, 221 | 0.7152 - 0.7152 * s, 0.7152 + 0.2848 * s, 0.7152 - 0.7152 * s, 0, 222 | 0.2126 - 0.2126 * s, 0.2126 - 0.2126 * s, 0.2126 + 0.7873 * s, 0, 223 | 0, 0, 0, 1, 224 | }; 225 | const int32_t divisor = 256; 226 | NSUInteger matrixSize = sizeof(floatingPointSaturationMatrix)/sizeof(floatingPointSaturationMatrix[0]); 227 | int16_t saturationMatrix[matrixSize]; 228 | for (NSUInteger i = 0; i < matrixSize; ++i) { 229 | saturationMatrix[i] = (int16_t)roundf(floatingPointSaturationMatrix[i] * divisor); 230 | } 231 | if (hasBlur) { 232 | vImageMatrixMultiply_ARGB8888(&effectOutBuffer, &effectInBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags); 233 | effectImageBuffersAreSwapped = YES; 234 | } 235 | else { 236 | vImageMatrixMultiply_ARGB8888(&effectInBuffer, &effectOutBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags); 237 | } 238 | } 239 | if (!effectImageBuffersAreSwapped) 240 | effectImage = UIGraphicsGetImageFromCurrentImageContext(); 241 | UIGraphicsEndImageContext(); 242 | 243 | if (effectImageBuffersAreSwapped) 244 | effectImage = UIGraphicsGetImageFromCurrentImageContext(); 245 | UIGraphicsEndImageContext(); 246 | } 247 | 248 | // Set up output context. 249 | UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]); 250 | CGContextRef outputContext = UIGraphicsGetCurrentContext(); 251 | CGContextScaleCTM(outputContext, 1.0, -1.0); 252 | CGContextTranslateCTM(outputContext, 0, -self.size.height); 253 | 254 | // Draw base image. 255 | CGContextDrawImage(outputContext, imageRect, self.CGImage); 256 | 257 | // Draw effect image. 258 | if (hasBlur) { 259 | CGContextSaveGState(outputContext); 260 | if (maskImage) { 261 | CGContextClipToMask(outputContext, imageRect, maskImage.CGImage); 262 | } 263 | CGContextDrawImage(outputContext, imageRect, effectImage.CGImage); 264 | CGContextRestoreGState(outputContext); 265 | } 266 | 267 | // Add in color tint. 268 | if (tintColor) { 269 | CGContextSaveGState(outputContext); 270 | CGContextSetFillColorWithColor(outputContext, tintColor.CGColor); 271 | CGContextFillRect(outputContext, imageRect); 272 | CGContextRestoreGState(outputContext); 273 | } 274 | 275 | // Output image is ready. 276 | UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext(); 277 | UIGraphicsEndImageContext(); 278 | 279 | return outputImage; 280 | } 281 | 282 | 283 | @end -------------------------------------------------------------------------------- /HyParallaxCurveHeaderViewDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 7A9FD1101D7432B200156442 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A9FD10F1D7432B200156442 /* main.m */; }; 11 | 7A9FD1131D7432B200156442 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A9FD1121D7432B200156442 /* AppDelegate.m */; }; 12 | 7A9FD1161D7432B200156442 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A9FD1151D7432B200156442 /* ViewController.m */; }; 13 | 7A9FD1191D7432B200156442 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7A9FD1171D7432B200156442 /* Main.storyboard */; }; 14 | 7A9FD11B1D7432B200156442 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7A9FD11A1D7432B200156442 /* Assets.xcassets */; }; 15 | 7A9FD11E1D7432B200156442 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7A9FD11C1D7432B200156442 /* LaunchScreen.storyboard */; }; 16 | 7A9FD1291D7432B200156442 /* HyParallaxCurveHeaderViewDemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A9FD1281D7432B200156442 /* HyParallaxCurveHeaderViewDemoTests.m */; }; 17 | 7A9FD1341D7432B200156442 /* HyParallaxCurveHeaderViewDemoUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A9FD1331D7432B200156442 /* HyParallaxCurveHeaderViewDemoUITests.m */; }; 18 | 7A9FD14B1D74333000156442 /* TestViews.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A9FD1491D74333000156442 /* TestViews.m */; }; 19 | 7A9FD14C1D74333000156442 /* TestViews.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7A9FD14A1D74333000156442 /* TestViews.xib */; }; 20 | 7A9FD14E1D7435EE00156442 /* preview.gif in Resources */ = {isa = PBXBuildFile; fileRef = 7A9FD14D1D7435EE00156442 /* preview.gif */; }; 21 | 7A9FD1541D75282D00156442 /* HyParallaxCurveHeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A9FD1511D75282D00156442 /* HyParallaxCurveHeaderView.m */; }; 22 | 7A9FD1551D75282D00156442 /* UIImage+ImageEffects.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A9FD1531D75282D00156442 /* UIImage+ImageEffects.m */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXContainerItemProxy section */ 26 | 7A9FD1251D7432B200156442 /* PBXContainerItemProxy */ = { 27 | isa = PBXContainerItemProxy; 28 | containerPortal = 7A9FD1031D7432B200156442 /* Project object */; 29 | proxyType = 1; 30 | remoteGlobalIDString = 7A9FD10A1D7432B200156442; 31 | remoteInfo = HyParallaxCurveHeaderViewDemo; 32 | }; 33 | 7A9FD1301D7432B200156442 /* PBXContainerItemProxy */ = { 34 | isa = PBXContainerItemProxy; 35 | containerPortal = 7A9FD1031D7432B200156442 /* Project object */; 36 | proxyType = 1; 37 | remoteGlobalIDString = 7A9FD10A1D7432B200156442; 38 | remoteInfo = HyParallaxCurveHeaderViewDemo; 39 | }; 40 | /* End PBXContainerItemProxy section */ 41 | 42 | /* Begin PBXFileReference section */ 43 | 7A9FD10B1D7432B200156442 /* HyParallaxCurveHeaderViewDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HyParallaxCurveHeaderViewDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 44 | 7A9FD10F1D7432B200156442 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 45 | 7A9FD1111D7432B200156442 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 46 | 7A9FD1121D7432B200156442 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 47 | 7A9FD1141D7432B200156442 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 48 | 7A9FD1151D7432B200156442 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 49 | 7A9FD1181D7432B200156442 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 50 | 7A9FD11A1D7432B200156442 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 51 | 7A9FD11D1D7432B200156442 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 52 | 7A9FD11F1D7432B200156442 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 53 | 7A9FD1241D7432B200156442 /* HyParallaxCurveHeaderViewDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = HyParallaxCurveHeaderViewDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 54 | 7A9FD1281D7432B200156442 /* HyParallaxCurveHeaderViewDemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HyParallaxCurveHeaderViewDemoTests.m; sourceTree = ""; }; 55 | 7A9FD12A1D7432B200156442 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 56 | 7A9FD12F1D7432B200156442 /* HyParallaxCurveHeaderViewDemoUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = HyParallaxCurveHeaderViewDemoUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 57 | 7A9FD1331D7432B200156442 /* HyParallaxCurveHeaderViewDemoUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HyParallaxCurveHeaderViewDemoUITests.m; sourceTree = ""; }; 58 | 7A9FD1351D7432B200156442 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 59 | 7A9FD1481D74333000156442 /* TestViews.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestViews.h; sourceTree = ""; }; 60 | 7A9FD1491D74333000156442 /* TestViews.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TestViews.m; sourceTree = ""; }; 61 | 7A9FD14A1D74333000156442 /* TestViews.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = TestViews.xib; sourceTree = ""; }; 62 | 7A9FD14D1D7435EE00156442 /* preview.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = preview.gif; sourceTree = ""; }; 63 | 7A9FD1501D75282D00156442 /* HyParallaxCurveHeaderView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HyParallaxCurveHeaderView.h; sourceTree = ""; }; 64 | 7A9FD1511D75282D00156442 /* HyParallaxCurveHeaderView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HyParallaxCurveHeaderView.m; sourceTree = ""; }; 65 | 7A9FD1521D75282D00156442 /* UIImage+ImageEffects.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+ImageEffects.h"; sourceTree = ""; }; 66 | 7A9FD1531D75282D00156442 /* UIImage+ImageEffects.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+ImageEffects.m"; sourceTree = ""; }; 67 | /* End PBXFileReference section */ 68 | 69 | /* Begin PBXFrameworksBuildPhase section */ 70 | 7A9FD1081D7432B200156442 /* Frameworks */ = { 71 | isa = PBXFrameworksBuildPhase; 72 | buildActionMask = 2147483647; 73 | files = ( 74 | ); 75 | runOnlyForDeploymentPostprocessing = 0; 76 | }; 77 | 7A9FD1211D7432B200156442 /* Frameworks */ = { 78 | isa = PBXFrameworksBuildPhase; 79 | buildActionMask = 2147483647; 80 | files = ( 81 | ); 82 | runOnlyForDeploymentPostprocessing = 0; 83 | }; 84 | 7A9FD12C1D7432B200156442 /* Frameworks */ = { 85 | isa = PBXFrameworksBuildPhase; 86 | buildActionMask = 2147483647; 87 | files = ( 88 | ); 89 | runOnlyForDeploymentPostprocessing = 0; 90 | }; 91 | /* End PBXFrameworksBuildPhase section */ 92 | 93 | /* Begin PBXGroup section */ 94 | 7A9FD1021D7432B200156442 = { 95 | isa = PBXGroup; 96 | children = ( 97 | 7A9FD10D1D7432B200156442 /* HyParallaxCurveHeaderViewDemo */, 98 | 7A9FD1271D7432B200156442 /* HyParallaxCurveHeaderViewDemoTests */, 99 | 7A9FD1321D7432B200156442 /* HyParallaxCurveHeaderViewDemoUITests */, 100 | 7A9FD10C1D7432B200156442 /* Products */, 101 | ); 102 | sourceTree = ""; 103 | }; 104 | 7A9FD10C1D7432B200156442 /* Products */ = { 105 | isa = PBXGroup; 106 | children = ( 107 | 7A9FD10B1D7432B200156442 /* HyParallaxCurveHeaderViewDemo.app */, 108 | 7A9FD1241D7432B200156442 /* HyParallaxCurveHeaderViewDemoTests.xctest */, 109 | 7A9FD12F1D7432B200156442 /* HyParallaxCurveHeaderViewDemoUITests.xctest */, 110 | ); 111 | name = Products; 112 | sourceTree = ""; 113 | }; 114 | 7A9FD10D1D7432B200156442 /* HyParallaxCurveHeaderViewDemo */ = { 115 | isa = PBXGroup; 116 | children = ( 117 | 7A9FD14F1D75282D00156442 /* HyParallaxCurveHeaderViewClass */, 118 | 7A9FD1111D7432B200156442 /* AppDelegate.h */, 119 | 7A9FD1121D7432B200156442 /* AppDelegate.m */, 120 | 7A9FD1141D7432B200156442 /* ViewController.h */, 121 | 7A9FD1151D7432B200156442 /* ViewController.m */, 122 | 7A9FD1171D7432B200156442 /* Main.storyboard */, 123 | 7A9FD11A1D7432B200156442 /* Assets.xcassets */, 124 | 7A9FD11C1D7432B200156442 /* LaunchScreen.storyboard */, 125 | 7A9FD11F1D7432B200156442 /* Info.plist */, 126 | 7A9FD10E1D7432B200156442 /* Supporting Files */, 127 | ); 128 | path = HyParallaxCurveHeaderViewDemo; 129 | sourceTree = ""; 130 | }; 131 | 7A9FD10E1D7432B200156442 /* Supporting Files */ = { 132 | isa = PBXGroup; 133 | children = ( 134 | 7A9FD1481D74333000156442 /* TestViews.h */, 135 | 7A9FD1491D74333000156442 /* TestViews.m */, 136 | 7A9FD14A1D74333000156442 /* TestViews.xib */, 137 | 7A9FD10F1D7432B200156442 /* main.m */, 138 | 7A9FD14D1D7435EE00156442 /* preview.gif */, 139 | ); 140 | name = "Supporting Files"; 141 | sourceTree = ""; 142 | }; 143 | 7A9FD1271D7432B200156442 /* HyParallaxCurveHeaderViewDemoTests */ = { 144 | isa = PBXGroup; 145 | children = ( 146 | 7A9FD1281D7432B200156442 /* HyParallaxCurveHeaderViewDemoTests.m */, 147 | 7A9FD12A1D7432B200156442 /* Info.plist */, 148 | ); 149 | path = HyParallaxCurveHeaderViewDemoTests; 150 | sourceTree = ""; 151 | }; 152 | 7A9FD1321D7432B200156442 /* HyParallaxCurveHeaderViewDemoUITests */ = { 153 | isa = PBXGroup; 154 | children = ( 155 | 7A9FD1331D7432B200156442 /* HyParallaxCurveHeaderViewDemoUITests.m */, 156 | 7A9FD1351D7432B200156442 /* Info.plist */, 157 | ); 158 | path = HyParallaxCurveHeaderViewDemoUITests; 159 | sourceTree = ""; 160 | }; 161 | 7A9FD14F1D75282D00156442 /* HyParallaxCurveHeaderViewClass */ = { 162 | isa = PBXGroup; 163 | children = ( 164 | 7A9FD1501D75282D00156442 /* HyParallaxCurveHeaderView.h */, 165 | 7A9FD1511D75282D00156442 /* HyParallaxCurveHeaderView.m */, 166 | 7A9FD1521D75282D00156442 /* UIImage+ImageEffects.h */, 167 | 7A9FD1531D75282D00156442 /* UIImage+ImageEffects.m */, 168 | ); 169 | path = HyParallaxCurveHeaderViewClass; 170 | sourceTree = ""; 171 | }; 172 | /* End PBXGroup section */ 173 | 174 | /* Begin PBXNativeTarget section */ 175 | 7A9FD10A1D7432B200156442 /* HyParallaxCurveHeaderViewDemo */ = { 176 | isa = PBXNativeTarget; 177 | buildConfigurationList = 7A9FD1381D7432B200156442 /* Build configuration list for PBXNativeTarget "HyParallaxCurveHeaderViewDemo" */; 178 | buildPhases = ( 179 | 7A9FD1071D7432B200156442 /* Sources */, 180 | 7A9FD1081D7432B200156442 /* Frameworks */, 181 | 7A9FD1091D7432B200156442 /* Resources */, 182 | ); 183 | buildRules = ( 184 | ); 185 | dependencies = ( 186 | ); 187 | name = HyParallaxCurveHeaderViewDemo; 188 | productName = HyParallaxCurveHeaderViewDemo; 189 | productReference = 7A9FD10B1D7432B200156442 /* HyParallaxCurveHeaderViewDemo.app */; 190 | productType = "com.apple.product-type.application"; 191 | }; 192 | 7A9FD1231D7432B200156442 /* HyParallaxCurveHeaderViewDemoTests */ = { 193 | isa = PBXNativeTarget; 194 | buildConfigurationList = 7A9FD13B1D7432B200156442 /* Build configuration list for PBXNativeTarget "HyParallaxCurveHeaderViewDemoTests" */; 195 | buildPhases = ( 196 | 7A9FD1201D7432B200156442 /* Sources */, 197 | 7A9FD1211D7432B200156442 /* Frameworks */, 198 | 7A9FD1221D7432B200156442 /* Resources */, 199 | ); 200 | buildRules = ( 201 | ); 202 | dependencies = ( 203 | 7A9FD1261D7432B200156442 /* PBXTargetDependency */, 204 | ); 205 | name = HyParallaxCurveHeaderViewDemoTests; 206 | productName = HyParallaxCurveHeaderViewDemoTests; 207 | productReference = 7A9FD1241D7432B200156442 /* HyParallaxCurveHeaderViewDemoTests.xctest */; 208 | productType = "com.apple.product-type.bundle.unit-test"; 209 | }; 210 | 7A9FD12E1D7432B200156442 /* HyParallaxCurveHeaderViewDemoUITests */ = { 211 | isa = PBXNativeTarget; 212 | buildConfigurationList = 7A9FD13E1D7432B200156442 /* Build configuration list for PBXNativeTarget "HyParallaxCurveHeaderViewDemoUITests" */; 213 | buildPhases = ( 214 | 7A9FD12B1D7432B200156442 /* Sources */, 215 | 7A9FD12C1D7432B200156442 /* Frameworks */, 216 | 7A9FD12D1D7432B200156442 /* Resources */, 217 | ); 218 | buildRules = ( 219 | ); 220 | dependencies = ( 221 | 7A9FD1311D7432B200156442 /* PBXTargetDependency */, 222 | ); 223 | name = HyParallaxCurveHeaderViewDemoUITests; 224 | productName = HyParallaxCurveHeaderViewDemoUITests; 225 | productReference = 7A9FD12F1D7432B200156442 /* HyParallaxCurveHeaderViewDemoUITests.xctest */; 226 | productType = "com.apple.product-type.bundle.ui-testing"; 227 | }; 228 | /* End PBXNativeTarget section */ 229 | 230 | /* Begin PBXProject section */ 231 | 7A9FD1031D7432B200156442 /* Project object */ = { 232 | isa = PBXProject; 233 | attributes = { 234 | LastUpgradeCheck = 0800; 235 | ORGANIZATIONNAME = "@Hy"; 236 | TargetAttributes = { 237 | 7A9FD10A1D7432B200156442 = { 238 | CreatedOnToolsVersion = 8.0; 239 | DevelopmentTeam = 4GZ4P57LRH; 240 | ProvisioningStyle = Automatic; 241 | }; 242 | 7A9FD1231D7432B200156442 = { 243 | CreatedOnToolsVersion = 8.0; 244 | ProvisioningStyle = Automatic; 245 | TestTargetID = 7A9FD10A1D7432B200156442; 246 | }; 247 | 7A9FD12E1D7432B200156442 = { 248 | CreatedOnToolsVersion = 8.0; 249 | ProvisioningStyle = Automatic; 250 | TestTargetID = 7A9FD10A1D7432B200156442; 251 | }; 252 | }; 253 | }; 254 | buildConfigurationList = 7A9FD1061D7432B200156442 /* Build configuration list for PBXProject "HyParallaxCurveHeaderViewDemo" */; 255 | compatibilityVersion = "Xcode 3.2"; 256 | developmentRegion = English; 257 | hasScannedForEncodings = 0; 258 | knownRegions = ( 259 | en, 260 | Base, 261 | ); 262 | mainGroup = 7A9FD1021D7432B200156442; 263 | productRefGroup = 7A9FD10C1D7432B200156442 /* Products */; 264 | projectDirPath = ""; 265 | projectRoot = ""; 266 | targets = ( 267 | 7A9FD10A1D7432B200156442 /* HyParallaxCurveHeaderViewDemo */, 268 | 7A9FD1231D7432B200156442 /* HyParallaxCurveHeaderViewDemoTests */, 269 | 7A9FD12E1D7432B200156442 /* HyParallaxCurveHeaderViewDemoUITests */, 270 | ); 271 | }; 272 | /* End PBXProject section */ 273 | 274 | /* Begin PBXResourcesBuildPhase section */ 275 | 7A9FD1091D7432B200156442 /* Resources */ = { 276 | isa = PBXResourcesBuildPhase; 277 | buildActionMask = 2147483647; 278 | files = ( 279 | 7A9FD14C1D74333000156442 /* TestViews.xib in Resources */, 280 | 7A9FD14E1D7435EE00156442 /* preview.gif in Resources */, 281 | 7A9FD11E1D7432B200156442 /* LaunchScreen.storyboard in Resources */, 282 | 7A9FD11B1D7432B200156442 /* Assets.xcassets in Resources */, 283 | 7A9FD1191D7432B200156442 /* Main.storyboard in Resources */, 284 | ); 285 | runOnlyForDeploymentPostprocessing = 0; 286 | }; 287 | 7A9FD1221D7432B200156442 /* Resources */ = { 288 | isa = PBXResourcesBuildPhase; 289 | buildActionMask = 2147483647; 290 | files = ( 291 | ); 292 | runOnlyForDeploymentPostprocessing = 0; 293 | }; 294 | 7A9FD12D1D7432B200156442 /* Resources */ = { 295 | isa = PBXResourcesBuildPhase; 296 | buildActionMask = 2147483647; 297 | files = ( 298 | ); 299 | runOnlyForDeploymentPostprocessing = 0; 300 | }; 301 | /* End PBXResourcesBuildPhase section */ 302 | 303 | /* Begin PBXSourcesBuildPhase section */ 304 | 7A9FD1071D7432B200156442 /* Sources */ = { 305 | isa = PBXSourcesBuildPhase; 306 | buildActionMask = 2147483647; 307 | files = ( 308 | 7A9FD14B1D74333000156442 /* TestViews.m in Sources */, 309 | 7A9FD1541D75282D00156442 /* HyParallaxCurveHeaderView.m in Sources */, 310 | 7A9FD1551D75282D00156442 /* UIImage+ImageEffects.m in Sources */, 311 | 7A9FD1161D7432B200156442 /* ViewController.m in Sources */, 312 | 7A9FD1131D7432B200156442 /* AppDelegate.m in Sources */, 313 | 7A9FD1101D7432B200156442 /* main.m in Sources */, 314 | ); 315 | runOnlyForDeploymentPostprocessing = 0; 316 | }; 317 | 7A9FD1201D7432B200156442 /* Sources */ = { 318 | isa = PBXSourcesBuildPhase; 319 | buildActionMask = 2147483647; 320 | files = ( 321 | 7A9FD1291D7432B200156442 /* HyParallaxCurveHeaderViewDemoTests.m in Sources */, 322 | ); 323 | runOnlyForDeploymentPostprocessing = 0; 324 | }; 325 | 7A9FD12B1D7432B200156442 /* Sources */ = { 326 | isa = PBXSourcesBuildPhase; 327 | buildActionMask = 2147483647; 328 | files = ( 329 | 7A9FD1341D7432B200156442 /* HyParallaxCurveHeaderViewDemoUITests.m in Sources */, 330 | ); 331 | runOnlyForDeploymentPostprocessing = 0; 332 | }; 333 | /* End PBXSourcesBuildPhase section */ 334 | 335 | /* Begin PBXTargetDependency section */ 336 | 7A9FD1261D7432B200156442 /* PBXTargetDependency */ = { 337 | isa = PBXTargetDependency; 338 | target = 7A9FD10A1D7432B200156442 /* HyParallaxCurveHeaderViewDemo */; 339 | targetProxy = 7A9FD1251D7432B200156442 /* PBXContainerItemProxy */; 340 | }; 341 | 7A9FD1311D7432B200156442 /* PBXTargetDependency */ = { 342 | isa = PBXTargetDependency; 343 | target = 7A9FD10A1D7432B200156442 /* HyParallaxCurveHeaderViewDemo */; 344 | targetProxy = 7A9FD1301D7432B200156442 /* PBXContainerItemProxy */; 345 | }; 346 | /* End PBXTargetDependency section */ 347 | 348 | /* Begin PBXVariantGroup section */ 349 | 7A9FD1171D7432B200156442 /* Main.storyboard */ = { 350 | isa = PBXVariantGroup; 351 | children = ( 352 | 7A9FD1181D7432B200156442 /* Base */, 353 | ); 354 | name = Main.storyboard; 355 | sourceTree = ""; 356 | }; 357 | 7A9FD11C1D7432B200156442 /* LaunchScreen.storyboard */ = { 358 | isa = PBXVariantGroup; 359 | children = ( 360 | 7A9FD11D1D7432B200156442 /* Base */, 361 | ); 362 | name = LaunchScreen.storyboard; 363 | sourceTree = ""; 364 | }; 365 | /* End PBXVariantGroup section */ 366 | 367 | /* Begin XCBuildConfiguration section */ 368 | 7A9FD1361D7432B200156442 /* Debug */ = { 369 | isa = XCBuildConfiguration; 370 | buildSettings = { 371 | ALWAYS_SEARCH_USER_PATHS = NO; 372 | CLANG_ANALYZER_NONNULL = YES; 373 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 374 | CLANG_CXX_LIBRARY = "libc++"; 375 | CLANG_ENABLE_MODULES = YES; 376 | CLANG_ENABLE_OBJC_ARC = YES; 377 | CLANG_WARN_BOOL_CONVERSION = YES; 378 | CLANG_WARN_CONSTANT_CONVERSION = YES; 379 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 380 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 381 | CLANG_WARN_EMPTY_BODY = YES; 382 | CLANG_WARN_ENUM_CONVERSION = YES; 383 | CLANG_WARN_INFINITE_RECURSION = YES; 384 | CLANG_WARN_INT_CONVERSION = YES; 385 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 386 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 387 | CLANG_WARN_UNREACHABLE_CODE = YES; 388 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 389 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 390 | COPY_PHASE_STRIP = NO; 391 | DEBUG_INFORMATION_FORMAT = dwarf; 392 | ENABLE_STRICT_OBJC_MSGSEND = YES; 393 | ENABLE_TESTABILITY = YES; 394 | GCC_C_LANGUAGE_STANDARD = gnu99; 395 | GCC_DYNAMIC_NO_PIC = NO; 396 | GCC_NO_COMMON_BLOCKS = YES; 397 | GCC_OPTIMIZATION_LEVEL = 0; 398 | GCC_PREPROCESSOR_DEFINITIONS = ( 399 | "DEBUG=1", 400 | "$(inherited)", 401 | ); 402 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 403 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 404 | GCC_WARN_UNDECLARED_SELECTOR = YES; 405 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 406 | GCC_WARN_UNUSED_FUNCTION = YES; 407 | GCC_WARN_UNUSED_VARIABLE = YES; 408 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 409 | MTL_ENABLE_DEBUG_INFO = YES; 410 | ONLY_ACTIVE_ARCH = YES; 411 | SDKROOT = iphoneos; 412 | }; 413 | name = Debug; 414 | }; 415 | 7A9FD1371D7432B200156442 /* Release */ = { 416 | isa = XCBuildConfiguration; 417 | buildSettings = { 418 | ALWAYS_SEARCH_USER_PATHS = NO; 419 | CLANG_ANALYZER_NONNULL = YES; 420 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 421 | CLANG_CXX_LIBRARY = "libc++"; 422 | CLANG_ENABLE_MODULES = YES; 423 | CLANG_ENABLE_OBJC_ARC = YES; 424 | CLANG_WARN_BOOL_CONVERSION = YES; 425 | CLANG_WARN_CONSTANT_CONVERSION = YES; 426 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 427 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 428 | CLANG_WARN_EMPTY_BODY = YES; 429 | CLANG_WARN_ENUM_CONVERSION = YES; 430 | CLANG_WARN_INFINITE_RECURSION = YES; 431 | CLANG_WARN_INT_CONVERSION = YES; 432 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 433 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 434 | CLANG_WARN_UNREACHABLE_CODE = YES; 435 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 436 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 437 | COPY_PHASE_STRIP = NO; 438 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 439 | ENABLE_NS_ASSERTIONS = NO; 440 | ENABLE_STRICT_OBJC_MSGSEND = YES; 441 | GCC_C_LANGUAGE_STANDARD = gnu99; 442 | GCC_NO_COMMON_BLOCKS = YES; 443 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 444 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 445 | GCC_WARN_UNDECLARED_SELECTOR = YES; 446 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 447 | GCC_WARN_UNUSED_FUNCTION = YES; 448 | GCC_WARN_UNUSED_VARIABLE = YES; 449 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 450 | MTL_ENABLE_DEBUG_INFO = NO; 451 | SDKROOT = iphoneos; 452 | VALIDATE_PRODUCT = YES; 453 | }; 454 | name = Release; 455 | }; 456 | 7A9FD1391D7432B200156442 /* Debug */ = { 457 | isa = XCBuildConfiguration; 458 | buildSettings = { 459 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 460 | DEVELOPMENT_TEAM = 4GZ4P57LRH; 461 | INFOPLIST_FILE = HyParallaxCurveHeaderViewDemo/Info.plist; 462 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 463 | PRODUCT_BUNDLE_IDENTIFIER = Hy.HyParallaxCurveHeaderViewDemo; 464 | PRODUCT_NAME = "$(TARGET_NAME)"; 465 | }; 466 | name = Debug; 467 | }; 468 | 7A9FD13A1D7432B200156442 /* Release */ = { 469 | isa = XCBuildConfiguration; 470 | buildSettings = { 471 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 472 | DEVELOPMENT_TEAM = 4GZ4P57LRH; 473 | INFOPLIST_FILE = HyParallaxCurveHeaderViewDemo/Info.plist; 474 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 475 | PRODUCT_BUNDLE_IDENTIFIER = Hy.HyParallaxCurveHeaderViewDemo; 476 | PRODUCT_NAME = "$(TARGET_NAME)"; 477 | }; 478 | name = Release; 479 | }; 480 | 7A9FD13C1D7432B200156442 /* Debug */ = { 481 | isa = XCBuildConfiguration; 482 | buildSettings = { 483 | BUNDLE_LOADER = "$(TEST_HOST)"; 484 | INFOPLIST_FILE = HyParallaxCurveHeaderViewDemoTests/Info.plist; 485 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 486 | PRODUCT_BUNDLE_IDENTIFIER = Hy.HyParallaxCurveHeaderViewDemoTests; 487 | PRODUCT_NAME = "$(TARGET_NAME)"; 488 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/HyParallaxCurveHeaderViewDemo.app/HyParallaxCurveHeaderViewDemo"; 489 | }; 490 | name = Debug; 491 | }; 492 | 7A9FD13D1D7432B200156442 /* Release */ = { 493 | isa = XCBuildConfiguration; 494 | buildSettings = { 495 | BUNDLE_LOADER = "$(TEST_HOST)"; 496 | INFOPLIST_FILE = HyParallaxCurveHeaderViewDemoTests/Info.plist; 497 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 498 | PRODUCT_BUNDLE_IDENTIFIER = Hy.HyParallaxCurveHeaderViewDemoTests; 499 | PRODUCT_NAME = "$(TARGET_NAME)"; 500 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/HyParallaxCurveHeaderViewDemo.app/HyParallaxCurveHeaderViewDemo"; 501 | }; 502 | name = Release; 503 | }; 504 | 7A9FD13F1D7432B200156442 /* Debug */ = { 505 | isa = XCBuildConfiguration; 506 | buildSettings = { 507 | INFOPLIST_FILE = HyParallaxCurveHeaderViewDemoUITests/Info.plist; 508 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 509 | PRODUCT_BUNDLE_IDENTIFIER = Hy.HyParallaxCurveHeaderViewDemoUITests; 510 | PRODUCT_NAME = "$(TARGET_NAME)"; 511 | TEST_TARGET_NAME = HyParallaxCurveHeaderViewDemo; 512 | }; 513 | name = Debug; 514 | }; 515 | 7A9FD1401D7432B200156442 /* Release */ = { 516 | isa = XCBuildConfiguration; 517 | buildSettings = { 518 | INFOPLIST_FILE = HyParallaxCurveHeaderViewDemoUITests/Info.plist; 519 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 520 | PRODUCT_BUNDLE_IDENTIFIER = Hy.HyParallaxCurveHeaderViewDemoUITests; 521 | PRODUCT_NAME = "$(TARGET_NAME)"; 522 | TEST_TARGET_NAME = HyParallaxCurveHeaderViewDemo; 523 | }; 524 | name = Release; 525 | }; 526 | /* End XCBuildConfiguration section */ 527 | 528 | /* Begin XCConfigurationList section */ 529 | 7A9FD1061D7432B200156442 /* Build configuration list for PBXProject "HyParallaxCurveHeaderViewDemo" */ = { 530 | isa = XCConfigurationList; 531 | buildConfigurations = ( 532 | 7A9FD1361D7432B200156442 /* Debug */, 533 | 7A9FD1371D7432B200156442 /* Release */, 534 | ); 535 | defaultConfigurationIsVisible = 0; 536 | defaultConfigurationName = Release; 537 | }; 538 | 7A9FD1381D7432B200156442 /* Build configuration list for PBXNativeTarget "HyParallaxCurveHeaderViewDemo" */ = { 539 | isa = XCConfigurationList; 540 | buildConfigurations = ( 541 | 7A9FD1391D7432B200156442 /* Debug */, 542 | 7A9FD13A1D7432B200156442 /* Release */, 543 | ); 544 | defaultConfigurationIsVisible = 0; 545 | }; 546 | 7A9FD13B1D7432B200156442 /* Build configuration list for PBXNativeTarget "HyParallaxCurveHeaderViewDemoTests" */ = { 547 | isa = XCConfigurationList; 548 | buildConfigurations = ( 549 | 7A9FD13C1D7432B200156442 /* Debug */, 550 | 7A9FD13D1D7432B200156442 /* Release */, 551 | ); 552 | defaultConfigurationIsVisible = 0; 553 | }; 554 | 7A9FD13E1D7432B200156442 /* Build configuration list for PBXNativeTarget "HyParallaxCurveHeaderViewDemoUITests" */ = { 555 | isa = XCConfigurationList; 556 | buildConfigurations = ( 557 | 7A9FD13F1D7432B200156442 /* Debug */, 558 | 7A9FD1401D7432B200156442 /* Release */, 559 | ); 560 | defaultConfigurationIsVisible = 0; 561 | }; 562 | /* End XCConfigurationList section */ 563 | }; 564 | rootObject = 7A9FD1031D7432B200156442 /* Project object */; 565 | } 566 | --------------------------------------------------------------------------------