├── .gitignore ├── .swift-version ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── TVButton.podspec ├── TVButton.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ └── TVButton.xcscheme ├── TVButton ├── Info.plist ├── Specular.png ├── TVButton.h ├── TVButton.swift ├── TVButtonAnimation.swift └── TVButtonConstants.swift ├── TVButtonTests ├── Info.plist └── TVButtonTests.swift ├── build.sh └── examples ├── .DS_Store ├── StarWars ├── .DS_Store ├── Podfile ├── Sample.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── Sample.xcscheme ├── Sample │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── Info.plist │ ├── KyloA.png │ ├── KyloB.png │ ├── KyloC.png │ ├── KyloE.png │ └── ViewController.swift └── SampleTests │ ├── Info.plist │ └── SampleTests.swift └── TVButton ├── Podfile ├── Sample.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ └── Sample.xcscheme ├── Sample ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist ├── TVButtonBackground.png ├── TVButtonPattern.png ├── TVButtonTop.png └── ViewController.swift └── SampleTests ├── Info.plist └── SampleTests.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | # Pods/ 27 | 28 | # Carthage 29 | # 30 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 31 | # Carthage/Checkouts 32 | 33 | Carthage/Build 34 | .DS_Store 35 | examples/TVButton/.DS_Store 36 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 3.0 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | osx_image: xcode8.1 2 | language: objective-c 3 | env: 4 | global: 5 | - LC_CTYPE=en_US.UTF-8 6 | - LANG=en_US.UTF-8 7 | before_install: 8 | - gem install cocoapods --pre 9 | - xcrun simctl list 10 | install: echo "<3" 11 | env: 12 | - MODE=build 13 | - MODE=examples 14 | script: ./build.sh $MODE 15 | 16 | # whitelist 17 | branches: 18 | only: 19 | - master 20 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## [0.1.5](https://github.com/marmelroy/TVButton/tree/0.1.5) (2015-11-12) 4 | [Full Changelog](https://github.com/marmelroy/TVButton/compare/0.1.4...0.1.5) 5 | 6 | ## [0.1.4](https://github.com/marmelroy/TVButton/tree/0.1.4) (2015-11-11) 7 | [Full Changelog](https://github.com/marmelroy/TVButton/compare/0.1.3...0.1.4) 8 | 9 | ## [0.1.3](https://github.com/marmelroy/TVButton/tree/0.1.3) (2015-11-10) 10 | [Full Changelog](https://github.com/marmelroy/TVButton/compare/0.1.2...0.1.3) 11 | 12 | **Closed issues:** 13 | 14 | - Images for ready [\#3](https://github.com/marmelroy/TVButton/issues/3) 15 | - TvOS Support [\#2](https://github.com/marmelroy/TVButton/issues/2) 16 | 17 | ## [0.1.2](https://github.com/marmelroy/TVButton/tree/0.1.2) (2015-11-09) 18 | [Full Changelog](https://github.com/marmelroy/TVButton/compare/0.1...0.1.2) 19 | 20 | **Closed issues:** 21 | 22 | - Images for README [\#1](https://github.com/marmelroy/TVButton/issues/1) 23 | 24 | ## [0.1](https://github.com/marmelroy/TVButton/tree/0.1) (2015-11-08) 25 | 26 | 27 | \* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Roy Marmelstein 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![TVButton - Apple TV Parallax icons on iOS](https://cloud.githubusercontent.com/assets/889949/11056798/b0b54632-8785-11e5-8ef2-af9c579815f9.png) 2 | 3 | [![Build Status](https://travis-ci.org/marmelroy/TVButton.svg?branch=master)](https://travis-ci.org/marmelroy/TVButton) [![Version](http://img.shields.io/cocoapods/v/TVButton.svg)](http://cocoapods.org/?q=TVButton) 4 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 5 | 6 | # TVButton 7 | Recreating the cool parallax icons from Apple TV as iOS UIButtons (in Swift). The effect is triggered by long pressing or dragging. 8 | 9 | ![Star Wars TVButton](http://i.giphy.com/xTiTnCqL5arYHW92Lu.gif) 10 | 11 | ## Usage 12 | 13 | Import TVButton at the top of your Swift ViewController. 14 | 15 | ```swift 16 | import TVButton 17 | ``` 18 | 19 | Create and position your TVButton in interface builder or in code. 20 | 21 | For the parallax TVButton you will need at least two layers of images (three recommended). For best results, the button and the images should all have the same dimensions. Assign the relevant UIImages to TVButtonLayers and provide them as a layers array to the TVButton. 22 | ```swift 23 | let background = TVButtonLayer(image: UIImage(named: "TVButtonBackground.png")!) 24 | let pattern = TVButtonLayer(image: UIImage(named: "TVButtonPattern.png")!) 25 | let top = TVButtonLayer(image: UIImage(named: "TVButtonTop.png")!) 26 | tvButton.layers = [background, pattern, top] 27 | ``` 28 | 29 | You can customize the parallax intensity of your TVButton. Default value is 1.0 and it's very subtle. Maximum recommended value is 2.0. 30 | ```swift 31 | tvButton.parallaxIntensity = 1.3 32 | ``` 33 | 34 | ![TVButton in action](http://i.giphy.com/l0O9zc8b49oDi209y.gif) 35 | 36 | Enjoy! 37 | 38 | ### Setting up with [CocoaPods](http://cocoapods.org/?q=TVButton) 39 | ```ruby 40 | source 'https://github.com/CocoaPods/Specs.git' 41 | pod 'TVButton', '~> 1.0' 42 | ``` 43 | 44 | ### Setting up with Carthage 45 | 46 | [Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that automates the process of adding frameworks to your Cocoa application. 47 | 48 | You can install Carthage with [Homebrew](http://brew.sh/) using the following command: 49 | 50 | ```bash 51 | $ brew update 52 | $ brew install carthage 53 | ``` 54 | 55 | To integrate TVButton into your Xcode project using Carthage, specify it in your `Cartfile`: 56 | 57 | ```ogdl 58 | github "marmelroy/TVButton" 59 | ``` 60 | -------------------------------------------------------------------------------- /TVButton.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod lib lint TVButton.podspec' to ensure this is a 3 | # valid spec before submitting. 4 | # 5 | # Any lines starting with a # are optional, but their use is encouraged 6 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | s.name = "TVButton" 11 | s.version = "1.0.0" 12 | s.summary = "Apple TV style parallax icons as iOS UIButtons" 13 | 14 | # This description is used to generate tags and improve search results. 15 | # * Think: What does it do? Why did you write it? What is the focus? 16 | # * Try to keep it short, snappy and to the point. 17 | # * Write the description between the DESC delimiters below. 18 | # * Finally, don't worry about the indent, CocoaPods strips it! 19 | s.description = <<-DESC 20 | Recreating the cool parallax icons from Apple TV as iOS UIButtons (in Swift). 21 | DESC 22 | 23 | s.homepage = "https://github.com/marmelroy/TVButton" 24 | # s.screenshots = "www.example.com/screenshots_1", "www.example.com/screenshots_2" 25 | s.license = 'MIT' 26 | s.author = { "Roy Marmelstein" => "marmelroy@gmail.com" } 27 | s.source = { :git => "https://github.com/marmelroy/TVButton.git", :tag => s.version.to_s } 28 | s.social_media_url = "http://twitter.com/marmelroy" 29 | 30 | s.platform = :ios, '8.0' 31 | s.requires_arc = true 32 | 33 | s.source_files = "TVButton" 34 | s.resources = "TVButton/Specular.png" 35 | 36 | # s.public_header_files = 'Pod/Classes/**/*.h' 37 | # s.dependency 'AFNetworking', '~> 2.3' 38 | end 39 | -------------------------------------------------------------------------------- /TVButton.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 342AA0901BEEBE6F00B1A7D9 /* TVButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 342AA08F1BEEBE6F00B1A7D9 /* TVButton.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | 342AA0971BEEBE6F00B1A7D9 /* TVButton.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 342AA08C1BEEBE6F00B1A7D9 /* TVButton.framework */; }; 12 | 342AA09C1BEEBE6F00B1A7D9 /* TVButtonTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 342AA09B1BEEBE6F00B1A7D9 /* TVButtonTests.swift */; }; 13 | 342AA0A71BEEBF6E00B1A7D9 /* TVButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 342AA0A61BEEBF6E00B1A7D9 /* TVButton.swift */; }; 14 | 342AA0A91BEEBF7500B1A7D9 /* Specular.png in Resources */ = {isa = PBXBuildFile; fileRef = 342AA0A81BEEBF7500B1A7D9 /* Specular.png */; }; 15 | 34F374BE1BF1B0890085BE13 /* TVButtonAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F374BD1BF1B0890085BE13 /* TVButtonAnimation.swift */; }; 16 | 34F374C01BF1B0E60085BE13 /* TVButtonConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F374BF1BF1B0E60085BE13 /* TVButtonConstants.swift */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXContainerItemProxy section */ 20 | 342AA0981BEEBE6F00B1A7D9 /* PBXContainerItemProxy */ = { 21 | isa = PBXContainerItemProxy; 22 | containerPortal = 342AA0831BEEBE6F00B1A7D9 /* Project object */; 23 | proxyType = 1; 24 | remoteGlobalIDString = 342AA08B1BEEBE6F00B1A7D9; 25 | remoteInfo = TVButton; 26 | }; 27 | /* End PBXContainerItemProxy section */ 28 | 29 | /* Begin PBXFileReference section */ 30 | 342AA08C1BEEBE6F00B1A7D9 /* TVButton.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TVButton.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 31 | 342AA08F1BEEBE6F00B1A7D9 /* TVButton.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVButton.h; sourceTree = ""; }; 32 | 342AA0911BEEBE6F00B1A7D9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 33 | 342AA0961BEEBE6F00B1A7D9 /* TVButtonTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TVButtonTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 34 | 342AA09B1BEEBE6F00B1A7D9 /* TVButtonTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TVButtonTests.swift; sourceTree = ""; }; 35 | 342AA09D1BEEBE6F00B1A7D9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 36 | 342AA0A61BEEBF6E00B1A7D9 /* TVButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TVButton.swift; sourceTree = ""; }; 37 | 342AA0A81BEEBF7500B1A7D9 /* Specular.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Specular.png; sourceTree = ""; }; 38 | 34F374BD1BF1B0890085BE13 /* TVButtonAnimation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TVButtonAnimation.swift; sourceTree = ""; }; 39 | 34F374BF1BF1B0E60085BE13 /* TVButtonConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TVButtonConstants.swift; sourceTree = ""; }; 40 | /* End PBXFileReference section */ 41 | 42 | /* Begin PBXFrameworksBuildPhase section */ 43 | 342AA0881BEEBE6F00B1A7D9 /* Frameworks */ = { 44 | isa = PBXFrameworksBuildPhase; 45 | buildActionMask = 2147483647; 46 | files = ( 47 | ); 48 | runOnlyForDeploymentPostprocessing = 0; 49 | }; 50 | 342AA0931BEEBE6F00B1A7D9 /* Frameworks */ = { 51 | isa = PBXFrameworksBuildPhase; 52 | buildActionMask = 2147483647; 53 | files = ( 54 | 342AA0971BEEBE6F00B1A7D9 /* TVButton.framework in Frameworks */, 55 | ); 56 | runOnlyForDeploymentPostprocessing = 0; 57 | }; 58 | /* End PBXFrameworksBuildPhase section */ 59 | 60 | /* Begin PBXGroup section */ 61 | 342AA0821BEEBE6F00B1A7D9 = { 62 | isa = PBXGroup; 63 | children = ( 64 | 342AA08E1BEEBE6F00B1A7D9 /* TVButton */, 65 | 342AA09A1BEEBE6F00B1A7D9 /* TVButtonTests */, 66 | 342AA08D1BEEBE6F00B1A7D9 /* Products */, 67 | ); 68 | sourceTree = ""; 69 | }; 70 | 342AA08D1BEEBE6F00B1A7D9 /* Products */ = { 71 | isa = PBXGroup; 72 | children = ( 73 | 342AA08C1BEEBE6F00B1A7D9 /* TVButton.framework */, 74 | 342AA0961BEEBE6F00B1A7D9 /* TVButtonTests.xctest */, 75 | ); 76 | name = Products; 77 | sourceTree = ""; 78 | }; 79 | 342AA08E1BEEBE6F00B1A7D9 /* TVButton */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | 34F374CE1BF1B7EE0085BE13 /* Sources */, 83 | 34F374CF1BF1B7F30085BE13 /* Resources */, 84 | 342AA08F1BEEBE6F00B1A7D9 /* TVButton.h */, 85 | 342AA0911BEEBE6F00B1A7D9 /* Info.plist */, 86 | ); 87 | path = TVButton; 88 | sourceTree = ""; 89 | }; 90 | 342AA09A1BEEBE6F00B1A7D9 /* TVButtonTests */ = { 91 | isa = PBXGroup; 92 | children = ( 93 | 342AA09B1BEEBE6F00B1A7D9 /* TVButtonTests.swift */, 94 | 342AA09D1BEEBE6F00B1A7D9 /* Info.plist */, 95 | ); 96 | path = TVButtonTests; 97 | sourceTree = ""; 98 | }; 99 | 34F374CE1BF1B7EE0085BE13 /* Sources */ = { 100 | isa = PBXGroup; 101 | children = ( 102 | 342AA0A61BEEBF6E00B1A7D9 /* TVButton.swift */, 103 | 34F374BD1BF1B0890085BE13 /* TVButtonAnimation.swift */, 104 | 34F374BF1BF1B0E60085BE13 /* TVButtonConstants.swift */, 105 | ); 106 | name = Sources; 107 | sourceTree = ""; 108 | }; 109 | 34F374CF1BF1B7F30085BE13 /* Resources */ = { 110 | isa = PBXGroup; 111 | children = ( 112 | 342AA0A81BEEBF7500B1A7D9 /* Specular.png */, 113 | ); 114 | name = Resources; 115 | sourceTree = ""; 116 | }; 117 | /* End PBXGroup section */ 118 | 119 | /* Begin PBXHeadersBuildPhase section */ 120 | 342AA0891BEEBE6F00B1A7D9 /* Headers */ = { 121 | isa = PBXHeadersBuildPhase; 122 | buildActionMask = 2147483647; 123 | files = ( 124 | 342AA0901BEEBE6F00B1A7D9 /* TVButton.h in Headers */, 125 | ); 126 | runOnlyForDeploymentPostprocessing = 0; 127 | }; 128 | /* End PBXHeadersBuildPhase section */ 129 | 130 | /* Begin PBXNativeTarget section */ 131 | 342AA08B1BEEBE6F00B1A7D9 /* TVButton */ = { 132 | isa = PBXNativeTarget; 133 | buildConfigurationList = 342AA0A01BEEBE6F00B1A7D9 /* Build configuration list for PBXNativeTarget "TVButton" */; 134 | buildPhases = ( 135 | 342AA0871BEEBE6F00B1A7D9 /* Sources */, 136 | 342AA0881BEEBE6F00B1A7D9 /* Frameworks */, 137 | 342AA0891BEEBE6F00B1A7D9 /* Headers */, 138 | 342AA08A1BEEBE6F00B1A7D9 /* Resources */, 139 | ); 140 | buildRules = ( 141 | ); 142 | dependencies = ( 143 | ); 144 | name = TVButton; 145 | productName = TVButton; 146 | productReference = 342AA08C1BEEBE6F00B1A7D9 /* TVButton.framework */; 147 | productType = "com.apple.product-type.framework"; 148 | }; 149 | 342AA0951BEEBE6F00B1A7D9 /* TVButtonTests */ = { 150 | isa = PBXNativeTarget; 151 | buildConfigurationList = 342AA0A31BEEBE6F00B1A7D9 /* Build configuration list for PBXNativeTarget "TVButtonTests" */; 152 | buildPhases = ( 153 | 342AA0921BEEBE6F00B1A7D9 /* Sources */, 154 | 342AA0931BEEBE6F00B1A7D9 /* Frameworks */, 155 | 342AA0941BEEBE6F00B1A7D9 /* Resources */, 156 | ); 157 | buildRules = ( 158 | ); 159 | dependencies = ( 160 | 342AA0991BEEBE6F00B1A7D9 /* PBXTargetDependency */, 161 | ); 162 | name = TVButtonTests; 163 | productName = TVButtonTests; 164 | productReference = 342AA0961BEEBE6F00B1A7D9 /* TVButtonTests.xctest */; 165 | productType = "com.apple.product-type.bundle.unit-test"; 166 | }; 167 | /* End PBXNativeTarget section */ 168 | 169 | /* Begin PBXProject section */ 170 | 342AA0831BEEBE6F00B1A7D9 /* Project object */ = { 171 | isa = PBXProject; 172 | attributes = { 173 | LastSwiftUpdateCheck = 0710; 174 | LastUpgradeCheck = 0810; 175 | ORGANIZATIONNAME = "Roy Marmelstein"; 176 | TargetAttributes = { 177 | 342AA08B1BEEBE6F00B1A7D9 = { 178 | CreatedOnToolsVersion = 7.1; 179 | LastSwiftMigration = 0810; 180 | }; 181 | 342AA0951BEEBE6F00B1A7D9 = { 182 | CreatedOnToolsVersion = 7.1; 183 | LastSwiftMigration = 0810; 184 | }; 185 | }; 186 | }; 187 | buildConfigurationList = 342AA0861BEEBE6F00B1A7D9 /* Build configuration list for PBXProject "TVButton" */; 188 | compatibilityVersion = "Xcode 3.2"; 189 | developmentRegion = English; 190 | hasScannedForEncodings = 0; 191 | knownRegions = ( 192 | en, 193 | ); 194 | mainGroup = 342AA0821BEEBE6F00B1A7D9; 195 | productRefGroup = 342AA08D1BEEBE6F00B1A7D9 /* Products */; 196 | projectDirPath = ""; 197 | projectRoot = ""; 198 | targets = ( 199 | 342AA08B1BEEBE6F00B1A7D9 /* TVButton */, 200 | 342AA0951BEEBE6F00B1A7D9 /* TVButtonTests */, 201 | ); 202 | }; 203 | /* End PBXProject section */ 204 | 205 | /* Begin PBXResourcesBuildPhase section */ 206 | 342AA08A1BEEBE6F00B1A7D9 /* Resources */ = { 207 | isa = PBXResourcesBuildPhase; 208 | buildActionMask = 2147483647; 209 | files = ( 210 | 342AA0A91BEEBF7500B1A7D9 /* Specular.png in Resources */, 211 | ); 212 | runOnlyForDeploymentPostprocessing = 0; 213 | }; 214 | 342AA0941BEEBE6F00B1A7D9 /* Resources */ = { 215 | isa = PBXResourcesBuildPhase; 216 | buildActionMask = 2147483647; 217 | files = ( 218 | ); 219 | runOnlyForDeploymentPostprocessing = 0; 220 | }; 221 | /* End PBXResourcesBuildPhase section */ 222 | 223 | /* Begin PBXSourcesBuildPhase section */ 224 | 342AA0871BEEBE6F00B1A7D9 /* Sources */ = { 225 | isa = PBXSourcesBuildPhase; 226 | buildActionMask = 2147483647; 227 | files = ( 228 | 34F374C01BF1B0E60085BE13 /* TVButtonConstants.swift in Sources */, 229 | 34F374BE1BF1B0890085BE13 /* TVButtonAnimation.swift in Sources */, 230 | 342AA0A71BEEBF6E00B1A7D9 /* TVButton.swift in Sources */, 231 | ); 232 | runOnlyForDeploymentPostprocessing = 0; 233 | }; 234 | 342AA0921BEEBE6F00B1A7D9 /* Sources */ = { 235 | isa = PBXSourcesBuildPhase; 236 | buildActionMask = 2147483647; 237 | files = ( 238 | 342AA09C1BEEBE6F00B1A7D9 /* TVButtonTests.swift in Sources */, 239 | ); 240 | runOnlyForDeploymentPostprocessing = 0; 241 | }; 242 | /* End PBXSourcesBuildPhase section */ 243 | 244 | /* Begin PBXTargetDependency section */ 245 | 342AA0991BEEBE6F00B1A7D9 /* PBXTargetDependency */ = { 246 | isa = PBXTargetDependency; 247 | target = 342AA08B1BEEBE6F00B1A7D9 /* TVButton */; 248 | targetProxy = 342AA0981BEEBE6F00B1A7D9 /* PBXContainerItemProxy */; 249 | }; 250 | /* End PBXTargetDependency section */ 251 | 252 | /* Begin XCBuildConfiguration section */ 253 | 342AA09E1BEEBE6F00B1A7D9 /* Debug */ = { 254 | isa = XCBuildConfiguration; 255 | buildSettings = { 256 | ALWAYS_SEARCH_USER_PATHS = NO; 257 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 258 | CLANG_CXX_LIBRARY = "libc++"; 259 | CLANG_ENABLE_MODULES = YES; 260 | CLANG_ENABLE_OBJC_ARC = YES; 261 | CLANG_WARN_BOOL_CONVERSION = YES; 262 | CLANG_WARN_CONSTANT_CONVERSION = YES; 263 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 264 | CLANG_WARN_EMPTY_BODY = YES; 265 | CLANG_WARN_ENUM_CONVERSION = YES; 266 | CLANG_WARN_INFINITE_RECURSION = YES; 267 | CLANG_WARN_INT_CONVERSION = YES; 268 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 269 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 270 | CLANG_WARN_UNREACHABLE_CODE = YES; 271 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 272 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 273 | COPY_PHASE_STRIP = NO; 274 | CURRENT_PROJECT_VERSION = 8; 275 | DEBUG_INFORMATION_FORMAT = dwarf; 276 | ENABLE_STRICT_OBJC_MSGSEND = YES; 277 | ENABLE_TESTABILITY = YES; 278 | GCC_C_LANGUAGE_STANDARD = gnu99; 279 | GCC_DYNAMIC_NO_PIC = NO; 280 | GCC_NO_COMMON_BLOCKS = YES; 281 | GCC_OPTIMIZATION_LEVEL = 0; 282 | GCC_PREPROCESSOR_DEFINITIONS = ( 283 | "DEBUG=1", 284 | "$(inherited)", 285 | ); 286 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 287 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 288 | GCC_WARN_UNDECLARED_SELECTOR = YES; 289 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 290 | GCC_WARN_UNUSED_FUNCTION = YES; 291 | GCC_WARN_UNUSED_VARIABLE = YES; 292 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 293 | MTL_ENABLE_DEBUG_INFO = YES; 294 | ONLY_ACTIVE_ARCH = YES; 295 | SDKROOT = iphoneos; 296 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 297 | TARGETED_DEVICE_FAMILY = "1,2"; 298 | VERSIONING_SYSTEM = "apple-generic"; 299 | VERSION_INFO_PREFIX = ""; 300 | }; 301 | name = Debug; 302 | }; 303 | 342AA09F1BEEBE6F00B1A7D9 /* Release */ = { 304 | isa = XCBuildConfiguration; 305 | buildSettings = { 306 | ALWAYS_SEARCH_USER_PATHS = NO; 307 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 308 | CLANG_CXX_LIBRARY = "libc++"; 309 | CLANG_ENABLE_MODULES = YES; 310 | CLANG_ENABLE_OBJC_ARC = YES; 311 | CLANG_WARN_BOOL_CONVERSION = YES; 312 | CLANG_WARN_CONSTANT_CONVERSION = YES; 313 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 314 | CLANG_WARN_EMPTY_BODY = YES; 315 | CLANG_WARN_ENUM_CONVERSION = YES; 316 | CLANG_WARN_INFINITE_RECURSION = YES; 317 | CLANG_WARN_INT_CONVERSION = YES; 318 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 319 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 320 | CLANG_WARN_UNREACHABLE_CODE = YES; 321 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 322 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 323 | COPY_PHASE_STRIP = NO; 324 | CURRENT_PROJECT_VERSION = 8; 325 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 326 | ENABLE_NS_ASSERTIONS = NO; 327 | ENABLE_STRICT_OBJC_MSGSEND = YES; 328 | GCC_C_LANGUAGE_STANDARD = gnu99; 329 | GCC_NO_COMMON_BLOCKS = YES; 330 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 331 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 332 | GCC_WARN_UNDECLARED_SELECTOR = YES; 333 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 334 | GCC_WARN_UNUSED_FUNCTION = YES; 335 | GCC_WARN_UNUSED_VARIABLE = YES; 336 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 337 | MTL_ENABLE_DEBUG_INFO = NO; 338 | SDKROOT = iphoneos; 339 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 340 | TARGETED_DEVICE_FAMILY = "1,2"; 341 | VALIDATE_PRODUCT = YES; 342 | VERSIONING_SYSTEM = "apple-generic"; 343 | VERSION_INFO_PREFIX = ""; 344 | }; 345 | name = Release; 346 | }; 347 | 342AA0A11BEEBE6F00B1A7D9 /* Debug */ = { 348 | isa = XCBuildConfiguration; 349 | buildSettings = { 350 | CLANG_ENABLE_MODULES = YES; 351 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 352 | DEFINES_MODULE = YES; 353 | DYLIB_COMPATIBILITY_VERSION = 1; 354 | DYLIB_CURRENT_VERSION = 8; 355 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 356 | INFOPLIST_FILE = TVButton/Info.plist; 357 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 358 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 359 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 360 | PRODUCT_BUNDLE_IDENTIFIER = com.roymarmelstein.TVButton; 361 | PRODUCT_NAME = "$(TARGET_NAME)"; 362 | SKIP_INSTALL = YES; 363 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 364 | SWIFT_VERSION = 3.0; 365 | }; 366 | name = Debug; 367 | }; 368 | 342AA0A21BEEBE6F00B1A7D9 /* Release */ = { 369 | isa = XCBuildConfiguration; 370 | buildSettings = { 371 | CLANG_ENABLE_MODULES = YES; 372 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 373 | DEFINES_MODULE = YES; 374 | DYLIB_COMPATIBILITY_VERSION = 1; 375 | DYLIB_CURRENT_VERSION = 8; 376 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 377 | INFOPLIST_FILE = TVButton/Info.plist; 378 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 379 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 380 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 381 | PRODUCT_BUNDLE_IDENTIFIER = com.roymarmelstein.TVButton; 382 | PRODUCT_NAME = "$(TARGET_NAME)"; 383 | SKIP_INSTALL = YES; 384 | SWIFT_VERSION = 3.0; 385 | }; 386 | name = Release; 387 | }; 388 | 342AA0A41BEEBE6F00B1A7D9 /* Debug */ = { 389 | isa = XCBuildConfiguration; 390 | buildSettings = { 391 | INFOPLIST_FILE = TVButtonTests/Info.plist; 392 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 393 | PRODUCT_BUNDLE_IDENTIFIER = com.roymarmelstein.TVButtonTests; 394 | PRODUCT_NAME = "$(TARGET_NAME)"; 395 | SWIFT_VERSION = 3.0; 396 | }; 397 | name = Debug; 398 | }; 399 | 342AA0A51BEEBE6F00B1A7D9 /* Release */ = { 400 | isa = XCBuildConfiguration; 401 | buildSettings = { 402 | INFOPLIST_FILE = TVButtonTests/Info.plist; 403 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 404 | PRODUCT_BUNDLE_IDENTIFIER = com.roymarmelstein.TVButtonTests; 405 | PRODUCT_NAME = "$(TARGET_NAME)"; 406 | SWIFT_VERSION = 3.0; 407 | }; 408 | name = Release; 409 | }; 410 | /* End XCBuildConfiguration section */ 411 | 412 | /* Begin XCConfigurationList section */ 413 | 342AA0861BEEBE6F00B1A7D9 /* Build configuration list for PBXProject "TVButton" */ = { 414 | isa = XCConfigurationList; 415 | buildConfigurations = ( 416 | 342AA09E1BEEBE6F00B1A7D9 /* Debug */, 417 | 342AA09F1BEEBE6F00B1A7D9 /* Release */, 418 | ); 419 | defaultConfigurationIsVisible = 0; 420 | defaultConfigurationName = Release; 421 | }; 422 | 342AA0A01BEEBE6F00B1A7D9 /* Build configuration list for PBXNativeTarget "TVButton" */ = { 423 | isa = XCConfigurationList; 424 | buildConfigurations = ( 425 | 342AA0A11BEEBE6F00B1A7D9 /* Debug */, 426 | 342AA0A21BEEBE6F00B1A7D9 /* Release */, 427 | ); 428 | defaultConfigurationIsVisible = 0; 429 | defaultConfigurationName = Release; 430 | }; 431 | 342AA0A31BEEBE6F00B1A7D9 /* Build configuration list for PBXNativeTarget "TVButtonTests" */ = { 432 | isa = XCConfigurationList; 433 | buildConfigurations = ( 434 | 342AA0A41BEEBE6F00B1A7D9 /* Debug */, 435 | 342AA0A51BEEBE6F00B1A7D9 /* Release */, 436 | ); 437 | defaultConfigurationIsVisible = 0; 438 | defaultConfigurationName = Release; 439 | }; 440 | /* End XCConfigurationList section */ 441 | }; 442 | rootObject = 342AA0831BEEBE6F00B1A7D9 /* Project object */; 443 | } 444 | -------------------------------------------------------------------------------- /TVButton.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /TVButton.xcodeproj/xcshareddata/xcschemes/TVButton.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /TVButton/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 8 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /TVButton/Specular.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marmelroy/TVButton/5252ebf5a2a8cf6aa05dfc7889f7e6473f0e73db/TVButton/Specular.png -------------------------------------------------------------------------------- /TVButton/TVButton.h: -------------------------------------------------------------------------------- 1 | // 2 | // TVButton.h 3 | // TVButton 4 | // 5 | // Created by Roy Marmelstein on 08/11/2015. 6 | // Copyright © 2015 Roy Marmelstein. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for TVButton. 12 | FOUNDATION_EXPORT double TVButtonVersionNumber; 13 | 14 | //! Project version string for TVButton. 15 | FOUNDATION_EXPORT const unsigned char TVButtonVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /TVButton/TVButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TVButton.swift 3 | // TVButton 4 | // 5 | // Created by Roy Marmelstein on 08/11/2015. 6 | // Copyright © 2015 Roy Marmelstein. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | Parallax Layer Object 13 | */ 14 | public struct TVButtonLayer { 15 | /// UIImage to display. It is essential that all images have the same dimensions. 16 | var internalImage: UIImage? 17 | } 18 | 19 | public extension TVButtonLayer { 20 | /** 21 | Initialise the TVButton layer by passing a UIImage 22 | - Parameter image: UIImage to display. It is essential that all images have the same dimensions. 23 | */ 24 | public init(image: UIImage) { 25 | self.init(internalImage: image) 26 | } 27 | } 28 | 29 | /** 30 | TVButton Object 31 | */ 32 | open class TVButton: UIButton, UIGestureRecognizerDelegate { 33 | 34 | // MARK: Internal variables 35 | internal var containerView = UIView() 36 | internal var specularView = UIImageView() 37 | internal var tvButtonAnimation: TVButtonAnimation? 38 | 39 | internal var longPressGestureRecognizer: UILongPressGestureRecognizer? 40 | internal var panGestureRecognizer: UIPanGestureRecognizer? 41 | internal var tapGestureRecognizer: UITapGestureRecognizer? 42 | 43 | // MARK: Public variables 44 | 45 | /// Stack of TVButtonLayers inside the button 46 | open var layers: [TVButtonLayer]? { 47 | didSet { 48 | // Remove existing parallax layer views 49 | for subview in containerView.subviews { 50 | subview.removeFromSuperview() 51 | } 52 | // Instantiate an imageview with corners for every layer 53 | for layer in layers! { 54 | let imageView = UIImageView(image: layer.internalImage) 55 | imageView.layer.cornerRadius = cornerRadius 56 | imageView.clipsToBounds = true 57 | imageView.layer.needsDisplayOnBoundsChange = true 58 | containerView.addSubview(imageView) 59 | } 60 | // Add specular shine effect 61 | let frameworkBundle = Bundle(for: TVButton.self) 62 | let specularViewPath = frameworkBundle.path(forResource: "Specular", ofType: "png") 63 | specularView.image = UIImage(contentsOfFile:specularViewPath!) 64 | self.containerView.addSubview(specularView) 65 | } 66 | } 67 | 68 | /// Determines the intensity of the parallax depth effect. Default is 1.0. 69 | open var parallaxIntensity: CGFloat = defaultParallaxIntensity 70 | 71 | /// Shadow color for the TVButton. Default is black. 72 | open var shadowColor: UIColor = UIColor.black { 73 | didSet { 74 | self.layer.shadowColor = shadowColor.cgColor 75 | } 76 | } 77 | 78 | // MARK: Lifecycle 79 | 80 | /** 81 | Default init for TVObject with coder. 82 | */ 83 | public required init?(coder aDecoder: NSCoder) { 84 | super.init(coder: aDecoder) 85 | setup() 86 | } 87 | 88 | /** 89 | Default init for TVObject with frame. 90 | */ 91 | override public init(frame: CGRect) { 92 | super.init(frame: frame) 93 | setup() 94 | } 95 | 96 | /** 97 | Lays out subviews. 98 | */ 99 | override open func layoutSubviews() { 100 | super.layoutSubviews() 101 | containerView.frame = self.bounds 102 | self.layer.masksToBounds = false; 103 | let shadowPath = UIBezierPath(roundedRect: self.bounds, cornerRadius: cornerRadius) 104 | self.layer.shadowPath = shadowPath.cgPath 105 | 106 | // Stop here if animation is on 107 | if let animation = tvButtonAnimation { 108 | if animation.highlightMode == true { 109 | return 110 | } 111 | } 112 | 113 | // Adjust size for every subview 114 | for subview in containerView.subviews { 115 | if subview == specularView { 116 | subview.frame = CGRect(origin: subview.frame.origin, size: CGSize(width: specularScale * containerView.frame.size.width, height: specularScale * containerView.frame.size.height)) 117 | } 118 | else { 119 | subview.frame = CGRect(origin: subview.frame.origin, size: containerView.frame.size) 120 | } 121 | } 122 | } 123 | 124 | /** 125 | Button setup. Conducted on init. 126 | */ 127 | func setup() { 128 | containerView.isUserInteractionEnabled = false 129 | self.addSubview(containerView) 130 | containerView.clipsToBounds = true 131 | containerView.layer.cornerRadius = cornerRadius 132 | self.clipsToBounds = true 133 | specularView.alpha = 0.0 134 | specularView.contentMode = UIViewContentMode.scaleAspectFill 135 | self.layer.shadowRadius = self.bounds.size.height/(2*shadowFactor) 136 | self.layer.shadowOffset = CGSize(width: 0.0, height: shadowFactor/3) 137 | self.layer.shadowOpacity = 0.5; 138 | tvButtonAnimation = TVButtonAnimation(button: self) 139 | self.addGestureRecognizers() 140 | } 141 | 142 | 143 | // MARK: UIGestureRecognizer actions and delegate 144 | 145 | /** 146 | Adds the gesture recognizers to the button. 147 | */ 148 | func addGestureRecognizers(){ 149 | panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:))) 150 | panGestureRecognizer?.delegate = self 151 | self.addGestureRecognizer(panGestureRecognizer!) 152 | tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:))) 153 | self.addGestureRecognizer(tapGestureRecognizer!) 154 | longPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress(_:))) 155 | longPressGestureRecognizer?.delegate = self 156 | self.addGestureRecognizer(longPressGestureRecognizer!) 157 | } 158 | 159 | /** 160 | Pan gesture recognizer handler. 161 | - Parameter gestureRecognizer: TVButton's UIPanGestureRecognizer. 162 | */ 163 | func handlePan(_ gestureRecognizer: UIGestureRecognizer) { 164 | self.gestureRecognizerDidUpdate(gestureRecognizer) 165 | } 166 | 167 | /** 168 | Long press gesture recognizer handler. 169 | - Parameter gestureRecognizer: TVButton's UILongPressGestureRecognizer. 170 | */ 171 | func handleLongPress(_ gestureRecognizer: UIGestureRecognizer) { 172 | self.gestureRecognizerDidUpdate(gestureRecognizer) 173 | } 174 | 175 | /** 176 | Tap gesture recognizer handler. Sends TouchUpInside to super. 177 | - Parameter gestureRecognizer: TVButton's UITapGestureRecognizer. 178 | */ 179 | func handleTap(_ gestureRecognizer: UIGestureRecognizer) { 180 | super.sendActions(for: UIControlEvents.touchUpInside) 181 | } 182 | 183 | /** 184 | Determines button's reaction to gesturerecognizer. 185 | - Parameter gestureRecognizer: either UITapGestureRecognizer or UILongPressGestureRecognizer. 186 | */ 187 | func gestureRecognizerDidUpdate(_ gestureRecognizer: UIGestureRecognizer){ 188 | if layers == nil { 189 | return 190 | } 191 | let point = gestureRecognizer.location(in: self) 192 | if let animation = tvButtonAnimation { 193 | if gestureRecognizer.state == .began { 194 | animation.enterMovement() 195 | animation.processMovement(point) 196 | } 197 | else if gestureRecognizer.state == .changed { 198 | animation.processMovement(point) 199 | } 200 | else { 201 | if gestureRecognizer.state == .began || gestureRecognizer.state == .changed { 202 | return 203 | } 204 | animation.exitMovement() 205 | } 206 | } 207 | } 208 | 209 | // MARK: UIGestureRecognizerDelegate 210 | 211 | /** 212 | UIGestureRecognizerDelegate function to allow two UIGestureRecognizers to be recognized simultaneously. 213 | - Parameter gestureRecognizer: First gestureRecognizer. 214 | - Parameter otherGestureRecognizer: Second gestureRecognizer. 215 | */ 216 | open func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { 217 | return true 218 | } 219 | 220 | } 221 | -------------------------------------------------------------------------------- /TVButton/TVButtonAnimation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TVButtonAnimation.swift 3 | // TVButton 4 | // 5 | // Created by Roy Marmelstein on 10/11/2015. 6 | // Copyright © 2015 Roy Marmelstein. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | TVButtonAnimation class 13 | */ 14 | internal class TVButtonAnimation { 15 | 16 | var highlightMode: Bool = false { 17 | didSet { 18 | 19 | } 20 | } 21 | var button: TVButton? 22 | 23 | init(button: TVButton) { 24 | self.button = button 25 | } 26 | 27 | // Movement begins 28 | func enterMovement() { 29 | if highlightMode == true { 30 | return 31 | } 32 | if let tvButton = button { 33 | self.highlightMode = true 34 | let targetShadowOffset = CGSize(width: 0.0, height: tvButton.bounds.size.height/shadowFactor) 35 | tvButton.layer.removeAllAnimations() 36 | CATransaction.begin() 37 | CATransaction.setCompletionBlock({ () -> Void in 38 | tvButton.layer.shadowOffset = targetShadowOffset 39 | }) 40 | let shaowOffsetAnimation = CABasicAnimation(keyPath: "shadowOffset") 41 | shaowOffsetAnimation.toValue = NSValue(cgSize: targetShadowOffset) 42 | shaowOffsetAnimation.duration = animationDuration 43 | shaowOffsetAnimation.isRemovedOnCompletion = false 44 | shaowOffsetAnimation.fillMode = kCAFillModeForwards 45 | shaowOffsetAnimation.timingFunction = CAMediaTimingFunction(name: "easeOut") 46 | tvButton.layer.add(shaowOffsetAnimation, forKey: "shadowOffset") 47 | CATransaction.commit() 48 | let shadowOpacityAnimation = CABasicAnimation(keyPath: "shadowOpacity") 49 | shadowOpacityAnimation.toValue = 0.6 50 | shadowOpacityAnimation.duration = animationDuration 51 | shadowOpacityAnimation.isRemovedOnCompletion = false 52 | shadowOpacityAnimation.fillMode = kCAFillModeForwards 53 | shadowOpacityAnimation.timingFunction = CAMediaTimingFunction(name: "easeOut") 54 | tvButton.layer.add(shadowOpacityAnimation, forKey: "shadowOpacityAnimation") 55 | CATransaction.commit() 56 | } 57 | } 58 | 59 | // Movement continues 60 | func processMovement(_ point: CGPoint){ 61 | if (highlightMode == false) { 62 | return 63 | } 64 | if let tvButton = button { 65 | let offsetX = point.x / tvButton.bounds.size.width 66 | let offsetY = point.y / tvButton.bounds.size.height 67 | let dx = point.x - tvButton.bounds.size.width/2 68 | let dy = point.y - tvButton.bounds.size.height/2 69 | let xRotation = (dy - offsetY)*(rotateXFactor/tvButton.bounds.size.width) 70 | let yRotation = (offsetX - dx)*(rotateYFactor/tvButton.bounds.size.width) 71 | let zRotation = (xRotation + yRotation)/rotateZFactor 72 | 73 | let xTranslation = (-2*point.x/tvButton.bounds.size.width)*maxTranslationX 74 | let yTranslation = (-2*point.y/tvButton.bounds.size.height)*maxTranslationY 75 | 76 | let xRotateTransform = CATransform3DMakeRotation(degreesToRadians(xRotation), 1, 0, 0) 77 | let yRotateTransform = CATransform3DMakeRotation(degreesToRadians(yRotation), 0, 1, 0) 78 | let zRotateTransform = CATransform3DMakeRotation(degreesToRadians(zRotation), 0, 0, 1) 79 | 80 | let combinedRotateTransformXY = CATransform3DConcat(xRotateTransform, yRotateTransform) 81 | let combinedRotateTransformZ = CATransform3DConcat(combinedRotateTransformXY, zRotateTransform) 82 | let translationTransform = CATransform3DMakeTranslation(-xTranslation, yTranslation, 0.0) 83 | let combinedRotateTranslateTransform = CATransform3DConcat(combinedRotateTransformZ, translationTransform) 84 | let targetScaleTransform = CATransform3DMakeScale(highlightedScale, highlightedScale, highlightedScale) 85 | let combinedTransform = CATransform3DConcat(combinedRotateTranslateTransform, targetScaleTransform) 86 | 87 | UIView.animate(withDuration: animationDuration, delay: 0.0, options: UIViewAnimationOptions.curveEaseOut, animations: { () -> Void in 88 | tvButton.layer.transform = combinedTransform 89 | tvButton.specularView.alpha = specularAlpha 90 | tvButton.specularView.center = point 91 | for i in 1 ..< tvButton.containerView.subviews.count { 92 | let adjusted = i/2 93 | let scale = 1 + maxScaleDelta*CGFloat(adjusted/tvButton.containerView.subviews.count) 94 | let subview = tvButton.containerView.subviews[i] 95 | if subview != tvButton.specularView { 96 | subview.contentMode = UIViewContentMode.redraw 97 | subview.frame.size = CGSize(width: tvButton.bounds.size.width*scale, height: tvButton.bounds.size.height*scale) 98 | } 99 | } 100 | 101 | }, completion: nil) 102 | UIView.animate(withDuration: 0.16, delay: 0.0, options: UIViewAnimationOptions.curveEaseOut, animations: { () -> Void in 103 | for i in 1 ..< tvButton.containerView.subviews.count { 104 | let subview = tvButton.containerView.subviews[i] 105 | let xParallax = tvButton.parallaxIntensity*parallaxIntensityXFactor 106 | let yParallax = tvButton.parallaxIntensity*parallaxIntensityYFactor 107 | if subview != tvButton.specularView { 108 | subview.center = CGPoint(x: tvButton.bounds.size.width/2 + xTranslation*CGFloat(i)*xParallax, y: tvButton.bounds.size.height/2 + yTranslation*CGFloat(i)*0.3*yParallax) 109 | } 110 | } 111 | }, completion: nil) 112 | 113 | } 114 | } 115 | 116 | // Movement ends 117 | func exitMovement() { 118 | if highlightMode == false { 119 | return 120 | } 121 | if let tvButton = button { 122 | let targetShadowOffset = CGSize(width: 0.0, height: shadowFactor/3) 123 | let targetScaleTransform = CATransform3DMakeScale(1.0, 1.0, 1.0) 124 | tvButton.specularView.layer.removeAllAnimations() 125 | CATransaction.begin() 126 | CATransaction.setCompletionBlock({ () -> Void in 127 | tvButton.layer.transform = targetScaleTransform 128 | tvButton.layer.shadowOffset = targetShadowOffset 129 | self.highlightMode = false 130 | }) 131 | let shaowOffsetAnimation = CABasicAnimation(keyPath: "shadowOffset") 132 | shaowOffsetAnimation.toValue = NSValue(cgSize: targetShadowOffset) 133 | shaowOffsetAnimation.duration = animationDuration 134 | shaowOffsetAnimation.fillMode = kCAFillModeForwards 135 | shaowOffsetAnimation.isRemovedOnCompletion = false 136 | shaowOffsetAnimation.timingFunction = CAMediaTimingFunction(name: "easeOut") 137 | tvButton.layer.add(shaowOffsetAnimation, forKey: "shadowOffset") 138 | let scaleAnimation = CABasicAnimation(keyPath: "transform") 139 | scaleAnimation.toValue = NSValue(caTransform3D: targetScaleTransform) 140 | scaleAnimation.duration = animationDuration 141 | scaleAnimation.isRemovedOnCompletion = false 142 | scaleAnimation.fillMode = kCAFillModeForwards 143 | scaleAnimation.timingFunction = CAMediaTimingFunction(name: "easeOut") 144 | tvButton.layer.add(scaleAnimation, forKey: "scaleAnimation") 145 | CATransaction.commit() 146 | UIView.animate(withDuration: animationDuration, delay: 0.0, options: UIViewAnimationOptions.curveEaseOut, animations: { () -> Void in 147 | tvButton.transform = CGAffineTransform.identity 148 | tvButton.specularView.alpha = 0.0 149 | for i in 0 ..< tvButton.containerView.subviews.count { 150 | let subview = tvButton.containerView.subviews[i] 151 | subview.frame.size = CGSize(width: tvButton.bounds.size.width, height: tvButton.bounds.size.height) 152 | subview.center = CGPoint(x: tvButton.bounds.size.width/2, y: tvButton.bounds.size.height/2) 153 | } 154 | }, completion:nil) 155 | } 156 | } 157 | 158 | // MARK: Convenience 159 | 160 | func degreesToRadians(_ value:CGFloat) -> CGFloat { 161 | return value * CGFloat(M_PI) / 180.0 162 | } 163 | 164 | } 165 | -------------------------------------------------------------------------------- /TVButton/TVButtonConstants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TVButtonConstants.swift 3 | // TVButton 4 | // 5 | // Created by Roy Marmelstein on 10/11/2015. 6 | // Copyright © 2015 Roy Marmelstein. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // Affects reveal, hide and specular shine following animations 12 | let animationDuration: Double = 0.4 13 | 14 | // The corner radius of the button 15 | let cornerRadius: CGFloat = 5 16 | 17 | // Default parallax intensity 18 | let defaultParallaxIntensity: CGFloat = 1.0 19 | 20 | // The scaling on the TVButton when active 21 | let highlightedScale: CGFloat = 1.22 22 | 23 | // Max scale delta 24 | let maxScaleDelta: CGFloat = 0.12 25 | 26 | // Max translation value in x axis 27 | let maxTranslationX: CGFloat = 3.5 28 | 29 | // Max translation value in y axis 30 | let maxTranslationY: CGFloat = 2.5 31 | 32 | // A factor applied in the x axis on parallax intensity 33 | let parallaxIntensityXFactor: CGFloat = 0.3 34 | 35 | // A factor applied in the y axis on parallax intensity 36 | let parallaxIntensityYFactor: CGFloat = 0.2 37 | 38 | // A factor applied in the x axis on rotation 39 | let rotateXFactor: CGFloat = 12 40 | 41 | // A factor applied in the y axis on rotation 42 | let rotateYFactor: CGFloat = 14 43 | 44 | // A factor applied in the z axis on rotation 45 | let rotateZFactor: CGFloat = 9 46 | 47 | // Determines the size of the TVButton's shadow in comparison to the bounds 48 | let shadowFactor: CGFloat = 10 49 | 50 | // The scale of the specular shine 51 | let specularScale: CGFloat = 2.0 52 | 53 | // The scale of the specular shine 54 | let specularAlpha: CGFloat = 0.25 -------------------------------------------------------------------------------- /TVButtonTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 8 23 | 24 | 25 | -------------------------------------------------------------------------------- /TVButtonTests/TVButtonTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TVButtonTests.swift 3 | // TVButtonTests 4 | // 5 | // Created by Roy Marmelstein on 08/11/2015. 6 | // Copyright © 2015 Roy Marmelstein. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import TVButton 11 | 12 | class TVButtonTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # **** Update me when new Xcode versions are released! **** 4 | PLATFORM="platform=iOS Simulator,OS=10.1,name=iPhone 7" 5 | SDK="iphonesimulator" 6 | 7 | 8 | # It is pitch black. 9 | set -e 10 | function trap_handler() { 11 | echo -e "\n\nOh no! You walked directly into the slavering fangs of a lurking grue!" 12 | echo "**** You have died ****" 13 | exit 255 14 | } 15 | trap trap_handler INT TERM EXIT 16 | 17 | 18 | MODE="$1" 19 | 20 | if [ "$MODE" = "build" ]; then 21 | echo "Building TVButton." 22 | xcodebuild \ 23 | -project TVButton.xcodeproj \ 24 | -scheme TVButton \ 25 | -sdk "$SDK" \ 26 | -destination "$PLATFORM" \ 27 | build 28 | trap - EXIT 29 | exit 0 30 | fi 31 | 32 | if [ "$MODE" = "examples" ]; then 33 | echo "Building and testing all TVButton examples." 34 | 35 | for example in examples/*/; do 36 | echo "Building $example." 37 | pod install --project-directory=$example 38 | xcodebuild \ 39 | -workspace "${example}Sample.xcworkspace" \ 40 | -scheme Sample \ 41 | -sdk "$SDK" \ 42 | -destination "$PLATFORM" \ 43 | build 44 | done 45 | trap - EXIT 46 | exit 0 47 | fi 48 | 49 | echo "Unrecognised mode '$MODE'." 50 | -------------------------------------------------------------------------------- /examples/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marmelroy/TVButton/5252ebf5a2a8cf6aa05dfc7889f7e6473f0e73db/examples/.DS_Store -------------------------------------------------------------------------------- /examples/StarWars/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marmelroy/TVButton/5252ebf5a2a8cf6aa05dfc7889f7e6473f0e73db/examples/StarWars/.DS_Store -------------------------------------------------------------------------------- /examples/StarWars/Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, "9.3" 2 | 3 | target 'Sample' do 4 | use_frameworks! 5 | 6 | # Pods for Sample 7 | pod 'TVButton', :path => '../..' 8 | 9 | end 10 | -------------------------------------------------------------------------------- /examples/StarWars/Sample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 341E56F01BF0173C00D46D86 /* KyloA.png in Resources */ = {isa = PBXBuildFile; fileRef = 341E56EC1BF0173C00D46D86 /* KyloA.png */; }; 11 | 341E56F11BF0173C00D46D86 /* KyloB.png in Resources */ = {isa = PBXBuildFile; fileRef = 341E56ED1BF0173C00D46D86 /* KyloB.png */; }; 12 | 341E56F21BF0173C00D46D86 /* KyloC.png in Resources */ = {isa = PBXBuildFile; fileRef = 341E56EE1BF0173C00D46D86 /* KyloC.png */; }; 13 | 342929621BF05CEC00F8F58D /* KyloE.png in Resources */ = {isa = PBXBuildFile; fileRef = 342929611BF05CEC00F8F58D /* KyloE.png */; }; 14 | 3472096B1BB808D1004DE6DA /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3472096A1BB808D1004DE6DA /* AppDelegate.swift */; }; 15 | 3472096D1BB808D1004DE6DA /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3472096C1BB808D1004DE6DA /* ViewController.swift */; }; 16 | 347209701BB808D1004DE6DA /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3472096E1BB808D1004DE6DA /* Main.storyboard */; }; 17 | 347209721BB808D1004DE6DA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 347209711BB808D1004DE6DA /* Assets.xcassets */; }; 18 | 347209751BB808D1004DE6DA /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 347209731BB808D1004DE6DA /* LaunchScreen.storyboard */; }; 19 | 347209801BB808D1004DE6DA /* SampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3472097F1BB808D1004DE6DA /* SampleTests.swift */; }; 20 | 3472098E1BB80A4F004DE6DA /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3472098D1BB80A4F004DE6DA /* Foundation.framework */; }; 21 | 34D27C211BF1CD4F002247B5 /* TVButton.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34D27C1E1BF1CD45002247B5 /* TVButton.framework */; }; 22 | 34D27C221BF1CD4F002247B5 /* TVButton.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 34D27C1E1BF1CD45002247B5 /* TVButton.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXContainerItemProxy section */ 26 | 3472097C1BB808D1004DE6DA /* PBXContainerItemProxy */ = { 27 | isa = PBXContainerItemProxy; 28 | containerPortal = 3472095F1BB808D1004DE6DA /* Project object */; 29 | proxyType = 1; 30 | remoteGlobalIDString = 347209661BB808D1004DE6DA; 31 | remoteInfo = Sample; 32 | }; 33 | 34D27C1D1BF1CD45002247B5 /* PBXContainerItemProxy */ = { 34 | isa = PBXContainerItemProxy; 35 | containerPortal = 34D27C181BF1CD45002247B5 /* TVButton.xcodeproj */; 36 | proxyType = 2; 37 | remoteGlobalIDString = 342AA08C1BEEBE6F00B1A7D9; 38 | remoteInfo = TVButton; 39 | }; 40 | 34D27C1F1BF1CD45002247B5 /* PBXContainerItemProxy */ = { 41 | isa = PBXContainerItemProxy; 42 | containerPortal = 34D27C181BF1CD45002247B5 /* TVButton.xcodeproj */; 43 | proxyType = 2; 44 | remoteGlobalIDString = 342AA0961BEEBE6F00B1A7D9; 45 | remoteInfo = TVButtonTests; 46 | }; 47 | 34D27C231BF1CD4F002247B5 /* PBXContainerItemProxy */ = { 48 | isa = PBXContainerItemProxy; 49 | containerPortal = 34D27C181BF1CD45002247B5 /* TVButton.xcodeproj */; 50 | proxyType = 1; 51 | remoteGlobalIDString = 342AA08B1BEEBE6F00B1A7D9; 52 | remoteInfo = TVButton; 53 | }; 54 | /* End PBXContainerItemProxy section */ 55 | 56 | /* Begin PBXCopyFilesBuildPhase section */ 57 | 3435CCA51BC00184003F953B /* Embed Frameworks */ = { 58 | isa = PBXCopyFilesBuildPhase; 59 | buildActionMask = 2147483647; 60 | dstPath = ""; 61 | dstSubfolderSpec = 10; 62 | files = ( 63 | 34D27C221BF1CD4F002247B5 /* TVButton.framework in Embed Frameworks */, 64 | ); 65 | name = "Embed Frameworks"; 66 | runOnlyForDeploymentPostprocessing = 0; 67 | }; 68 | /* End PBXCopyFilesBuildPhase section */ 69 | 70 | /* Begin PBXFileReference section */ 71 | 341E56EC1BF0173C00D46D86 /* KyloA.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = KyloA.png; sourceTree = ""; }; 72 | 341E56ED1BF0173C00D46D86 /* KyloB.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = KyloB.png; sourceTree = ""; }; 73 | 341E56EE1BF0173C00D46D86 /* KyloC.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = KyloC.png; sourceTree = ""; }; 74 | 342929611BF05CEC00F8F58D /* KyloE.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = KyloE.png; sourceTree = ""; }; 75 | 347209671BB808D1004DE6DA /* Sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Sample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 76 | 3472096A1BB808D1004DE6DA /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 77 | 3472096C1BB808D1004DE6DA /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 78 | 3472096F1BB808D1004DE6DA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 79 | 347209711BB808D1004DE6DA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 80 | 347209741BB808D1004DE6DA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 81 | 347209761BB808D1004DE6DA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 82 | 3472097B1BB808D1004DE6DA /* SampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 83 | 3472097F1BB808D1004DE6DA /* SampleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SampleTests.swift; sourceTree = ""; }; 84 | 347209811BB808D1004DE6DA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 85 | 3472098D1BB80A4F004DE6DA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 86 | 34D27C181BF1CD45002247B5 /* TVButton.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = TVButton.xcodeproj; path = ../../TVButton.xcodeproj; sourceTree = ""; }; 87 | /* End PBXFileReference section */ 88 | 89 | /* Begin PBXFrameworksBuildPhase section */ 90 | 347209641BB808D1004DE6DA /* Frameworks */ = { 91 | isa = PBXFrameworksBuildPhase; 92 | buildActionMask = 2147483647; 93 | files = ( 94 | 34D27C211BF1CD4F002247B5 /* TVButton.framework in Frameworks */, 95 | 3472098E1BB80A4F004DE6DA /* Foundation.framework in Frameworks */, 96 | ); 97 | runOnlyForDeploymentPostprocessing = 0; 98 | }; 99 | 347209781BB808D1004DE6DA /* Frameworks */ = { 100 | isa = PBXFrameworksBuildPhase; 101 | buildActionMask = 2147483647; 102 | files = ( 103 | ); 104 | runOnlyForDeploymentPostprocessing = 0; 105 | }; 106 | /* End PBXFrameworksBuildPhase section */ 107 | 108 | /* Begin PBXGroup section */ 109 | 3472095E1BB808D1004DE6DA = { 110 | isa = PBXGroup; 111 | children = ( 112 | 34D27C181BF1CD45002247B5 /* TVButton.xcodeproj */, 113 | 347209691BB808D1004DE6DA /* Sample */, 114 | 3472097E1BB808D1004DE6DA /* SampleTests */, 115 | 347209681BB808D1004DE6DA /* Products */, 116 | ); 117 | sourceTree = ""; 118 | }; 119 | 347209681BB808D1004DE6DA /* Products */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | 347209671BB808D1004DE6DA /* Sample.app */, 123 | 3472097B1BB808D1004DE6DA /* SampleTests.xctest */, 124 | ); 125 | name = Products; 126 | sourceTree = ""; 127 | }; 128 | 347209691BB808D1004DE6DA /* Sample */ = { 129 | isa = PBXGroup; 130 | children = ( 131 | 3472096A1BB808D1004DE6DA /* AppDelegate.swift */, 132 | 3472096C1BB808D1004DE6DA /* ViewController.swift */, 133 | 341E56EC1BF0173C00D46D86 /* KyloA.png */, 134 | 341E56ED1BF0173C00D46D86 /* KyloB.png */, 135 | 341E56EE1BF0173C00D46D86 /* KyloC.png */, 136 | 342929611BF05CEC00F8F58D /* KyloE.png */, 137 | 3472096E1BB808D1004DE6DA /* Main.storyboard */, 138 | 347209711BB808D1004DE6DA /* Assets.xcassets */, 139 | 347209731BB808D1004DE6DA /* LaunchScreen.storyboard */, 140 | 347209761BB808D1004DE6DA /* Info.plist */, 141 | 3472098D1BB80A4F004DE6DA /* Foundation.framework */, 142 | ); 143 | path = Sample; 144 | sourceTree = ""; 145 | }; 146 | 3472097E1BB808D1004DE6DA /* SampleTests */ = { 147 | isa = PBXGroup; 148 | children = ( 149 | 3472097F1BB808D1004DE6DA /* SampleTests.swift */, 150 | 347209811BB808D1004DE6DA /* Info.plist */, 151 | ); 152 | path = SampleTests; 153 | sourceTree = ""; 154 | }; 155 | 34D27C191BF1CD45002247B5 /* Products */ = { 156 | isa = PBXGroup; 157 | children = ( 158 | 34D27C1E1BF1CD45002247B5 /* TVButton.framework */, 159 | 34D27C201BF1CD45002247B5 /* TVButtonTests.xctest */, 160 | ); 161 | name = Products; 162 | sourceTree = ""; 163 | }; 164 | /* End PBXGroup section */ 165 | 166 | /* Begin PBXNativeTarget section */ 167 | 347209661BB808D1004DE6DA /* Sample */ = { 168 | isa = PBXNativeTarget; 169 | buildConfigurationList = 347209841BB808D1004DE6DA /* Build configuration list for PBXNativeTarget "Sample" */; 170 | buildPhases = ( 171 | 347209631BB808D1004DE6DA /* Sources */, 172 | 347209641BB808D1004DE6DA /* Frameworks */, 173 | 347209651BB808D1004DE6DA /* Resources */, 174 | 3435CCA51BC00184003F953B /* Embed Frameworks */, 175 | ); 176 | buildRules = ( 177 | ); 178 | dependencies = ( 179 | 34D27C241BF1CD4F002247B5 /* PBXTargetDependency */, 180 | ); 181 | name = Sample; 182 | productName = Sample; 183 | productReference = 347209671BB808D1004DE6DA /* Sample.app */; 184 | productType = "com.apple.product-type.application"; 185 | }; 186 | 3472097A1BB808D1004DE6DA /* SampleTests */ = { 187 | isa = PBXNativeTarget; 188 | buildConfigurationList = 347209871BB808D1004DE6DA /* Build configuration list for PBXNativeTarget "SampleTests" */; 189 | buildPhases = ( 190 | 347209771BB808D1004DE6DA /* Sources */, 191 | 347209781BB808D1004DE6DA /* Frameworks */, 192 | 347209791BB808D1004DE6DA /* Resources */, 193 | ); 194 | buildRules = ( 195 | ); 196 | dependencies = ( 197 | 3472097D1BB808D1004DE6DA /* PBXTargetDependency */, 198 | ); 199 | name = SampleTests; 200 | productName = SampleTests; 201 | productReference = 3472097B1BB808D1004DE6DA /* SampleTests.xctest */; 202 | productType = "com.apple.product-type.bundle.unit-test"; 203 | }; 204 | /* End PBXNativeTarget section */ 205 | 206 | /* Begin PBXProject section */ 207 | 3472095F1BB808D1004DE6DA /* Project object */ = { 208 | isa = PBXProject; 209 | attributes = { 210 | LastUpgradeCheck = 0810; 211 | ORGANIZATIONNAME = "Roy Marmelstein"; 212 | TargetAttributes = { 213 | 347209661BB808D1004DE6DA = { 214 | CreatedOnToolsVersion = 7.0; 215 | LastSwiftMigration = 0810; 216 | }; 217 | 3472097A1BB808D1004DE6DA = { 218 | CreatedOnToolsVersion = 7.0; 219 | TestTargetID = 347209661BB808D1004DE6DA; 220 | }; 221 | }; 222 | }; 223 | buildConfigurationList = 347209621BB808D1004DE6DA /* Build configuration list for PBXProject "Sample" */; 224 | compatibilityVersion = "Xcode 3.2"; 225 | developmentRegion = English; 226 | hasScannedForEncodings = 0; 227 | knownRegions = ( 228 | en, 229 | Base, 230 | ); 231 | mainGroup = 3472095E1BB808D1004DE6DA; 232 | productRefGroup = 347209681BB808D1004DE6DA /* Products */; 233 | projectDirPath = ""; 234 | projectReferences = ( 235 | { 236 | ProductGroup = 34D27C191BF1CD45002247B5 /* Products */; 237 | ProjectRef = 34D27C181BF1CD45002247B5 /* TVButton.xcodeproj */; 238 | }, 239 | ); 240 | projectRoot = ""; 241 | targets = ( 242 | 347209661BB808D1004DE6DA /* Sample */, 243 | 3472097A1BB808D1004DE6DA /* SampleTests */, 244 | ); 245 | }; 246 | /* End PBXProject section */ 247 | 248 | /* Begin PBXReferenceProxy section */ 249 | 34D27C1E1BF1CD45002247B5 /* TVButton.framework */ = { 250 | isa = PBXReferenceProxy; 251 | fileType = wrapper.framework; 252 | path = TVButton.framework; 253 | remoteRef = 34D27C1D1BF1CD45002247B5 /* PBXContainerItemProxy */; 254 | sourceTree = BUILT_PRODUCTS_DIR; 255 | }; 256 | 34D27C201BF1CD45002247B5 /* TVButtonTests.xctest */ = { 257 | isa = PBXReferenceProxy; 258 | fileType = wrapper.cfbundle; 259 | path = TVButtonTests.xctest; 260 | remoteRef = 34D27C1F1BF1CD45002247B5 /* PBXContainerItemProxy */; 261 | sourceTree = BUILT_PRODUCTS_DIR; 262 | }; 263 | /* End PBXReferenceProxy section */ 264 | 265 | /* Begin PBXResourcesBuildPhase section */ 266 | 347209651BB808D1004DE6DA /* Resources */ = { 267 | isa = PBXResourcesBuildPhase; 268 | buildActionMask = 2147483647; 269 | files = ( 270 | 342929621BF05CEC00F8F58D /* KyloE.png in Resources */, 271 | 347209751BB808D1004DE6DA /* LaunchScreen.storyboard in Resources */, 272 | 341E56F01BF0173C00D46D86 /* KyloA.png in Resources */, 273 | 347209721BB808D1004DE6DA /* Assets.xcassets in Resources */, 274 | 341E56F21BF0173C00D46D86 /* KyloC.png in Resources */, 275 | 341E56F11BF0173C00D46D86 /* KyloB.png in Resources */, 276 | 347209701BB808D1004DE6DA /* Main.storyboard in Resources */, 277 | ); 278 | runOnlyForDeploymentPostprocessing = 0; 279 | }; 280 | 347209791BB808D1004DE6DA /* Resources */ = { 281 | isa = PBXResourcesBuildPhase; 282 | buildActionMask = 2147483647; 283 | files = ( 284 | ); 285 | runOnlyForDeploymentPostprocessing = 0; 286 | }; 287 | /* End PBXResourcesBuildPhase section */ 288 | 289 | /* Begin PBXSourcesBuildPhase section */ 290 | 347209631BB808D1004DE6DA /* Sources */ = { 291 | isa = PBXSourcesBuildPhase; 292 | buildActionMask = 2147483647; 293 | files = ( 294 | 3472096D1BB808D1004DE6DA /* ViewController.swift in Sources */, 295 | 3472096B1BB808D1004DE6DA /* AppDelegate.swift in Sources */, 296 | ); 297 | runOnlyForDeploymentPostprocessing = 0; 298 | }; 299 | 347209771BB808D1004DE6DA /* Sources */ = { 300 | isa = PBXSourcesBuildPhase; 301 | buildActionMask = 2147483647; 302 | files = ( 303 | 347209801BB808D1004DE6DA /* SampleTests.swift in Sources */, 304 | ); 305 | runOnlyForDeploymentPostprocessing = 0; 306 | }; 307 | /* End PBXSourcesBuildPhase section */ 308 | 309 | /* Begin PBXTargetDependency section */ 310 | 3472097D1BB808D1004DE6DA /* PBXTargetDependency */ = { 311 | isa = PBXTargetDependency; 312 | target = 347209661BB808D1004DE6DA /* Sample */; 313 | targetProxy = 3472097C1BB808D1004DE6DA /* PBXContainerItemProxy */; 314 | }; 315 | 34D27C241BF1CD4F002247B5 /* PBXTargetDependency */ = { 316 | isa = PBXTargetDependency; 317 | name = TVButton; 318 | targetProxy = 34D27C231BF1CD4F002247B5 /* PBXContainerItemProxy */; 319 | }; 320 | /* End PBXTargetDependency section */ 321 | 322 | /* Begin PBXVariantGroup section */ 323 | 3472096E1BB808D1004DE6DA /* Main.storyboard */ = { 324 | isa = PBXVariantGroup; 325 | children = ( 326 | 3472096F1BB808D1004DE6DA /* Base */, 327 | ); 328 | name = Main.storyboard; 329 | sourceTree = ""; 330 | }; 331 | 347209731BB808D1004DE6DA /* LaunchScreen.storyboard */ = { 332 | isa = PBXVariantGroup; 333 | children = ( 334 | 347209741BB808D1004DE6DA /* Base */, 335 | ); 336 | name = LaunchScreen.storyboard; 337 | sourceTree = ""; 338 | }; 339 | /* End PBXVariantGroup section */ 340 | 341 | /* Begin XCBuildConfiguration section */ 342 | 347209821BB808D1004DE6DA /* Debug */ = { 343 | isa = XCBuildConfiguration; 344 | buildSettings = { 345 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 346 | ALWAYS_SEARCH_USER_PATHS = NO; 347 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 348 | CLANG_CXX_LIBRARY = "libc++"; 349 | CLANG_ENABLE_MODULES = YES; 350 | CLANG_ENABLE_OBJC_ARC = YES; 351 | CLANG_WARN_BOOL_CONVERSION = YES; 352 | CLANG_WARN_CONSTANT_CONVERSION = YES; 353 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 354 | CLANG_WARN_EMPTY_BODY = YES; 355 | CLANG_WARN_ENUM_CONVERSION = YES; 356 | CLANG_WARN_INFINITE_RECURSION = YES; 357 | CLANG_WARN_INT_CONVERSION = YES; 358 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 359 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 360 | CLANG_WARN_UNREACHABLE_CODE = YES; 361 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 362 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 363 | COPY_PHASE_STRIP = NO; 364 | DEBUG_INFORMATION_FORMAT = dwarf; 365 | ENABLE_STRICT_OBJC_MSGSEND = YES; 366 | ENABLE_TESTABILITY = YES; 367 | GCC_C_LANGUAGE_STANDARD = gnu99; 368 | GCC_DYNAMIC_NO_PIC = NO; 369 | GCC_NO_COMMON_BLOCKS = YES; 370 | GCC_OPTIMIZATION_LEVEL = 0; 371 | GCC_PREPROCESSOR_DEFINITIONS = ( 372 | "DEBUG=1", 373 | "$(inherited)", 374 | ); 375 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 376 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 377 | GCC_WARN_UNDECLARED_SELECTOR = YES; 378 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 379 | GCC_WARN_UNUSED_FUNCTION = YES; 380 | GCC_WARN_UNUSED_VARIABLE = YES; 381 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 382 | MTL_ENABLE_DEBUG_INFO = YES; 383 | ONLY_ACTIVE_ARCH = YES; 384 | OTHER_LDFLAGS = "$(inherited)"; 385 | SDKROOT = iphoneos; 386 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 387 | }; 388 | name = Debug; 389 | }; 390 | 347209831BB808D1004DE6DA /* Release */ = { 391 | isa = XCBuildConfiguration; 392 | buildSettings = { 393 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 394 | ALWAYS_SEARCH_USER_PATHS = NO; 395 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 396 | CLANG_CXX_LIBRARY = "libc++"; 397 | CLANG_ENABLE_MODULES = YES; 398 | CLANG_ENABLE_OBJC_ARC = YES; 399 | CLANG_WARN_BOOL_CONVERSION = YES; 400 | CLANG_WARN_CONSTANT_CONVERSION = YES; 401 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 402 | CLANG_WARN_EMPTY_BODY = YES; 403 | CLANG_WARN_ENUM_CONVERSION = YES; 404 | CLANG_WARN_INFINITE_RECURSION = YES; 405 | CLANG_WARN_INT_CONVERSION = YES; 406 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 407 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 408 | CLANG_WARN_UNREACHABLE_CODE = YES; 409 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 410 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 411 | COPY_PHASE_STRIP = NO; 412 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 413 | ENABLE_NS_ASSERTIONS = NO; 414 | ENABLE_STRICT_OBJC_MSGSEND = YES; 415 | GCC_C_LANGUAGE_STANDARD = gnu99; 416 | GCC_NO_COMMON_BLOCKS = YES; 417 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 418 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 419 | GCC_WARN_UNDECLARED_SELECTOR = YES; 420 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 421 | GCC_WARN_UNUSED_FUNCTION = YES; 422 | GCC_WARN_UNUSED_VARIABLE = YES; 423 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 424 | MTL_ENABLE_DEBUG_INFO = NO; 425 | OTHER_LDFLAGS = "$(inherited)"; 426 | SDKROOT = iphoneos; 427 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 428 | VALIDATE_PRODUCT = YES; 429 | }; 430 | name = Release; 431 | }; 432 | 347209851BB808D1004DE6DA /* Debug */ = { 433 | isa = XCBuildConfiguration; 434 | buildSettings = { 435 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 436 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 437 | FRAMEWORK_SEARCH_PATHS = "$(inherited)"; 438 | INFOPLIST_FILE = Sample/Info.plist; 439 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 440 | OTHER_LDFLAGS = "$(inherited)"; 441 | PRODUCT_BUNDLE_IDENTIFIER = com.roymarmelstein.Sample; 442 | PRODUCT_NAME = "$(TARGET_NAME)"; 443 | SWIFT_VERSION = 3.0; 444 | }; 445 | name = Debug; 446 | }; 447 | 347209861BB808D1004DE6DA /* Release */ = { 448 | isa = XCBuildConfiguration; 449 | buildSettings = { 450 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 451 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 452 | FRAMEWORK_SEARCH_PATHS = "$(inherited)"; 453 | INFOPLIST_FILE = Sample/Info.plist; 454 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 455 | OTHER_LDFLAGS = "$(inherited)"; 456 | PRODUCT_BUNDLE_IDENTIFIER = com.roymarmelstein.Sample; 457 | PRODUCT_NAME = "$(TARGET_NAME)"; 458 | SWIFT_VERSION = 3.0; 459 | }; 460 | name = Release; 461 | }; 462 | 347209881BB808D1004DE6DA /* Debug */ = { 463 | isa = XCBuildConfiguration; 464 | buildSettings = { 465 | BUNDLE_LOADER = "$(TEST_HOST)"; 466 | FRAMEWORK_SEARCH_PATHS = ( 467 | "$(inherited)", 468 | "$(PROJECT_DIR)/Sample", 469 | ); 470 | INFOPLIST_FILE = SampleTests/Info.plist; 471 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 472 | PRODUCT_BUNDLE_IDENTIFIER = com.roymarmelstein.SampleTests; 473 | PRODUCT_NAME = "$(TARGET_NAME)"; 474 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Sample.app/Sample"; 475 | }; 476 | name = Debug; 477 | }; 478 | 347209891BB808D1004DE6DA /* Release */ = { 479 | isa = XCBuildConfiguration; 480 | buildSettings = { 481 | BUNDLE_LOADER = "$(TEST_HOST)"; 482 | FRAMEWORK_SEARCH_PATHS = ( 483 | "$(inherited)", 484 | "$(PROJECT_DIR)/Sample", 485 | ); 486 | INFOPLIST_FILE = SampleTests/Info.plist; 487 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 488 | PRODUCT_BUNDLE_IDENTIFIER = com.roymarmelstein.SampleTests; 489 | PRODUCT_NAME = "$(TARGET_NAME)"; 490 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Sample.app/Sample"; 491 | }; 492 | name = Release; 493 | }; 494 | /* End XCBuildConfiguration section */ 495 | 496 | /* Begin XCConfigurationList section */ 497 | 347209621BB808D1004DE6DA /* Build configuration list for PBXProject "Sample" */ = { 498 | isa = XCConfigurationList; 499 | buildConfigurations = ( 500 | 347209821BB808D1004DE6DA /* Debug */, 501 | 347209831BB808D1004DE6DA /* Release */, 502 | ); 503 | defaultConfigurationIsVisible = 0; 504 | defaultConfigurationName = Release; 505 | }; 506 | 347209841BB808D1004DE6DA /* Build configuration list for PBXNativeTarget "Sample" */ = { 507 | isa = XCConfigurationList; 508 | buildConfigurations = ( 509 | 347209851BB808D1004DE6DA /* Debug */, 510 | 347209861BB808D1004DE6DA /* Release */, 511 | ); 512 | defaultConfigurationIsVisible = 0; 513 | defaultConfigurationName = Release; 514 | }; 515 | 347209871BB808D1004DE6DA /* Build configuration list for PBXNativeTarget "SampleTests" */ = { 516 | isa = XCConfigurationList; 517 | buildConfigurations = ( 518 | 347209881BB808D1004DE6DA /* Debug */, 519 | 347209891BB808D1004DE6DA /* Release */, 520 | ); 521 | defaultConfigurationIsVisible = 0; 522 | defaultConfigurationName = Release; 523 | }; 524 | /* End XCConfigurationList section */ 525 | }; 526 | rootObject = 3472095F1BB808D1004DE6DA /* Project object */; 527 | } 528 | -------------------------------------------------------------------------------- /examples/StarWars/Sample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/StarWars/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /examples/StarWars/Sample/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Sample 4 | // 5 | // Created by Roy Marmelstein on 27/09/2015. 6 | // Copyright © 2015 Roy Marmelstein. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /examples/StarWars/Sample/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /examples/StarWars/Sample/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /examples/StarWars/Sample/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /examples/StarWars/Sample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /examples/StarWars/Sample/KyloA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marmelroy/TVButton/5252ebf5a2a8cf6aa05dfc7889f7e6473f0e73db/examples/StarWars/Sample/KyloA.png -------------------------------------------------------------------------------- /examples/StarWars/Sample/KyloB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marmelroy/TVButton/5252ebf5a2a8cf6aa05dfc7889f7e6473f0e73db/examples/StarWars/Sample/KyloB.png -------------------------------------------------------------------------------- /examples/StarWars/Sample/KyloC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marmelroy/TVButton/5252ebf5a2a8cf6aa05dfc7889f7e6473f0e73db/examples/StarWars/Sample/KyloC.png -------------------------------------------------------------------------------- /examples/StarWars/Sample/KyloE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marmelroy/TVButton/5252ebf5a2a8cf6aa05dfc7889f7e6473f0e73db/examples/StarWars/Sample/KyloE.png -------------------------------------------------------------------------------- /examples/StarWars/Sample/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // Sample 4 | // 5 | // Created by Roy Marmelstein on 08/11/2015. 6 | // Copyright © 2015 Roy Marmelstein. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Foundation 11 | import TVButton 12 | 13 | class ViewController: UIViewController { 14 | 15 | @IBOutlet weak var tvButton: TVButton! 16 | 17 | override func viewDidLoad() { 18 | super.viewDidLoad() 19 | let background = TVButtonLayer(image: UIImage(named: "KyloA.png")!) 20 | let pattern = TVButtonLayer(image: UIImage(named: "KyloB.png")!) 21 | let top = TVButtonLayer(image: UIImage(named: "KyloC.png")!) 22 | let uberTop = TVButtonLayer(image: UIImage(named: "KyloE.png")!) 23 | tvButton.layers = [background, pattern, uberTop, top] 24 | tvButton.parallaxIntensity = 1 25 | } 26 | 27 | override func didReceiveMemoryWarning() { 28 | super.didReceiveMemoryWarning() 29 | // Dispose of any resources that can be recreated. 30 | } 31 | 32 | } 33 | 34 | -------------------------------------------------------------------------------- /examples/StarWars/SampleTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /examples/StarWars/SampleTests/SampleTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SampleTests.swift 3 | // SampleTests 4 | // 5 | // Created by Roy Marmelstein on 27/09/2015. 6 | // Copyright © 2015 Roy Marmelstein. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import Sample 11 | 12 | class SampleTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measureBlock { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /examples/TVButton/Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, "9.3" 2 | 3 | target 'Sample' do 4 | use_frameworks! 5 | 6 | # Pods for Sample 7 | pod 'TVButton', :path => '../..' 8 | 9 | end 10 | -------------------------------------------------------------------------------- /examples/TVButton/Sample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 342AA0BA1BEEC97C00B1A7D9 /* TVButtonBackground.png in Resources */ = {isa = PBXBuildFile; fileRef = 342AA0B71BEEC97C00B1A7D9 /* TVButtonBackground.png */; }; 11 | 342AA0BB1BEEC97C00B1A7D9 /* TVButtonPattern.png in Resources */ = {isa = PBXBuildFile; fileRef = 342AA0B81BEEC97C00B1A7D9 /* TVButtonPattern.png */; }; 12 | 342AA0BC1BEEC97C00B1A7D9 /* TVButtonTop.png in Resources */ = {isa = PBXBuildFile; fileRef = 342AA0B91BEEC97C00B1A7D9 /* TVButtonTop.png */; }; 13 | 3472096B1BB808D1004DE6DA /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3472096A1BB808D1004DE6DA /* AppDelegate.swift */; }; 14 | 3472096D1BB808D1004DE6DA /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3472096C1BB808D1004DE6DA /* ViewController.swift */; }; 15 | 347209701BB808D1004DE6DA /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3472096E1BB808D1004DE6DA /* Main.storyboard */; }; 16 | 347209721BB808D1004DE6DA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 347209711BB808D1004DE6DA /* Assets.xcassets */; }; 17 | 347209751BB808D1004DE6DA /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 347209731BB808D1004DE6DA /* LaunchScreen.storyboard */; }; 18 | 347209801BB808D1004DE6DA /* SampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3472097F1BB808D1004DE6DA /* SampleTests.swift */; }; 19 | 3472098E1BB80A4F004DE6DA /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3472098D1BB80A4F004DE6DA /* Foundation.framework */; }; 20 | 34F374CA1BF1B5F20085BE13 /* TVButton.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34F374C71BF1B5E80085BE13 /* TVButton.framework */; }; 21 | 34F374CB1BF1B5F20085BE13 /* TVButton.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 34F374C71BF1B5E80085BE13 /* TVButton.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 22 | /* End PBXBuildFile section */ 23 | 24 | /* Begin PBXContainerItemProxy section */ 25 | 3472097C1BB808D1004DE6DA /* PBXContainerItemProxy */ = { 26 | isa = PBXContainerItemProxy; 27 | containerPortal = 3472095F1BB808D1004DE6DA /* Project object */; 28 | proxyType = 1; 29 | remoteGlobalIDString = 347209661BB808D1004DE6DA; 30 | remoteInfo = Sample; 31 | }; 32 | 34F374C61BF1B5E80085BE13 /* PBXContainerItemProxy */ = { 33 | isa = PBXContainerItemProxy; 34 | containerPortal = 34F374C11BF1B5E80085BE13 /* TVButton.xcodeproj */; 35 | proxyType = 2; 36 | remoteGlobalIDString = 342AA08C1BEEBE6F00B1A7D9; 37 | remoteInfo = TVButton; 38 | }; 39 | 34F374C81BF1B5E80085BE13 /* PBXContainerItemProxy */ = { 40 | isa = PBXContainerItemProxy; 41 | containerPortal = 34F374C11BF1B5E80085BE13 /* TVButton.xcodeproj */; 42 | proxyType = 2; 43 | remoteGlobalIDString = 342AA0961BEEBE6F00B1A7D9; 44 | remoteInfo = TVButtonTests; 45 | }; 46 | 34F374CC1BF1B5F20085BE13 /* PBXContainerItemProxy */ = { 47 | isa = PBXContainerItemProxy; 48 | containerPortal = 34F374C11BF1B5E80085BE13 /* TVButton.xcodeproj */; 49 | proxyType = 1; 50 | remoteGlobalIDString = 342AA08B1BEEBE6F00B1A7D9; 51 | remoteInfo = TVButton; 52 | }; 53 | /* End PBXContainerItemProxy section */ 54 | 55 | /* Begin PBXCopyFilesBuildPhase section */ 56 | 3435CCA51BC00184003F953B /* Embed Frameworks */ = { 57 | isa = PBXCopyFilesBuildPhase; 58 | buildActionMask = 2147483647; 59 | dstPath = ""; 60 | dstSubfolderSpec = 10; 61 | files = ( 62 | 34F374CB1BF1B5F20085BE13 /* TVButton.framework in Embed Frameworks */, 63 | ); 64 | name = "Embed Frameworks"; 65 | runOnlyForDeploymentPostprocessing = 0; 66 | }; 67 | /* End PBXCopyFilesBuildPhase section */ 68 | 69 | /* Begin PBXFileReference section */ 70 | 342AA0B71BEEC97C00B1A7D9 /* TVButtonBackground.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = TVButtonBackground.png; sourceTree = ""; }; 71 | 342AA0B81BEEC97C00B1A7D9 /* TVButtonPattern.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = TVButtonPattern.png; sourceTree = ""; }; 72 | 342AA0B91BEEC97C00B1A7D9 /* TVButtonTop.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = TVButtonTop.png; sourceTree = ""; }; 73 | 347209671BB808D1004DE6DA /* Sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Sample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 74 | 3472096A1BB808D1004DE6DA /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 75 | 3472096C1BB808D1004DE6DA /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 76 | 3472096F1BB808D1004DE6DA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 77 | 347209711BB808D1004DE6DA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 78 | 347209741BB808D1004DE6DA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 79 | 347209761BB808D1004DE6DA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 80 | 3472097B1BB808D1004DE6DA /* SampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 81 | 3472097F1BB808D1004DE6DA /* SampleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SampleTests.swift; sourceTree = ""; }; 82 | 347209811BB808D1004DE6DA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 83 | 3472098D1BB80A4F004DE6DA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 84 | 34F374C11BF1B5E80085BE13 /* TVButton.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = TVButton.xcodeproj; path = ../../TVButton.xcodeproj; sourceTree = ""; }; 85 | /* End PBXFileReference section */ 86 | 87 | /* Begin PBXFrameworksBuildPhase section */ 88 | 347209641BB808D1004DE6DA /* Frameworks */ = { 89 | isa = PBXFrameworksBuildPhase; 90 | buildActionMask = 2147483647; 91 | files = ( 92 | 34F374CA1BF1B5F20085BE13 /* TVButton.framework in Frameworks */, 93 | 3472098E1BB80A4F004DE6DA /* Foundation.framework in Frameworks */, 94 | ); 95 | runOnlyForDeploymentPostprocessing = 0; 96 | }; 97 | 347209781BB808D1004DE6DA /* Frameworks */ = { 98 | isa = PBXFrameworksBuildPhase; 99 | buildActionMask = 2147483647; 100 | files = ( 101 | ); 102 | runOnlyForDeploymentPostprocessing = 0; 103 | }; 104 | /* End PBXFrameworksBuildPhase section */ 105 | 106 | /* Begin PBXGroup section */ 107 | 3472095E1BB808D1004DE6DA = { 108 | isa = PBXGroup; 109 | children = ( 110 | 34F374C11BF1B5E80085BE13 /* TVButton.xcodeproj */, 111 | 347209691BB808D1004DE6DA /* Sample */, 112 | 3472097E1BB808D1004DE6DA /* SampleTests */, 113 | 347209681BB808D1004DE6DA /* Products */, 114 | ); 115 | sourceTree = ""; 116 | }; 117 | 347209681BB808D1004DE6DA /* Products */ = { 118 | isa = PBXGroup; 119 | children = ( 120 | 347209671BB808D1004DE6DA /* Sample.app */, 121 | 3472097B1BB808D1004DE6DA /* SampleTests.xctest */, 122 | ); 123 | name = Products; 124 | sourceTree = ""; 125 | }; 126 | 347209691BB808D1004DE6DA /* Sample */ = { 127 | isa = PBXGroup; 128 | children = ( 129 | 3472096A1BB808D1004DE6DA /* AppDelegate.swift */, 130 | 3472096C1BB808D1004DE6DA /* ViewController.swift */, 131 | 342AA0B71BEEC97C00B1A7D9 /* TVButtonBackground.png */, 132 | 342AA0B81BEEC97C00B1A7D9 /* TVButtonPattern.png */, 133 | 342AA0B91BEEC97C00B1A7D9 /* TVButtonTop.png */, 134 | 3472096E1BB808D1004DE6DA /* Main.storyboard */, 135 | 347209711BB808D1004DE6DA /* Assets.xcassets */, 136 | 347209731BB808D1004DE6DA /* LaunchScreen.storyboard */, 137 | 347209761BB808D1004DE6DA /* Info.plist */, 138 | 3472098D1BB80A4F004DE6DA /* Foundation.framework */, 139 | ); 140 | path = Sample; 141 | sourceTree = ""; 142 | }; 143 | 3472097E1BB808D1004DE6DA /* SampleTests */ = { 144 | isa = PBXGroup; 145 | children = ( 146 | 3472097F1BB808D1004DE6DA /* SampleTests.swift */, 147 | 347209811BB808D1004DE6DA /* Info.plist */, 148 | ); 149 | path = SampleTests; 150 | sourceTree = ""; 151 | }; 152 | 34F374C21BF1B5E80085BE13 /* Products */ = { 153 | isa = PBXGroup; 154 | children = ( 155 | 34F374C71BF1B5E80085BE13 /* TVButton.framework */, 156 | 34F374C91BF1B5E80085BE13 /* TVButtonTests.xctest */, 157 | ); 158 | name = Products; 159 | sourceTree = ""; 160 | }; 161 | /* End PBXGroup section */ 162 | 163 | /* Begin PBXNativeTarget section */ 164 | 347209661BB808D1004DE6DA /* Sample */ = { 165 | isa = PBXNativeTarget; 166 | buildConfigurationList = 347209841BB808D1004DE6DA /* Build configuration list for PBXNativeTarget "Sample" */; 167 | buildPhases = ( 168 | 347209631BB808D1004DE6DA /* Sources */, 169 | 347209641BB808D1004DE6DA /* Frameworks */, 170 | 347209651BB808D1004DE6DA /* Resources */, 171 | 3435CCA51BC00184003F953B /* Embed Frameworks */, 172 | ); 173 | buildRules = ( 174 | ); 175 | dependencies = ( 176 | 34F374CD1BF1B5F20085BE13 /* PBXTargetDependency */, 177 | ); 178 | name = Sample; 179 | productName = Sample; 180 | productReference = 347209671BB808D1004DE6DA /* Sample.app */; 181 | productType = "com.apple.product-type.application"; 182 | }; 183 | 3472097A1BB808D1004DE6DA /* SampleTests */ = { 184 | isa = PBXNativeTarget; 185 | buildConfigurationList = 347209871BB808D1004DE6DA /* Build configuration list for PBXNativeTarget "SampleTests" */; 186 | buildPhases = ( 187 | 347209771BB808D1004DE6DA /* Sources */, 188 | 347209781BB808D1004DE6DA /* Frameworks */, 189 | 347209791BB808D1004DE6DA /* Resources */, 190 | ); 191 | buildRules = ( 192 | ); 193 | dependencies = ( 194 | 3472097D1BB808D1004DE6DA /* PBXTargetDependency */, 195 | ); 196 | name = SampleTests; 197 | productName = SampleTests; 198 | productReference = 3472097B1BB808D1004DE6DA /* SampleTests.xctest */; 199 | productType = "com.apple.product-type.bundle.unit-test"; 200 | }; 201 | /* End PBXNativeTarget section */ 202 | 203 | /* Begin PBXProject section */ 204 | 3472095F1BB808D1004DE6DA /* Project object */ = { 205 | isa = PBXProject; 206 | attributes = { 207 | LastUpgradeCheck = 0810; 208 | ORGANIZATIONNAME = "Roy Marmelstein"; 209 | TargetAttributes = { 210 | 347209661BB808D1004DE6DA = { 211 | CreatedOnToolsVersion = 7.0; 212 | LastSwiftMigration = 0810; 213 | }; 214 | 3472097A1BB808D1004DE6DA = { 215 | CreatedOnToolsVersion = 7.0; 216 | TestTargetID = 347209661BB808D1004DE6DA; 217 | }; 218 | }; 219 | }; 220 | buildConfigurationList = 347209621BB808D1004DE6DA /* Build configuration list for PBXProject "Sample" */; 221 | compatibilityVersion = "Xcode 3.2"; 222 | developmentRegion = English; 223 | hasScannedForEncodings = 0; 224 | knownRegions = ( 225 | en, 226 | Base, 227 | ); 228 | mainGroup = 3472095E1BB808D1004DE6DA; 229 | productRefGroup = 347209681BB808D1004DE6DA /* Products */; 230 | projectDirPath = ""; 231 | projectReferences = ( 232 | { 233 | ProductGroup = 34F374C21BF1B5E80085BE13 /* Products */; 234 | ProjectRef = 34F374C11BF1B5E80085BE13 /* TVButton.xcodeproj */; 235 | }, 236 | ); 237 | projectRoot = ""; 238 | targets = ( 239 | 347209661BB808D1004DE6DA /* Sample */, 240 | 3472097A1BB808D1004DE6DA /* SampleTests */, 241 | ); 242 | }; 243 | /* End PBXProject section */ 244 | 245 | /* Begin PBXReferenceProxy section */ 246 | 34F374C71BF1B5E80085BE13 /* TVButton.framework */ = { 247 | isa = PBXReferenceProxy; 248 | fileType = wrapper.framework; 249 | path = TVButton.framework; 250 | remoteRef = 34F374C61BF1B5E80085BE13 /* PBXContainerItemProxy */; 251 | sourceTree = BUILT_PRODUCTS_DIR; 252 | }; 253 | 34F374C91BF1B5E80085BE13 /* TVButtonTests.xctest */ = { 254 | isa = PBXReferenceProxy; 255 | fileType = wrapper.cfbundle; 256 | path = TVButtonTests.xctest; 257 | remoteRef = 34F374C81BF1B5E80085BE13 /* PBXContainerItemProxy */; 258 | sourceTree = BUILT_PRODUCTS_DIR; 259 | }; 260 | /* End PBXReferenceProxy section */ 261 | 262 | /* Begin PBXResourcesBuildPhase section */ 263 | 347209651BB808D1004DE6DA /* Resources */ = { 264 | isa = PBXResourcesBuildPhase; 265 | buildActionMask = 2147483647; 266 | files = ( 267 | 347209751BB808D1004DE6DA /* LaunchScreen.storyboard in Resources */, 268 | 342AA0BB1BEEC97C00B1A7D9 /* TVButtonPattern.png in Resources */, 269 | 347209721BB808D1004DE6DA /* Assets.xcassets in Resources */, 270 | 342AA0BC1BEEC97C00B1A7D9 /* TVButtonTop.png in Resources */, 271 | 347209701BB808D1004DE6DA /* Main.storyboard in Resources */, 272 | 342AA0BA1BEEC97C00B1A7D9 /* TVButtonBackground.png in Resources */, 273 | ); 274 | runOnlyForDeploymentPostprocessing = 0; 275 | }; 276 | 347209791BB808D1004DE6DA /* Resources */ = { 277 | isa = PBXResourcesBuildPhase; 278 | buildActionMask = 2147483647; 279 | files = ( 280 | ); 281 | runOnlyForDeploymentPostprocessing = 0; 282 | }; 283 | /* End PBXResourcesBuildPhase section */ 284 | 285 | /* Begin PBXSourcesBuildPhase section */ 286 | 347209631BB808D1004DE6DA /* Sources */ = { 287 | isa = PBXSourcesBuildPhase; 288 | buildActionMask = 2147483647; 289 | files = ( 290 | 3472096D1BB808D1004DE6DA /* ViewController.swift in Sources */, 291 | 3472096B1BB808D1004DE6DA /* AppDelegate.swift in Sources */, 292 | ); 293 | runOnlyForDeploymentPostprocessing = 0; 294 | }; 295 | 347209771BB808D1004DE6DA /* Sources */ = { 296 | isa = PBXSourcesBuildPhase; 297 | buildActionMask = 2147483647; 298 | files = ( 299 | 347209801BB808D1004DE6DA /* SampleTests.swift in Sources */, 300 | ); 301 | runOnlyForDeploymentPostprocessing = 0; 302 | }; 303 | /* End PBXSourcesBuildPhase section */ 304 | 305 | /* Begin PBXTargetDependency section */ 306 | 3472097D1BB808D1004DE6DA /* PBXTargetDependency */ = { 307 | isa = PBXTargetDependency; 308 | target = 347209661BB808D1004DE6DA /* Sample */; 309 | targetProxy = 3472097C1BB808D1004DE6DA /* PBXContainerItemProxy */; 310 | }; 311 | 34F374CD1BF1B5F20085BE13 /* PBXTargetDependency */ = { 312 | isa = PBXTargetDependency; 313 | name = TVButton; 314 | targetProxy = 34F374CC1BF1B5F20085BE13 /* PBXContainerItemProxy */; 315 | }; 316 | /* End PBXTargetDependency section */ 317 | 318 | /* Begin PBXVariantGroup section */ 319 | 3472096E1BB808D1004DE6DA /* Main.storyboard */ = { 320 | isa = PBXVariantGroup; 321 | children = ( 322 | 3472096F1BB808D1004DE6DA /* Base */, 323 | ); 324 | name = Main.storyboard; 325 | sourceTree = ""; 326 | }; 327 | 347209731BB808D1004DE6DA /* LaunchScreen.storyboard */ = { 328 | isa = PBXVariantGroup; 329 | children = ( 330 | 347209741BB808D1004DE6DA /* Base */, 331 | ); 332 | name = LaunchScreen.storyboard; 333 | sourceTree = ""; 334 | }; 335 | /* End PBXVariantGroup section */ 336 | 337 | /* Begin XCBuildConfiguration section */ 338 | 347209821BB808D1004DE6DA /* Debug */ = { 339 | isa = XCBuildConfiguration; 340 | buildSettings = { 341 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 342 | ALWAYS_SEARCH_USER_PATHS = NO; 343 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 344 | CLANG_CXX_LIBRARY = "libc++"; 345 | CLANG_ENABLE_MODULES = YES; 346 | CLANG_ENABLE_OBJC_ARC = YES; 347 | CLANG_WARN_BOOL_CONVERSION = YES; 348 | CLANG_WARN_CONSTANT_CONVERSION = YES; 349 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 350 | CLANG_WARN_EMPTY_BODY = YES; 351 | CLANG_WARN_ENUM_CONVERSION = YES; 352 | CLANG_WARN_INFINITE_RECURSION = YES; 353 | CLANG_WARN_INT_CONVERSION = YES; 354 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 355 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 356 | CLANG_WARN_UNREACHABLE_CODE = YES; 357 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 358 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 359 | COPY_PHASE_STRIP = NO; 360 | DEBUG_INFORMATION_FORMAT = dwarf; 361 | ENABLE_STRICT_OBJC_MSGSEND = YES; 362 | ENABLE_TESTABILITY = YES; 363 | GCC_C_LANGUAGE_STANDARD = gnu99; 364 | GCC_DYNAMIC_NO_PIC = NO; 365 | GCC_NO_COMMON_BLOCKS = YES; 366 | GCC_OPTIMIZATION_LEVEL = 0; 367 | GCC_PREPROCESSOR_DEFINITIONS = ( 368 | "DEBUG=1", 369 | "$(inherited)", 370 | ); 371 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 372 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 373 | GCC_WARN_UNDECLARED_SELECTOR = YES; 374 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 375 | GCC_WARN_UNUSED_FUNCTION = YES; 376 | GCC_WARN_UNUSED_VARIABLE = YES; 377 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 378 | MTL_ENABLE_DEBUG_INFO = YES; 379 | ONLY_ACTIVE_ARCH = YES; 380 | OTHER_LDFLAGS = "$(inherited)"; 381 | SDKROOT = iphoneos; 382 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 383 | }; 384 | name = Debug; 385 | }; 386 | 347209831BB808D1004DE6DA /* Release */ = { 387 | isa = XCBuildConfiguration; 388 | buildSettings = { 389 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 390 | ALWAYS_SEARCH_USER_PATHS = NO; 391 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 392 | CLANG_CXX_LIBRARY = "libc++"; 393 | CLANG_ENABLE_MODULES = YES; 394 | CLANG_ENABLE_OBJC_ARC = YES; 395 | CLANG_WARN_BOOL_CONVERSION = YES; 396 | CLANG_WARN_CONSTANT_CONVERSION = YES; 397 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 398 | CLANG_WARN_EMPTY_BODY = YES; 399 | CLANG_WARN_ENUM_CONVERSION = YES; 400 | CLANG_WARN_INFINITE_RECURSION = YES; 401 | CLANG_WARN_INT_CONVERSION = YES; 402 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 403 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 404 | CLANG_WARN_UNREACHABLE_CODE = YES; 405 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 406 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 407 | COPY_PHASE_STRIP = NO; 408 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 409 | ENABLE_NS_ASSERTIONS = NO; 410 | ENABLE_STRICT_OBJC_MSGSEND = YES; 411 | GCC_C_LANGUAGE_STANDARD = gnu99; 412 | GCC_NO_COMMON_BLOCKS = YES; 413 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 414 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 415 | GCC_WARN_UNDECLARED_SELECTOR = YES; 416 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 417 | GCC_WARN_UNUSED_FUNCTION = YES; 418 | GCC_WARN_UNUSED_VARIABLE = YES; 419 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 420 | MTL_ENABLE_DEBUG_INFO = NO; 421 | OTHER_LDFLAGS = "$(inherited)"; 422 | SDKROOT = iphoneos; 423 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 424 | VALIDATE_PRODUCT = YES; 425 | }; 426 | name = Release; 427 | }; 428 | 347209851BB808D1004DE6DA /* Debug */ = { 429 | isa = XCBuildConfiguration; 430 | buildSettings = { 431 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 432 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 433 | FRAMEWORK_SEARCH_PATHS = "$(inherited)"; 434 | INFOPLIST_FILE = Sample/Info.plist; 435 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 436 | OTHER_LDFLAGS = "$(inherited)"; 437 | PRODUCT_BUNDLE_IDENTIFIER = com.roymarmelstein.Sample; 438 | PRODUCT_NAME = "$(TARGET_NAME)"; 439 | SWIFT_VERSION = 3.0; 440 | }; 441 | name = Debug; 442 | }; 443 | 347209861BB808D1004DE6DA /* Release */ = { 444 | isa = XCBuildConfiguration; 445 | buildSettings = { 446 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 447 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 448 | FRAMEWORK_SEARCH_PATHS = "$(inherited)"; 449 | INFOPLIST_FILE = Sample/Info.plist; 450 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 451 | OTHER_LDFLAGS = "$(inherited)"; 452 | PRODUCT_BUNDLE_IDENTIFIER = com.roymarmelstein.Sample; 453 | PRODUCT_NAME = "$(TARGET_NAME)"; 454 | SWIFT_VERSION = 3.0; 455 | }; 456 | name = Release; 457 | }; 458 | 347209881BB808D1004DE6DA /* Debug */ = { 459 | isa = XCBuildConfiguration; 460 | buildSettings = { 461 | BUNDLE_LOADER = "$(TEST_HOST)"; 462 | FRAMEWORK_SEARCH_PATHS = ( 463 | "$(inherited)", 464 | "$(PROJECT_DIR)/Sample", 465 | ); 466 | INFOPLIST_FILE = SampleTests/Info.plist; 467 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 468 | PRODUCT_BUNDLE_IDENTIFIER = com.roymarmelstein.SampleTests; 469 | PRODUCT_NAME = "$(TARGET_NAME)"; 470 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Sample.app/Sample"; 471 | }; 472 | name = Debug; 473 | }; 474 | 347209891BB808D1004DE6DA /* Release */ = { 475 | isa = XCBuildConfiguration; 476 | buildSettings = { 477 | BUNDLE_LOADER = "$(TEST_HOST)"; 478 | FRAMEWORK_SEARCH_PATHS = ( 479 | "$(inherited)", 480 | "$(PROJECT_DIR)/Sample", 481 | ); 482 | INFOPLIST_FILE = SampleTests/Info.plist; 483 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 484 | PRODUCT_BUNDLE_IDENTIFIER = com.roymarmelstein.SampleTests; 485 | PRODUCT_NAME = "$(TARGET_NAME)"; 486 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Sample.app/Sample"; 487 | }; 488 | name = Release; 489 | }; 490 | /* End XCBuildConfiguration section */ 491 | 492 | /* Begin XCConfigurationList section */ 493 | 347209621BB808D1004DE6DA /* Build configuration list for PBXProject "Sample" */ = { 494 | isa = XCConfigurationList; 495 | buildConfigurations = ( 496 | 347209821BB808D1004DE6DA /* Debug */, 497 | 347209831BB808D1004DE6DA /* Release */, 498 | ); 499 | defaultConfigurationIsVisible = 0; 500 | defaultConfigurationName = Release; 501 | }; 502 | 347209841BB808D1004DE6DA /* Build configuration list for PBXNativeTarget "Sample" */ = { 503 | isa = XCConfigurationList; 504 | buildConfigurations = ( 505 | 347209851BB808D1004DE6DA /* Debug */, 506 | 347209861BB808D1004DE6DA /* Release */, 507 | ); 508 | defaultConfigurationIsVisible = 0; 509 | defaultConfigurationName = Release; 510 | }; 511 | 347209871BB808D1004DE6DA /* Build configuration list for PBXNativeTarget "SampleTests" */ = { 512 | isa = XCConfigurationList; 513 | buildConfigurations = ( 514 | 347209881BB808D1004DE6DA /* Debug */, 515 | 347209891BB808D1004DE6DA /* Release */, 516 | ); 517 | defaultConfigurationIsVisible = 0; 518 | defaultConfigurationName = Release; 519 | }; 520 | /* End XCConfigurationList section */ 521 | }; 522 | rootObject = 3472095F1BB808D1004DE6DA /* Project object */; 523 | } 524 | -------------------------------------------------------------------------------- /examples/TVButton/Sample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/TVButton/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /examples/TVButton/Sample/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Sample 4 | // 5 | // Created by Roy Marmelstein on 27/09/2015. 6 | // Copyright © 2015 Roy Marmelstein. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /examples/TVButton/Sample/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /examples/TVButton/Sample/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /examples/TVButton/Sample/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /examples/TVButton/Sample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /examples/TVButton/Sample/TVButtonBackground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marmelroy/TVButton/5252ebf5a2a8cf6aa05dfc7889f7e6473f0e73db/examples/TVButton/Sample/TVButtonBackground.png -------------------------------------------------------------------------------- /examples/TVButton/Sample/TVButtonPattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marmelroy/TVButton/5252ebf5a2a8cf6aa05dfc7889f7e6473f0e73db/examples/TVButton/Sample/TVButtonPattern.png -------------------------------------------------------------------------------- /examples/TVButton/Sample/TVButtonTop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marmelroy/TVButton/5252ebf5a2a8cf6aa05dfc7889f7e6473f0e73db/examples/TVButton/Sample/TVButtonTop.png -------------------------------------------------------------------------------- /examples/TVButton/Sample/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // Sample 4 | // 5 | // Created by Roy Marmelstein on 08/11/2015. 6 | // Copyright © 2015 Roy Marmelstein. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Foundation 11 | import TVButton 12 | 13 | class ViewController: UIViewController { 14 | 15 | @IBOutlet weak var tvButton: TVButton! 16 | 17 | override func viewDidLoad() { 18 | super.viewDidLoad() 19 | let background = TVButtonLayer(image: UIImage(named: "TVButtonBackground.png")!) 20 | let pattern = TVButtonLayer(image: UIImage(named: "TVButtonPattern.png")!) 21 | let top = TVButtonLayer(image: UIImage(named: "TVButtonTop.png")!) 22 | tvButton.layers = [background, pattern, top] 23 | } 24 | 25 | override func didReceiveMemoryWarning() { 26 | super.didReceiveMemoryWarning() 27 | // Dispose of any resources that can be recreated. 28 | } 29 | 30 | } 31 | 32 | -------------------------------------------------------------------------------- /examples/TVButton/SampleTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /examples/TVButton/SampleTests/SampleTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SampleTests.swift 3 | // SampleTests 4 | // 5 | // Created by Roy Marmelstein on 27/09/2015. 6 | // Copyright © 2015 Roy Marmelstein. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import Sample 11 | 12 | class SampleTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measureBlock { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | --------------------------------------------------------------------------------