├── .gitignore
├── Binary Quantized Embeddings Search
├── README.md
└── rag.py
├── Blur Effects ObjC
├── Blur Effects.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── Blur Effects
│ ├── AppDelegate.h
│ ├── AppDelegate.m
│ ├── Assets.xcassets
│ ├── AccentColor.colorset
│ │ └── Contents.json
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ ├── Contents.json
│ └── Grass.imageset
│ │ ├── Contents.json
│ │ └── Grass.jpeg
│ ├── Base.lproj
│ └── LaunchScreen.storyboard
│ ├── Info.plist
│ ├── SceneDelegate.h
│ ├── SceneDelegate.m
│ ├── ViewController.h
│ ├── ViewController.m
│ └── main.m
├── CAGradientLayer Example ObjC
├── CAGradientLayer Example ObjC.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── CAGradientLayer Example ObjC
│ ├── AppDelegate.h
│ ├── AppDelegate.m
│ ├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── Contents.json
│ ├── Base.lproj
│ └── LaunchScreen.storyboard
│ ├── Info.plist
│ ├── KHGradientView.h
│ ├── KHGradientView.m
│ ├── SceneDelegate.h
│ ├── SceneDelegate.m
│ ├── ViewController.h
│ ├── ViewController.m
│ └── main.m
├── CAGradientLayer Example Swift
├── CAGradientLayer Example Swift.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── CAGradientLayer Example Swift
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── Contents.json
│ ├── Base.lproj
│ └── LaunchScreen.storyboard
│ ├── Info.plist
│ ├── KHGradientView.swift
│ ├── SceneDelegate.swift
│ └── ViewController.swift
├── External Shadow ObjC
├── External Shadow.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── External Shadow
│ ├── AppDelegate.h
│ ├── AppDelegate.m
│ ├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ ├── Checkerboard.imageset
│ │ ├── Checkerboard.png
│ │ └── Contents.json
│ └── Contents.json
│ ├── Base.lproj
│ └── LaunchScreen.storyboard
│ ├── Info.plist
│ ├── SceneDelegate.h
│ ├── SceneDelegate.m
│ ├── ViewController.h
│ ├── ViewController.m
│ └── main.m
├── External Shadow Swift
├── External Shadow Swift.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── External Shadow Swift
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ ├── Checkerboard.imageset
│ │ ├── Checkerboard.png
│ │ └── Contents.json
│ └── Contents.json
│ ├── Base.lproj
│ └── LaunchScreen.storyboard
│ ├── Info.plist
│ ├── SceneDelegate.swift
│ └── ViewController.swift
├── Illustrations
└── Illustrations
│ ├── Illustrations.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
│ └── Illustrations
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── AccentColor.colorset
│ │ └── Contents.json
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ ├── Contents.json
│ └── arrow.clockwise.custom.imageset
│ │ ├── Contents.json
│ │ └── arrow.clockwise.custom.svg
│ ├── Base.lproj
│ └── LaunchScreen.storyboard
│ ├── Demos
│ ├── Anchor Points
│ │ ├── AnchorPointDemoViewController.swift
│ │ └── KHVisualiseView.swift
│ └── DemoViewController.swift
│ ├── Illustrations.entitlements
│ ├── Info.plist
│ ├── MP4
│ ├── MP4Exporter.swift
│ └── MP4Recorder.swift
│ ├── SceneDelegate.swift
│ └── ViewController.swift
├── LICENSE
├── ObjC Live Preview
├── Live Preview
│ ├── AppDelegate.h
│ ├── AppDelegate.m
│ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ └── Contents.json
│ │ └── Contents.json
│ ├── Base.lproj
│ │ └── LaunchScreen.storyboard
│ ├── Info.plist
│ ├── KHGradientView.h
│ ├── KHGradientView.m
│ ├── ObjC Live Preview-Bridging-Header.h
│ ├── SceneDelegate.h
│ ├── SceneDelegate.m
│ ├── SwiftUIView.swift
│ ├── ViewController.h
│ ├── ViewController.m
│ └── main.m
└── ObjC Live Preview.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── Photo Picker ObjC
├── Photo Picker ObjC.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── Photo Picker ObjC
│ ├── AppDelegate.h
│ ├── AppDelegate.m
│ ├── Assets.xcassets
│ ├── AccentColor.colorset
│ │ └── Contents.json
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── Contents.json
│ ├── Base.lproj
│ └── LaunchScreen.storyboard
│ ├── Info.plist
│ ├── SceneDelegate.h
│ ├── SceneDelegate.m
│ ├── ViewController.h
│ ├── ViewController.m
│ └── main.m
├── Photo Picker Swift
├── Photo Picker Swift.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── Photo Picker Swift
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── AccentColor.colorset
│ │ └── Contents.json
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── Contents.json
│ ├── Base.lproj
│ └── LaunchScreen.storyboard
│ ├── Info.plist
│ ├── SceneDelegate.swift
│ └── ViewController.swift
├── README.md
├── Read Write Image Metadata ObjC
├── Read Write Image Metadata ObjC.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── Read Write Image Metadata ObjC
│ ├── AppDelegate.h
│ ├── AppDelegate.m
│ ├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── Contents.json
│ ├── Base.lproj
│ └── LaunchScreen.storyboard
│ ├── Info.plist
│ ├── Read Write Image Metadata ObjC.entitlements
│ ├── SceneDelegate.h
│ ├── SceneDelegate.m
│ ├── ViewController.h
│ ├── ViewController.m
│ └── main.m
├── Read Write Image Metadata Swift
├── Read Write Image Metadata Swift.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── Read Write Image Metadata Swift
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── Contents.json
│ ├── Base.lproj
│ └── LaunchScreen.storyboard
│ ├── Info.plist
│ ├── Read Write Image Metadata Swift.entitlements
│ ├── SceneDelegate.swift
│ └── ViewController.swift
├── macCatalyst-titlebar-tabbar-objc
├── Titlebar-TabBar.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── xcuserdata
│ │ └── kylehowells.xcuserdatad
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
└── Titlebar-TabBar
│ ├── AppDelegate.h
│ ├── AppDelegate.m
│ ├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ ├── Contents.json
│ ├── first.imageset
│ │ ├── Contents.json
│ │ └── first.pdf
│ └── second.imageset
│ │ ├── Contents.json
│ │ └── second.pdf
│ ├── Base.lproj
│ └── LaunchScreen.storyboard
│ ├── FirstViewController.h
│ ├── FirstViewController.m
│ ├── Info.plist
│ ├── SceneDelegate.h
│ ├── SceneDelegate.m
│ ├── SecondViewController.h
│ ├── SecondViewController.m
│ ├── Titlebar-TabBar.entitlements
│ └── main.m
└── macCatalyst-titlebar-tabbar-swift
├── Titlebar-TabBar.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── xcuserdata
│ └── kylehowells.xcuserdatad
│ └── xcschemes
│ └── xcschememanagement.plist
└── Titlebar-TabBar
├── AppDelegate.swift
├── Assets.xcassets
├── AppIcon.appiconset
│ └── Contents.json
├── Contents.json
├── first.imageset
│ ├── Contents.json
│ └── first.pdf
└── second.imageset
│ ├── Contents.json
│ └── second.pdf
├── Base.lproj
└── LaunchScreen.storyboard
├── FirstViewController.swift
├── Info.plist
├── SceneDelegate.swift
├── SecondViewController.swift
└── Titlebar-TabBar.entitlements
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## User settings
6 | xcuserdata/*
7 | xcuserdata/
8 | xcuserdata
9 |
10 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
11 | *.xcscmblueprint
12 | *.xccheckout
13 |
14 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
15 | build/
16 | DerivedData/
17 | *.moved-aside
18 | *.pbxuser
19 | !default.pbxuser
20 | *.mode1v3
21 | !default.mode1v3
22 | *.mode2v3
23 | !default.mode2v3
24 | *.perspectivev3
25 | !default.perspectivev3
26 |
27 | ## Obj-C/Swift specific
28 | *.hmap
29 |
30 | ## App packaging
31 | *.ipa
32 | *.dSYM.zip
33 | *.dSYM
34 |
35 | *.xcuserstate
36 | *.xcuserdatad
37 | .DS_Store
38 | Binary Quantized Embeddings Search/rag.db
39 |
--------------------------------------------------------------------------------
/Binary Quantized Embeddings Search/README.md:
--------------------------------------------------------------------------------
1 | # Demo Semantic Text Search Using Binary Embeddings
2 |
3 | This project demonstrates semantic text search using binary quantized embeddings for efficient storage and retrieval.
4 |
5 | Blog post: [Binary Quantized Embeddings - How to use binary quantized embeddings for semantic text search](https://ikyle.me/blog/2025/binary-quantized-embeddings)
6 |
7 | ## Command Line Interface Usage
8 |
9 | ### Loading Text Segments
10 |
11 | ```bash
12 | # Load with auto-generated ID
13 | uv run rag.py load --text "This is a sample text to be stored in the database"
14 |
15 | # Load with custom ID and metadata
16 | uv run rag.py load --id "custom-id" --text "Another sample with a custom ID" --metadata '{"source": "example", "date": "2023-07-01"}'
17 | ```
18 |
19 | ### Searching for Similar Text
20 |
21 | ```bash
22 | # Basic search with default limit (5 results)
23 | python rag.py search "Find text similar to this query"
24 |
25 | # Search with custom result limit
26 | python rag.py search "Another search query" --limit 10
27 | ```
28 |
29 | ### Removing Segments
30 |
31 | ```bash
32 | # Remove a segment by ID
33 | python rag.py remove --id "custom-id"
34 | ```
35 |
--------------------------------------------------------------------------------
/Blur Effects ObjC/Blur Effects.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Blur Effects ObjC/Blur Effects.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Blur Effects ObjC/Blur Effects/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // Blur Effects
4 | //
5 | // Created by Kyle Howells on 01/04/2022.
6 | //
7 |
8 | #import
9 |
10 | @interface AppDelegate : UIResponder
11 |
12 |
13 | @end
14 |
15 |
--------------------------------------------------------------------------------
/Blur Effects ObjC/Blur Effects/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // Blur Effects
4 | //
5 | // Created by Kyle Howells on 01/04/2022.
6 | //
7 |
8 | #import "AppDelegate.h"
9 |
10 | @interface AppDelegate ()
11 |
12 | @end
13 |
14 | @implementation AppDelegate
15 |
16 |
17 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
18 | // Override point for customization after application launch.
19 | return YES;
20 | }
21 |
22 |
23 | #pragma mark - UISceneSession lifecycle
24 |
25 |
26 | - (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options {
27 | // Called when a new scene session is being created.
28 | // Use this method to select a configuration to create the new scene with.
29 | return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role];
30 | }
31 |
32 |
33 | - (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet *)sceneSessions {
34 | // Called when the user discards a scene session.
35 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
36 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
37 | }
38 |
39 |
40 | @end
41 |
--------------------------------------------------------------------------------
/Blur Effects ObjC/Blur Effects/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Blur Effects ObjC/Blur Effects/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/Blur Effects ObjC/Blur Effects/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Blur Effects ObjC/Blur Effects/Assets.xcassets/Grass.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Grass.jpeg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Blur Effects ObjC/Blur Effects/Assets.xcassets/Grass.imageset/Grass.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kylehowells/ikyle.me-code-examples/502052a2e5da56c6fdb78148ea5ac7e132efab32/Blur Effects ObjC/Blur Effects/Assets.xcassets/Grass.imageset/Grass.jpeg
--------------------------------------------------------------------------------
/Blur Effects ObjC/Blur Effects/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 |
--------------------------------------------------------------------------------
/Blur Effects ObjC/Blur Effects/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | UIApplicationSceneManifest
6 |
7 | UIApplicationSupportsMultipleScenes
8 |
9 | UISceneConfigurations
10 |
11 | UIWindowSceneSessionRoleApplication
12 |
13 |
14 | UISceneConfigurationName
15 | Default Configuration
16 | UISceneDelegateClassName
17 | SceneDelegate
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/Blur Effects ObjC/Blur Effects/SceneDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.h
3 | // Blur Effects
4 | //
5 | // Created by Kyle Howells on 01/04/2022.
6 | //
7 |
8 | #import
9 |
10 | @interface SceneDelegate : UIResponder
11 |
12 | @property (strong, nonatomic) UIWindow * window;
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/Blur Effects ObjC/Blur Effects/SceneDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.m
3 | // Blur Effects
4 | //
5 | // Created by Kyle Howells on 01/04/2022.
6 | //
7 |
8 | #import "SceneDelegate.h"
9 | #import "ViewController.h"
10 |
11 | @interface SceneDelegate ()
12 |
13 | @end
14 |
15 |
16 | @implementation SceneDelegate
17 |
18 | - (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
19 | self.window = [[UIWindow alloc] initWithWindowScene:(UIWindowScene*)scene];
20 | self.window.rootViewController = [[ViewController alloc] init];
21 | [self.window makeKeyAndVisible];
22 | }
23 |
24 | - (void)sceneDidDisconnect:(UIScene *)scene {
25 | // Called as the scene is being released by the system.
26 | // This occurs shortly after the scene enters the background, or when its session is discarded.
27 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
28 | // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
29 | }
30 |
31 |
32 | - (void)sceneDidBecomeActive:(UIScene *)scene {
33 | // Called when the scene has moved from an inactive state to an active state.
34 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
35 | }
36 |
37 |
38 | - (void)sceneWillResignActive:(UIScene *)scene {
39 | // Called when the scene will move from an active state to an inactive state.
40 | // This may occur due to temporary interruptions (ex. an incoming phone call).
41 | }
42 |
43 |
44 | - (void)sceneWillEnterForeground:(UIScene *)scene {
45 | // Called as the scene transitions from the background to the foreground.
46 | // Use this method to undo the changes made on entering the background.
47 | }
48 |
49 |
50 | - (void)sceneDidEnterBackground:(UIScene *)scene {
51 | // Called as the scene transitions from the foreground to the background.
52 | // Use this method to save data, release shared resources, and store enough scene-specific state information
53 | // to restore the scene back to its current state.
54 | }
55 |
56 |
57 | @end
58 |
--------------------------------------------------------------------------------
/Blur Effects ObjC/Blur Effects/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // Blur Effects
4 | //
5 | // Created by Kyle Howells on 01/04/2022.
6 | //
7 |
8 | #import
9 |
10 | @interface ViewController : UIViewController
11 |
12 |
13 | @end
14 |
15 |
--------------------------------------------------------------------------------
/Blur Effects ObjC/Blur Effects/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // Blur Effects
4 | //
5 | // Created by Kyle Howells on 01/04/2022.
6 | //
7 |
8 | #import
9 | #import "AppDelegate.h"
10 |
11 | int main(int argc, char * argv[]) {
12 | NSString * appDelegateClassName;
13 | @autoreleasepool {
14 | // Setup code that might create autoreleased objects goes here.
15 | appDelegateClassName = NSStringFromClass([AppDelegate class]);
16 | }
17 | return UIApplicationMain(argc, argv, nil, appDelegateClassName);
18 | }
19 |
--------------------------------------------------------------------------------
/CAGradientLayer Example ObjC/CAGradientLayer Example ObjC.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/CAGradientLayer Example ObjC/CAGradientLayer Example ObjC.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/CAGradientLayer Example ObjC/CAGradientLayer Example ObjC/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // CAGradientLayer Example ObjC
4 | //
5 | // Created by Kyle Howells on 14/06/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/CAGradientLayer Example ObjC/CAGradientLayer Example ObjC/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // CAGradientLayer Example ObjC
4 | //
5 | // Created by Kyle Howells on 14/06/2020.
6 | // Copyright © 2020 Kyle Howells. 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 | #pragma mark - UISceneSession lifecycle
25 |
26 |
27 | - (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options {
28 | // Called when a new scene session is being created.
29 | // Use this method to select a configuration to create the new scene with.
30 | return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role];
31 | }
32 |
33 |
34 | - (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet *)sceneSessions {
35 | // Called when the user discards a scene session.
36 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
37 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
38 | }
39 |
40 |
41 | @end
42 |
--------------------------------------------------------------------------------
/CAGradientLayer Example ObjC/CAGradientLayer Example ObjC/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/CAGradientLayer Example ObjC/CAGradientLayer Example ObjC/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/CAGradientLayer Example ObjC/CAGradientLayer Example ObjC/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 |
--------------------------------------------------------------------------------
/CAGradientLayer Example ObjC/CAGradientLayer Example ObjC/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 | UISceneConfigurations
28 |
29 | UIWindowSceneSessionRoleApplication
30 |
31 |
32 | UISceneConfigurationName
33 | Default Configuration
34 | UISceneDelegateClassName
35 | SceneDelegate
36 |
37 |
38 |
39 |
40 | UILaunchStoryboardName
41 | LaunchScreen
42 | UIRequiredDeviceCapabilities
43 |
44 | armv7
45 |
46 | UISupportedInterfaceOrientations
47 |
48 | UIInterfaceOrientationPortrait
49 | UIInterfaceOrientationLandscapeLeft
50 | UIInterfaceOrientationLandscapeRight
51 |
52 | UISupportedInterfaceOrientations~ipad
53 |
54 | UIInterfaceOrientationPortrait
55 | UIInterfaceOrientationPortraitUpsideDown
56 | UIInterfaceOrientationLandscapeLeft
57 | UIInterfaceOrientationLandscapeRight
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/CAGradientLayer Example ObjC/CAGradientLayer Example ObjC/KHGradientView.h:
--------------------------------------------------------------------------------
1 | //
2 | // KHGradientView.h
3 | //
4 | // Created by Kyle Howells on 09/06/2020.
5 | // Copyright © 2020 Kyle Howells. All rights reserved.
6 | //
7 |
8 | #import
9 | @import QuartzCore;
10 |
11 | @interface KHGradientView : UIView
12 | @property(nonatomic, readonly, strong) CAGradientLayer *layer;
13 | //-(CAGradientLayer*)gradientLayer;
14 | @end
15 |
--------------------------------------------------------------------------------
/CAGradientLayer Example ObjC/CAGradientLayer Example ObjC/KHGradientView.m:
--------------------------------------------------------------------------------
1 | //
2 | // KHGradientView.m
3 | //
4 | // Created by Kyle Howells on 09/06/2020.
5 | // Copyright © 2020 Kyle Howells. All rights reserved.
6 | //
7 |
8 | #import "KHGradientView.h"
9 |
10 | @implementation KHGradientView
11 | @dynamic layer;
12 |
13 | +(Class)layerClass{
14 | return [CAGradientLayer class];
15 | }
16 |
17 | //-(CAGradientLayer*)gradientLayer{
18 | // return (CAGradientLayer*)[self layer];
19 | //}
20 | @end
21 |
--------------------------------------------------------------------------------
/CAGradientLayer Example ObjC/CAGradientLayer Example ObjC/SceneDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.h
3 | // CAGradientLayer Example ObjC
4 | //
5 | // Created by Kyle Howells on 14/06/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface SceneDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow * window;
14 |
15 | @end
16 |
17 |
--------------------------------------------------------------------------------
/CAGradientLayer Example ObjC/CAGradientLayer Example ObjC/SceneDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.m
3 | // CAGradientLayer Example ObjC
4 | //
5 | // Created by Kyle Howells on 14/06/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | #import "SceneDelegate.h"
10 | #import "ViewController.h"
11 |
12 | @interface SceneDelegate ()
13 | @end
14 |
15 | @implementation SceneDelegate
16 |
17 | - (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
18 | self.window = [[UIWindow alloc] initWithWindowScene:(UIWindowScene*)scene];
19 | self.window.rootViewController = [[ViewController alloc] init];
20 | [self.window makeKeyAndVisible];
21 | }
22 |
23 |
24 | - (void)sceneDidDisconnect:(UIScene *)scene {
25 | // Called as the scene is being released by the system.
26 | // This occurs shortly after the scene enters the background, or when its session is discarded.
27 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
28 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
29 | }
30 |
31 |
32 | - (void)sceneDidBecomeActive:(UIScene *)scene {
33 | // Called when the scene has moved from an inactive state to an active state.
34 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
35 | }
36 |
37 |
38 | - (void)sceneWillResignActive:(UIScene *)scene {
39 | // Called when the scene will move from an active state to an inactive state.
40 | // This may occur due to temporary interruptions (ex. an incoming phone call).
41 | }
42 |
43 |
44 | - (void)sceneWillEnterForeground:(UIScene *)scene {
45 | // Called as the scene transitions from the background to the foreground.
46 | // Use this method to undo the changes made on entering the background.
47 | }
48 |
49 |
50 | - (void)sceneDidEnterBackground:(UIScene *)scene {
51 | // Called as the scene transitions from the foreground to the background.
52 | // Use this method to save data, release shared resources, and store enough scene-specific state information
53 | // to restore the scene back to its current state.
54 | }
55 |
56 |
57 | @end
58 |
--------------------------------------------------------------------------------
/CAGradientLayer Example ObjC/CAGradientLayer Example ObjC/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // CAGradientLayer Example ObjC
4 | //
5 | // Created by Kyle Howells on 14/06/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ViewController : UIViewController
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/CAGradientLayer Example ObjC/CAGradientLayer Example ObjC/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // CAGradientLayer Example ObjC
4 | //
5 | // Created by Kyle Howells on 14/06/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | NSString * appDelegateClassName;
14 | @autoreleasepool {
15 | // Setup code that might create autoreleased objects goes here.
16 | appDelegateClassName = NSStringFromClass([AppDelegate class]);
17 | }
18 | return UIApplicationMain(argc, argv, nil, appDelegateClassName);
19 | }
20 |
--------------------------------------------------------------------------------
/CAGradientLayer Example Swift/CAGradientLayer Example Swift.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/CAGradientLayer Example Swift/CAGradientLayer Example Swift.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/CAGradientLayer Example Swift/CAGradientLayer Example Swift/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // CAGradientLayer Example Swift
4 | //
5 | // Created by Kyle Howells on 15/06/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 |
15 |
16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
17 | // Override point for customization after application launch.
18 | return true
19 | }
20 |
21 | // MARK: UISceneSession Lifecycle
22 |
23 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
24 | // Called when a new scene session is being created.
25 | // Use this method to select a configuration to create the new scene with.
26 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
27 | }
28 |
29 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {
30 | // Called when the user discards a scene session.
31 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
32 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
33 | }
34 |
35 |
36 | }
37 |
38 |
--------------------------------------------------------------------------------
/CAGradientLayer Example Swift/CAGradientLayer Example Swift/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/CAGradientLayer Example Swift/CAGradientLayer Example Swift/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/CAGradientLayer Example Swift/CAGradientLayer Example Swift/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 |
--------------------------------------------------------------------------------
/CAGradientLayer Example Swift/CAGradientLayer Example Swift/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 | UISceneConfigurations
28 |
29 | UIWindowSceneSessionRoleApplication
30 |
31 |
32 | UISceneConfigurationName
33 | Default Configuration
34 | UISceneDelegateClassName
35 | $(PRODUCT_MODULE_NAME).SceneDelegate
36 |
37 |
38 |
39 |
40 | UILaunchStoryboardName
41 | LaunchScreen
42 | UIRequiredDeviceCapabilities
43 |
44 | armv7
45 |
46 | UISupportedInterfaceOrientations
47 |
48 | UIInterfaceOrientationPortrait
49 | UIInterfaceOrientationLandscapeLeft
50 | UIInterfaceOrientationLandscapeRight
51 |
52 | UISupportedInterfaceOrientations~ipad
53 |
54 | UIInterfaceOrientationPortrait
55 | UIInterfaceOrientationPortraitUpsideDown
56 | UIInterfaceOrientationLandscapeLeft
57 | UIInterfaceOrientationLandscapeRight
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/CAGradientLayer Example Swift/CAGradientLayer Example Swift/KHGradientView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // KHGradientView.swift
3 | //
4 | // Created by Kyle Howells on 15/06/2020.
5 | // Copyright © 2020 Kyle Howells. All rights reserved.
6 | //
7 |
8 | import UIKit
9 |
10 | class KHGradientView: UIView {
11 |
12 | override open class var layerClass: AnyClass {
13 | return CAGradientLayer.classForCoder()
14 | }
15 |
16 | var gradientLayer : CAGradientLayer {
17 | return self.layer as! CAGradientLayer
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/CAGradientLayer Example Swift/CAGradientLayer Example Swift/SceneDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.swift
3 | // CAGradientLayer Example Swift
4 | //
5 | // Created by Kyle Howells on 15/06/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class SceneDelegate: UIResponder, UIWindowSceneDelegate {
12 |
13 | var window: UIWindow?
14 |
15 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
16 | guard let windowScene = (scene as? UIWindowScene) else { return }
17 |
18 | self.window = UIWindow(windowScene: windowScene)
19 | self.window?.rootViewController = ViewController()
20 | self.window?.makeKeyAndVisible()
21 | }
22 |
23 | func sceneDidDisconnect(_ scene: UIScene) {
24 | // Called as the scene is being released by the system.
25 | // This occurs shortly after the scene enters the background, or when its session is discarded.
26 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
27 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
28 | }
29 |
30 | func sceneDidBecomeActive(_ scene: UIScene) {
31 | // Called when the scene has moved from an inactive state to an active state.
32 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
33 | }
34 |
35 | func sceneWillResignActive(_ scene: UIScene) {
36 | // Called when the scene will move from an active state to an inactive state.
37 | // This may occur due to temporary interruptions (ex. an incoming phone call).
38 | }
39 |
40 | func sceneWillEnterForeground(_ scene: UIScene) {
41 | // Called as the scene transitions from the background to the foreground.
42 | // Use this method to undo the changes made on entering the background.
43 | }
44 |
45 | func sceneDidEnterBackground(_ scene: UIScene) {
46 | // Called as the scene transitions from the foreground to the background.
47 | // Use this method to save data, release shared resources, and store enough scene-specific state information
48 | // to restore the scene back to its current state.
49 | }
50 |
51 |
52 | }
53 |
54 |
--------------------------------------------------------------------------------
/CAGradientLayer Example Swift/CAGradientLayer Example Swift/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // CAGradientLayer Example Swift
4 | //
5 | // Created by Kyle Howells on 15/06/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ViewController: UIViewController {
12 |
13 | //
14 | // Linear Gradient
15 | //
16 | lazy var linGradientView:KHGradientView = {
17 | let v = KHGradientView()
18 | v.gradientLayer.type = CAGradientLayerType.axial
19 | v.gradientLayer.colors =
20 | [
21 | UIColor(red: 48.0/255.0, green: 35.0/255.0, blue: 174.0/255.0, alpha: 1.0).cgColor,
22 | UIColor(red: 200.0/255.0, green: 109.0/255.0, blue: 215.0/255.0, alpha: 1.0).cgColor
23 | ]
24 | v.gradientLayer.startPoint = CGPoint.zero
25 | v.gradientLayer.endPoint = CGPoint(x: 1, y: 1)
26 | return v
27 | }()
28 |
29 |
30 | //
31 | // Radial Gradient
32 | //
33 | lazy var radGradientView:KHGradientView = {
34 | let v = KHGradientView()
35 | v.gradientLayer.type = CAGradientLayerType.radial
36 | v.gradientLayer.colors =
37 | [
38 | UIColor(red: 0.0/255.0, green: 101.0/255.0, blue: 255.0/255.0, alpha: 1.0).cgColor,
39 | UIColor(red: 0.0/255.0, green: 40.0/255.0, blue: 101.0/255.0, alpha: 1.0).cgColor
40 | ]
41 | v.gradientLayer.startPoint = CGPoint(x: 0.5, y: 0.5)
42 | v.gradientLayer.endPoint = CGPoint(x: 0, y: 1)
43 | return v
44 | }()
45 |
46 |
47 | //
48 | // Angluar Gradient
49 | //
50 | lazy var angGradientView:KHGradientView = {
51 | let v = KHGradientView()
52 | v.gradientLayer.type = CAGradientLayerType.conic
53 | v.gradientLayer.colors =
54 | [
55 | UIColor(red: 245.0/255.0, green: 81.0/255.0, blue: 95.0/255.0, alpha: 1.0).cgColor,
56 | UIColor(red: 159.0/255.0, green: 4.0/255.0, blue: 27.0/255.0, alpha: 1.0).cgColor
57 | ]
58 | v.gradientLayer.startPoint = CGPoint(x: 0.5, y: 0.5)
59 | v.gradientLayer.endPoint = CGPoint(x: 1, y: 0.5)
60 | return v
61 | }()
62 |
63 | override func viewDidLoad() {
64 | super.viewDidLoad()
65 | // Do any additional setup after loading the view.
66 |
67 | self.view.addSubview(self.linGradientView)
68 | self.view.addSubview(self.radGradientView)
69 | self.view.addSubview(self.angGradientView)
70 | }
71 |
72 | override var prefersStatusBarHidden: Bool {
73 | return true
74 | }
75 |
76 | override func viewDidLayoutSubviews() {
77 | super.viewDidLayoutSubviews()
78 | let size = self.view.bounds.size
79 |
80 | if size.height > size.width {
81 | // Vertical layout
82 |
83 | let height = size.height / 3
84 |
85 | self.linGradientView.frame = {
86 | var frame = CGRect()
87 | frame.size.height = height
88 | frame.size.width = size.width
89 | return frame
90 | }()
91 |
92 | self.radGradientView.frame = {
93 | var frame = CGRect()
94 | frame.origin.y = height
95 | frame.size.height = height
96 | frame.size.width = size.width
97 | return frame
98 | }()
99 |
100 | self.angGradientView.frame = {
101 | var frame = CGRect()
102 | frame.origin.y = size.height - height
103 | frame.size.height = height
104 | frame.size.width = size.width
105 | return frame
106 | }()
107 |
108 | }
109 | else {
110 | // Horizontal layout
111 |
112 | let width = size.width / 3
113 |
114 | self.linGradientView.frame = {
115 | var frame = CGRect()
116 | frame.size.height = size.height
117 | frame.size.width = width
118 | return frame
119 | }()
120 |
121 | self.radGradientView.frame = {
122 | var frame = CGRect()
123 | frame.origin.x = width
124 | frame.size.height = size.height
125 | frame.size.width = width
126 | return frame
127 | }()
128 |
129 | self.angGradientView.frame = {
130 | var frame = CGRect()
131 | frame.origin.x = size.width - width
132 | frame.size.height = size.height
133 | frame.size.width = width
134 | return frame
135 | }()
136 | }
137 |
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/External Shadow ObjC/External Shadow.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/External Shadow ObjC/External Shadow.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/External Shadow ObjC/External Shadow/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // External Shadow
4 | //
5 | // Created by Kyle Howells on 16/06/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/External Shadow ObjC/External Shadow/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // External Shadow
4 | //
5 | // Created by Kyle Howells on 16/06/2020.
6 | // Copyright © 2020 Kyle Howells. 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 | #pragma mark - UISceneSession lifecycle
25 |
26 |
27 | - (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options {
28 | // Called when a new scene session is being created.
29 | // Use this method to select a configuration to create the new scene with.
30 | return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role];
31 | }
32 |
33 |
34 | - (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet *)sceneSessions {
35 | // Called when the user discards a scene session.
36 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
37 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
38 | }
39 |
40 |
41 | @end
42 |
--------------------------------------------------------------------------------
/External Shadow ObjC/External Shadow/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/External Shadow ObjC/External Shadow/Assets.xcassets/Checkerboard.imageset/Checkerboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kylehowells/ikyle.me-code-examples/502052a2e5da56c6fdb78148ea5ac7e132efab32/External Shadow ObjC/External Shadow/Assets.xcassets/Checkerboard.imageset/Checkerboard.png
--------------------------------------------------------------------------------
/External Shadow ObjC/External Shadow/Assets.xcassets/Checkerboard.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Checkerboard.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/External Shadow ObjC/External Shadow/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/External Shadow ObjC/External Shadow/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 |
--------------------------------------------------------------------------------
/External Shadow ObjC/External Shadow/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 | UISceneConfigurations
28 |
29 | UIWindowSceneSessionRoleApplication
30 |
31 |
32 | UISceneConfigurationName
33 | Default Configuration
34 | UISceneDelegateClassName
35 | SceneDelegate
36 |
37 |
38 |
39 |
40 | UILaunchStoryboardName
41 | LaunchScreen
42 | UIRequiredDeviceCapabilities
43 |
44 | armv7
45 |
46 | UISupportedInterfaceOrientations
47 |
48 | UIInterfaceOrientationPortrait
49 | UIInterfaceOrientationLandscapeLeft
50 | UIInterfaceOrientationLandscapeRight
51 |
52 | UISupportedInterfaceOrientations~ipad
53 |
54 | UIInterfaceOrientationPortrait
55 | UIInterfaceOrientationPortraitUpsideDown
56 | UIInterfaceOrientationLandscapeLeft
57 | UIInterfaceOrientationLandscapeRight
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/External Shadow ObjC/External Shadow/SceneDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.h
3 | // External Shadow
4 | //
5 | // Created by Kyle Howells on 16/06/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface SceneDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow * window;
14 |
15 | @end
16 |
17 |
--------------------------------------------------------------------------------
/External Shadow ObjC/External Shadow/SceneDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.m
3 | // External Shadow
4 | //
5 | // Created by Kyle Howells on 16/06/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | #import "SceneDelegate.h"
10 | #import "ViewController.h"
11 |
12 | @interface SceneDelegate ()
13 | @end
14 |
15 | @implementation SceneDelegate
16 |
17 | - (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
18 | self.window = [[UIWindow alloc] initWithWindowScene:(UIWindowScene*)scene];
19 | self.window.rootViewController = [[ViewController alloc] init];
20 | [self.window makeKeyAndVisible];
21 | }
22 |
23 |
24 | - (void)sceneDidDisconnect:(UIScene *)scene {
25 | // Called as the scene is being released by the system.
26 | // This occurs shortly after the scene enters the background, or when its session is discarded.
27 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
28 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
29 | }
30 |
31 |
32 | - (void)sceneDidBecomeActive:(UIScene *)scene {
33 | // Called when the scene has moved from an inactive state to an active state.
34 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
35 | }
36 |
37 |
38 | - (void)sceneWillResignActive:(UIScene *)scene {
39 | // Called when the scene will move from an active state to an inactive state.
40 | // This may occur due to temporary interruptions (ex. an incoming phone call).
41 | }
42 |
43 |
44 | - (void)sceneWillEnterForeground:(UIScene *)scene {
45 | // Called as the scene transitions from the background to the foreground.
46 | // Use this method to undo the changes made on entering the background.
47 | }
48 |
49 |
50 | - (void)sceneDidEnterBackground:(UIScene *)scene {
51 | // Called as the scene transitions from the foreground to the background.
52 | // Use this method to save data, release shared resources, and store enough scene-specific state information
53 | // to restore the scene back to its current state.
54 | }
55 |
56 |
57 | @end
58 |
--------------------------------------------------------------------------------
/External Shadow ObjC/External Shadow/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // External Shadow
4 | //
5 | // Created by Kyle Howells on 16/06/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ViewController : UIViewController
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/External Shadow ObjC/External Shadow/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // External Shadow
4 | //
5 | // Created by Kyle Howells on 16/06/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | #import "ViewController.h"
10 |
11 | @interface ViewController ()
12 | @end
13 |
14 | @implementation ViewController{
15 | UIView *shadowView;
16 | }
17 |
18 | - (void)viewDidLoad {
19 | [super viewDidLoad];
20 |
21 | self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"Checkerboard"]];
22 |
23 | //
24 | // Create Shadow View
25 | //
26 | shadowView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
27 | shadowView.backgroundColor = [UIColor colorWithRed:0 green:1 blue:0 alpha:0.5];
28 | shadowView.center = self.view.center;
29 | shadowView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin;
30 | [self.view addSubview:shadowView];
31 | shadowView.layer.cornerRadius = 10;
32 |
33 | //
34 | // Add a shadow to the view
35 | //
36 | shadowView.layer.shadowColor = [UIColor blackColor].CGColor;
37 | shadowView.layer.shadowOffset = CGSizeMake(0, 1);
38 | shadowView.layer.shadowRadius = 20;
39 | shadowView.layer.shadowOpacity = 1;
40 | // Set the shadow path
41 | shadowView.layer.shadowPath = [UIBezierPath bezierPathWithRoundedRect:({
42 | CGRect frame = shadowView.bounds;
43 | frame.origin.x = 0;
44 | frame;
45 | }) cornerRadius:shadowView.layer.cornerRadius].CGPath;
46 |
47 |
48 | //
49 | // Setup a mask to match the view
50 | //
51 | CAShapeLayer *maskLayer = [CAShapeLayer layer];
52 | maskLayer.frame = shadowView.bounds;
53 | maskLayer.path = [UIBezierPath bezierPathWithRoundedRect:shadowView.bounds cornerRadius:shadowView.layer.cornerRadius].CGPath;
54 |
55 | //
56 | // Make the mask area bigger than the view, so the shadow itself does not get clipped by the mask
57 | //
58 | CGFloat shadowBorder = (shadowView.layer.shadowRadius * 2) + 5;// 50.0;
59 | maskLayer.frame = CGRectInset( maskLayer.frame, -shadowBorder, -shadowBorder ); // Make bigger
60 | maskLayer.frame = CGRectOffset( maskLayer.frame, shadowBorder/2.0, shadowBorder/2.0 ); // Move top and left
61 |
62 | // Allow for cut outs in the shape
63 | maskLayer.fillRule = kCAFillRuleEvenOdd;
64 |
65 | //
66 | // Create new path
67 | //
68 | CGMutablePathRef pathMasking = CGPathCreateMutable();
69 | // Add the outer view frame
70 | CGPathAddPath(pathMasking, NULL, [UIBezierPath bezierPathWithRect:maskLayer.frame].CGPath);
71 | // Translate into the shape back to the smaller original view's frame start point
72 | CGAffineTransform catShiftBorder = CGAffineTransformMakeTranslation( shadowBorder/2.0, shadowBorder/2.0);
73 | // Now add the original path for the cut out the shape of the original view
74 | CGPathAddPath(pathMasking, NULL, CGPathCreateCopyByTransformingPath(maskLayer.path, &catShiftBorder ) );
75 | // Set this big rect with a small cutout rect as the mask
76 | maskLayer.path = pathMasking;
77 |
78 | //
79 | // Set as a mask on the view with the shadow
80 | //
81 | shadowView.layer.mask = maskLayer;
82 |
83 |
84 | UIView *contentView = [[UIView alloc] initWithFrame:shadowView.frame];
85 | contentView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin;
86 | contentView.backgroundColor = [UIColor colorWithRed:0 green:1 blue:0 alpha:0.5];
87 | contentView.layer.cornerRadius = 10;
88 | [self.view addSubview:contentView];
89 | }
90 |
91 |
92 | @end
93 |
--------------------------------------------------------------------------------
/External Shadow ObjC/External Shadow/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // External Shadow
4 | //
5 | // Created by Kyle Howells on 16/06/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | NSString * appDelegateClassName;
14 | @autoreleasepool {
15 | // Setup code that might create autoreleased objects goes here.
16 | appDelegateClassName = NSStringFromClass([AppDelegate class]);
17 | }
18 | return UIApplicationMain(argc, argv, nil, appDelegateClassName);
19 | }
20 |
--------------------------------------------------------------------------------
/External Shadow Swift/External Shadow Swift.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/External Shadow Swift/External Shadow Swift.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/External Shadow Swift/External Shadow Swift/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // External Shadow Swift
4 | //
5 | // Created by Kyle Howells on 16/06/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 |
15 |
16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
17 | // Override point for customization after application launch.
18 | return true
19 | }
20 |
21 | // MARK: UISceneSession Lifecycle
22 |
23 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
24 | // Called when a new scene session is being created.
25 | // Use this method to select a configuration to create the new scene with.
26 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
27 | }
28 |
29 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {
30 | // Called when the user discards a scene session.
31 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
32 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
33 | }
34 |
35 |
36 | }
37 |
38 |
--------------------------------------------------------------------------------
/External Shadow Swift/External Shadow Swift/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/External Shadow Swift/External Shadow Swift/Assets.xcassets/Checkerboard.imageset/Checkerboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kylehowells/ikyle.me-code-examples/502052a2e5da56c6fdb78148ea5ac7e132efab32/External Shadow Swift/External Shadow Swift/Assets.xcassets/Checkerboard.imageset/Checkerboard.png
--------------------------------------------------------------------------------
/External Shadow Swift/External Shadow Swift/Assets.xcassets/Checkerboard.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Checkerboard.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/External Shadow Swift/External Shadow Swift/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/External Shadow Swift/External Shadow Swift/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 |
--------------------------------------------------------------------------------
/External Shadow Swift/External Shadow Swift/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 | UISceneConfigurations
28 |
29 | UIWindowSceneSessionRoleApplication
30 |
31 |
32 | UISceneConfigurationName
33 | Default Configuration
34 | UISceneDelegateClassName
35 | $(PRODUCT_MODULE_NAME).SceneDelegate
36 |
37 |
38 |
39 |
40 | UILaunchStoryboardName
41 | LaunchScreen
42 | UIRequiredDeviceCapabilities
43 |
44 | armv7
45 |
46 | UISupportedInterfaceOrientations
47 |
48 | UIInterfaceOrientationPortrait
49 | UIInterfaceOrientationLandscapeLeft
50 | UIInterfaceOrientationLandscapeRight
51 |
52 | UISupportedInterfaceOrientations~ipad
53 |
54 | UIInterfaceOrientationPortrait
55 | UIInterfaceOrientationPortraitUpsideDown
56 | UIInterfaceOrientationLandscapeLeft
57 | UIInterfaceOrientationLandscapeRight
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/External Shadow Swift/External Shadow Swift/SceneDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.swift
3 | // External Shadow Swift
4 | //
5 | // Created by Kyle Howells on 16/06/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class SceneDelegate: UIResponder, UIWindowSceneDelegate {
12 |
13 | var window: UIWindow?
14 |
15 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
16 | guard let windowScene = (scene as? UIWindowScene) else { return }
17 |
18 | let window = UIWindow(windowScene: windowScene)
19 | window.rootViewController = ViewController()
20 | self.window = window
21 | window.makeKeyAndVisible()
22 | }
23 |
24 | func sceneDidDisconnect(_ scene: UIScene) {
25 | // Called as the scene is being released by the system.
26 | // This occurs shortly after the scene enters the background, or when its session is discarded.
27 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
28 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
29 | }
30 |
31 | func sceneDidBecomeActive(_ scene: UIScene) {
32 | // Called when the scene has moved from an inactive state to an active state.
33 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
34 | }
35 |
36 | func sceneWillResignActive(_ scene: UIScene) {
37 | // Called when the scene will move from an active state to an inactive state.
38 | // This may occur due to temporary interruptions (ex. an incoming phone call).
39 | }
40 |
41 | func sceneWillEnterForeground(_ scene: UIScene) {
42 | // Called as the scene transitions from the background to the foreground.
43 | // Use this method to undo the changes made on entering the background.
44 | }
45 |
46 | func sceneDidEnterBackground(_ scene: UIScene) {
47 | // Called as the scene transitions from the foreground to the background.
48 | // Use this method to save data, release shared resources, and store enough scene-specific state information
49 | // to restore the scene back to its current state.
50 | }
51 |
52 |
53 | }
54 |
55 |
--------------------------------------------------------------------------------
/External Shadow Swift/External Shadow Swift/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // External Shadow Swift
4 | //
5 | // Created by Kyle Howells on 16/06/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ViewController: UIViewController {
12 |
13 | override func viewDidLoad() {
14 | super.viewDidLoad()
15 |
16 | view.backgroundColor = UIColor(patternImage: UIImage(named: "Checkerboard")!)
17 |
18 |
19 | //
20 | // Create Shadow View
21 | //
22 | let shadowView = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
23 | shadowView.backgroundColor = UIColor(red: 0, green: 1, blue: 0, alpha: 0.5)
24 | shadowView.center = view.center
25 | shadowView.autoresizingMask = [.flexibleTopMargin, .flexibleRightMargin, .flexibleBottomMargin, .flexibleLeftMargin]
26 | view.addSubview(shadowView)
27 | shadowView.layer.cornerRadius = 10
28 |
29 |
30 | //
31 | // Add a shadow to the view
32 | //
33 | shadowView.layer.shadowColor = UIColor.black.cgColor
34 | shadowView.layer.shadowOffset = CGSize(width:0, height:1)
35 | shadowView.layer.shadowRadius = 20
36 | shadowView.layer.shadowOpacity = 1
37 | // Set the shadow path
38 | shadowView.layer.shadowPath = UIBezierPath(roundedRect: shadowView.bounds, cornerRadius: shadowView.layer.cornerRadius).cgPath
39 |
40 |
41 | //
42 | // Setup a mask to match the view
43 | //
44 | let maskLayer = CAShapeLayer()
45 | maskLayer.frame = shadowView.bounds
46 | maskLayer.path = UIBezierPath(roundedRect: shadowView.bounds, cornerRadius: shadowView.layer.cornerRadius).cgPath
47 |
48 | //
49 | // Make the mask area bigger than the view, so the shadow itself does not get clipped by the mask
50 | //
51 | let shadowBorder:CGFloat = (shadowView.layer.shadowRadius * 2) + 5;
52 | maskLayer.frame = maskLayer.frame.insetBy(dx: -shadowBorder, dy: -shadowBorder) // Make bigger
53 | maskLayer.frame = maskLayer.frame.offsetBy(dx: shadowBorder/2, dy: shadowBorder/2) // Move top and left
54 |
55 | // Allow for cut outs in the shape
56 | maskLayer.fillRule = .evenOdd
57 |
58 |
59 | //
60 | // Create new path
61 | //
62 | let pathMasking = CGMutablePath()
63 | // Add the outer view frame
64 | pathMasking.addPath(UIBezierPath(rect: maskLayer.frame).cgPath)
65 | // Translate into the shape back to the smaller original view's frame start point
66 | var catShiftBorder = CGAffineTransform(translationX: shadowBorder/2, y: shadowBorder/2)
67 | // Now add the original path for the cut out the shape of the original view
68 | pathMasking.addPath(maskLayer.path!.copy(using: &catShiftBorder)!)
69 | // Set this big rect with a small cutout rect as the mask
70 | maskLayer.path = pathMasking;
71 |
72 |
73 | //
74 | // Set as a mask on the view with the shadow
75 | //
76 | shadowView.layer.mask = maskLayer;
77 |
78 |
79 | //
80 | // Content view to use
81 | //
82 | let contentView = UIView(frame: shadowView.frame)
83 | contentView.backgroundColor = UIColor(red: 0, green: 1, blue: 0, alpha: 0.5)
84 | contentView.center = shadowView.center
85 | contentView.autoresizingMask = [.flexibleTopMargin, .flexibleRightMargin, .flexibleBottomMargin, .flexibleLeftMargin]
86 | view.addSubview(contentView)
87 | contentView.layer.cornerRadius = shadowView.layer.cornerRadius
88 | }
89 |
90 | }
91 |
92 |
--------------------------------------------------------------------------------
/Illustrations/Illustrations/Illustrations.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Illustrations/Illustrations/Illustrations.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Illustrations/Illustrations/Illustrations/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // Illustrations
4 | //
5 | // Created by Kyle Howells on 22/04/2022.
6 | //
7 |
8 | import UIKit
9 |
10 | @main
11 | class AppDelegate: UIResponder, UIApplicationDelegate {
12 |
13 |
14 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
15 | // Override point for customization after application launch.
16 | return true
17 | }
18 |
19 |
20 | // MARK: UISceneSession Lifecycle
21 |
22 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
23 | // Called when a new scene session is being created.
24 | // Use this method to select a configuration to create the new scene with.
25 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
26 | }
27 |
28 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {
29 | // Called when the user discards a scene session.
30 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
31 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/Illustrations/Illustrations/Illustrations/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Illustrations/Illustrations/Illustrations/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/Illustrations/Illustrations/Illustrations/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Illustrations/Illustrations/Illustrations/Assets.xcassets/arrow.clockwise.custom.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "arrow.clockwise.custom.svg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Illustrations/Illustrations/Illustrations/Assets.xcassets/arrow.clockwise.custom.imageset/arrow.clockwise.custom.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Illustrations/Illustrations/Illustrations/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 |
--------------------------------------------------------------------------------
/Illustrations/Illustrations/Illustrations/Demos/Anchor Points/KHVisualiseView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // KHVisualiseView.swift
3 | // Illustrations
4 | //
5 | // Created by Kyle Howells on 22/04/2022.
6 | //
7 |
8 | import UIKit
9 | import CoreGraphics
10 |
11 | class KHVisualiseView: UIView {
12 |
13 | override init(frame: CGRect) {
14 | super.init(frame: frame)
15 |
16 | self.backgroundView.layer.borderWidth = 4
17 |
18 | self.addSubview(self.backgroundView)
19 | self.addSubview(self.titleLabel)
20 | self.addSubview(self.anchorPointView)
21 | self.addSubview(self.rotationImageView)
22 |
23 | // Using defer to make the didSet run
24 | defer {
25 | self.primaryColor = UIColor(red: 252.0/255.0, green: 185.0/255.0, blue: 45.0/255.0, alpha: 1)
26 | }
27 | }
28 |
29 | @available(*, unavailable)
30 | required init?(coder: NSCoder) {
31 | fatalError("init(coder:) has not been implemented")
32 | }
33 |
34 | var primaryColor:UIColor = UIColor(red: 252.0/255.0, green: 185.0/255.0, blue: 45.0/255.0, alpha: 1) {
35 | didSet {
36 | self.backgroundView.backgroundColor = self.primaryColor.withAlphaComponent(0.5)
37 | self.backgroundView.layer.borderColor = self.primaryColor.cgColor
38 | }
39 | }
40 |
41 |
42 | // MARK: - Background
43 |
44 | let backgroundView: UIView = {
45 | let view = UIView()
46 | return view
47 | }()
48 |
49 |
50 | // MARK: - Title
51 |
52 | let titleLabel: UILabel = {
53 | let l: UILabel = UILabel()
54 | l.alpha = 0.5
55 | l.textColor = UIColor.black
56 | l.font = UIFont.systemFont(ofSize: 15, weight: .medium)
57 | l.adjustsFontSizeToFitWidth = true
58 | l.allowsDefaultTighteningForTruncation = true
59 | //l.showsExpansionTextWhenTruncated = true
60 | return l
61 | }()
62 |
63 | enum Position {
64 | case topLeft
65 | case topCenter
66 | case topRight
67 |
68 | case middleLeft
69 | case middleCenter
70 | case middleRight
71 |
72 | case bottomLeft
73 | case bottomCenter
74 | case bottomRight
75 | }
76 | var titlePosition:Position = .topLeft {
77 | didSet {
78 | self.setNeedsLayout()
79 | }
80 | }
81 |
82 |
83 | let anchorPointView:UIView = {
84 | let view = UIView(frame: CGRect(x: 0, y: 0, width: 12, height: 12))
85 | view.alpha = 0
86 | view.backgroundColor = UIColor(red: 70.0/255.0, green: 165.0/255.0, blue: 226.0/255.0, alpha: 0.5)
87 |
88 | view.layer.borderColor = UIColor(red: 70.0/255.0, green: 165.0/255.0, blue: 226.0/255.0, alpha: 1.0).cgColor
89 | view.layer.borderWidth = 3
90 |
91 | view.layer.cornerRadius = view.bounds.width * 0.5
92 | return view
93 | }()
94 |
95 |
96 | let rotationImageView:UIImageView = {
97 | let imv = UIImageView(image: UIImage(named: "arrow.clockwise.custom"))
98 | imv.tintColor = UIColor.black
99 | imv.frame = CGRect(x: 0, y: 0, width: 40, height: 40)
100 | imv.contentMode = UIView.ContentMode.scaleAspectFit
101 | imv.layer.anchorPoint = CGPoint(x: 0.52, y: 0.56)
102 | imv.alpha = 0
103 | return imv
104 | }()
105 |
106 |
107 | // MARK: - Layout
108 |
109 | override func layoutSubviews() {
110 | super.layoutSubviews()
111 |
112 | let size: CGSize = self.bounds.size
113 |
114 | self.backgroundView.frame = self.bounds
115 |
116 | let borderWidth = self.backgroundView.layer.borderWidth
117 |
118 | self.titleLabel.frame = {
119 | let labelSize = self.titleLabel.sizeThatFits(size)
120 |
121 | var frame = CGRect()
122 | frame.size = labelSize
123 | frame.size.width = min(frame.width, size.width - (borderWidth * 2))
124 | frame.size.height = min(frame.height, size.height - (borderWidth * 2))
125 |
126 | switch self.titlePosition {
127 | case .topLeft:
128 | frame.origin.x = (borderWidth + 1)
129 | frame.origin.y = (borderWidth + 1)
130 |
131 | case .topCenter:
132 | frame.origin.x = (size.width - frame.width) * 0.5
133 | frame.origin.y = (borderWidth + 1)
134 |
135 | case .topRight:
136 | frame.origin.x = (size.width - (frame.width + (borderWidth + 1)))
137 | frame.origin.y = (borderWidth + 1)
138 |
139 | case .middleLeft:
140 | frame.origin.x = (borderWidth + 1)
141 | frame.origin.y = (size.height - frame.height) * 0.5
142 |
143 | case .middleCenter:
144 | frame.origin.x = (size.width - frame.width) * 0.5
145 | frame.origin.y = (size.height - frame.height) * 0.5
146 |
147 | case .middleRight:
148 | frame.origin.x = (size.width - (frame.width + (borderWidth + 1)))
149 | frame.origin.y = (size.height - frame.height) * 0.5
150 |
151 | case .bottomLeft:
152 | frame.origin.x = (borderWidth + 1)
153 | frame.origin.y = (size.height - (frame.height + (borderWidth + 1)))
154 |
155 | case .bottomCenter:
156 | frame.origin.x = (size.width - frame.width) * 0.5
157 | frame.origin.y = (size.height - (frame.height + (borderWidth + 1)))
158 |
159 | case .bottomRight:
160 | frame.origin.x = (size.width - (frame.width + (borderWidth + 1)))
161 | frame.origin.y = (size.height - (frame.height + (borderWidth + 1)))
162 | }
163 |
164 | return frame
165 | }()
166 |
167 | self.anchorPointView.center = CGPoint(
168 | x: size.width * self.layer.anchorPoint.x,
169 | y: size.height * self.layer.anchorPoint.y
170 | )
171 | self.rotationImageView.center = self.anchorPointView.center
172 |
173 | }
174 |
175 | }
176 |
--------------------------------------------------------------------------------
/Illustrations/Illustrations/Illustrations/Demos/DemoViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DemoViewController.swift
3 | // Illustrations
4 | //
5 | // Created by Kyle Howells on 22/04/2022.
6 | //
7 |
8 | import UIKit
9 |
10 | class DemoViewController: UIViewController {
11 |
12 | /// Display at exactly this size for internal animations to make sense
13 | @objc class var displaySize:CGSize {
14 | return CGSize(width: 1280, height: 720)
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/Illustrations/Illustrations/Illustrations/Illustrations.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Illustrations/Illustrations/Illustrations/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | UIApplicationSceneManifest
6 |
7 | UIApplicationSupportsMultipleScenes
8 |
9 | UISceneConfigurations
10 |
11 | UIWindowSceneSessionRoleApplication
12 |
13 |
14 | UISceneConfigurationName
15 | Default Configuration
16 | UISceneDelegateClassName
17 | $(PRODUCT_MODULE_NAME).SceneDelegate
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/Illustrations/Illustrations/Illustrations/MP4/MP4Recorder.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MP4Recorder.swift
3 | // Code Examples
4 | //
5 | // Created by Kyle Howells on 03/07/2022.
6 | //
7 |
8 |
9 | import UIKit
10 | import AVFoundation
11 | import CoreGraphics
12 |
13 |
14 | // MARK: - MP4Recorder
15 |
16 | /// Screen records and write the result to an MP4
17 | class MP4Recorder: NSObject {
18 |
19 | private let videoExporter: MP4Exporter
20 |
21 | private lazy var displayLink: CADisplayLink = { [unowned self] in
22 | let displayLink = CADisplayLink(target: self, selector: #selector(self.update))
23 | displayLink.preferredFrameRateRange = CAFrameRateRange(minimum: 60, maximum: 60)
24 | return displayLink
25 | }()
26 |
27 | let renderFrame: ()->UIImage
28 |
29 |
30 | /// <#Description#>
31 | /// - Parameters:
32 | /// - videoSize: <#videoSize description#>
33 | /// - outputURL: <#outputURL description#>
34 | /// - renderFrame: <#renderFrame description#>
35 | init?(videoSize: CGSize, outputURL: URL, renderFrame: @escaping ()->UIImage) {
36 | guard let exporter = MP4Exporter(videoSize: videoSize, outputURL: outputURL) else { return nil }
37 |
38 | self.videoExporter = exporter
39 |
40 | self.renderFrame = renderFrame
41 |
42 | super.init()
43 |
44 | self.displayLink.add(to: .current, forMode: .common)
45 |
46 | guard self.videoExporter.addImage(image: renderFrame(), withPresentationTime: CMTime.zero) else { return nil }
47 | }
48 |
49 |
50 | // MARK: - Render Frame
51 |
52 | private var firstFrameTime:CFTimeInterval? = nil
53 |
54 | @objc private func update()
55 | {
56 | let timestamp = self.displayLink.timestamp
57 |
58 | if let firstFrameTime: CFTimeInterval = self.firstFrameTime {
59 | let image:UIImage = self.renderFrame()
60 |
61 | let timeDiff: CFTimeInterval = (timestamp - firstFrameTime)
62 |
63 | let presentationTime = CMTime(seconds: Double(timeDiff), preferredTimescale: 10000)
64 |
65 | if self.videoExporter.addImage(image: image, withPresentationTime: presentationTime) == false {
66 | print("ERROR: Failed to append frame")
67 | }
68 | }
69 |
70 | if self.firstFrameTime == nil && timestamp > 0 {
71 | self.firstFrameTime = timestamp
72 | }
73 | }
74 |
75 |
76 | // MARK: - Stop Video
77 |
78 | /// <#Description#>
79 | /// - Parameter completion: <#completion description#>
80 | func stopRecording(completion: @escaping ()->()) {
81 | self.displayLink.invalidate()
82 |
83 | self.videoExporter.stopRecording(completion: {
84 | print("Finished Screen Recording")
85 | })
86 | }
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/Illustrations/Illustrations/Illustrations/SceneDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.swift
3 | // Illustrations
4 | //
5 | // Created by Kyle Howells on 22/04/2022.
6 | //
7 |
8 | import UIKit
9 |
10 | class SceneDelegate: UIResponder, UIWindowSceneDelegate {
11 |
12 | var window: UIWindow?
13 |
14 |
15 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
16 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
17 | guard let windowScene = (scene as? UIWindowScene) else { return }
18 |
19 | let window = UIWindow(windowScene: windowScene)
20 | window.rootViewController = ViewController()
21 | self.window = window
22 | window.makeKeyAndVisible()
23 | }
24 |
25 | func sceneDidDisconnect(_ scene: UIScene) {
26 | // Called as the scene is being released by the system.
27 | // This occurs shortly after the scene enters the background, or when its session is discarded.
28 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
29 | // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
30 | }
31 |
32 | func sceneDidBecomeActive(_ scene: UIScene) {
33 | // Called when the scene has moved from an inactive state to an active state.
34 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
35 | }
36 |
37 | func sceneWillResignActive(_ scene: UIScene) {
38 | // Called when the scene will move from an active state to an inactive state.
39 | // This may occur due to temporary interruptions (ex. an incoming phone call).
40 | }
41 |
42 | func sceneWillEnterForeground(_ scene: UIScene) {
43 | // Called as the scene transitions from the background to the foreground.
44 | // Use this method to undo the changes made on entering the background.
45 | }
46 |
47 | func sceneDidEnterBackground(_ scene: UIScene) {
48 | // Called as the scene transitions from the foreground to the background.
49 | // Use this method to save data, release shared resources, and store enough scene-specific state information
50 | // to restore the scene back to its current state.
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | This is free and unencumbered software released into the public domain.
2 |
3 | Anyone is free to copy, modify, publish, use, compile, sell, or
4 | distribute this software, either in source code form or as a compiled
5 | binary, for any purpose, commercial or non-commercial, and by any
6 | means.
7 |
8 | In jurisdictions that recognize copyright laws, the author or authors
9 | of this software dedicate any and all copyright interest in the
10 | software to the public domain. We make this dedication for the benefit
11 | of the public at large and to the detriment of our heirs and
12 | successors. We intend this dedication to be an overt act of
13 | relinquishment in perpetuity of all present and future rights to this
14 | software under copyright law.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
24 | For more information, please refer to
25 |
--------------------------------------------------------------------------------
/ObjC Live Preview/Live Preview/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // Live Preview
4 | //
5 | // Created by Kyle Howells on 01/07/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/ObjC Live Preview/Live Preview/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // Live Preview
4 | //
5 | // Created by Kyle Howells on 01/07/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 |
11 | @interface AppDelegate ()
12 |
13 | @end
14 |
15 |
16 | @implementation AppDelegate
17 |
18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
19 | // Override point for customization after application launch.
20 | return YES;
21 | }
22 |
23 |
24 | #pragma mark - UISceneSession lifecycle
25 |
26 | - (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options {
27 | // Called when a new scene session is being created.
28 | // Use this method to select a configuration to create the new scene with.
29 | return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role];
30 | }
31 |
32 | - (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet *)sceneSessions {
33 | // Called when the user discards a scene session.
34 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
35 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
36 | }
37 |
38 | @end
39 |
--------------------------------------------------------------------------------
/ObjC Live Preview/Live Preview/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/ObjC Live Preview/Live Preview/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/ObjC Live Preview/Live Preview/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 |
--------------------------------------------------------------------------------
/ObjC Live Preview/Live Preview/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 | UISceneConfigurations
28 |
29 | UIWindowSceneSessionRoleApplication
30 |
31 |
32 | UISceneConfigurationName
33 | Default Configuration
34 | UISceneDelegateClassName
35 | SceneDelegate
36 |
37 |
38 |
39 |
40 | UILaunchStoryboardName
41 | LaunchScreen
42 | UIRequiredDeviceCapabilities
43 |
44 | armv7
45 |
46 | UISupportedInterfaceOrientations
47 |
48 | UIInterfaceOrientationPortrait
49 | UIInterfaceOrientationLandscapeLeft
50 | UIInterfaceOrientationLandscapeRight
51 |
52 | UISupportedInterfaceOrientations~ipad
53 |
54 | UIInterfaceOrientationPortrait
55 | UIInterfaceOrientationPortraitUpsideDown
56 | UIInterfaceOrientationLandscapeLeft
57 | UIInterfaceOrientationLandscapeRight
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/ObjC Live Preview/Live Preview/KHGradientView.h:
--------------------------------------------------------------------------------
1 | //
2 | // KHGradientView.h
3 | // ObjC Live Preview
4 | //
5 | // Created by Kyle Howells on 01/07/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | @import UIKit;
10 | @import QuartzCore;
11 |
12 | @interface KHGradientView : UIView
13 | @property(nonatomic, readonly, strong) CAGradientLayer *layer;
14 | @end
15 |
--------------------------------------------------------------------------------
/ObjC Live Preview/Live Preview/KHGradientView.m:
--------------------------------------------------------------------------------
1 | //
2 | // KHGradientView.m
3 | // ObjC Live Preview
4 | //
5 | // Created by Kyle Howells on 01/07/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | #import "KHGradientView.h"
10 |
11 | @implementation KHGradientView
12 | @dynamic layer;
13 |
14 | +(Class)layerClass{
15 | return [CAGradientLayer class];
16 | }
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/ObjC Live Preview/Live Preview/ObjC Live Preview-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | //
2 | // Use this file to import your target's public headers that you would like to expose to Swift.
3 | //
4 |
5 | #import "ViewController.h"
6 |
--------------------------------------------------------------------------------
/ObjC Live Preview/Live Preview/SceneDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.h
3 | // Live Preview
4 | //
5 | // Created by Kyle Howells on 01/07/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface SceneDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow * window;
14 |
15 | @end
16 |
17 |
--------------------------------------------------------------------------------
/ObjC Live Preview/Live Preview/SceneDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.m
3 | // Live Preview
4 | //
5 | // Created by Kyle Howells on 01/07/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | #import "SceneDelegate.h"
10 | #import "ViewController.h"
11 |
12 | @interface SceneDelegate ()
13 |
14 | @end
15 |
16 |
17 | @implementation SceneDelegate
18 |
19 | - (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
20 | self.window = [[UIWindow alloc] initWithWindowScene:(UIWindowScene*)scene];
21 | self.window.rootViewController = [[ViewController alloc] init];
22 | [self.window makeKeyAndVisible];
23 | }
24 |
25 | - (void)sceneDidDisconnect:(UIScene *)scene {
26 | // Called as the scene is being released by the system.
27 | // This occurs shortly after the scene enters the background, or when its session is discarded.
28 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
29 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
30 | }
31 |
32 | - (void)sceneDidBecomeActive:(UIScene *)scene {
33 | // Called when the scene has moved from an inactive state to an active state.
34 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
35 | }
36 |
37 | - (void)sceneWillResignActive:(UIScene *)scene {
38 | // Called when the scene will move from an active state to an inactive state.
39 | // This may occur due to temporary interruptions (ex. an incoming phone call).
40 | }
41 |
42 | - (void)sceneWillEnterForeground:(UIScene *)scene {
43 | // Called as the scene transitions from the background to the foreground.
44 | // Use this method to undo the changes made on entering the background.
45 | }
46 |
47 | - (void)sceneDidEnterBackground:(UIScene *)scene {
48 | // Called as the scene transitions from the foreground to the background.
49 | // Use this method to save data, release shared resources, and store enough scene-specific state information
50 | // to restore the scene back to its current state.
51 | }
52 |
53 | @end
54 |
--------------------------------------------------------------------------------
/ObjC Live Preview/Live Preview/SwiftUIView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwiftUIView.swift
3 | // ObjC Live Preview
4 | //
5 | // Created by Kyle Howells on 01/07/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | import SwiftUI
10 |
11 | struct VCRepresentable: UIViewControllerRepresentable {
12 | func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
13 | // leave this empty
14 | }
15 |
16 | @available(iOS 13.0.0, *)
17 | func makeUIViewController(context: Context) -> UIViewController {
18 | return VCClass()
19 | }
20 | }
21 |
22 | struct SwiftUIView_Previews: PreviewProvider {
23 | static var previews: some View {
24 | VCRepresentable()
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/ObjC Live Preview/Live Preview/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // Live Preview
4 | //
5 | // Created by Kyle Howells on 01/07/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/ObjC Live Preview/Live Preview/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // Live Preview
4 | //
5 | // Created by Kyle Howells on 01/07/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | #import "ViewController.h"
10 | #import "KHGradientView.h"
11 |
12 | @interface ViewController ()
13 |
14 | @end
15 |
16 |
17 | @implementation ViewController{
18 | KHGradientView *backgroundView;
19 | UILabel *label;
20 | }
21 |
22 | - (void)viewDidLoad {
23 | [super viewDidLoad];
24 | self.view.backgroundColor = [UIColor blackColor];
25 |
26 | backgroundView = [[KHGradientView alloc] init];
27 | backgroundView.layer.colors =
28 | @[
29 | (id)[UIColor colorWithRed: 48.0/255.0 green: 35.0/255.0 blue: 174.0/255.0 alpha: 1.0].CGColor,
30 | (id)[UIColor colorWithRed: 200.0/255.0 green: 109.0/255.0 blue: 215.0/255.0 alpha: 1.0].CGColor
31 | ];
32 | [self.view addSubview:backgroundView];
33 |
34 | label = [[UILabel alloc] init];
35 | label.font = [UIFont systemFontOfSize:20 weight:UIFontWeightBold];
36 | label.text = @" Hello World ";
37 | label.textAlignment = NSTextAlignmentCenter;
38 | label.textColor = [UIColor blackColor];
39 | label.backgroundColor = [UIColor whiteColor];
40 | label.layer.cornerRadius = 8;
41 | label.layer.masksToBounds = YES;
42 | [self.view addSubview:label];
43 | }
44 |
45 |
46 | - (void)viewDidLayoutSubviews{
47 | [super viewDidLayoutSubviews];
48 | const CGSize size = self.view.bounds.size;
49 |
50 | backgroundView.frame = self.view.bounds;
51 |
52 | [label sizeToFit];
53 | label.frame = CGRectInset(label.frame, -10, -10);
54 | label.center = CGPointMake(size.width * 0.5, size.height * 0.5);
55 | }
56 |
57 | @end
58 |
--------------------------------------------------------------------------------
/ObjC Live Preview/Live Preview/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // Live Preview
4 | //
5 | // Created by Kyle Howells on 01/07/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | NSString * appDelegateClassName;
14 | @autoreleasepool {
15 | // Setup code that might create autoreleased objects goes here.
16 | appDelegateClassName = NSStringFromClass([AppDelegate class]);
17 | }
18 | return UIApplicationMain(argc, argv, nil, appDelegateClassName);
19 | }
20 |
--------------------------------------------------------------------------------
/ObjC Live Preview/ObjC Live Preview.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ObjC Live Preview/ObjC Live Preview.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Photo Picker ObjC/Photo Picker ObjC.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Photo Picker ObjC/Photo Picker ObjC.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Photo Picker ObjC/Photo Picker ObjC/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // Photo Picker ObjC
4 | //
5 | // Created by Kyle Howells on 23/06/2020.
6 | //
7 |
8 | #import
9 |
10 | @interface AppDelegate : UIResponder
11 |
12 |
13 | @end
14 |
15 |
--------------------------------------------------------------------------------
/Photo Picker ObjC/Photo Picker ObjC/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // Photo Picker ObjC
4 | //
5 | // Created by Kyle Howells on 23/06/2020.
6 | //
7 |
8 | #import "AppDelegate.h"
9 |
10 | @interface AppDelegate ()
11 |
12 | @end
13 |
14 | @implementation AppDelegate
15 |
16 |
17 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
18 | // Override point for customization after application launch.
19 | return YES;
20 | }
21 |
22 |
23 | #pragma mark - UISceneSession lifecycle
24 |
25 |
26 | - (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options {
27 | // Called when a new scene session is being created.
28 | // Use this method to select a configuration to create the new scene with.
29 | return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role];
30 | }
31 |
32 |
33 | - (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet *)sceneSessions {
34 | // Called when the user discards a scene session.
35 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
36 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
37 | }
38 |
39 |
40 | @end
41 |
--------------------------------------------------------------------------------
/Photo Picker ObjC/Photo Picker ObjC/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Photo Picker ObjC/Photo Picker ObjC/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/Photo Picker ObjC/Photo Picker ObjC/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Photo Picker ObjC/Photo Picker ObjC/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 |
--------------------------------------------------------------------------------
/Photo Picker ObjC/Photo Picker ObjC/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 | UISceneConfigurations
28 |
29 | UIWindowSceneSessionRoleApplication
30 |
31 |
32 | UISceneConfigurationName
33 | Default Configuration
34 | UISceneDelegateClassName
35 | SceneDelegate
36 |
37 |
38 |
39 |
40 | NSPhotoLibraryUsageDescription
41 | Test
42 | UIApplicationSupportsIndirectInputEvents
43 |
44 | UILaunchStoryboardName
45 | LaunchScreen
46 | UIRequiredDeviceCapabilities
47 |
48 | armv7
49 |
50 | UISupportedInterfaceOrientations
51 |
52 | UIInterfaceOrientationPortrait
53 | UIInterfaceOrientationLandscapeLeft
54 | UIInterfaceOrientationLandscapeRight
55 |
56 | UISupportedInterfaceOrientations~ipad
57 |
58 | UIInterfaceOrientationPortrait
59 | UIInterfaceOrientationPortraitUpsideDown
60 | UIInterfaceOrientationLandscapeLeft
61 | UIInterfaceOrientationLandscapeRight
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/Photo Picker ObjC/Photo Picker ObjC/SceneDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.h
3 | // Photo Picker ObjC
4 | //
5 | // Created by Kyle Howells on 23/06/2020.
6 | //
7 |
8 | #import
9 |
10 | @interface SceneDelegate : UIResponder
11 |
12 | @property (strong, nonatomic) UIWindow * window;
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/Photo Picker ObjC/Photo Picker ObjC/SceneDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.m
3 | // Photo Picker ObjC
4 | //
5 | // Created by Kyle Howells on 23/06/2020.
6 | //
7 |
8 | #import "SceneDelegate.h"
9 | #import "ViewController.h"
10 |
11 | @interface SceneDelegate ()
12 |
13 | @end
14 |
15 |
16 | @implementation SceneDelegate
17 |
18 | - (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
19 | self.window = [[UIWindow alloc] initWithWindowScene:(UIWindowScene*)scene];
20 | self.window.rootViewController = [[ViewController alloc] init];
21 | [self.window makeKeyAndVisible];
22 | }
23 |
24 |
25 | - (void)sceneDidDisconnect:(UIScene *)scene {
26 | // Called as the scene is being released by the system.
27 | // This occurs shortly after the scene enters the background, or when its session is discarded.
28 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
29 | // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
30 | }
31 |
32 |
33 | - (void)sceneDidBecomeActive:(UIScene *)scene {
34 | // Called when the scene has moved from an inactive state to an active state.
35 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
36 | }
37 |
38 |
39 | - (void)sceneWillResignActive:(UIScene *)scene {
40 | // Called when the scene will move from an active state to an inactive state.
41 | // This may occur due to temporary interruptions (ex. an incoming phone call).
42 | }
43 |
44 |
45 | - (void)sceneWillEnterForeground:(UIScene *)scene {
46 | // Called as the scene transitions from the background to the foreground.
47 | // Use this method to undo the changes made on entering the background.
48 | }
49 |
50 |
51 | - (void)sceneDidEnterBackground:(UIScene *)scene {
52 | // Called as the scene transitions from the foreground to the background.
53 | // Use this method to save data, release shared resources, and store enough scene-specific state information
54 | // to restore the scene back to its current state.
55 | }
56 |
57 |
58 | @end
59 |
--------------------------------------------------------------------------------
/Photo Picker ObjC/Photo Picker ObjC/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // Photo Picker ObjC
4 | //
5 | // Created by Kyle Howells on 23/06/2020.
6 | //
7 |
8 | #import
9 |
10 | @interface ViewController : UIViewController
11 |
12 |
13 | @end
14 |
15 |
--------------------------------------------------------------------------------
/Photo Picker ObjC/Photo Picker ObjC/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // Photo Picker ObjC
4 | //
5 | // Created by Kyle Howells on 23/06/2020.
6 | //
7 |
8 | #import "ViewController.h"
9 | #import
10 | #import
11 | @import MobileCoreServices;
12 |
13 | @interface ViewController ()
14 |
15 | @end
16 |
17 | @implementation ViewController{
18 | UIScrollView *scrollView;
19 | NSMutableArray * imageViews;
20 | UIButton *selectButton;
21 | }
22 |
23 | - (void)viewDidLoad {
24 | [super viewDidLoad];
25 |
26 | self.view.backgroundColor = [UIColor whiteColor];
27 |
28 | imageViews = [NSMutableArray array];
29 |
30 | // Create ScrollView
31 | scrollView = [[UIScrollView alloc] init];
32 | scrollView.backgroundColor = [UIColor colorWithWhite:0.98 alpha:1];
33 | [self.view addSubview:scrollView];
34 |
35 | // Select Photos Button
36 | selectButton = [UIButton buttonWithType:UIButtonTypeSystem];
37 | [selectButton setTitle:@"Select Photos" forState:UIControlStateNormal];
38 | [selectButton addTarget:self action:@selector(selectPressed:) forControlEvents:UIControlEventTouchUpInside];
39 | [selectButton sizeToFit];
40 | [self.view addSubview:selectButton];
41 | }
42 |
43 | -(void)viewDidLayoutSubviews{
44 | [super viewDidLayoutSubviews];
45 | const CGSize size = self.view.bounds.size;
46 | const UIEdgeInsets safeArea = self.view.safeAreaInsets;
47 |
48 | selectButton.frame = ({
49 | CGRect frame = CGRectZero;
50 | frame.size.width = MIN(size.width - 20, 250);
51 | frame.size.height = 40;
52 | frame.origin.y = size.height - (frame.size.height + 20 + safeArea.bottom);
53 | frame.origin.x = (size.width - frame.size.width) * 0.5;
54 | frame;
55 | });
56 |
57 | scrollView.frame = ({
58 | CGRect frame = CGRectZero;
59 | frame.origin.y = safeArea.top + 10;
60 | frame.size.height = (selectButton.frame.origin.y - 20) - frame.origin.y;
61 | frame.size.width = size.width - 40;
62 | frame.origin.x = (size.width - frame.size.width) * 0.5;
63 | frame;
64 | });
65 |
66 | CGFloat y = 10;
67 | for (NSInteger i = 0; i < imageViews.count; i++) {
68 | UIImageView *imageView = imageViews[i];
69 | imageView.frame = ({
70 | CGRect frame = CGRectZero;
71 | frame.origin.y = y;
72 | frame.size.width = MIN(scrollView.bounds.size.width - 20, 300);
73 | frame.origin.x = (scrollView.bounds.size.width - frame.size.width) * 0.5;
74 | frame.size.height = MIN(frame.size.width * 0.75, 250);
75 | y += frame.size.height + 10;
76 | frame;
77 | });
78 | }
79 | scrollView.contentSize = CGSizeMake(0, y);
80 | }
81 |
82 | #pragma mark Helpers
83 |
84 | -(UIImageView*)newImageViewForImage:(UIImage*)image{
85 | UIImageView *imageView = [[UIImageView alloc] init];
86 | imageView.contentMode = UIViewContentModeScaleAspectFit;
87 | imageView.backgroundColor = [UIColor blackColor];
88 | imageView.image = image;
89 | return imageView;
90 | }
91 |
92 | -(void)clearImageViews{
93 | for (UIImageView *imageView in imageViews) {
94 | [imageView removeFromSuperview];
95 | }
96 | [imageViews removeAllObjects];
97 | }
98 |
99 | #pragma mark - PHPicker
100 |
101 | -(void)selectPressed:(id)sender{
102 | PHPickerConfiguration *config = [[PHPickerConfiguration alloc] init];
103 | config.selectionLimit = 3;
104 | config.filter = [PHPickerFilter imagesFilter];
105 |
106 | PHPickerViewController *pickerViewController = [[PHPickerViewController alloc] initWithConfiguration:config];
107 | pickerViewController.delegate = self;
108 | [self presentViewController:pickerViewController animated:YES completion:nil];
109 | }
110 |
111 | -(void)picker:(PHPickerViewController *)picker didFinishPicking:(NSArray *)results{
112 | NSLog(@"-picker:%@ didFinishPicking:%@", picker, results);
113 |
114 | [self clearImageViews];
115 | [picker dismissViewControllerAnimated:YES completion:nil];
116 |
117 | for (PHPickerResult *result in results) {
118 | NSLog(@"result: %@", result);
119 |
120 | NSLog(@"%@", result.assetIdentifier);
121 | NSLog(@"%@", result.itemProvider);
122 |
123 | // Get UIImage
124 | [result.itemProvider loadObjectOfClass:[UIImage class] completionHandler:^(__kindof id _Nullable object, NSError * _Nullable error) {
125 | NSLog(@"object: %@, error: %@", object, error);
126 |
127 | if ([object isKindOfClass:[UIImage class]]) {
128 | dispatch_async(dispatch_get_main_queue(), ^{
129 | UIImageView *imageView = [self newImageViewForImage:(UIImage*)object];
130 | [self->imageViews addObject:imageView];
131 | [self->scrollView addSubview:imageView];
132 | [self.view setNeedsLayout];
133 | });
134 | }
135 | }];
136 |
137 | // Get file
138 | // [result.itemProvider loadItemForTypeIdentifier:(NSString *)kUTTypeImage options:nil completionHandler:^(id item, NSError *error) {
139 | // NSLog(@"%@", item);
140 | // NSLog(@"%@", [item class]);
141 | //
142 | // if ([item isKindOfClass:[NSURL class]]) {
143 | // NSError *error = nil;
144 | // NSData *data = [NSData dataWithContentsOfURL:item options:0 error:&error];
145 | // NSLog(@"%@", data);
146 | // NSLog(@"%@", error);
147 | // }
148 | // }];
149 | }
150 | }
151 |
152 | @end
153 |
--------------------------------------------------------------------------------
/Photo Picker ObjC/Photo Picker ObjC/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // Photo Picker ObjC
4 | //
5 | // Created by Kyle Howells on 23/06/2020.
6 | //
7 |
8 | #import
9 | #import "AppDelegate.h"
10 |
11 | int main(int argc, char * argv[]) {
12 | NSString * appDelegateClassName;
13 | @autoreleasepool {
14 | // Setup code that might create autoreleased objects goes here.
15 | appDelegateClassName = NSStringFromClass([AppDelegate class]);
16 | }
17 | return UIApplicationMain(argc, argv, nil, appDelegateClassName);
18 | }
19 |
--------------------------------------------------------------------------------
/Photo Picker Swift/Photo Picker Swift.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Photo Picker Swift/Photo Picker Swift.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Photo Picker Swift/Photo Picker Swift/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // Photo Picker Swift
4 | //
5 | // Created by Kyle Howells on 23/06/2020.
6 | //
7 |
8 | import UIKit
9 |
10 | @UIApplicationMain
11 | class AppDelegate: UIResponder, UIApplicationDelegate {
12 |
13 |
14 |
15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
16 | // Override point for customization after application launch.
17 | return true
18 | }
19 |
20 | // MARK: UISceneSession Lifecycle
21 |
22 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
23 | // Called when a new scene session is being created.
24 | // Use this method to select a configuration to create the new scene with.
25 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
26 | }
27 |
28 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {
29 | // Called when the user discards a scene session.
30 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
31 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
32 | }
33 |
34 |
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/Photo Picker Swift/Photo Picker Swift/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Photo Picker Swift/Photo Picker Swift/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/Photo Picker Swift/Photo Picker Swift/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Photo Picker Swift/Photo Picker Swift/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 |
--------------------------------------------------------------------------------
/Photo Picker Swift/Photo Picker Swift/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 | UISceneConfigurations
28 |
29 | UIWindowSceneSessionRoleApplication
30 |
31 |
32 | UISceneConfigurationName
33 | Default Configuration
34 | UISceneDelegateClassName
35 | $(PRODUCT_MODULE_NAME).SceneDelegate
36 |
37 |
38 |
39 |
40 | UIApplicationSupportsIndirectInputEvents
41 |
42 | UILaunchStoryboardName
43 | LaunchScreen
44 | UIRequiredDeviceCapabilities
45 |
46 | armv7
47 |
48 | UISupportedInterfaceOrientations
49 |
50 | UIInterfaceOrientationPortrait
51 | UIInterfaceOrientationLandscapeLeft
52 | UIInterfaceOrientationLandscapeRight
53 |
54 | UISupportedInterfaceOrientations~ipad
55 |
56 | UIInterfaceOrientationPortrait
57 | UIInterfaceOrientationPortraitUpsideDown
58 | UIInterfaceOrientationLandscapeLeft
59 | UIInterfaceOrientationLandscapeRight
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/Photo Picker Swift/Photo Picker Swift/SceneDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.swift
3 | // Photo Picker Swift
4 | //
5 | // Created by Kyle Howells on 23/06/2020.
6 | //
7 |
8 | import UIKit
9 |
10 | class SceneDelegate: UIResponder, UIWindowSceneDelegate {
11 |
12 | var window: UIWindow?
13 |
14 |
15 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
16 | guard let windowScene = (scene as? UIWindowScene) else { return }
17 |
18 | let window = UIWindow(windowScene: windowScene)
19 | window.rootViewController = ViewController()
20 | self.window = window
21 | window.makeKeyAndVisible()
22 | }
23 |
24 | func sceneDidDisconnect(_ scene: UIScene) {
25 | // Called as the scene is being released by the system.
26 | // This occurs shortly after the scene enters the background, or when its session is discarded.
27 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
28 | // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
29 | }
30 |
31 | func sceneDidBecomeActive(_ scene: UIScene) {
32 | // Called when the scene has moved from an inactive state to an active state.
33 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
34 | }
35 |
36 | func sceneWillResignActive(_ scene: UIScene) {
37 | // Called when the scene will move from an active state to an inactive state.
38 | // This may occur due to temporary interruptions (ex. an incoming phone call).
39 | }
40 |
41 | func sceneWillEnterForeground(_ scene: UIScene) {
42 | // Called as the scene transitions from the background to the foreground.
43 | // Use this method to undo the changes made on entering the background.
44 | }
45 |
46 | func sceneDidEnterBackground(_ scene: UIScene) {
47 | // Called as the scene transitions from the foreground to the background.
48 | // Use this method to save data, release shared resources, and store enough scene-specific state information
49 | // to restore the scene back to its current state.
50 | }
51 |
52 |
53 | }
54 |
55 |
--------------------------------------------------------------------------------
/Photo Picker Swift/Photo Picker Swift/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // Photo Picker Swift
4 | //
5 | // Created by Kyle Howells on 23/06/2020.
6 | //
7 |
8 | import UIKit
9 | import PhotosUI
10 |
11 | class ViewController: UIViewController, PHPickerViewControllerDelegate {
12 |
13 | // MARK: - PHPickerViewController
14 |
15 | @objc func pickPhotos()
16 | {
17 | var config = PHPickerConfiguration()
18 | config.selectionLimit = 3
19 | config.filter = PHPickerFilter.images
20 |
21 | let pickerViewController = PHPickerViewController(configuration: config)
22 | pickerViewController.delegate = self
23 | self.present(pickerViewController, animated: true, completion: nil)
24 | }
25 |
26 | // MARK: PHPickerViewControllerDelegate
27 |
28 | func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
29 | picker.dismiss(animated: true, completion: nil)
30 | print(picker)
31 | print(results)
32 |
33 | for result in results {
34 | print(result.assetIdentifier)
35 | print(result.itemProvider)
36 |
37 | result.itemProvider.loadObject(ofClass: UIImage.self, completionHandler: { (object, error) in
38 | print(object)
39 | print(error)
40 | if let image = object as? UIImage {
41 | DispatchQueue.main.async {
42 | let imv = self.newImageView(image: image)
43 | self.imageViews.append(imv)
44 | self.scrollView.addSubview(imv)
45 | self.view.setNeedsLayout()
46 | }
47 | }
48 | })
49 | }
50 | }
51 |
52 |
53 |
54 | // MARK: - View Setup
55 |
56 | lazy var scrollView:UIScrollView = {
57 | let s = UIScrollView()
58 | s.backgroundColor = UIColor(white: 0.98, alpha: 1)
59 | return s
60 | }()
61 |
62 | lazy var button:UIButton = {
63 | let b = UIButton(type: .system)
64 | b.setTitle("Select Photos", for: .normal)
65 | b.addTarget(self, action: #selector(pickPhotos), for: .touchUpInside)
66 | b.sizeToFit()
67 | return b
68 | }()
69 |
70 | var imageViews = [UIImageView]()
71 |
72 | func newImageView(image:UIImage?) -> UIImageView {
73 | let imv = UIImageView()
74 | imv.backgroundColor = .black
75 | imv.image = image
76 | return imv
77 | }
78 |
79 | override func viewDidLoad() {
80 | super.viewDidLoad()
81 |
82 | self.view.backgroundColor = UIColor.white
83 |
84 | self.view.addSubview(self.scrollView)
85 | self.view.addSubview(self.button)
86 | }
87 |
88 | override func viewDidLayoutSubviews() {
89 | super.viewDidLayoutSubviews()
90 | let size = self.view.bounds.size
91 | let safeArea = self.view.safeAreaInsets
92 | let padding:CGFloat = 10
93 |
94 | button.frame = {
95 | var f = CGRect.zero
96 | f.size.width = min(size.width - (padding * 2), 250)
97 | f.size.height = 40
98 | f.origin.x = (size.width - f.width) * 0.5
99 | f.origin.y = size.height - (safeArea.bottom + padding + f.size.height)
100 | return f
101 | }()
102 |
103 | scrollView.frame = {
104 | var f = CGRect.zero
105 | f.origin.y = safeArea.top + padding
106 | f.size.width = size.width - (padding * 2)
107 | f.size.height = (button.frame.minY - 20) - f.origin.y
108 | f.origin.x = (size.width - f.width) * 0.5
109 | return f
110 | }()
111 |
112 | var y:CGFloat = 10
113 | for imageView in imageViews {
114 | imageView.frame = {
115 | var f = CGRect.zero
116 | f.origin.y = y
117 | f.size.width = min(scrollView.bounds.width - (padding * 2), 300)
118 | f.size.height = min(f.width * 0.75, 250)
119 | f.origin.x = (scrollView.bounds.width - f.size.width) * 0.5
120 | y += f.size.height + padding
121 | return f
122 | }()
123 | }
124 | scrollView.contentSize = CGSize(width: 0, height: y)
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ikyle.me-code-examples
2 | Smaller code examples from my blog posts on ikyle.me
3 |
--------------------------------------------------------------------------------
/Read Write Image Metadata ObjC/Read Write Image Metadata ObjC.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Read Write Image Metadata ObjC/Read Write Image Metadata ObjC.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Read Write Image Metadata ObjC/Read Write Image Metadata ObjC/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // Read Write Image Metadata ObjC
4 | //
5 | // Created by Kyle Howells on 13/07/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/Read Write Image Metadata ObjC/Read Write Image Metadata ObjC/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // Read Write Image Metadata ObjC
4 | //
5 | // Created by Kyle Howells on 13/07/2020.
6 | // Copyright © 2020 Kyle Howells. 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 | #pragma mark - UISceneSession lifecycle
25 |
26 |
27 | - (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options {
28 | // Called when a new scene session is being created.
29 | // Use this method to select a configuration to create the new scene with.
30 | return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role];
31 | }
32 |
33 |
34 | - (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet *)sceneSessions {
35 | // Called when the user discards a scene session.
36 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
37 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
38 | }
39 |
40 |
41 | @end
42 |
--------------------------------------------------------------------------------
/Read Write Image Metadata ObjC/Read Write Image Metadata ObjC/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/Read Write Image Metadata ObjC/Read Write Image Metadata ObjC/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Read Write Image Metadata ObjC/Read Write Image Metadata ObjC/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 |
--------------------------------------------------------------------------------
/Read Write Image Metadata ObjC/Read Write Image Metadata ObjC/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 | UISceneConfigurations
28 |
29 | UIWindowSceneSessionRoleApplication
30 |
31 |
32 | UISceneConfigurationName
33 | Default Configuration
34 | UISceneDelegateClassName
35 | SceneDelegate
36 |
37 |
38 |
39 |
40 | UILaunchStoryboardName
41 | LaunchScreen
42 | UIRequiredDeviceCapabilities
43 |
44 | armv7
45 |
46 | UISupportedInterfaceOrientations
47 |
48 | UIInterfaceOrientationPortrait
49 | UIInterfaceOrientationLandscapeLeft
50 | UIInterfaceOrientationLandscapeRight
51 |
52 | UISupportedInterfaceOrientations~ipad
53 |
54 | UIInterfaceOrientationPortrait
55 | UIInterfaceOrientationPortraitUpsideDown
56 | UIInterfaceOrientationLandscapeLeft
57 | UIInterfaceOrientationLandscapeRight
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/Read Write Image Metadata ObjC/Read Write Image Metadata ObjC/Read Write Image Metadata ObjC.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.files.user-selected.read-write
8 |
9 | com.apple.security.network.client
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Read Write Image Metadata ObjC/Read Write Image Metadata ObjC/SceneDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.h
3 | // Read Write Image Metadata ObjC
4 | //
5 | // Created by Kyle Howells on 13/07/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface SceneDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow * window;
14 |
15 | @end
16 |
17 |
--------------------------------------------------------------------------------
/Read Write Image Metadata ObjC/Read Write Image Metadata ObjC/SceneDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.m
3 | // Read Write Image Metadata ObjC
4 | //
5 | // Created by Kyle Howells on 13/07/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | #import "SceneDelegate.h"
10 | #import "ViewController.h"
11 |
12 | @interface SceneDelegate ()
13 |
14 | @end
15 |
16 |
17 | @implementation SceneDelegate
18 |
19 | - (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
20 | self.window = [[UIWindow alloc] initWithWindowScene:(UIWindowScene*)scene];
21 | self.window.rootViewController = [[ViewController alloc] init];
22 | [self.window makeKeyAndVisible];
23 | }
24 |
25 |
26 | - (void)sceneDidDisconnect:(UIScene *)scene {
27 | // Called as the scene is being released by the system.
28 | // This occurs shortly after the scene enters the background, or when its session is discarded.
29 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
30 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
31 | }
32 |
33 |
34 | - (void)sceneDidBecomeActive:(UIScene *)scene {
35 | // Called when the scene has moved from an inactive state to an active state.
36 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
37 | }
38 |
39 |
40 | - (void)sceneWillResignActive:(UIScene *)scene {
41 | // Called when the scene will move from an active state to an inactive state.
42 | // This may occur due to temporary interruptions (ex. an incoming phone call).
43 | }
44 |
45 |
46 | - (void)sceneWillEnterForeground:(UIScene *)scene {
47 | // Called as the scene transitions from the background to the foreground.
48 | // Use this method to undo the changes made on entering the background.
49 | }
50 |
51 |
52 | - (void)sceneDidEnterBackground:(UIScene *)scene {
53 | // Called as the scene transitions from the foreground to the background.
54 | // Use this method to save data, release shared resources, and store enough scene-specific state information
55 | // to restore the scene back to its current state.
56 | }
57 |
58 | @end
59 |
--------------------------------------------------------------------------------
/Read Write Image Metadata ObjC/Read Write Image Metadata ObjC/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // Read Write Image Metadata ObjC
4 | //
5 | // Created by Kyle Howells on 13/07/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ViewController : UIViewController
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/Read Write Image Metadata ObjC/Read Write Image Metadata ObjC/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // Read Write Image Metadata ObjC
4 | //
5 | // Created by Kyle Howells on 13/07/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | NSString * appDelegateClassName;
14 | @autoreleasepool {
15 | // Setup code that might create autoreleased objects goes here.
16 | appDelegateClassName = NSStringFromClass([AppDelegate class]);
17 | }
18 | return UIApplicationMain(argc, argv, nil, appDelegateClassName);
19 | }
20 |
--------------------------------------------------------------------------------
/Read Write Image Metadata Swift/Read Write Image Metadata Swift.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Read Write Image Metadata Swift/Read Write Image Metadata Swift.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Read Write Image Metadata Swift/Read Write Image Metadata Swift/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // Read Write Image Metadata Swift
4 | //
5 | // Created by Kyle Howells on 10/07/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 |
15 |
16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
17 | // Override point for customization after application launch.
18 | return true
19 | }
20 |
21 | // MARK: UISceneSession Lifecycle
22 |
23 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
24 | // Called when a new scene session is being created.
25 | // Use this method to select a configuration to create the new scene with.
26 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
27 | }
28 |
29 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {
30 | // Called when the user discards a scene session.
31 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
32 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
33 | }
34 |
35 |
36 | }
37 |
38 |
--------------------------------------------------------------------------------
/Read Write Image Metadata Swift/Read Write Image Metadata Swift/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/Read Write Image Metadata Swift/Read Write Image Metadata Swift/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Read Write Image Metadata Swift/Read Write Image Metadata Swift/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 |
--------------------------------------------------------------------------------
/Read Write Image Metadata Swift/Read Write Image Metadata Swift/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 | UISceneConfigurations
28 |
29 | UIWindowSceneSessionRoleApplication
30 |
31 |
32 | UISceneConfigurationName
33 | Default Configuration
34 | UISceneDelegateClassName
35 | $(PRODUCT_MODULE_NAME).SceneDelegate
36 |
37 |
38 |
39 |
40 | UILaunchStoryboardName
41 | LaunchScreen
42 | UIRequiredDeviceCapabilities
43 |
44 | armv7
45 |
46 | UISupportedInterfaceOrientations
47 |
48 | UIInterfaceOrientationPortrait
49 | UIInterfaceOrientationLandscapeLeft
50 | UIInterfaceOrientationLandscapeRight
51 |
52 | UISupportedInterfaceOrientations~ipad
53 |
54 | UIInterfaceOrientationPortrait
55 | UIInterfaceOrientationPortraitUpsideDown
56 | UIInterfaceOrientationLandscapeLeft
57 | UIInterfaceOrientationLandscapeRight
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/Read Write Image Metadata Swift/Read Write Image Metadata Swift/Read Write Image Metadata Swift.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Read Write Image Metadata Swift/Read Write Image Metadata Swift/SceneDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.swift
3 | // Read Write Image Metadata Swift
4 | //
5 | // Created by Kyle Howells on 10/07/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class SceneDelegate: UIResponder, UIWindowSceneDelegate {
12 |
13 | var window: UIWindow?
14 |
15 |
16 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
17 | guard let windowScene = (scene as? UIWindowScene) else { return }
18 |
19 | let window = UIWindow(windowScene: windowScene)
20 | window.rootViewController = ViewController()
21 | self.window = window
22 | window.makeKeyAndVisible()
23 | }
24 |
25 | func sceneDidDisconnect(_ scene: UIScene) {
26 | // Called as the scene is being released by the system.
27 | // This occurs shortly after the scene enters the background, or when its session is discarded.
28 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
29 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
30 | }
31 |
32 | func sceneDidBecomeActive(_ scene: UIScene) {
33 | // Called when the scene has moved from an inactive state to an active state.
34 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
35 | }
36 |
37 | func sceneWillResignActive(_ scene: UIScene) {
38 | // Called when the scene will move from an active state to an inactive state.
39 | // This may occur due to temporary interruptions (ex. an incoming phone call).
40 | }
41 |
42 | func sceneWillEnterForeground(_ scene: UIScene) {
43 | // Called as the scene transitions from the background to the foreground.
44 | // Use this method to undo the changes made on entering the background.
45 | }
46 |
47 | func sceneDidEnterBackground(_ scene: UIScene) {
48 | // Called as the scene transitions from the foreground to the background.
49 | // Use this method to save data, release shared resources, and store enough scene-specific state information
50 | // to restore the scene back to its current state.
51 | }
52 |
53 |
54 | }
55 |
56 |
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-objc/Titlebar-TabBar.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-objc/Titlebar-TabBar.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-objc/Titlebar-TabBar.xcodeproj/xcuserdata/kylehowells.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | Titlebar-TabBar.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-objc/Titlebar-TabBar/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // Titlebar-TabBar
4 | //
5 | // Created by Kyle Howells on 31/05/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-objc/Titlebar-TabBar/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // Titlebar-TabBar
4 | //
5 | // Created by Kyle Howells on 31/05/2020.
6 | // Copyright © 2020 Kyle Howells. 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 | #pragma mark - UISceneSession lifecycle
25 |
26 |
27 | - (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options {
28 | // Called when a new scene session is being created.
29 | // Use this method to select a configuration to create the new scene with.
30 | return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role];
31 | }
32 |
33 |
34 | - (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet *)sceneSessions {
35 | // Called when the user discards a scene session.
36 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
37 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
38 | }
39 |
40 |
41 | @end
42 |
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-objc/Titlebar-TabBar/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-objc/Titlebar-TabBar/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-objc/Titlebar-TabBar/Assets.xcassets/first.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "first.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-objc/Titlebar-TabBar/Assets.xcassets/first.imageset/first.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kylehowells/ikyle.me-code-examples/502052a2e5da56c6fdb78148ea5ac7e132efab32/macCatalyst-titlebar-tabbar-objc/Titlebar-TabBar/Assets.xcassets/first.imageset/first.pdf
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-objc/Titlebar-TabBar/Assets.xcassets/second.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "second.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-objc/Titlebar-TabBar/Assets.xcassets/second.imageset/second.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kylehowells/ikyle.me-code-examples/502052a2e5da56c6fdb78148ea5ac7e132efab32/macCatalyst-titlebar-tabbar-objc/Titlebar-TabBar/Assets.xcassets/second.imageset/second.pdf
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-objc/Titlebar-TabBar/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 |
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-objc/Titlebar-TabBar/FirstViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // FirstViewController.h
3 | // Titlebar-TabBar
4 | //
5 | // Created by Kyle Howells on 31/05/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface FirstViewController : UIViewController
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-objc/Titlebar-TabBar/FirstViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // FirstViewController.m
3 | // Titlebar-TabBar
4 | //
5 | // Created by Kyle Howells on 31/05/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | #import "FirstViewController.h"
10 |
11 | @interface FirstViewController ()
12 |
13 | @end
14 |
15 | @implementation FirstViewController
16 |
17 | - (void)viewDidLoad {
18 | [super viewDidLoad];
19 | // Do any additional setup after loading the view.
20 |
21 | self.title = @"First";
22 |
23 | self.view.backgroundColor = [UIColor whiteColor];
24 |
25 | UILabel *label = [[UILabel alloc] init];
26 | label.textColor = [UIColor lightGrayColor];
27 | label.text = @"First View";
28 | [label sizeToFit];
29 | [self.view addSubview:label];
30 | label.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin;
31 | label.center = self.view.center;
32 | }
33 |
34 |
35 | @end
36 |
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-objc/Titlebar-TabBar/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 | UISceneConfigurations
28 |
29 | UIWindowSceneSessionRoleApplication
30 |
31 |
32 | UISceneConfigurationName
33 | Default Configuration
34 | UISceneDelegateClassName
35 | SceneDelegate
36 |
37 |
38 |
39 |
40 | UILaunchStoryboardName
41 | LaunchScreen
42 | UIRequiredDeviceCapabilities
43 |
44 | armv7
45 |
46 | UIStatusBarTintParameters
47 |
48 | UINavigationBar
49 |
50 | Style
51 | UIBarStyleDefault
52 | Translucent
53 |
54 |
55 |
56 | UISupportedInterfaceOrientations
57 |
58 | UIInterfaceOrientationPortrait
59 | UIInterfaceOrientationLandscapeLeft
60 | UIInterfaceOrientationLandscapeRight
61 |
62 | UISupportedInterfaceOrientations~ipad
63 |
64 | UIInterfaceOrientationPortrait
65 | UIInterfaceOrientationPortraitUpsideDown
66 | UIInterfaceOrientationLandscapeLeft
67 | UIInterfaceOrientationLandscapeRight
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-objc/Titlebar-TabBar/SceneDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.h
3 | // Titlebar-TabBar
4 | //
5 | // Created by Kyle Howells on 31/05/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface SceneDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow * window;
14 |
15 | @end
16 |
17 |
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-objc/Titlebar-TabBar/SceneDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.m
3 | // Titlebar-TabBar
4 | //
5 | // Created by Kyle Howells on 31/05/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | #import "SceneDelegate.h"
10 | #import "FirstViewController.h"
11 | #import "SecondViewController.h"
12 |
13 | #if TARGET_OS_MACCATALYST
14 | #import
15 |
16 | @interface SceneDelegate ()
17 | #else
18 | @interface SceneDelegate ()
19 | #endif
20 | @property (nonatomic, strong) UITabBarController *tabbarController;
21 | @end
22 |
23 |
24 |
25 | @implementation SceneDelegate
26 |
27 | - (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions
28 | {
29 | self.window = [[UIWindow alloc] initWithWindowScene:(UIWindowScene*)scene];
30 | _tabbarController = [[UITabBarController alloc] init];
31 | _tabbarController.viewControllers = @[ [[FirstViewController alloc] init], [[SecondViewController alloc] init] ];
32 |
33 | #if TARGET_OS_MACCATALYST
34 | NSToolbar *toolbar = [[NSToolbar alloc] initWithIdentifier:@"mainToolbar"];
35 | toolbar.centeredItemIdentifier = @"mainTabsToolbarItem";
36 | toolbar.delegate = self;
37 |
38 | [(UIWindowScene*)scene titlebar].toolbar = toolbar;
39 | [(UIWindowScene*)scene titlebar].titleVisibility = UITitlebarTitleVisibilityHidden;
40 |
41 | _tabbarController.tabBar.hidden = YES;
42 | #endif
43 |
44 | self.window.rootViewController = _tabbarController;
45 | [self.window makeKeyAndVisible];
46 | }
47 |
48 |
49 | - (void)sceneDidDisconnect:(UIScene *)scene {
50 | // Called as the scene is being released by the system.
51 | // This occurs shortly after the scene enters the background, or when its session is discarded.
52 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
53 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
54 | }
55 |
56 |
57 | - (void)sceneDidBecomeActive:(UIScene *)scene {
58 | // Called when the scene has moved from an inactive state to an active state.
59 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
60 | }
61 |
62 |
63 | - (void)sceneWillResignActive:(UIScene *)scene {
64 | // Called when the scene will move from an active state to an inactive state.
65 | // This may occur due to temporary interruptions (ex. an incoming phone call).
66 | }
67 |
68 |
69 | - (void)sceneWillEnterForeground:(UIScene *)scene {
70 | // Called as the scene transitions from the background to the foreground.
71 | // Use this method to undo the changes made on entering the background.
72 | }
73 |
74 |
75 | - (void)sceneDidEnterBackground:(UIScene *)scene {
76 | // Called as the scene transitions from the foreground to the background.
77 | // Use this method to save data, release shared resources, and store enough scene-specific state information
78 | // to restore the scene back to its current state.
79 | }
80 |
81 |
82 | #pragma mark - NSToolbarDelegate
83 |
84 | #if TARGET_OS_MACCATALYST
85 |
86 | - (nullable NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSToolbarItemIdentifier)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag
87 | {
88 | if ([itemIdentifier isEqualToString:@"mainTabsToolbarItem"]) {
89 | NSToolbarItemGroup *group = [NSToolbarItemGroup groupWithItemIdentifier:itemIdentifier
90 | titles:@[@"First", @"Second"]
91 | selectionMode:NSToolbarItemGroupSelectionModeSelectOne
92 | labels:@[@"First view", @"Second view"]
93 | target:self
94 | action:@selector(toolbarGroupSelectionChanged:)];
95 | [group setSelectedIndex:0];
96 | return group;
97 | }
98 |
99 | return nil;
100 | }
101 |
102 | /* Returns the ordered list of items to be shown in the toolbar by default. If during initialization, no overriding values are found in the user defaults, or if the user chooses to revert to the default items this set will be used. */
103 | - (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar{
104 | return @[@"mainTabsToolbarItem"];
105 | }
106 |
107 | /* Returns the list of all allowed items by identifier. By default, the toolbar does not assume any items are allowed, even the separator. So, every allowed item must be explicitly listed. The set of allowed items is used to construct the customization palette. The order of items does not necessarily guarantee the order of appearance in the palette. At minimum, you should return the default item list.*/
108 | - (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar{
109 | return [self toolbarDefaultItemIdentifiers:toolbar];
110 | }
111 |
112 |
113 | -(void)toolbarGroupSelectionChanged:(NSToolbarItemGroup*)sender{
114 | self.tabbarController.selectedIndex = sender.selectedIndex;
115 | }
116 | #endif
117 |
118 | @end
119 |
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-objc/Titlebar-TabBar/SecondViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // SecondViewController.h
3 | // Titlebar-TabBar
4 | //
5 | // Created by Kyle Howells on 31/05/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface SecondViewController : UIViewController
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-objc/Titlebar-TabBar/SecondViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // SecondViewController.m
3 | // Titlebar-TabBar
4 | //
5 | // Created by Kyle Howells on 31/05/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | #import "SecondViewController.h"
10 |
11 | @interface SecondViewController ()
12 |
13 | @end
14 |
15 | @implementation SecondViewController
16 |
17 | - (void)viewDidLoad {
18 | [super viewDidLoad];
19 | // Do any additional setup after loading the view.
20 |
21 | self.title = @"Second";
22 |
23 | self.view.backgroundColor = [UIColor whiteColor];
24 |
25 | UILabel *label = [[UILabel alloc] init];
26 | label.textColor = [UIColor lightGrayColor];
27 | label.text = @"Second View";
28 | [label sizeToFit];
29 | [self.view addSubview:label];
30 | label.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin;
31 | label.center = self.view.center;
32 | }
33 |
34 |
35 | @end
36 |
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-objc/Titlebar-TabBar/Titlebar-TabBar.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.network.client
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-objc/Titlebar-TabBar/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // Titlebar-TabBar
4 | //
5 | // Created by Kyle Howells on 31/05/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | NSString * appDelegateClassName;
14 | @autoreleasepool {
15 | // Setup code that might create autoreleased objects goes here.
16 | appDelegateClassName = NSStringFromClass([AppDelegate class]);
17 | }
18 | return UIApplicationMain(argc, argv, nil, appDelegateClassName);
19 | }
20 |
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-swift/Titlebar-TabBar.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-swift/Titlebar-TabBar.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-swift/Titlebar-TabBar.xcodeproj/xcuserdata/kylehowells.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | Titlebar-TabBar.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-swift/Titlebar-TabBar/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // Titlebar-TabBar
4 | //
5 | // Created by Kyle Howells on 31/05/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
15 | // Override point for customization after application launch.
16 | return true
17 | }
18 |
19 | // MARK: UISceneSession Lifecycle
20 |
21 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
22 | // Called when a new scene session is being created.
23 | // Use this method to select a configuration to create the new scene with.
24 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
25 | }
26 |
27 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {
28 | // Called when the user discards a scene session.
29 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
30 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-swift/Titlebar-TabBar/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-swift/Titlebar-TabBar/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-swift/Titlebar-TabBar/Assets.xcassets/first.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "first.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-swift/Titlebar-TabBar/Assets.xcassets/first.imageset/first.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kylehowells/ikyle.me-code-examples/502052a2e5da56c6fdb78148ea5ac7e132efab32/macCatalyst-titlebar-tabbar-swift/Titlebar-TabBar/Assets.xcassets/first.imageset/first.pdf
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-swift/Titlebar-TabBar/Assets.xcassets/second.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "second.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-swift/Titlebar-TabBar/Assets.xcassets/second.imageset/second.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kylehowells/ikyle.me-code-examples/502052a2e5da56c6fdb78148ea5ac7e132efab32/macCatalyst-titlebar-tabbar-swift/Titlebar-TabBar/Assets.xcassets/second.imageset/second.pdf
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-swift/Titlebar-TabBar/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 |
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-swift/Titlebar-TabBar/FirstViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FirstViewController.swift
3 | // Titlebar-TabBar
4 | //
5 | // Created by Kyle Howells on 31/05/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class FirstViewController: UIViewController {
12 |
13 | override func viewDidLoad() {
14 | super.viewDidLoad()
15 | // Do any additional setup after loading the view.
16 | self.title = "First"
17 |
18 | self.view.backgroundColor = .white
19 |
20 | let label = UILabel()
21 | label.text = "First View"
22 | label.textColor = UIColor.lightGray
23 | label.sizeToFit()
24 | self.view.addSubview(label)
25 | label.autoresizingMask = [.flexibleTopMargin, .flexibleRightMargin, .flexibleBottomMargin, .flexibleLeftMargin]
26 | label.center = self.view.center
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-swift/Titlebar-TabBar/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 | UISceneConfigurations
28 |
29 | UIWindowSceneSessionRoleApplication
30 |
31 |
32 | UISceneConfigurationName
33 | Default Configuration
34 | UISceneDelegateClassName
35 | $(PRODUCT_MODULE_NAME).SceneDelegate
36 |
37 |
38 |
39 |
40 | UILaunchStoryboardName
41 | LaunchScreen
42 | UIRequiredDeviceCapabilities
43 |
44 | armv7
45 |
46 | UIStatusBarTintParameters
47 |
48 | UINavigationBar
49 |
50 | Style
51 | UIBarStyleDefault
52 | Translucent
53 |
54 |
55 |
56 | UISupportedInterfaceOrientations
57 |
58 | UIInterfaceOrientationPortrait
59 | UIInterfaceOrientationLandscapeLeft
60 | UIInterfaceOrientationLandscapeRight
61 |
62 | UISupportedInterfaceOrientations~ipad
63 |
64 | UIInterfaceOrientationPortrait
65 | UIInterfaceOrientationPortraitUpsideDown
66 | UIInterfaceOrientationLandscapeLeft
67 | UIInterfaceOrientationLandscapeRight
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-swift/Titlebar-TabBar/SceneDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.swift
3 | // Titlebar-TabBar
4 | //
5 | // Created by Kyle Howells on 31/05/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class SceneDelegate: UIResponder, UIWindowSceneDelegate, NSToolbarDelegate {
12 |
13 | var window: UIWindow?
14 | var tabBarController: UITabBarController!
15 |
16 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
17 | guard let windowScene = (scene as? UIWindowScene) else { return }
18 |
19 | let window = UIWindow(windowScene: windowScene)
20 |
21 | tabBarController = UITabBarController()
22 | tabBarController.viewControllers = [FirstViewController(), SecondViewController()]
23 | window.rootViewController = tabBarController
24 | self.window = window
25 | window.makeKeyAndVisible()
26 |
27 |
28 | #if targetEnvironment(macCatalyst)
29 | let toolbar = NSToolbar(identifier: "mainToolbar")
30 | toolbar.centeredItemIdentifier = NSToolbarItem.Identifier(rawValue: "mainTabsToolbarItem")
31 | toolbar.delegate = self
32 |
33 | windowScene.titlebar?.titleVisibility = .hidden
34 | windowScene.titlebar?.toolbar = toolbar
35 |
36 | tabBarController.tabBar.isHidden = true
37 | #endif
38 | }
39 |
40 | func sceneDidDisconnect(_ scene: UIScene) {
41 | // Called as the scene is being released by the system.
42 | // This occurs shortly after the scene enters the background, or when its session is discarded.
43 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
44 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
45 | }
46 |
47 | func sceneDidBecomeActive(_ scene: UIScene) {
48 | // Called when the scene has moved from an inactive state to an active state.
49 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
50 | }
51 |
52 | func sceneWillResignActive(_ scene: UIScene) {
53 | // Called when the scene will move from an active state to an inactive state.
54 | // This may occur due to temporary interruptions (ex. an incoming phone call).
55 | }
56 |
57 | func sceneWillEnterForeground(_ scene: UIScene) {
58 | // Called as the scene transitions from the background to the foreground.
59 | // Use this method to undo the changes made on entering the background.
60 | }
61 |
62 | func sceneDidEnterBackground(_ scene: UIScene) {
63 | // Called as the scene transitions from the foreground to the background.
64 | // Use this method to save data, release shared resources, and store enough scene-specific state information
65 | // to restore the scene back to its current state.
66 | }
67 |
68 |
69 | // MARK: - NSToolbarDelegate
70 |
71 | func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem?
72 | {
73 | if (itemIdentifier.rawValue == "mainTabsToolbarItem")
74 | {
75 | let group = NSToolbarItemGroup.init(itemIdentifier: itemIdentifier,
76 | titles: ["First", "Second"],
77 | selectionMode: .selectOne,
78 | labels: ["First view", "Second view"],
79 | target: self, action: #selector(toolbarGroupSelectionChanged))
80 | group.setSelected(true, at: 0)
81 | return group
82 | }
83 |
84 | return nil
85 | }
86 |
87 | func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
88 | return [NSToolbarItem.Identifier(rawValue: "mainTabsToolbarItem")]
89 | }
90 |
91 | func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
92 | return self.toolbarDefaultItemIdentifiers(toolbar)
93 | }
94 |
95 |
96 | @objc func toolbarGroupSelectionChanged(_ sender: NSToolbarItemGroup) {
97 | print("toolbarGroupSelectionChanged( \(sender.selectedIndex) )")
98 | tabBarController.selectedIndex = sender.selectedIndex
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-swift/Titlebar-TabBar/SecondViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SecondViewController.swift
3 | // Titlebar-TabBar
4 | //
5 | // Created by Kyle Howells on 31/05/2020.
6 | // Copyright © 2020 Kyle Howells. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class SecondViewController: UIViewController {
12 |
13 | override func viewDidLoad() {
14 | super.viewDidLoad()
15 | // Do any additional setup after loading the view.
16 | self.title = "Second"
17 |
18 | self.view.backgroundColor = .white
19 |
20 | let label = UILabel()
21 | label.text = "Second View"
22 | label.textColor = UIColor.lightGray
23 | label.sizeToFit()
24 | self.view.addSubview(label)
25 | label.autoresizingMask = [.flexibleTopMargin, .flexibleRightMargin, .flexibleBottomMargin, .flexibleLeftMargin]
26 | label.center = self.view.center
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/macCatalyst-titlebar-tabbar-swift/Titlebar-TabBar/Titlebar-TabBar.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.network.client
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------