├── screenshot.jpg
├── TOGlintyStringView
├── TOGlintyStringView.xcassets
│ ├── Contents.json
│ ├── TOGlintyStringViewChevron.imageset
│ │ ├── UIGlintyStringViewChevron.png
│ │ ├── UIGlintyStringViewChevron@2x.png
│ │ ├── UIGlintyStringViewChevron@3x.png
│ │ └── Contents.json
│ ├── TOGlintyStringViewShimmerMask.imageset
│ │ ├── UIGlintyStringViewShimmerMask.png
│ │ ├── UIGlintyStringViewShimmerMask@2x.png
│ │ ├── UIGlintyStringViewShimmerMask@3x.png
│ │ └── Contents.json
│ └── TOGlintyStringViewReflectionMask.imageset
│ │ ├── UIGlintyStringViewReflectionMask.png
│ │ ├── UIGlintyStringViewReflectionMask@2x.png
│ │ ├── UIGlintyStringViewReflectionMask@3x.png
│ │ └── Contents.json
├── TOGlintyShapeLayer.h
├── TOGlintyGradientLayer.h
├── TOGlintyStringView.h
├── ARCGPathFromString.h
├── TOGlintyShapeLayer.m
├── TOGlintyGradientLayer.m
├── ARCGPathFromString.m
└── TOGlintyStringView.m
├── TOGlintyStringViewExample
├── IMG_2875.PNG
├── ViewController.h
├── AppDelegate.h
├── main.m
├── ViewController.m
├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── Info.plist
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
└── AppDelegate.m
├── TOGlintyStringViewExample.xcodeproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
└── project.pbxproj
├── LICENSE
├── .gitignore
└── README.md
/screenshot.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TimOliver/TOGlintyStringView/HEAD/screenshot.jpg
--------------------------------------------------------------------------------
/TOGlintyStringView/TOGlintyStringView.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/TOGlintyStringViewExample/IMG_2875.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TimOliver/TOGlintyStringView/HEAD/TOGlintyStringViewExample/IMG_2875.PNG
--------------------------------------------------------------------------------
/TOGlintyStringView/TOGlintyStringView.xcassets/TOGlintyStringViewChevron.imageset/UIGlintyStringViewChevron.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TimOliver/TOGlintyStringView/HEAD/TOGlintyStringView/TOGlintyStringView.xcassets/TOGlintyStringViewChevron.imageset/UIGlintyStringViewChevron.png
--------------------------------------------------------------------------------
/TOGlintyStringView/TOGlintyStringView.xcassets/TOGlintyStringViewChevron.imageset/UIGlintyStringViewChevron@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TimOliver/TOGlintyStringView/HEAD/TOGlintyStringView/TOGlintyStringView.xcassets/TOGlintyStringViewChevron.imageset/UIGlintyStringViewChevron@2x.png
--------------------------------------------------------------------------------
/TOGlintyStringView/TOGlintyStringView.xcassets/TOGlintyStringViewChevron.imageset/UIGlintyStringViewChevron@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TimOliver/TOGlintyStringView/HEAD/TOGlintyStringView/TOGlintyStringView.xcassets/TOGlintyStringViewChevron.imageset/UIGlintyStringViewChevron@3x.png
--------------------------------------------------------------------------------
/TOGlintyStringView/TOGlintyStringView.xcassets/TOGlintyStringViewShimmerMask.imageset/UIGlintyStringViewShimmerMask.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TimOliver/TOGlintyStringView/HEAD/TOGlintyStringView/TOGlintyStringView.xcassets/TOGlintyStringViewShimmerMask.imageset/UIGlintyStringViewShimmerMask.png
--------------------------------------------------------------------------------
/TOGlintyStringView/TOGlintyStringView.xcassets/TOGlintyStringViewShimmerMask.imageset/UIGlintyStringViewShimmerMask@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TimOliver/TOGlintyStringView/HEAD/TOGlintyStringView/TOGlintyStringView.xcassets/TOGlintyStringViewShimmerMask.imageset/UIGlintyStringViewShimmerMask@2x.png
--------------------------------------------------------------------------------
/TOGlintyStringView/TOGlintyStringView.xcassets/TOGlintyStringViewShimmerMask.imageset/UIGlintyStringViewShimmerMask@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TimOliver/TOGlintyStringView/HEAD/TOGlintyStringView/TOGlintyStringView.xcassets/TOGlintyStringViewShimmerMask.imageset/UIGlintyStringViewShimmerMask@3x.png
--------------------------------------------------------------------------------
/TOGlintyStringView/TOGlintyStringView.xcassets/TOGlintyStringViewReflectionMask.imageset/UIGlintyStringViewReflectionMask.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TimOliver/TOGlintyStringView/HEAD/TOGlintyStringView/TOGlintyStringView.xcassets/TOGlintyStringViewReflectionMask.imageset/UIGlintyStringViewReflectionMask.png
--------------------------------------------------------------------------------
/TOGlintyStringViewExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/TOGlintyStringView/TOGlintyStringView.xcassets/TOGlintyStringViewReflectionMask.imageset/UIGlintyStringViewReflectionMask@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TimOliver/TOGlintyStringView/HEAD/TOGlintyStringView/TOGlintyStringView.xcassets/TOGlintyStringViewReflectionMask.imageset/UIGlintyStringViewReflectionMask@2x.png
--------------------------------------------------------------------------------
/TOGlintyStringView/TOGlintyStringView.xcassets/TOGlintyStringViewReflectionMask.imageset/UIGlintyStringViewReflectionMask@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TimOliver/TOGlintyStringView/HEAD/TOGlintyStringView/TOGlintyStringView.xcassets/TOGlintyStringViewReflectionMask.imageset/UIGlintyStringViewReflectionMask@3x.png
--------------------------------------------------------------------------------
/TOGlintyStringViewExample/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // TOGlintyStringView
4 | //
5 | // Created by Tim Oliver on 30/01/2016.
6 | // Copyright © 2016 Tim Oliver. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ViewController : UIViewController
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/TOGlintyStringViewExample/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // TOGlintyStringView
4 | //
5 | // Created by Tim Oliver on 30/01/2016.
6 | // Copyright © 2016 Tim Oliver. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 | @end
16 |
17 |
--------------------------------------------------------------------------------
/TOGlintyStringViewExample/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // TOGlintyStringView
4 | //
5 | // Created by Tim Oliver on 30/01/2016.
6 | // Copyright © 2016 Tim Oliver. 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 |
--------------------------------------------------------------------------------
/TOGlintyStringView/TOGlintyStringView.xcassets/TOGlintyStringViewChevron.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "UIGlintyStringViewChevron.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "UIGlintyStringViewChevron@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "UIGlintyStringViewChevron@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/TOGlintyStringView/TOGlintyStringView.xcassets/TOGlintyStringViewShimmerMask.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "UIGlintyStringViewShimmerMask.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "UIGlintyStringViewShimmerMask@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "UIGlintyStringViewShimmerMask@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/TOGlintyStringView/TOGlintyStringView.xcassets/TOGlintyStringViewReflectionMask.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "UIGlintyStringViewReflectionMask.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "UIGlintyStringViewReflectionMask@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "UIGlintyStringViewReflectionMask@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/TOGlintyStringViewExample/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // TOGlintyStringView
4 | //
5 | // Created by Tim Oliver on 30/01/2016.
6 | // Copyright © 2016 Tim Oliver. All rights reserved.
7 | //
8 |
9 | #import "ViewController.h"
10 | #import "TOGlintyStringView.h"
11 |
12 | @interface ViewController ()
13 |
14 | @property (nonatomic, strong) IBOutlet TOGlintyStringView *stringView;
15 |
16 | @end
17 |
18 | @implementation ViewController
19 |
20 | - (void)viewDidLoad {
21 | [super viewDidLoad];
22 | self.stringView.chevronImage = [TOGlintyStringView defaultChevronImage];
23 | }
24 |
25 | - (UIStatusBarStyle)preferredStatusBarStyle
26 | {
27 | return UIStatusBarStyleLightContent;
28 | }
29 |
30 | - (BOOL)prefersStatusBarHidden
31 | {
32 | return YES;
33 | }
34 |
35 | @end
36 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Tim Oliver
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/TOGlintyStringView/TOGlintyShapeLayer.h:
--------------------------------------------------------------------------------
1 | //
2 | // TOGlintyShapeLayer.h
3 | //
4 | // Copyright 2016 Timothy Oliver. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
21 | // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 |
23 | #import
24 |
25 | @interface TOGlintyShapeLayer : CAShapeLayer
26 |
27 | @end
28 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata
19 |
20 | ## Other
21 | *.xccheckout
22 | *.moved-aside
23 | *.xcuserstate
24 | *.xcscmblueprint
25 |
26 | ## Obj-C/Swift specific
27 | *.hmap
28 | *.ipa
29 |
30 | # CocoaPods
31 | #
32 | # We recommend against adding the Pods directory to your .gitignore. However
33 | # you should judge for yourself, the pros and cons are mentioned at:
34 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
35 | #
36 | # Pods/
37 |
38 | # Carthage
39 | #
40 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
41 | # Carthage/Checkouts
42 |
43 | Carthage/Build
44 |
45 | # fastlane
46 | #
47 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
48 | # screenshots whenever they are needed.
49 | # For more information about the recommended setup visit:
50 | # https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md
51 |
52 | fastlane/report.xml
53 | fastlane/screenshots
54 |
--------------------------------------------------------------------------------
/TOGlintyStringViewExample/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "ipad",
35 | "size" : "29x29",
36 | "scale" : "1x"
37 | },
38 | {
39 | "idiom" : "ipad",
40 | "size" : "29x29",
41 | "scale" : "2x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "40x40",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "40x40",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "76x76",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "76x76",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "83.5x83.5",
66 | "scale" : "2x"
67 | }
68 | ],
69 | "info" : {
70 | "version" : 1,
71 | "author" : "xcode"
72 | }
73 | }
--------------------------------------------------------------------------------
/TOGlintyStringView/TOGlintyGradientLayer.h:
--------------------------------------------------------------------------------
1 | //
2 | // TOGlintyGradientLayer.h
3 | //
4 | // Copyright 2016 Timothy Oliver. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
21 | // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 |
23 | #import
24 |
25 | @interface TOGlintyGradientLayer : CALayer
26 |
27 | @property (nonatomic, strong) CALayer *reflectionLayer;
28 | @property (nonatomic, strong) CAGradientLayer *gradientLayer;
29 | @property (nonatomic, strong) CALayer *shimmerLayer;
30 |
31 | - (void)startAnimation;
32 | - (void)stopAnimation;
33 |
34 | @end
35 |
--------------------------------------------------------------------------------
/TOGlintyStringViewExample/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 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 | UIInterfaceOrientationLandscapeRight
38 |
39 | UISupportedInterfaceOrientations~ipad
40 |
41 | UIInterfaceOrientationPortrait
42 | UIInterfaceOrientationPortraitUpsideDown
43 | UIInterfaceOrientationLandscapeLeft
44 | UIInterfaceOrientationLandscapeRight
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/TOGlintyStringViewExample/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 |
--------------------------------------------------------------------------------
/TOGlintyStringView/TOGlintyStringView.h:
--------------------------------------------------------------------------------
1 | //
2 | // TOGlintyStringView.h
3 | //
4 | // Copyright 2016 Timothy Oliver. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
21 | // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 |
23 | #import
24 |
25 | #if TARGET_OS_IPHONE
26 | #define TO_VIEW_FOR_PLATFORM UIView
27 | #elif TARGET_OS_MAC
28 | #define TOGLINTY_CROSSPLATFORM_VIEW NSView
29 | #endif
30 |
31 | #if TARGET_OS_IPHONE
32 | #define TO_FONT_FOR_PLATFORM UIFont
33 | #elif TARGET_OS_MAC
34 | #define TO_FONT_FOR_PLATFORM NSFont
35 | #endif
36 |
37 | #if TARGET_OS_IPHONE
38 | #define TO_IMAGE_FOR_PLATFORM UIImage
39 | #elif TARGET_OS_MAC
40 | #define TO_IMAGE_FOR_PLATFORM NSImage
41 | #endif
42 |
43 | @interface TOGlintyStringView : TO_VIEW_FOR_PLATFORM
44 |
45 | @property (nonatomic, copy) NSString *text;
46 | @property (nonatomic, assign) CGFloat chevronSpacing;
47 |
48 | @property (nonatomic, strong) TO_FONT_FOR_PLATFORM *font;
49 | @property (nonatomic, strong) TO_IMAGE_FOR_PLATFORM *chevronImage;
50 | @property (nonatomic, readonly) TO_VIEW_FOR_PLATFORM *effectView;
51 |
52 | + (id)defaultChevronImage;
53 |
54 | @end
55 |
--------------------------------------------------------------------------------
/TOGlintyStringViewExample/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // TOGlintyStringView
4 | //
5 | // Created by Tim Oliver on 30/01/2016.
6 | // Copyright © 2016 Tim Oliver. 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 | - (void)applicationWillResignActive:(UIApplication *)application {
24 | // 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.
25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
26 | }
27 |
28 | - (void)applicationDidEnterBackground:(UIApplication *)application {
29 | // 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.
30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
31 | }
32 |
33 | - (void)applicationWillEnterForeground:(UIApplication *)application {
34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
35 | }
36 |
37 | - (void)applicationDidBecomeActive:(UIApplication *)application {
38 | // 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.
39 | }
40 |
41 | - (void)applicationWillTerminate:(UIApplication *)application {
42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
43 | }
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/TOGlintyStringView/ARCGPathFromString.h:
--------------------------------------------------------------------------------
1 | //
2 | // ARCGPathFromString.h
3 | //
4 | // Created by Adrian Russell on 08/08/2014.
5 | // Copyright (c) 2014 Adrian Russell. All rights reserved.
6 | //
7 | // This software is provided 'as-is', without any express or implied
8 | // warranty. In no event will the authors be held liable for any damages
9 | // arising from the use of this software. Permission is granted to anyone to
10 | // use this software for any purpose, including commercial applications, and to
11 | // alter it and redistribute it freely, subject to the following restrictions:
12 | //
13 | // 1. The origin of this software must not be misrepresented; you must not
14 | // claim that you wrote the original software. If you use this software
15 | // in a product, an acknowledgment in the product documentation would be
16 | // appreciated but is not required.
17 | // 2. Altered source versions must be plainly marked as such, and must not be
18 | // misrepresented as being the original software.
19 | // 3. This notice may not be removed or altered from any source
20 | // distribution.
21 | //
22 |
23 | #import
24 | #import
25 |
26 | // Tim Oliver: To ensure proper cross-platform linking
27 | #if TARGET_OS_IPHONE
28 | #import
29 | #elif TARGET_OS_MAC
30 | #import
31 | #endif
32 |
33 | /**
34 | Creates a CGPath from a specified attributed string.
35 | @param attrString The attributed string to produce the path for. Must not be `nil`.
36 | @return A new CGPath that contains a path with paths for all the glyphs for specifed string.
37 | @discussion This string will always be on a single line even if the string contains linebreaks.
38 | */
39 | CGPathRef CGPathCreateSingleLineStringWithAttributedString(NSAttributedString *attrString);
40 |
41 | /**
42 | Creates a CGPath from a specified attributed string that can span over multiple lines of text.
43 | @param attrString The attributed string to produce the path for. Must not be `nil`.
44 | @param maxWidth The maximum width of a line, if a line when rendered is longer than this width then the line is broken to a new line. Must be greater than 0.
45 | @param maxHeight The maximum height of the text block. Must be greater than 0.
46 | @return A new CGPath that contains a path with paths for all the glyphs for specifed string.
47 | */
48 | CGPathRef CGPathCreateMultilineStringWithAttributedString(NSAttributedString *attrString, CGFloat maxWidth, CGFloat maxHeight);
--------------------------------------------------------------------------------
/TOGlintyStringView/TOGlintyShapeLayer.m:
--------------------------------------------------------------------------------
1 | //
2 | // TOGlintyShapeLayer.m
3 | //
4 | // Copyright 2016 Timothy Oliver. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
21 | // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 |
23 | #import "TOGlintyShapeLayer.h"
24 |
25 | @interface CAFilter : NSObject
26 |
27 | @property (copy) NSString *name;
28 |
29 | + (instancetype)filterWithName:(id)name;
30 | - (instancetype)initWithName:(id)name;
31 |
32 | @end
33 |
34 | @implementation TOGlintyShapeLayer
35 |
36 | - (instancetype)init
37 | {
38 | if (self = [super init]) {
39 | self.opaque = NO;
40 | self.shouldRasterize = YES;
41 | [self setValue:@(NO) forKey:@"allowsGroupBlending"];
42 | self.lineDashPattern = @[@(10), @(10)];
43 | self.lineJoin = @"round";
44 | self.lineCap = @"round";
45 | self.miterLimit = 5;
46 | self.lineWidth = 1.5f;
47 | self.allowsGroupOpacity = NO;
48 | self.strokeColor = CGColorCreate(CGColorSpaceCreateDeviceGray(), (CGFloat []){1.0f, 1.0f});
49 | self.backgroundColor = CGColorCreate(CGColorSpaceCreateDeviceGray(), (CGFloat []){0.0f, 1.0f});
50 | self.transform = CATransform3DScale(CATransform3DIdentity, 1.0f, -1.0f, 1.0f);
51 |
52 | // WARNING: This is exposing a private API and will absolutely
53 | // not be accepted on the App Store. Use at your own risk!
54 | CAFilter *blurFilter = [CAFilter filterWithName:@"gaussianBlur"];
55 | [blurFilter setValue:@(1) forKey:@"inputRadius"];
56 | self.filters = @[blurFilter];
57 | }
58 |
59 | return self;
60 | }
61 |
62 | @end
63 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # TOGlintyStringView
4 | `TOGlintyStringView` is a complete re-implementation of [`_UIGlintyStringView`](https://github.com/JaviSoto/iOS9-Runtime-Headers/blob/51598b5f73399e4737bc067ed6b9bd5bd9a8b0d1/Frameworks/UIKit.framework/_UIGlintyStringView.h), the internal UIKit `UIView` responsible for the '> slide to unlock' text on the lock screen of every iOS device running iOS 7 through to iOS 9.
5 |
6 | It was created by copying the `UIView` / `CALayer` configuration of `_UIGlintyStringView` after introspecting it via [Reveal app](http://revealapp.com) as well as a lot of console logging.
7 |
8 | As this library (most likely) cannot be used in shipping iOS apps, it's being presented here without warranty in the hopes it may have educational value to fellow developers!
9 |
10 | # How does it work?
11 |
12 | I'll improve this section down the line, but in a nutshell, it is comprised of 6 discrete `CALayer` objects:
13 |
14 | * The top layer contains a bitmap of the text, used as a mask to clip the rest of the content.
15 | * The second layer is a flat, partially transparent grey layer used as the base color of the effect.
16 | * The third layer is the white 'sheen' gradient that results in the pure white section of the effect.
17 | * The fourth layer is a simple `CAGradientLayer` that when blended with the gradient layers above and below it, creates a wedge shape falloff on either side of the sheen effect.
18 | * The fifth layer is a much wider, and less opaque gradient that creates the 'build-up' effect on either side of the sheen.
19 | * The sixth layer is a `CAShapeLayer` that takes a `CGPath` outline of the text, and produces a blurred, dashed-line outline, that is then blended with the gradients to produce that subtle 'fractal' effect.
20 |
21 | All of this is possible in an (officially unsupported on iOS) feature of Core Animation allowing layers to be blended together using a variety of filters.
22 |
23 | # Is it safe for the App Store?
24 | HAHAHAHA absolutely not. In order to make this effect possible, two private APIs needed to be invoked:
25 |
26 | * To enable blending on `CALayer` objects, the `allowsGroupBlending` property must be set to NO. This property is not officially exposed, but trivial to access, and probably easy to obfuscate from the app submission scanner.
27 | * To create the blurring of the dashes in the `CAShapeLayer`, it is necessary to instantiate a `CAFilter` instance. As this class definitely isn't exposed on iOS, using it would immediately be caught by the automatic private API detection system Apple uses in app submissions.
28 |
29 | While you're free to try, I wouldn't recommend trying to submit an app to the App Store using this view.
30 |
31 | # Credits
32 |
33 | `TOGlintyStringView` was created by Tim Oliver as a Core Animation experiment.
34 |
35 | It also incorporates the [`string-to-CGPathRef`](https://github.com/aderussell/string-to-CGPathRef) library, created by Adrian Russell, 2014
36 |
37 | iPhone 6s Plus device mockup by [Pixeden](http://www.pixeden.com).
38 |
39 | # License
40 |
41 | `TOGlintyStringView` is available under the MIT license. Please see the [LICENSE](LICENSE) file for more information. 
42 |
--------------------------------------------------------------------------------
/TOGlintyStringViewExample/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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/TOGlintyStringView/TOGlintyGradientLayer.m:
--------------------------------------------------------------------------------
1 | //
2 | // TOGlintyGradientLayer.m
3 | //
4 | // Copyright 2016 Timothy Oliver. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
21 | // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 |
23 |
24 | #import "TOGlintyGradientLayer.h"
25 |
26 | #if TARGET_OS_IPHONE
27 | #import
28 | #elif TARGET_OS_MAC
29 | #import
30 | #endif
31 |
32 | @interface TOGlintyGradientLayer ()
33 |
34 | - (void)setUp;
35 |
36 | - (CAKeyframeAnimation *)shimmerAnimation;
37 | - (CAKeyframeAnimation *)reflectionAnimation;
38 |
39 | @end
40 |
41 | @implementation TOGlintyGradientLayer
42 |
43 | - (instancetype)init
44 | {
45 | if (self = [super init]) {
46 | [self setUp];
47 | }
48 |
49 | return self;
50 | }
51 |
52 | - (void)setUp
53 | {
54 | [self setValue:@(NO) forKey:@"allowsGroupBlending"];
55 | self.opaque = NO;
56 | self.masksToBounds = YES;
57 | self.allowsGroupOpacity = NO;
58 |
59 | CGImageRef reflectionImage = nil;
60 | CGSize reflectionSize = CGSizeZero;
61 |
62 | CGImageRef shimmerImage = nil;
63 | CGSize shimmerSize = CGSizeZero;
64 |
65 | #if TARGET_OS_IPHONE
66 | UIImage *_reflectionImage = [UIImage imageNamed:@"TOGlintyStringViewReflectionMask"];
67 | reflectionSize = _reflectionImage.size;
68 | reflectionImage = _reflectionImage.CGImage;
69 |
70 | UIImage *_shimmerImage = [UIImage imageNamed:@"TOGlintyStringViewShimmerMask"];
71 | shimmerSize = _shimmerImage.size;
72 | shimmerImage = _shimmerImage.CGImage;
73 | #elif TARGET_OS_MAC
74 | NSImage *_reflectionImage = [NSImage imageNamed:@"TOGlintyStringViewReflectionMask"];
75 | reflectionImage = [_reflectionImage CGImageForProposedRect:(CGRect){CGPointZero, _reflectionImage.size} context:NULL hints:nil];
76 |
77 | NSImage *_shimmerImage = [NSImage imageNamed:@"TOGlintyStringViewShimmerMask"];
78 | shimmerImage = [_shimmerImage CGImageForProposedRect:(CGRect){CGPointZero, _shimmerImage.size} context:NULL hints:nil];
79 | #endif
80 |
81 | self.shimmerLayer = [[CALayer alloc] init];
82 | self.shimmerLayer.opaque = NO;
83 | self.shimmerLayer.frame = (CGRect){CGPointZero, {646, 46}};
84 | self.shimmerLayer.opacity = 0.9f;
85 | self.shimmerLayer.contents = (__bridge id)shimmerImage;
86 | self.shimmerLayer.compositingFilter = @"linearLightBlendMode";
87 | [self.shimmerLayer setValue:@(NO) forKey:@"allowsGroupBlending"];
88 | self.shimmerLayer.allowsGroupOpacity = NO;
89 | [self addSublayer:self.shimmerLayer];
90 |
91 | self.gradientLayer = [[CAGradientLayer alloc] init];
92 | self.gradientLayer.allowsGroupOpacity = YES;
93 | self.gradientLayer.opaque = YES;
94 | self.gradientLayer.opacity = 0.35;
95 | self.gradientLayer.compositingFilter = @"colorDodgeBlendMode";
96 |
97 | CGColorRef lowPointColor = CGColorCreate(CGColorSpaceCreateDeviceGray(), (CGFloat []){0.05f, 1.0f});
98 | CGColorRef highPointColor = CGColorCreate(CGColorSpaceCreateDeviceGray(), (CGFloat []){0.95f, 1.0f});
99 | self.gradientLayer.colors = @[(__bridge id)lowPointColor, (__bridge id)highPointColor, (__bridge id)lowPointColor];
100 | self.gradientLayer.frame = (CGRect){CGPointZero, {646, 46}};
101 | [self addSublayer:self.gradientLayer];
102 |
103 | self.reflectionLayer = [[CALayer alloc] init];
104 | self.reflectionLayer.opaque = NO;
105 | self.reflectionLayer.frame = (CGRect){CGPointZero, {646, 46}};
106 | self.reflectionLayer.opacity = 0.75f;
107 | self.reflectionLayer.contents = (__bridge id)reflectionImage;
108 | self.reflectionLayer.allowsGroupOpacity = YES;
109 | self.reflectionLayer.compositingFilter = @"multiplyBlendMode";
110 | [self addSublayer:self.reflectionLayer];
111 | }
112 |
113 | - (void)setFrame:(CGRect)frame
114 | {
115 | [super setFrame:frame];
116 |
117 | frame = self.gradientLayer.frame;
118 | frame.origin.y = (CGRectGetHeight(self.frame) - CGRectGetHeight(frame)) * 0.5f;
119 | frame.origin.y += 2;
120 | self.gradientLayer.frame = frame;
121 | }
122 |
123 | - (void)startAnimation
124 | {
125 | [self.reflectionLayer addAnimation:[self reflectionAnimation] forKey:@"reflectionAnimation"];
126 | [self.shimmerLayer addAnimation:[self shimmerAnimation] forKey:@"shimmerAnimation"];
127 | }
128 |
129 | - (void)stopAnimation
130 | {
131 | [self.reflectionLayer removeAllAnimations];
132 | [self.shimmerLayer removeAllAnimations];
133 | }
134 |
135 | - (CAKeyframeAnimation *)shimmerAnimation
136 | {
137 | CAKeyframeAnimation *shimmerAnimation = [[CAKeyframeAnimation alloc] init];
138 | shimmerAnimation.values = @[@(0), @(320)];
139 | shimmerAnimation.keyTimes = @[@(0), @(1)];
140 | shimmerAnimation.repeatCount = HUGE_VALF;
141 | shimmerAnimation.removedOnCompletion = NO;
142 | shimmerAnimation.duration = 2;
143 | shimmerAnimation.fillMode = @"both";
144 | shimmerAnimation.keyPath = @"position.x";
145 | return shimmerAnimation;
146 | }
147 |
148 | - (CAKeyframeAnimation *)reflectionAnimation
149 | {
150 | CAKeyframeAnimation *reflectionAnimation = [[CAKeyframeAnimation alloc] init];
151 | reflectionAnimation.values = @[@(0), @(320)];
152 | reflectionAnimation.keyTimes = @[@(0), @(1)];
153 | reflectionAnimation.repeatCount = HUGE_VALF;
154 | reflectionAnimation.removedOnCompletion = NO;
155 | reflectionAnimation.fillMode = @"both";
156 | reflectionAnimation.duration = 2;
157 | reflectionAnimation.keyPath = @"position.x";
158 | return reflectionAnimation;
159 | }
160 |
161 | @end
162 |
--------------------------------------------------------------------------------
/TOGlintyStringView/ARCGPathFromString.m:
--------------------------------------------------------------------------------
1 | //
2 | // ARCGPathFromString.m
3 | //
4 | // Created by Adrian Russell on 08/08/2014.
5 | // Copyright (c) 2014 Adrian Russell. All rights reserved.
6 | //
7 | // This software is provided 'as-is', without any express or implied
8 | // warranty. In no event will the authors be held liable for any damages
9 | // arising from the use of this software. Permission is granted to anyone to
10 | // use this software for any purpose, including commercial applications, and to
11 | // alter it and redistribute it freely, subject to the following restrictions:
12 | //
13 | // 1. The origin of this software must not be misrepresented; you must not
14 | // claim that you wrote the original software. If you use this software
15 | // in a product, an acknowledgment in the product documentation would be
16 | // appreciated but is not required.
17 | // 2. Altered source versions must be plainly marked as such, and must not be
18 | // misrepresented as being the original software.
19 | // 3. This notice may not be removed or altered from any source
20 | // distribution.
21 | //
22 |
23 | #import "ARCGPathFromString.h"
24 |
25 | #pragma mark Single Line String Path
26 |
27 | CGPathRef CGPathCreateSingleLineStringWithAttributedString(NSAttributedString *attrString)
28 | {
29 | CGMutablePathRef letters = CGPathCreateMutable();
30 |
31 |
32 | CTLineRef line = CTLineCreateWithAttributedString((__bridge CFAttributedStringRef)attrString);
33 |
34 | CFArrayRef runArray = CTLineGetGlyphRuns(line);
35 |
36 | // for each RUN
37 | for (CFIndex runIndex = 0; runIndex < CFArrayGetCount(runArray); runIndex++)
38 | {
39 | // Get FONT for this run
40 | CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex(runArray, runIndex);
41 | CTFontRef runFont = CFDictionaryGetValue(CTRunGetAttributes(run), kCTFontAttributeName);
42 |
43 | // for each GLYPH in run
44 | for (CFIndex runGlyphIndex = 0; runGlyphIndex < CTRunGetGlyphCount(run); runGlyphIndex++)
45 | {
46 | // get Glyph & Glyph-data
47 | CFRange thisGlyphRange = CFRangeMake(runGlyphIndex, 1);
48 | CGGlyph glyph;
49 | CGPoint position;
50 | CTRunGetGlyphs(run, thisGlyphRange, &glyph);
51 | CTRunGetPositions(run, thisGlyphRange, &position);
52 |
53 | // Get PATH of outline
54 | {
55 | CGPathRef letter = CTFontCreatePathForGlyph(runFont, glyph, NULL);
56 | CGAffineTransform t = CGAffineTransformMakeTranslation(position.x, position.y);
57 | CGPathAddPath(letters, &t, letter);
58 | CGPathRelease(letter);
59 | }
60 | }
61 | }
62 |
63 | CFRelease(line);
64 |
65 | CGPathRef finalPath = CGPathCreateCopy(letters);
66 | CGPathRelease(letters);
67 | return finalPath;
68 | }
69 |
70 |
71 | #pragma mark - Multiple Line String Path
72 |
73 | CGPathRef CGPathCreateMultilineStringWithAttributedString(NSAttributedString *attrString, CGFloat maxWidth, CGFloat maxHeight)
74 | {
75 |
76 | CGMutablePathRef letters = CGPathCreateMutable();
77 |
78 | CGRect bounds = CGRectMake(0, 0, maxWidth, maxHeight);
79 |
80 | CGPathRef pathRef = CGPathCreateWithRect(bounds, NULL);
81 |
82 | CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)(attrString));
83 | CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), pathRef, NULL);
84 |
85 | CFArrayRef lines = CTFrameGetLines(frame);
86 |
87 | CGPoint *points = malloc(sizeof(CGPoint) * CFArrayGetCount(lines));
88 |
89 | CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), points);
90 |
91 | NSInteger numLines = CFArrayGetCount(lines);
92 | // for each LINE
93 | for (CFIndex lineIndex = 0; lineIndex < numLines; lineIndex++)
94 | {
95 | CTLineRef lineRef = CFArrayGetValueAtIndex(lines, lineIndex);
96 |
97 | CFRange r = CTLineGetStringRange(lineRef);
98 |
99 | NSParagraphStyle *paragraphStyle = [attrString attribute:NSParagraphStyleAttributeName atIndex:r.location effectiveRange:NULL];
100 | NSTextAlignment alignment = paragraphStyle.alignment;
101 |
102 |
103 | CGFloat flushFactor = 0.0;
104 | if (alignment == NSTextAlignmentLeft) {
105 | flushFactor = 0.0;
106 | } else if (alignment == NSTextAlignmentCenter) {
107 | flushFactor = 0.5;
108 | } else if (alignment == NSTextAlignmentRight) {
109 | flushFactor = 1.0;
110 | }
111 |
112 | CGFloat penOffset = CTLineGetPenOffsetForFlush(lineRef, flushFactor, maxWidth);
113 |
114 | // create a new justified line if the alignment is justified
115 | if (alignment == NSTextAlignmentJustified) {
116 | lineRef = CTLineCreateJustifiedLine(lineRef, 1.0, maxWidth);
117 | penOffset = 0;
118 | }
119 |
120 | CGFloat lineOffset = numLines == 1 ? 0 : maxHeight - points[lineIndex].y;
121 |
122 | CFArrayRef runArray = CTLineGetGlyphRuns(lineRef);
123 |
124 | // for each RUN
125 | for (CFIndex runIndex = 0; runIndex < CFArrayGetCount(runArray); runIndex++)
126 | {
127 | // Get FONT for this run
128 | CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex(runArray, runIndex);
129 | CTFontRef runFont = CFDictionaryGetValue(CTRunGetAttributes(run), kCTFontAttributeName);
130 |
131 | // for each GLYPH in run
132 | for (CFIndex runGlyphIndex = 0; runGlyphIndex < CTRunGetGlyphCount(run); runGlyphIndex++)
133 | {
134 | // get Glyph & Glyph-data
135 | CFRange thisGlyphRange = CFRangeMake(runGlyphIndex, 1);
136 | CGGlyph glyph;
137 | CGPoint position;
138 | CTRunGetGlyphs(run, thisGlyphRange, &glyph);
139 | CTRunGetPositions(run, thisGlyphRange, &position);
140 |
141 | position.y -= lineOffset;
142 | position.x += penOffset;
143 |
144 | CGPathRef letter = CTFontCreatePathForGlyph(runFont, glyph, NULL);
145 | CGAffineTransform t = CGAffineTransformMakeTranslation(position.x, position.y);
146 | CGPathAddPath(letters, &t, letter);
147 | CGPathRelease(letter);
148 | }
149 | }
150 |
151 | // if the text is justified then release the new justified line we created.
152 | if (alignment == NSTextAlignmentJustified) {
153 | CFRelease(lineRef);
154 | }
155 | }
156 |
157 | free(points);
158 |
159 | CGPathRelease(pathRef);
160 | CFRelease(frame);
161 | CFRelease(framesetter);
162 |
163 | CGRect pathBounds = CGPathGetBoundingBox(letters);
164 | CGAffineTransform transform = CGAffineTransformMakeTranslation(-pathBounds.origin.x, -pathBounds.origin.y);
165 | CGPathRef finalPath = CGPathCreateCopyByTransformingPath(letters, &transform);
166 | CGPathRelease(letters);
167 |
168 | return finalPath;
169 | }
170 |
--------------------------------------------------------------------------------
/TOGlintyStringView/TOGlintyStringView.m:
--------------------------------------------------------------------------------
1 | //
2 | // TOGlintyStringView.m
3 | //
4 | // Copyright 2016 Timothy Oliver. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
21 | // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 |
23 | #import
24 |
25 | #import "TOGlintyStringView.h"
26 | #import "TOGlintyShapeLayer.h"
27 | #import "TOGlintyGradientLayer.h"
28 | #import "ARCGPathFromString.h"
29 |
30 | @interface TOGlintyStringView ()
31 |
32 | @property (nonatomic, strong) TOGlintyGradientLayer *gradientLayer;
33 | @property (nonatomic, strong) TOGlintyShapeLayer *shapeLayer;
34 | @property (nonatomic, strong) CALayer *fillLayer;
35 | @property (nonatomic, strong) CALayer *textLayer;
36 |
37 | @property (nonatomic, assign) CGPathRef textPath;
38 |
39 | #if TARGET_OS_IPHONE
40 | @property (nonatomic, strong, readwrite) UIView *effectView;
41 | #elif TARGET_OS_MAC
42 | @property (nonatomic, strong, readwrite) NSView *effectView;
43 | #endif
44 |
45 | - (CGPathRef)pathForCurrentTextAndFont;
46 | - (CGPathRef)offsetForChevronWithTextPath:(CGPathRef)path offset:(CGPoint *)offset;
47 |
48 | - (void)setUp;
49 | - (void)resetContent;
50 | - (void)sizeLayersForContent;
51 | - (void)renderContent;
52 |
53 | @end
54 |
55 | @implementation TOGlintyStringView
56 |
57 | #pragma mark - View Creation -
58 | - (instancetype)initWithFrame:(CGRect)frame
59 | {
60 | if (self = [super initWithFrame:frame]) {
61 | [self setUp];
62 | }
63 |
64 | return self;
65 | }
66 |
67 | - (instancetype)initWithCoder:(NSCoder *)aDecoder
68 | {
69 | if (self = [super initWithCoder:aDecoder]) {
70 | [self setUp];
71 | }
72 |
73 | return self;
74 | }
75 |
76 | #pragma mark - Set-up -
77 | - (void)setUp
78 | {
79 | self.text = NSLocalizedString(@"slide to unlock", @"");
80 | self.chevronSpacing = 10.0f;
81 |
82 | #if TARGET_OS_IPHONE
83 | self.font = [UIFont systemFontOfSize:24.0f];
84 | #elif TARGET_OS_MAC
85 | self.font = [NSFont systemFontOfSize:24.0f];
86 | #endif
87 |
88 | //Configure this view
89 | #if TARGET_OS_IPHONE
90 | #elif TARGET_OS_MAC
91 | self.wantsLayer = YES;
92 | #endif
93 |
94 | self.layer.allowsGroupOpacity = YES;
95 | self.layer.opaque = NO;
96 | self.opaque = NO;
97 |
98 | // TECHNICALLY a private API, but necessary to allow discrete blend modes on layers
99 | [self.layer setValue:@(NO) forKey:@"allowsGroupBlending"];
100 |
101 | //Create the effect view
102 | if (self.effectView == nil) {
103 | #if TARGET_OS_IPHONE
104 | self.effectView = [[UIView alloc] initWithFrame:CGRectZero];
105 | self.effectView.opaque = NO;;
106 | #elif TARGET_OS_MAC
107 | self.effectView = [[NSView alloc] initWithFrame:CGRectZero];
108 | self.effectView.wantsLayer = YES;
109 | #endif
110 | [self.effectView.layer setValue:@(NO) forKey:@"allowsGroupBlending"];
111 | self.effectView.layer.compositingFilter = @"linearLightBlendMode";
112 | self.effectView.layer.opaque = NO;
113 | [self addSubview:self.effectView];
114 | }
115 |
116 | if (self.shapeLayer == nil) {
117 | self.shapeLayer = [[TOGlintyShapeLayer alloc] init];
118 | [self.effectView.layer addSublayer:self.shapeLayer];
119 | }
120 |
121 | if (self.gradientLayer == nil) {
122 | self.gradientLayer = [[TOGlintyGradientLayer alloc] init];
123 | [self.effectView.layer addSublayer:self.gradientLayer];
124 | }
125 |
126 | if (self.fillLayer == nil) {
127 | self.fillLayer = [[CALayer alloc] init];
128 | self.fillLayer.compositingFilter = @"screenBlendMode";
129 | self.fillLayer.allowsGroupOpacity = NO;
130 | [self.fillLayer setValue:@(NO) forKey:@"allowsGroupBlending"];
131 | self.fillLayer.backgroundColor = CGColorCreate(CGColorSpaceCreateDeviceGray(), (CGFloat []){0.39f, 1.0f});
132 | [self.effectView.layer addSublayer:self.fillLayer];
133 | }
134 |
135 | if (self.textLayer == nil) {
136 | self.textLayer = [[CALayer alloc] init];
137 | self.textLayer.compositingFilter = @"destIn";
138 | self.textLayer.rasterizationScale = 2.0f;
139 | self.textLayer.contentsScale = 2.0f;
140 | self.textLayer.allowsGroupOpacity = YES;
141 | [self.effectView.layer addSublayer:self.textLayer];
142 | }
143 | }
144 |
145 | - (void)didMoveToSuperview
146 | {
147 | [super didMoveToSuperview];
148 | [self resetContent];
149 | [self.gradientLayer startAnimation];
150 | }
151 |
152 | - (void)layoutSubviews
153 | {
154 | CGRect frame = self.effectView.frame;
155 | frame.origin.x = (CGRectGetWidth(self.bounds) - CGRectGetWidth(frame)) * 0.5f;
156 | frame.origin.y = (CGRectGetHeight(self.bounds) - CGRectGetHeight(frame)) * 0.5f;
157 | self.effectView.frame = frame;
158 | }
159 |
160 | - (void)resetContent
161 | {
162 | [self sizeLayersForContent];
163 | [self renderContent];
164 | [self setNeedsLayout];
165 | }
166 |
167 | - (void)sizeLayersForContent
168 | {
169 | //Release our reference to the previous path for now
170 | if (self.textPath) {
171 | CGPathRelease(self.textPath);
172 | self.textPath = nil;
173 | }
174 |
175 | CGPoint offset = CGPointZero;
176 | self.textPath = [self pathForCurrentTextAndFont];
177 |
178 | CGRect bounds = CGPathGetPathBoundingBox(self.textPath);
179 | bounds.size.height = ceilf(bounds.size.height);
180 | bounds.size.width = ceilf(bounds.size.width);
181 |
182 | if (self.chevronImage) {
183 | self.textPath = [self offsetForChevronWithTextPath:self.textPath offset:&offset];
184 |
185 | CGSize chevronSize = [self.chevronImage size];
186 | bounds.size.height = MAX(offset.y + bounds.size.height, chevronSize.height);
187 | bounds.size.width += offset.x;
188 | }
189 |
190 | self.shapeLayer.path = self.textPath;
191 |
192 | bounds.origin = CGPointZero;
193 | self.shapeLayer.frame = bounds;
194 | self.textLayer.frame = bounds;
195 | self.fillLayer.frame = bounds;
196 | self.gradientLayer.frame = bounds;
197 |
198 | self.effectView.frame = bounds;
199 | }
200 |
201 | - (void)renderContent
202 | {
203 | CGImageRef image = nil;
204 | CGSize size = self.textLayer.frame.size;
205 |
206 | #if TARGET_OS_IPHONE
207 | UIGraphicsBeginImageContextWithOptions(size, NO, 0.0f);
208 | CGContextRef context = UIGraphicsGetCurrentContext();
209 | CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
210 | CGContextTranslateCTM(context, 0, size.height);
211 | CGContextScaleCTM(context, 1.0f, -1.0f);
212 | [self.chevronImage drawAtPoint:CGPointZero];
213 | CGContextAddPath(context, self.textPath);
214 | CGContextFillPath(context);
215 | image = [UIGraphicsGetImageFromCurrentImageContext() CGImage];
216 | UIGraphicsEndImageContext();
217 | #elif TARGET_OS_MAC
218 |
219 | NSImage *im = [[NSImage alloc] initWithSize:size];
220 | NSBitmapImageRep *rep = [[NSBitmapImageRep alloc]
221 | initWithBitmapDataPlanes:NULL
222 | pixelsWide:size.width
223 | pixelsHigh:size.height
224 | bitsPerSample:8
225 | samplesPerPixel:4
226 | hasAlpha:YES
227 | isPlanar:NO
228 | colorSpaceName:NSCalibratedRGBColorSpace
229 | bytesPerRow:0
230 | bitsPerPixel:0];
231 |
232 | [im addRepresentation:rep];
233 | [im lockFocus];
234 |
235 | CGColorRef fillColor = CGColorCreate(CGColorSpaceCreateDeviceGray(), (CGFloat []){1.0f, 1.0f});
236 |
237 | CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
238 | CGContextTranslateCTM(context, 0, size.height);
239 | CGContextScaleCTM(context, 1.0f, -1.0f);
240 | CGContextAddPath(context, self.textPath);
241 | CGContextSetFillColorWithColor(context, fillColor);
242 | CGContextFillPath(context);
243 |
244 | [im unlock]
245 |
246 | image = [im CGImageForProposedRect:(CGRect){CGPointZero, size} context:NULL hints:nil];
247 |
248 | #endif
249 |
250 | self.textLayer.contents = (__bridge id)image;
251 | }
252 |
253 | - (CGPathRef)pathForCurrentTextAndFont
254 | {
255 | NSDictionary *attributes = @{NSFontAttributeName : self.font};
256 | NSAttributedString *string = [[NSAttributedString alloc] initWithString:self.text attributes:attributes];
257 | CGPathRef path = CGPathCreateSingleLineStringWithAttributedString(string);
258 |
259 | //Normalize the path to make sure its bounds are properly at 0,0
260 | CGRect frame = CGPathGetPathBoundingBox(path);
261 | CGAffineTransform transform = CGAffineTransformMakeTranslation(-frame.origin.x, -frame.origin.y);
262 | CGPathRef newPath = CGPathCreateCopyByTransformingPath(path, &transform);
263 | CGPathRelease(path);
264 |
265 | return newPath;
266 | }
267 |
268 | - (CGPathRef)offsetForChevronWithTextPath:(CGPathRef)path offset:(CGPoint *)offset
269 | {
270 | if (self.chevronImage == nil) {
271 | return NULL;
272 | }
273 |
274 | CGSize chevronSize = [self.chevronImage size];
275 | CGPoint _offset = CGPointZero;
276 | CGRect bounds = CGPathGetPathBoundingBox(path);
277 |
278 | // offset the text path horizontally by the chevron
279 | _offset.x = fabs(bounds.origin.x) + chevronSize.width + self.chevronSpacing;
280 |
281 | //if the chevron is bigger than the text, offset the text vertically
282 | if (bounds.size.height < chevronSize.height) {
283 | _offset.y = (chevronSize.height - CGRectGetHeight(bounds)) * 0.5f;
284 | }
285 |
286 | *offset = _offset;
287 |
288 | CGAffineTransform transform = CGAffineTransformMakeTranslation(_offset.x, _offset.y);
289 | CGPathRef translatedPath = CGPathCreateCopyByTransformingPath(path, &transform);
290 | CGPathRelease(path);
291 |
292 | return translatedPath;
293 | }
294 |
295 | #pragma mark - Property Methods -
296 | - (void)setChevronImage:(id)chevronImage
297 | {
298 | if (_chevronImage == chevronImage) {
299 | return;
300 | }
301 |
302 | _chevronImage = chevronImage;
303 |
304 | [self resetContent];
305 | }
306 |
307 | #pragma mark - Class Methods -
308 | + (id)defaultChevronImage
309 | {
310 | return (id)[TO_IMAGE_FOR_PLATFORM imageNamed:@"TOGlintyStringViewChevron"];
311 | }
312 |
313 | @end
314 |
--------------------------------------------------------------------------------
/TOGlintyStringViewExample.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 220D4B2E1C5E4C20006426A5 /* TOGlintyStringView.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 220D4B2D1C5E4C20006426A5 /* TOGlintyStringView.xcassets */; };
11 | 2215702D1C5DADAF00AE3649 /* IMG_2875.PNG in Resources */ = {isa = PBXBuildFile; fileRef = 2215702C1C5DADAF00AE3649 /* IMG_2875.PNG */; };
12 | 228A2EE51C5C7537002D8852 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 228A2EDA1C5C7537002D8852 /* AppDelegate.m */; };
13 | 228A2EE61C5C7537002D8852 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 228A2EDB1C5C7537002D8852 /* Assets.xcassets */; };
14 | 228A2EE71C5C7537002D8852 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 228A2EDC1C5C7537002D8852 /* LaunchScreen.storyboard */; };
15 | 228A2EE81C5C7537002D8852 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 228A2EDE1C5C7537002D8852 /* Main.storyboard */; };
16 | 228A2EEB1C5C7537002D8852 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 228A2EE21C5C7537002D8852 /* main.m */; };
17 | 228A2EEC1C5C7537002D8852 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 228A2EE41C5C7537002D8852 /* ViewController.m */; };
18 | 228A2EF01C5C7655002D8852 /* TOGlintyStringView.m in Sources */ = {isa = PBXBuildFile; fileRef = 228A2EEF1C5C7655002D8852 /* TOGlintyStringView.m */; };
19 | 228A2EF31C5C7726002D8852 /* TOGlintyShapeLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 228A2EF21C5C7726002D8852 /* TOGlintyShapeLayer.m */; };
20 | 228A2EF61C5C77A9002D8852 /* TOGlintyGradientLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 228A2EF51C5C77A9002D8852 /* TOGlintyGradientLayer.m */; };
21 | 228A2EFD1C5C8BAD002D8852 /* ARCGPathFromString.m in Sources */ = {isa = PBXBuildFile; fileRef = 228A2EFA1C5C8BAD002D8852 /* ARCGPathFromString.m */; };
22 | /* End PBXBuildFile section */
23 |
24 | /* Begin PBXFileReference section */
25 | 220D4B2D1C5E4C20006426A5 /* TOGlintyStringView.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = TOGlintyStringView.xcassets; path = TOGlintyStringView/TOGlintyStringView.xcassets; sourceTree = ""; };
26 | 2215702C1C5DADAF00AE3649 /* IMG_2875.PNG */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = IMG_2875.PNG; sourceTree = ""; };
27 | 228A2EBE1C5C69B2002D8852 /* TOGlintyStringViewExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TOGlintyStringViewExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
28 | 228A2ED91C5C7537002D8852 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
29 | 228A2EDA1C5C7537002D8852 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
30 | 228A2EDB1C5C7537002D8852 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
31 | 228A2EDD1C5C7537002D8852 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
32 | 228A2EDF1C5C7537002D8852 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
33 | 228A2EE01C5C7537002D8852 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
34 | 228A2EE21C5C7537002D8852 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
35 | 228A2EE31C5C7537002D8852 /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; };
36 | 228A2EE41C5C7537002D8852 /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; };
37 | 228A2EEE1C5C7655002D8852 /* TOGlintyStringView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TOGlintyStringView.h; path = TOGlintyStringView/TOGlintyStringView.h; sourceTree = ""; };
38 | 228A2EEF1C5C7655002D8852 /* TOGlintyStringView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TOGlintyStringView.m; path = TOGlintyStringView/TOGlintyStringView.m; sourceTree = ""; };
39 | 228A2EF11C5C7726002D8852 /* TOGlintyShapeLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TOGlintyShapeLayer.h; path = TOGlintyStringView/TOGlintyShapeLayer.h; sourceTree = ""; };
40 | 228A2EF21C5C7726002D8852 /* TOGlintyShapeLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TOGlintyShapeLayer.m; path = TOGlintyStringView/TOGlintyShapeLayer.m; sourceTree = ""; };
41 | 228A2EF41C5C77A9002D8852 /* TOGlintyGradientLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TOGlintyGradientLayer.h; path = TOGlintyStringView/TOGlintyGradientLayer.h; sourceTree = ""; };
42 | 228A2EF51C5C77A9002D8852 /* TOGlintyGradientLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TOGlintyGradientLayer.m; path = TOGlintyStringView/TOGlintyGradientLayer.m; sourceTree = ""; };
43 | 228A2EF91C5C8BAD002D8852 /* ARCGPathFromString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ARCGPathFromString.h; path = TOGlintyStringView/ARCGPathFromString.h; sourceTree = ""; };
44 | 228A2EFA1C5C8BAD002D8852 /* ARCGPathFromString.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ARCGPathFromString.m; path = TOGlintyStringView/ARCGPathFromString.m; sourceTree = ""; };
45 | /* End PBXFileReference section */
46 |
47 | /* Begin PBXFrameworksBuildPhase section */
48 | 228A2EBB1C5C69B2002D8852 /* Frameworks */ = {
49 | isa = PBXFrameworksBuildPhase;
50 | buildActionMask = 2147483647;
51 | files = (
52 | );
53 | runOnlyForDeploymentPostprocessing = 0;
54 | };
55 | /* End PBXFrameworksBuildPhase section */
56 |
57 | /* Begin PBXGroup section */
58 | 228A2EB51C5C69B2002D8852 = {
59 | isa = PBXGroup;
60 | children = (
61 | 228A2EED1C5C7604002D8852 /* TOGlintyStringView */,
62 | 228A2ED81C5C7537002D8852 /* TOGlintyStringViewExample */,
63 | 228A2EBF1C5C69B2002D8852 /* Products */,
64 | );
65 | sourceTree = "";
66 | };
67 | 228A2EBF1C5C69B2002D8852 /* Products */ = {
68 | isa = PBXGroup;
69 | children = (
70 | 228A2EBE1C5C69B2002D8852 /* TOGlintyStringViewExample.app */,
71 | );
72 | name = Products;
73 | sourceTree = "";
74 | };
75 | 228A2ED81C5C7537002D8852 /* TOGlintyStringViewExample */ = {
76 | isa = PBXGroup;
77 | children = (
78 | 2215702C1C5DADAF00AE3649 /* IMG_2875.PNG */,
79 | 228A2ED91C5C7537002D8852 /* AppDelegate.h */,
80 | 228A2EDA1C5C7537002D8852 /* AppDelegate.m */,
81 | 228A2EDB1C5C7537002D8852 /* Assets.xcassets */,
82 | 228A2EDC1C5C7537002D8852 /* LaunchScreen.storyboard */,
83 | 228A2EDE1C5C7537002D8852 /* Main.storyboard */,
84 | 228A2EE01C5C7537002D8852 /* Info.plist */,
85 | 228A2EE21C5C7537002D8852 /* main.m */,
86 | 228A2EE31C5C7537002D8852 /* ViewController.h */,
87 | 228A2EE41C5C7537002D8852 /* ViewController.m */,
88 | );
89 | path = TOGlintyStringViewExample;
90 | sourceTree = "";
91 | };
92 | 228A2EED1C5C7604002D8852 /* TOGlintyStringView */ = {
93 | isa = PBXGroup;
94 | children = (
95 | 228A2EEE1C5C7655002D8852 /* TOGlintyStringView.h */,
96 | 228A2EEF1C5C7655002D8852 /* TOGlintyStringView.m */,
97 | 228A2EF11C5C7726002D8852 /* TOGlintyShapeLayer.h */,
98 | 228A2EF21C5C7726002D8852 /* TOGlintyShapeLayer.m */,
99 | 228A2EF41C5C77A9002D8852 /* TOGlintyGradientLayer.h */,
100 | 228A2EF51C5C77A9002D8852 /* TOGlintyGradientLayer.m */,
101 | 228A2EF91C5C8BAD002D8852 /* ARCGPathFromString.h */,
102 | 228A2EFA1C5C8BAD002D8852 /* ARCGPathFromString.m */,
103 | 220D4B2D1C5E4C20006426A5 /* TOGlintyStringView.xcassets */,
104 | );
105 | name = TOGlintyStringView;
106 | sourceTree = "";
107 | };
108 | /* End PBXGroup section */
109 |
110 | /* Begin PBXNativeTarget section */
111 | 228A2EBD1C5C69B2002D8852 /* TOGlintyStringViewExample */ = {
112 | isa = PBXNativeTarget;
113 | buildConfigurationList = 228A2ED51C5C69B2002D8852 /* Build configuration list for PBXNativeTarget "TOGlintyStringViewExample" */;
114 | buildPhases = (
115 | 228A2EBA1C5C69B2002D8852 /* Sources */,
116 | 228A2EBB1C5C69B2002D8852 /* Frameworks */,
117 | 228A2EBC1C5C69B2002D8852 /* Resources */,
118 | );
119 | buildRules = (
120 | );
121 | dependencies = (
122 | );
123 | name = TOGlintyStringViewExample;
124 | productName = TOGlintyStringView;
125 | productReference = 228A2EBE1C5C69B2002D8852 /* TOGlintyStringViewExample.app */;
126 | productType = "com.apple.product-type.application";
127 | };
128 | /* End PBXNativeTarget section */
129 |
130 | /* Begin PBXProject section */
131 | 228A2EB61C5C69B2002D8852 /* Project object */ = {
132 | isa = PBXProject;
133 | attributes = {
134 | LastUpgradeCheck = 0730;
135 | ORGANIZATIONNAME = "Tim Oliver";
136 | TargetAttributes = {
137 | 228A2EBD1C5C69B2002D8852 = {
138 | CreatedOnToolsVersion = 7.2;
139 | };
140 | };
141 | };
142 | buildConfigurationList = 228A2EB91C5C69B2002D8852 /* Build configuration list for PBXProject "TOGlintyStringViewExample" */;
143 | compatibilityVersion = "Xcode 3.2";
144 | developmentRegion = English;
145 | hasScannedForEncodings = 0;
146 | knownRegions = (
147 | en,
148 | Base,
149 | );
150 | mainGroup = 228A2EB51C5C69B2002D8852;
151 | productRefGroup = 228A2EBF1C5C69B2002D8852 /* Products */;
152 | projectDirPath = "";
153 | projectRoot = "";
154 | targets = (
155 | 228A2EBD1C5C69B2002D8852 /* TOGlintyStringViewExample */,
156 | );
157 | };
158 | /* End PBXProject section */
159 |
160 | /* Begin PBXResourcesBuildPhase section */
161 | 228A2EBC1C5C69B2002D8852 /* Resources */ = {
162 | isa = PBXResourcesBuildPhase;
163 | buildActionMask = 2147483647;
164 | files = (
165 | 2215702D1C5DADAF00AE3649 /* IMG_2875.PNG in Resources */,
166 | 220D4B2E1C5E4C20006426A5 /* TOGlintyStringView.xcassets in Resources */,
167 | 228A2EE81C5C7537002D8852 /* Main.storyboard in Resources */,
168 | 228A2EE61C5C7537002D8852 /* Assets.xcassets in Resources */,
169 | 228A2EE71C5C7537002D8852 /* LaunchScreen.storyboard in Resources */,
170 | );
171 | runOnlyForDeploymentPostprocessing = 0;
172 | };
173 | /* End PBXResourcesBuildPhase section */
174 |
175 | /* Begin PBXSourcesBuildPhase section */
176 | 228A2EBA1C5C69B2002D8852 /* Sources */ = {
177 | isa = PBXSourcesBuildPhase;
178 | buildActionMask = 2147483647;
179 | files = (
180 | 228A2EEC1C5C7537002D8852 /* ViewController.m in Sources */,
181 | 228A2EF31C5C7726002D8852 /* TOGlintyShapeLayer.m in Sources */,
182 | 228A2EEB1C5C7537002D8852 /* main.m in Sources */,
183 | 228A2EFD1C5C8BAD002D8852 /* ARCGPathFromString.m in Sources */,
184 | 228A2EF61C5C77A9002D8852 /* TOGlintyGradientLayer.m in Sources */,
185 | 228A2EE51C5C7537002D8852 /* AppDelegate.m in Sources */,
186 | 228A2EF01C5C7655002D8852 /* TOGlintyStringView.m in Sources */,
187 | );
188 | runOnlyForDeploymentPostprocessing = 0;
189 | };
190 | /* End PBXSourcesBuildPhase section */
191 |
192 | /* Begin PBXVariantGroup section */
193 | 228A2EDC1C5C7537002D8852 /* LaunchScreen.storyboard */ = {
194 | isa = PBXVariantGroup;
195 | children = (
196 | 228A2EDD1C5C7537002D8852 /* Base */,
197 | );
198 | name = LaunchScreen.storyboard;
199 | sourceTree = "";
200 | };
201 | 228A2EDE1C5C7537002D8852 /* Main.storyboard */ = {
202 | isa = PBXVariantGroup;
203 | children = (
204 | 228A2EDF1C5C7537002D8852 /* Base */,
205 | );
206 | name = Main.storyboard;
207 | sourceTree = "";
208 | };
209 | /* End PBXVariantGroup section */
210 |
211 | /* Begin XCBuildConfiguration section */
212 | 228A2ED31C5C69B2002D8852 /* Debug */ = {
213 | isa = XCBuildConfiguration;
214 | buildSettings = {
215 | ALWAYS_SEARCH_USER_PATHS = NO;
216 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
217 | CLANG_CXX_LIBRARY = "libc++";
218 | CLANG_ENABLE_MODULES = YES;
219 | CLANG_ENABLE_OBJC_ARC = YES;
220 | CLANG_WARN_BOOL_CONVERSION = YES;
221 | CLANG_WARN_CONSTANT_CONVERSION = YES;
222 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
223 | CLANG_WARN_EMPTY_BODY = YES;
224 | CLANG_WARN_ENUM_CONVERSION = YES;
225 | CLANG_WARN_INT_CONVERSION = YES;
226 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
227 | CLANG_WARN_UNREACHABLE_CODE = YES;
228 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
229 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
230 | COPY_PHASE_STRIP = NO;
231 | DEBUG_INFORMATION_FORMAT = dwarf;
232 | ENABLE_STRICT_OBJC_MSGSEND = YES;
233 | ENABLE_TESTABILITY = YES;
234 | GCC_C_LANGUAGE_STANDARD = gnu99;
235 | GCC_DYNAMIC_NO_PIC = NO;
236 | GCC_NO_COMMON_BLOCKS = YES;
237 | GCC_OPTIMIZATION_LEVEL = 0;
238 | GCC_PREPROCESSOR_DEFINITIONS = (
239 | "DEBUG=1",
240 | "$(inherited)",
241 | );
242 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
243 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
244 | GCC_WARN_UNDECLARED_SELECTOR = YES;
245 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
246 | GCC_WARN_UNUSED_FUNCTION = YES;
247 | GCC_WARN_UNUSED_VARIABLE = YES;
248 | IPHONEOS_DEPLOYMENT_TARGET = 9.2;
249 | MTL_ENABLE_DEBUG_INFO = YES;
250 | ONLY_ACTIVE_ARCH = YES;
251 | SDKROOT = iphoneos;
252 | TARGETED_DEVICE_FAMILY = "1,2";
253 | };
254 | name = Debug;
255 | };
256 | 228A2ED41C5C69B2002D8852 /* Release */ = {
257 | isa = XCBuildConfiguration;
258 | buildSettings = {
259 | ALWAYS_SEARCH_USER_PATHS = NO;
260 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
261 | CLANG_CXX_LIBRARY = "libc++";
262 | CLANG_ENABLE_MODULES = YES;
263 | CLANG_ENABLE_OBJC_ARC = YES;
264 | CLANG_WARN_BOOL_CONVERSION = YES;
265 | CLANG_WARN_CONSTANT_CONVERSION = YES;
266 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
267 | CLANG_WARN_EMPTY_BODY = YES;
268 | CLANG_WARN_ENUM_CONVERSION = YES;
269 | CLANG_WARN_INT_CONVERSION = YES;
270 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
271 | CLANG_WARN_UNREACHABLE_CODE = YES;
272 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
273 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
274 | COPY_PHASE_STRIP = NO;
275 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
276 | ENABLE_NS_ASSERTIONS = NO;
277 | ENABLE_STRICT_OBJC_MSGSEND = YES;
278 | GCC_C_LANGUAGE_STANDARD = gnu99;
279 | GCC_NO_COMMON_BLOCKS = YES;
280 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
281 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
282 | GCC_WARN_UNDECLARED_SELECTOR = YES;
283 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
284 | GCC_WARN_UNUSED_FUNCTION = YES;
285 | GCC_WARN_UNUSED_VARIABLE = YES;
286 | IPHONEOS_DEPLOYMENT_TARGET = 9.2;
287 | MTL_ENABLE_DEBUG_INFO = NO;
288 | SDKROOT = iphoneos;
289 | TARGETED_DEVICE_FAMILY = "1,2";
290 | VALIDATE_PRODUCT = YES;
291 | };
292 | name = Release;
293 | };
294 | 228A2ED61C5C69B2002D8852 /* Debug */ = {
295 | isa = XCBuildConfiguration;
296 | buildSettings = {
297 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
298 | FRAMEWORK_SEARCH_PATHS = (
299 | "$(inherited)",
300 | "$(PROJECT_DIR)/TOGlintyStringViewExample",
301 | "\"$(SYSTEM_APPS_DIR)/Reveal.app/Contents/SharedSupport/iOS-Libraries\"",
302 | );
303 | INFOPLIST_FILE = TOGlintyStringViewExample/Info.plist;
304 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
305 | PRODUCT_BUNDLE_IDENTIFIER = co.timoliver.TOGlintyStringView;
306 | PRODUCT_NAME = TOGlintyStringViewExample;
307 | };
308 | name = Debug;
309 | };
310 | 228A2ED71C5C69B2002D8852 /* Release */ = {
311 | isa = XCBuildConfiguration;
312 | buildSettings = {
313 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
314 | FRAMEWORK_SEARCH_PATHS = (
315 | "$(inherited)",
316 | "$(PROJECT_DIR)/TOGlintyStringViewExample",
317 | "\"$(SYSTEM_APPS_DIR)/Reveal.app/Contents/SharedSupport/iOS-Libraries\"",
318 | );
319 | INFOPLIST_FILE = TOGlintyStringViewExample/Info.plist;
320 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
321 | PRODUCT_BUNDLE_IDENTIFIER = co.timoliver.TOGlintyStringView;
322 | PRODUCT_NAME = TOGlintyStringViewExample;
323 | };
324 | name = Release;
325 | };
326 | /* End XCBuildConfiguration section */
327 |
328 | /* Begin XCConfigurationList section */
329 | 228A2EB91C5C69B2002D8852 /* Build configuration list for PBXProject "TOGlintyStringViewExample" */ = {
330 | isa = XCConfigurationList;
331 | buildConfigurations = (
332 | 228A2ED31C5C69B2002D8852 /* Debug */,
333 | 228A2ED41C5C69B2002D8852 /* Release */,
334 | );
335 | defaultConfigurationIsVisible = 0;
336 | defaultConfigurationName = Release;
337 | };
338 | 228A2ED51C5C69B2002D8852 /* Build configuration list for PBXNativeTarget "TOGlintyStringViewExample" */ = {
339 | isa = XCConfigurationList;
340 | buildConfigurations = (
341 | 228A2ED61C5C69B2002D8852 /* Debug */,
342 | 228A2ED71C5C69B2002D8852 /* Release */,
343 | );
344 | defaultConfigurationIsVisible = 0;
345 | defaultConfigurationName = Release;
346 | };
347 | /* End XCConfigurationList section */
348 | };
349 | rootObject = 228A2EB61C5C69B2002D8852 /* Project object */;
350 | }
351 |
--------------------------------------------------------------------------------