├── 1.gif ├── README.md ├── mtTVPlayer.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── CoverFlowLayout.xcscmblueprint │ └── xcuserdata │ │ ├── Broccoli.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ │ └── MartinRGB.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ ├── Broccoli.xcuserdatad │ └── xcschemes │ │ ├── CoverFlowLayout.xcscheme │ │ └── xcschememanagement.plist │ └── MartinRGB.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── mtTVPlayer.xcscheme │ └── xcschememanagement.plist └── mtTVPlayer ├── AppDelegate.swift ├── Assets.xcassets ├── AppIcon.appiconset │ └── Contents.json ├── Contents.json ├── Play.imageset │ ├── Contents.json │ └── Play.png ├── Vinyl.imageset │ ├── Contents.json │ └── Vinyl.png ├── album1.imageset │ ├── Contents.json │ └── album1.jpg ├── album10.imageset │ ├── Contents.json │ └── album10.jpg ├── album2.imageset │ ├── Contents.json │ └── album2.jpg ├── album3.imageset │ ├── Contents.json │ └── album3.jpg ├── album4.imageset │ ├── Contents.json │ └── album4.jpg ├── album5.imageset │ ├── Contents.json │ └── album5.jpg ├── album6.imageset │ ├── Contents.json │ └── album6.jpg ├── album7.imageset │ ├── Contents.json │ └── album7.jpg ├── album8.imageset │ ├── Contents.json │ └── album8.jpg ├── album9.imageset │ ├── Contents.json │ └── album9.jpg ├── max.imageset │ ├── Contents.json │ └── max.png ├── min.imageset │ ├── Contents.json │ └── min.png ├── pause.imageset │ ├── Contents.json │ └── pause.png └── tvBG.imageset │ ├── Contents.json │ └── tvBG.png ├── Base.lproj ├── LaunchScreen.storyboard ├── Main.storyboard ├── song1.mp3 ├── song10.mp3 ├── song2.mp3 ├── song3.mp3 ├── song4.mp3 ├── song5.mp3 ├── song6.mp3 ├── song7.mp3 ├── song8.mp3 └── song9.mp3 ├── CoverFlowLayout.swift ├── DIN-Bold.otf ├── DIN-BoldItalic.otf ├── Info.plist ├── ViewController.swift ├── song6.mp3 └── song7.mp3 /1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinRGB/MTMusicPlayer/e263038c3743215cc94b1940a307ef541a537dce/1.gif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MTTVPlayer 2 | 3 | *simple implement an AV Player & my workmates Xerlee's Animation* 4 | 5 | 6 | 7 | 8 | Inspired by Xerlee's design work [ 9 | Music App For Tv/Pad](https://dribbble.com/shots/2377536-Music-App-For-Tv-Pad) 10 | 11 | and broccolii's code work [CoverflowLayout](https://github.com/broccolii/CoverFlowLayout) 12 | 13 | I made this player for exercise 14 | 15 | 16 | 17 | ![My Current Progress](https://github.com/MartinRGB/MTMusicPlayer/blob/master/1.gif?raw=true) 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | P.S. thanks to [ 26 | JustinFincher](https://github.com/JustinFincher) [mmoaay](https://github.com/mmoaay) [SergioChan](https://github.com/SergioChan) ,they teach me some knowledge about AVFoundation 27 | 28 | -------------------------------------------------------------------------------- /mtTVPlayer.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 2E821AE71C0EFC2B0089CB89 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E821ADB1C0EFC2B0089CB89 /* AppDelegate.swift */; }; 11 | 2E821AE81C0EFC2B0089CB89 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2E821ADC1C0EFC2B0089CB89 /* Assets.xcassets */; }; 12 | 2E821AE91C0EFC2B0089CB89 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2E821ADE1C0EFC2B0089CB89 /* LaunchScreen.storyboard */; }; 13 | 2E821AEA1C0EFC2B0089CB89 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2E821AE01C0EFC2B0089CB89 /* Main.storyboard */; }; 14 | 2E821AEB1C0EFC2B0089CB89 /* CoverFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E821AE21C0EFC2B0089CB89 /* CoverFlowLayout.swift */; }; 15 | 2E821AEC1C0EFC2B0089CB89 /* DIN-Bold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 2E821AE31C0EFC2B0089CB89 /* DIN-Bold.otf */; }; 16 | 2E821AED1C0EFC2B0089CB89 /* DIN-BoldItalic.otf in Resources */ = {isa = PBXBuildFile; fileRef = 2E821AE41C0EFC2B0089CB89 /* DIN-BoldItalic.otf */; }; 17 | 2E821AEE1C0EFC2B0089CB89 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 2E821AE51C0EFC2B0089CB89 /* Info.plist */; }; 18 | 2E821AEF1C0EFC2B0089CB89 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E821AE61C0EFC2B0089CB89 /* ViewController.swift */; }; 19 | 2E821AF41C0EFDD10089CB89 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2E821AF01C0EFDD10089CB89 /* LaunchScreen.storyboard */; }; 20 | 2E821AF51C0EFDD10089CB89 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2E821AF21C0EFDD10089CB89 /* Main.storyboard */; }; 21 | 2E821B231C0F0AC20089CB89 /* song6.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 2E821B191C0F0AC20089CB89 /* song6.mp3 */; }; 22 | 2E821B241C0F0AC20089CB89 /* song7.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 2E821B1A1C0F0AC20089CB89 /* song7.mp3 */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXFileReference section */ 26 | 2E821ADB1C0EFC2B0089CB89 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = mtTVPlayer/AppDelegate.swift; sourceTree = SOURCE_ROOT; }; 27 | 2E821ADC1C0EFC2B0089CB89 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = mtTVPlayer/Assets.xcassets; sourceTree = SOURCE_ROOT; }; 28 | 2E821ADF1C0EFC2B0089CB89 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = LaunchScreen.storyboard; sourceTree = ""; }; 29 | 2E821AE11C0EFC2B0089CB89 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Main.storyboard; sourceTree = ""; }; 30 | 2E821AE21C0EFC2B0089CB89 /* CoverFlowLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CoverFlowLayout.swift; path = mtTVPlayer/CoverFlowLayout.swift; sourceTree = SOURCE_ROOT; }; 31 | 2E821AE31C0EFC2B0089CB89 /* DIN-Bold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "DIN-Bold.otf"; path = "mtTVPlayer/DIN-Bold.otf"; sourceTree = SOURCE_ROOT; }; 32 | 2E821AE41C0EFC2B0089CB89 /* DIN-BoldItalic.otf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "DIN-BoldItalic.otf"; path = "mtTVPlayer/DIN-BoldItalic.otf"; sourceTree = SOURCE_ROOT; }; 33 | 2E821AE51C0EFC2B0089CB89 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = mtTVPlayer/Info.plist; sourceTree = SOURCE_ROOT; }; 34 | 2E821AE61C0EFC2B0089CB89 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ViewController.swift; path = mtTVPlayer/ViewController.swift; sourceTree = SOURCE_ROOT; }; 35 | 2E821AF11C0EFDD10089CB89 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = mtTVPlayer/Base.lproj/LaunchScreen.storyboard; sourceTree = SOURCE_ROOT; }; 36 | 2E821AF31C0EFDD10089CB89 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = mtTVPlayer/Base.lproj/Main.storyboard; sourceTree = SOURCE_ROOT; }; 37 | 2E821AF71C0F0AA70089CB89 /* Base */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = Base; path = song1.mp3; sourceTree = ""; }; 38 | 2E821AF91C0F0AA70089CB89 /* Base */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = Base; path = song2.mp3; sourceTree = ""; }; 39 | 2E821AFB1C0F0AA70089CB89 /* Base */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = Base; path = song3.mp3; sourceTree = ""; }; 40 | 2E821AFD1C0F0AA70089CB89 /* Base */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = Base; path = song4.mp3; sourceTree = ""; }; 41 | 2E821AFF1C0F0AA70089CB89 /* Base */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = Base; path = song5.mp3; sourceTree = ""; }; 42 | 2E821B011C0F0AA70089CB89 /* Base */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = Base; path = song6.mp3; sourceTree = ""; }; 43 | 2E821B031C0F0AA70089CB89 /* Base */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = Base; path = song7.mp3; sourceTree = ""; }; 44 | 2E821B051C0F0AA70089CB89 /* Base */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = Base; path = song8.mp3; sourceTree = ""; }; 45 | 2E821B071C0F0AA70089CB89 /* Base */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = Base; path = song9.mp3; sourceTree = ""; }; 46 | 2E821B091C0F0AA70089CB89 /* Base */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = Base; path = song10.mp3; sourceTree = ""; }; 47 | 2E821B191C0F0AC20089CB89 /* song6.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = song6.mp3; path = mtTVPlayer/song6.mp3; sourceTree = SOURCE_ROOT; }; 48 | 2E821B1A1C0F0AC20089CB89 /* song7.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = song7.mp3; path = mtTVPlayer/song7.mp3; sourceTree = SOURCE_ROOT; }; 49 | A43F39FD1C074ABD0019A555 /* mtTVPlayer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = mtTVPlayer.app; sourceTree = BUILT_PRODUCTS_DIR; }; 50 | /* End PBXFileReference section */ 51 | 52 | /* Begin PBXFrameworksBuildPhase section */ 53 | A43F39FA1C074ABD0019A555 /* Frameworks */ = { 54 | isa = PBXFrameworksBuildPhase; 55 | buildActionMask = 2147483647; 56 | files = ( 57 | ); 58 | runOnlyForDeploymentPostprocessing = 0; 59 | }; 60 | /* End PBXFrameworksBuildPhase section */ 61 | 62 | /* Begin PBXGroup section */ 63 | 2E821ADD1C0EFC2B0089CB89 /* Base.lproj */ = { 64 | isa = PBXGroup; 65 | children = ( 66 | 2E821AF61C0F0AA70089CB89 /* song1.mp3 */, 67 | 2E821AF81C0F0AA70089CB89 /* song2.mp3 */, 68 | 2E821AFA1C0F0AA70089CB89 /* song3.mp3 */, 69 | 2E821AFC1C0F0AA70089CB89 /* song4.mp3 */, 70 | 2E821AFE1C0F0AA70089CB89 /* song5.mp3 */, 71 | 2E821B001C0F0AA70089CB89 /* song6.mp3 */, 72 | 2E821B021C0F0AA70089CB89 /* song7.mp3 */, 73 | 2E821B041C0F0AA70089CB89 /* song8.mp3 */, 74 | 2E821B061C0F0AA70089CB89 /* song9.mp3 */, 75 | 2E821B081C0F0AA70089CB89 /* song10.mp3 */, 76 | 2E821ADE1C0EFC2B0089CB89 /* LaunchScreen.storyboard */, 77 | 2E821AE01C0EFC2B0089CB89 /* Main.storyboard */, 78 | ); 79 | name = Base.lproj; 80 | path = mtTVPlayer/Base.lproj; 81 | sourceTree = SOURCE_ROOT; 82 | }; 83 | 2E821B281C0F0ACC0089CB89 /* Songlist */ = { 84 | isa = PBXGroup; 85 | children = ( 86 | 2E821B191C0F0AC20089CB89 /* song6.mp3 */, 87 | 2E821B1A1C0F0AC20089CB89 /* song7.mp3 */, 88 | ); 89 | name = Songlist; 90 | sourceTree = ""; 91 | }; 92 | A43F39F41C074ABD0019A555 = { 93 | isa = PBXGroup; 94 | children = ( 95 | A43F39FF1C074ABD0019A555 /* mtTVPlayer */, 96 | A43F39FE1C074ABD0019A555 /* Products */, 97 | ); 98 | sourceTree = ""; 99 | }; 100 | A43F39FE1C074ABD0019A555 /* Products */ = { 101 | isa = PBXGroup; 102 | children = ( 103 | A43F39FD1C074ABD0019A555 /* mtTVPlayer.app */, 104 | ); 105 | name = Products; 106 | sourceTree = ""; 107 | }; 108 | A43F39FF1C074ABD0019A555 /* mtTVPlayer */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | 2E821ADB1C0EFC2B0089CB89 /* AppDelegate.swift */, 112 | 2E821AE61C0EFC2B0089CB89 /* ViewController.swift */, 113 | 2E821AE21C0EFC2B0089CB89 /* CoverFlowLayout.swift */, 114 | 2E821ADC1C0EFC2B0089CB89 /* Assets.xcassets */, 115 | 2E821B281C0F0ACC0089CB89 /* Songlist */, 116 | 2E821ADD1C0EFC2B0089CB89 /* Base.lproj */, 117 | 2E821AF01C0EFDD10089CB89 /* LaunchScreen.storyboard */, 118 | 2E821AF21C0EFDD10089CB89 /* Main.storyboard */, 119 | 2E821AE31C0EFC2B0089CB89 /* DIN-Bold.otf */, 120 | 2E821AE41C0EFC2B0089CB89 /* DIN-BoldItalic.otf */, 121 | 2E821AE51C0EFC2B0089CB89 /* Info.plist */, 122 | ); 123 | name = mtTVPlayer; 124 | path = CoverFlowLayout; 125 | sourceTree = ""; 126 | }; 127 | /* End PBXGroup section */ 128 | 129 | /* Begin PBXNativeTarget section */ 130 | A43F39FC1C074ABD0019A555 /* mtTVPlayer */ = { 131 | isa = PBXNativeTarget; 132 | buildConfigurationList = A43F3A0F1C074ABD0019A555 /* Build configuration list for PBXNativeTarget "mtTVPlayer" */; 133 | buildPhases = ( 134 | A43F39F91C074ABD0019A555 /* Sources */, 135 | A43F39FA1C074ABD0019A555 /* Frameworks */, 136 | A43F39FB1C074ABD0019A555 /* Resources */, 137 | ); 138 | buildRules = ( 139 | ); 140 | dependencies = ( 141 | ); 142 | name = mtTVPlayer; 143 | productName = CoverFlowLayout; 144 | productReference = A43F39FD1C074ABD0019A555 /* mtTVPlayer.app */; 145 | productType = "com.apple.product-type.application"; 146 | }; 147 | /* End PBXNativeTarget section */ 148 | 149 | /* Begin PBXProject section */ 150 | A43F39F51C074ABD0019A555 /* Project object */ = { 151 | isa = PBXProject; 152 | attributes = { 153 | LastSwiftUpdateCheck = 0710; 154 | LastUpgradeCheck = 0710; 155 | ORGANIZATIONNAME = Broccoli; 156 | TargetAttributes = { 157 | A43F39FC1C074ABD0019A555 = { 158 | CreatedOnToolsVersion = 7.1.1; 159 | DevelopmentTeam = 8377DUVBBA; 160 | }; 161 | }; 162 | }; 163 | buildConfigurationList = A43F39F81C074ABD0019A555 /* Build configuration list for PBXProject "mtTVPlayer" */; 164 | compatibilityVersion = "Xcode 3.2"; 165 | developmentRegion = English; 166 | hasScannedForEncodings = 0; 167 | knownRegions = ( 168 | en, 169 | Base, 170 | ); 171 | mainGroup = A43F39F41C074ABD0019A555; 172 | productRefGroup = A43F39FE1C074ABD0019A555 /* Products */; 173 | projectDirPath = ""; 174 | projectRoot = ""; 175 | targets = ( 176 | A43F39FC1C074ABD0019A555 /* mtTVPlayer */, 177 | ); 178 | }; 179 | /* End PBXProject section */ 180 | 181 | /* Begin PBXResourcesBuildPhase section */ 182 | A43F39FB1C074ABD0019A555 /* Resources */ = { 183 | isa = PBXResourcesBuildPhase; 184 | buildActionMask = 2147483647; 185 | files = ( 186 | 2E821AED1C0EFC2B0089CB89 /* DIN-BoldItalic.otf in Resources */, 187 | 2E821AEC1C0EFC2B0089CB89 /* DIN-Bold.otf in Resources */, 188 | 2E821B231C0F0AC20089CB89 /* song6.mp3 in Resources */, 189 | 2E821AEA1C0EFC2B0089CB89 /* Main.storyboard in Resources */, 190 | 2E821AF51C0EFDD10089CB89 /* Main.storyboard in Resources */, 191 | 2E821AE91C0EFC2B0089CB89 /* LaunchScreen.storyboard in Resources */, 192 | 2E821AF41C0EFDD10089CB89 /* LaunchScreen.storyboard in Resources */, 193 | 2E821AEE1C0EFC2B0089CB89 /* Info.plist in Resources */, 194 | 2E821B241C0F0AC20089CB89 /* song7.mp3 in Resources */, 195 | 2E821AE81C0EFC2B0089CB89 /* Assets.xcassets in Resources */, 196 | ); 197 | runOnlyForDeploymentPostprocessing = 0; 198 | }; 199 | /* End PBXResourcesBuildPhase section */ 200 | 201 | /* Begin PBXSourcesBuildPhase section */ 202 | A43F39F91C074ABD0019A555 /* Sources */ = { 203 | isa = PBXSourcesBuildPhase; 204 | buildActionMask = 2147483647; 205 | files = ( 206 | 2E821AEF1C0EFC2B0089CB89 /* ViewController.swift in Sources */, 207 | 2E821AE71C0EFC2B0089CB89 /* AppDelegate.swift in Sources */, 208 | 2E821AEB1C0EFC2B0089CB89 /* CoverFlowLayout.swift in Sources */, 209 | ); 210 | runOnlyForDeploymentPostprocessing = 0; 211 | }; 212 | /* End PBXSourcesBuildPhase section */ 213 | 214 | /* Begin PBXVariantGroup section */ 215 | 2E821ADE1C0EFC2B0089CB89 /* LaunchScreen.storyboard */ = { 216 | isa = PBXVariantGroup; 217 | children = ( 218 | 2E821ADF1C0EFC2B0089CB89 /* Base */, 219 | ); 220 | name = LaunchScreen.storyboard; 221 | sourceTree = ""; 222 | }; 223 | 2E821AE01C0EFC2B0089CB89 /* Main.storyboard */ = { 224 | isa = PBXVariantGroup; 225 | children = ( 226 | 2E821AE11C0EFC2B0089CB89 /* Base */, 227 | ); 228 | name = Main.storyboard; 229 | sourceTree = ""; 230 | }; 231 | 2E821AF01C0EFDD10089CB89 /* LaunchScreen.storyboard */ = { 232 | isa = PBXVariantGroup; 233 | children = ( 234 | 2E821AF11C0EFDD10089CB89 /* Base */, 235 | ); 236 | name = LaunchScreen.storyboard; 237 | sourceTree = ""; 238 | }; 239 | 2E821AF21C0EFDD10089CB89 /* Main.storyboard */ = { 240 | isa = PBXVariantGroup; 241 | children = ( 242 | 2E821AF31C0EFDD10089CB89 /* Base */, 243 | ); 244 | name = Main.storyboard; 245 | sourceTree = ""; 246 | }; 247 | 2E821AF61C0F0AA70089CB89 /* song1.mp3 */ = { 248 | isa = PBXVariantGroup; 249 | children = ( 250 | 2E821AF71C0F0AA70089CB89 /* Base */, 251 | ); 252 | name = song1.mp3; 253 | sourceTree = ""; 254 | }; 255 | 2E821AF81C0F0AA70089CB89 /* song2.mp3 */ = { 256 | isa = PBXVariantGroup; 257 | children = ( 258 | 2E821AF91C0F0AA70089CB89 /* Base */, 259 | ); 260 | name = song2.mp3; 261 | sourceTree = ""; 262 | }; 263 | 2E821AFA1C0F0AA70089CB89 /* song3.mp3 */ = { 264 | isa = PBXVariantGroup; 265 | children = ( 266 | 2E821AFB1C0F0AA70089CB89 /* Base */, 267 | ); 268 | name = song3.mp3; 269 | sourceTree = ""; 270 | }; 271 | 2E821AFC1C0F0AA70089CB89 /* song4.mp3 */ = { 272 | isa = PBXVariantGroup; 273 | children = ( 274 | 2E821AFD1C0F0AA70089CB89 /* Base */, 275 | ); 276 | name = song4.mp3; 277 | sourceTree = ""; 278 | }; 279 | 2E821AFE1C0F0AA70089CB89 /* song5.mp3 */ = { 280 | isa = PBXVariantGroup; 281 | children = ( 282 | 2E821AFF1C0F0AA70089CB89 /* Base */, 283 | ); 284 | name = song5.mp3; 285 | sourceTree = ""; 286 | }; 287 | 2E821B001C0F0AA70089CB89 /* song6.mp3 */ = { 288 | isa = PBXVariantGroup; 289 | children = ( 290 | 2E821B011C0F0AA70089CB89 /* Base */, 291 | ); 292 | name = song6.mp3; 293 | sourceTree = ""; 294 | }; 295 | 2E821B021C0F0AA70089CB89 /* song7.mp3 */ = { 296 | isa = PBXVariantGroup; 297 | children = ( 298 | 2E821B031C0F0AA70089CB89 /* Base */, 299 | ); 300 | name = song7.mp3; 301 | sourceTree = ""; 302 | }; 303 | 2E821B041C0F0AA70089CB89 /* song8.mp3 */ = { 304 | isa = PBXVariantGroup; 305 | children = ( 306 | 2E821B051C0F0AA70089CB89 /* Base */, 307 | ); 308 | name = song8.mp3; 309 | sourceTree = ""; 310 | }; 311 | 2E821B061C0F0AA70089CB89 /* song9.mp3 */ = { 312 | isa = PBXVariantGroup; 313 | children = ( 314 | 2E821B071C0F0AA70089CB89 /* Base */, 315 | ); 316 | name = song9.mp3; 317 | sourceTree = ""; 318 | }; 319 | 2E821B081C0F0AA70089CB89 /* song10.mp3 */ = { 320 | isa = PBXVariantGroup; 321 | children = ( 322 | 2E821B091C0F0AA70089CB89 /* Base */, 323 | ); 324 | name = song10.mp3; 325 | sourceTree = ""; 326 | }; 327 | /* End PBXVariantGroup section */ 328 | 329 | /* Begin XCBuildConfiguration section */ 330 | A43F3A0D1C074ABD0019A555 /* Debug */ = { 331 | isa = XCBuildConfiguration; 332 | buildSettings = { 333 | ALWAYS_SEARCH_USER_PATHS = NO; 334 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 335 | CLANG_CXX_LIBRARY = "libc++"; 336 | CLANG_ENABLE_MODULES = YES; 337 | CLANG_ENABLE_OBJC_ARC = YES; 338 | CLANG_WARN_BOOL_CONVERSION = YES; 339 | CLANG_WARN_CONSTANT_CONVERSION = YES; 340 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 341 | CLANG_WARN_EMPTY_BODY = YES; 342 | CLANG_WARN_ENUM_CONVERSION = YES; 343 | CLANG_WARN_INT_CONVERSION = YES; 344 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 345 | CLANG_WARN_UNREACHABLE_CODE = YES; 346 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 347 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 348 | COPY_PHASE_STRIP = NO; 349 | DEBUG_INFORMATION_FORMAT = dwarf; 350 | ENABLE_STRICT_OBJC_MSGSEND = YES; 351 | ENABLE_TESTABILITY = YES; 352 | GCC_C_LANGUAGE_STANDARD = gnu99; 353 | GCC_DYNAMIC_NO_PIC = NO; 354 | GCC_NO_COMMON_BLOCKS = YES; 355 | GCC_OPTIMIZATION_LEVEL = 0; 356 | GCC_PREPROCESSOR_DEFINITIONS = ( 357 | "DEBUG=1", 358 | "$(inherited)", 359 | ); 360 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 361 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 362 | GCC_WARN_UNDECLARED_SELECTOR = YES; 363 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 364 | GCC_WARN_UNUSED_FUNCTION = YES; 365 | GCC_WARN_UNUSED_VARIABLE = YES; 366 | IPHONEOS_DEPLOYMENT_TARGET = 9.1; 367 | MTL_ENABLE_DEBUG_INFO = YES; 368 | ONLY_ACTIVE_ARCH = YES; 369 | SDKROOT = iphoneos; 370 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 371 | TARGETED_DEVICE_FAMILY = "1,2"; 372 | }; 373 | name = Debug; 374 | }; 375 | A43F3A0E1C074ABD0019A555 /* Release */ = { 376 | isa = XCBuildConfiguration; 377 | buildSettings = { 378 | ALWAYS_SEARCH_USER_PATHS = NO; 379 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 380 | CLANG_CXX_LIBRARY = "libc++"; 381 | CLANG_ENABLE_MODULES = YES; 382 | CLANG_ENABLE_OBJC_ARC = YES; 383 | CLANG_WARN_BOOL_CONVERSION = YES; 384 | CLANG_WARN_CONSTANT_CONVERSION = YES; 385 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 386 | CLANG_WARN_EMPTY_BODY = YES; 387 | CLANG_WARN_ENUM_CONVERSION = YES; 388 | CLANG_WARN_INT_CONVERSION = YES; 389 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 390 | CLANG_WARN_UNREACHABLE_CODE = YES; 391 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 392 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 393 | COPY_PHASE_STRIP = NO; 394 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 395 | ENABLE_NS_ASSERTIONS = NO; 396 | ENABLE_STRICT_OBJC_MSGSEND = YES; 397 | GCC_C_LANGUAGE_STANDARD = gnu99; 398 | GCC_NO_COMMON_BLOCKS = YES; 399 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 400 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 401 | GCC_WARN_UNDECLARED_SELECTOR = YES; 402 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 403 | GCC_WARN_UNUSED_FUNCTION = YES; 404 | GCC_WARN_UNUSED_VARIABLE = YES; 405 | IPHONEOS_DEPLOYMENT_TARGET = 9.1; 406 | MTL_ENABLE_DEBUG_INFO = NO; 407 | SDKROOT = iphoneos; 408 | TARGETED_DEVICE_FAMILY = "1,2"; 409 | VALIDATE_PRODUCT = YES; 410 | }; 411 | name = Release; 412 | }; 413 | A43F3A101C074ABD0019A555 /* Debug */ = { 414 | isa = XCBuildConfiguration; 415 | buildSettings = { 416 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 417 | CODE_SIGN_IDENTITY = "iPhone Developer"; 418 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 419 | INFOPLIST_FILE = "$(SRCROOT)/mtTVPlayer/Info.plist"; 420 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 421 | PRODUCT_BUNDLE_IDENTIFIER = com.MartinStudio.MTTVplayer; 422 | PRODUCT_NAME = mtTVPlayer; 423 | PROVISIONING_PROFILE = ""; 424 | TARGETED_DEVICE_FAMILY = 2; 425 | }; 426 | name = Debug; 427 | }; 428 | A43F3A111C074ABD0019A555 /* Release */ = { 429 | isa = XCBuildConfiguration; 430 | buildSettings = { 431 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 432 | CODE_SIGN_IDENTITY = "iPhone Developer"; 433 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 434 | INFOPLIST_FILE = "$(SRCROOT)/mtTVPlayer/Info.plist"; 435 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 436 | PRODUCT_BUNDLE_IDENTIFIER = com.MartinStudio.MTTVplayer; 437 | PRODUCT_NAME = mtTVPlayer; 438 | PROVISIONING_PROFILE = ""; 439 | TARGETED_DEVICE_FAMILY = 2; 440 | }; 441 | name = Release; 442 | }; 443 | /* End XCBuildConfiguration section */ 444 | 445 | /* Begin XCConfigurationList section */ 446 | A43F39F81C074ABD0019A555 /* Build configuration list for PBXProject "mtTVPlayer" */ = { 447 | isa = XCConfigurationList; 448 | buildConfigurations = ( 449 | A43F3A0D1C074ABD0019A555 /* Debug */, 450 | A43F3A0E1C074ABD0019A555 /* Release */, 451 | ); 452 | defaultConfigurationIsVisible = 0; 453 | defaultConfigurationName = Release; 454 | }; 455 | A43F3A0F1C074ABD0019A555 /* Build configuration list for PBXNativeTarget "mtTVPlayer" */ = { 456 | isa = XCConfigurationList; 457 | buildConfigurations = ( 458 | A43F3A101C074ABD0019A555 /* Debug */, 459 | A43F3A111C074ABD0019A555 /* Release */, 460 | ); 461 | defaultConfigurationIsVisible = 0; 462 | defaultConfigurationName = Release; 463 | }; 464 | /* End XCConfigurationList section */ 465 | }; 466 | rootObject = A43F39F51C074ABD0019A555 /* Project object */; 467 | } 468 | -------------------------------------------------------------------------------- /mtTVPlayer.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /mtTVPlayer.xcodeproj/project.xcworkspace/xcshareddata/CoverFlowLayout.xcscmblueprint: -------------------------------------------------------------------------------- 1 | { 2 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "0FBFB078993A8E30684AD0F54DFEC7F60287D3DA", 3 | "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { 4 | 5 | }, 6 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : { 7 | "2ADE6DD5FE3F220904FC8623C0EDE339BC93A3D6" : 0, 8 | "0FBFB078993A8E30684AD0F54DFEC7F60287D3DA" : 0 9 | }, 10 | "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "B57E253C-1299-44D7-BD38-1AAC474763D2", 11 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { 12 | "2ADE6DD5FE3F220904FC8623C0EDE339BC93A3D6" : "", 13 | "0FBFB078993A8E30684AD0F54DFEC7F60287D3DA" : "CoverFlowLayout\/" 14 | }, 15 | "DVTSourceControlWorkspaceBlueprintNameKey" : "CoverFlowLayout", 16 | "DVTSourceControlWorkspaceBlueprintVersion" : 204, 17 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "CoverFlowLayout.xcodeproj", 18 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [ 19 | { 20 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/broccolii\/CoverFlowLayout.git", 21 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 22 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "0FBFB078993A8E30684AD0F54DFEC7F60287D3DA" 23 | }, 24 | { 25 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/broccolii\/LoadingView.git", 26 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 27 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "2ADE6DD5FE3F220904FC8623C0EDE339BC93A3D6" 28 | } 29 | ] 30 | } -------------------------------------------------------------------------------- /mtTVPlayer.xcodeproj/project.xcworkspace/xcuserdata/Broccoli.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinRGB/MTMusicPlayer/e263038c3743215cc94b1940a307ef541a537dce/mtTVPlayer.xcodeproj/project.xcworkspace/xcuserdata/Broccoli.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /mtTVPlayer.xcodeproj/project.xcworkspace/xcuserdata/MartinRGB.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinRGB/MTMusicPlayer/e263038c3743215cc94b1940a307ef541a537dce/mtTVPlayer.xcodeproj/project.xcworkspace/xcuserdata/MartinRGB.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /mtTVPlayer.xcodeproj/xcuserdata/Broccoli.xcuserdatad/xcschemes/CoverFlowLayout.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 | -------------------------------------------------------------------------------- /mtTVPlayer.xcodeproj/xcuserdata/Broccoli.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | CoverFlowLayout.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | A43F39FC1C074ABD0019A555 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /mtTVPlayer.xcodeproj/xcuserdata/MartinRGB.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /mtTVPlayer.xcodeproj/xcuserdata/MartinRGB.xcuserdatad/xcschemes/mtTVPlayer.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 | -------------------------------------------------------------------------------- /mtTVPlayer.xcodeproj/xcuserdata/MartinRGB.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | mtTVPlayer.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | A43F39FC1C074ABD0019A555 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /mtTVPlayer/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // CoverFlowLayout 4 | // 5 | // Created by Broccoli on 15/11/26. 6 | // Copyright © 2015年 Broccoli. 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: [NSObject: AnyObject]?) -> 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 | -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "83.5x83.5", 66 | "scale" : "2x" 67 | } 68 | ], 69 | "info" : { 70 | "version" : 1, 71 | "author" : "xcode" 72 | } 73 | } -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/Play.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "Play.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/Play.imageset/Play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinRGB/MTMusicPlayer/e263038c3743215cc94b1940a307ef541a537dce/mtTVPlayer/Assets.xcassets/Play.imageset/Play.png -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/Vinyl.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "Vinyl.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/Vinyl.imageset/Vinyl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinRGB/MTMusicPlayer/e263038c3743215cc94b1940a307ef541a537dce/mtTVPlayer/Assets.xcassets/Vinyl.imageset/Vinyl.png -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/album1.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "album1.jpg", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/album1.imageset/album1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinRGB/MTMusicPlayer/e263038c3743215cc94b1940a307ef541a537dce/mtTVPlayer/Assets.xcassets/album1.imageset/album1.jpg -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/album10.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "album10.jpg", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/album10.imageset/album10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinRGB/MTMusicPlayer/e263038c3743215cc94b1940a307ef541a537dce/mtTVPlayer/Assets.xcassets/album10.imageset/album10.jpg -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/album2.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "album2.jpg", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/album2.imageset/album2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinRGB/MTMusicPlayer/e263038c3743215cc94b1940a307ef541a537dce/mtTVPlayer/Assets.xcassets/album2.imageset/album2.jpg -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/album3.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "album3.jpg", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/album3.imageset/album3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinRGB/MTMusicPlayer/e263038c3743215cc94b1940a307ef541a537dce/mtTVPlayer/Assets.xcassets/album3.imageset/album3.jpg -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/album4.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "album4.jpg", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/album4.imageset/album4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinRGB/MTMusicPlayer/e263038c3743215cc94b1940a307ef541a537dce/mtTVPlayer/Assets.xcassets/album4.imageset/album4.jpg -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/album5.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "album5.jpg", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/album5.imageset/album5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinRGB/MTMusicPlayer/e263038c3743215cc94b1940a307ef541a537dce/mtTVPlayer/Assets.xcassets/album5.imageset/album5.jpg -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/album6.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "album6.jpg", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/album6.imageset/album6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinRGB/MTMusicPlayer/e263038c3743215cc94b1940a307ef541a537dce/mtTVPlayer/Assets.xcassets/album6.imageset/album6.jpg -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/album7.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "album7.jpg", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/album7.imageset/album7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinRGB/MTMusicPlayer/e263038c3743215cc94b1940a307ef541a537dce/mtTVPlayer/Assets.xcassets/album7.imageset/album7.jpg -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/album8.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "album8.jpg", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/album8.imageset/album8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinRGB/MTMusicPlayer/e263038c3743215cc94b1940a307ef541a537dce/mtTVPlayer/Assets.xcassets/album8.imageset/album8.jpg -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/album9.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "album9.jpg", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/album9.imageset/album9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinRGB/MTMusicPlayer/e263038c3743215cc94b1940a307ef541a537dce/mtTVPlayer/Assets.xcassets/album9.imageset/album9.jpg -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/max.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "max.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/max.imageset/max.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinRGB/MTMusicPlayer/e263038c3743215cc94b1940a307ef541a537dce/mtTVPlayer/Assets.xcassets/max.imageset/max.png -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/min.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "min.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/min.imageset/min.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinRGB/MTMusicPlayer/e263038c3743215cc94b1940a307ef541a537dce/mtTVPlayer/Assets.xcassets/min.imageset/min.png -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/pause.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "pause.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/pause.imageset/pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinRGB/MTMusicPlayer/e263038c3743215cc94b1940a307ef541a537dce/mtTVPlayer/Assets.xcassets/pause.imageset/pause.png -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/tvBG.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "tvBG.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /mtTVPlayer/Assets.xcassets/tvBG.imageset/tvBG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinRGB/MTMusicPlayer/e263038c3743215cc94b1940a307ef541a537dce/mtTVPlayer/Assets.xcassets/tvBG.imageset/tvBG.png -------------------------------------------------------------------------------- /mtTVPlayer/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 | 29 | -------------------------------------------------------------------------------- /mtTVPlayer/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /mtTVPlayer/Base.lproj/song1.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinRGB/MTMusicPlayer/e263038c3743215cc94b1940a307ef541a537dce/mtTVPlayer/Base.lproj/song1.mp3 -------------------------------------------------------------------------------- /mtTVPlayer/Base.lproj/song10.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinRGB/MTMusicPlayer/e263038c3743215cc94b1940a307ef541a537dce/mtTVPlayer/Base.lproj/song10.mp3 -------------------------------------------------------------------------------- /mtTVPlayer/Base.lproj/song2.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinRGB/MTMusicPlayer/e263038c3743215cc94b1940a307ef541a537dce/mtTVPlayer/Base.lproj/song2.mp3 -------------------------------------------------------------------------------- /mtTVPlayer/Base.lproj/song3.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinRGB/MTMusicPlayer/e263038c3743215cc94b1940a307ef541a537dce/mtTVPlayer/Base.lproj/song3.mp3 -------------------------------------------------------------------------------- /mtTVPlayer/Base.lproj/song4.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinRGB/MTMusicPlayer/e263038c3743215cc94b1940a307ef541a537dce/mtTVPlayer/Base.lproj/song4.mp3 -------------------------------------------------------------------------------- /mtTVPlayer/Base.lproj/song5.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinRGB/MTMusicPlayer/e263038c3743215cc94b1940a307ef541a537dce/mtTVPlayer/Base.lproj/song5.mp3 -------------------------------------------------------------------------------- /mtTVPlayer/Base.lproj/song6.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinRGB/MTMusicPlayer/e263038c3743215cc94b1940a307ef541a537dce/mtTVPlayer/Base.lproj/song6.mp3 -------------------------------------------------------------------------------- /mtTVPlayer/Base.lproj/song7.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinRGB/MTMusicPlayer/e263038c3743215cc94b1940a307ef541a537dce/mtTVPlayer/Base.lproj/song7.mp3 -------------------------------------------------------------------------------- /mtTVPlayer/Base.lproj/song8.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinRGB/MTMusicPlayer/e263038c3743215cc94b1940a307ef541a537dce/mtTVPlayer/Base.lproj/song8.mp3 -------------------------------------------------------------------------------- /mtTVPlayer/Base.lproj/song9.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinRGB/MTMusicPlayer/e263038c3743215cc94b1940a307ef541a537dce/mtTVPlayer/Base.lproj/song9.mp3 -------------------------------------------------------------------------------- /mtTVPlayer/CoverFlowLayout.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CoverFlowLayout.swift 3 | // CoverFlowLayout 4 | // 5 | // Created by Broccoli on 15/11/26. 6 | // Copyright © 2015年 Broccoli. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public var vinylMoveValue:CGFloat = 0.0 12 | 13 | class CoverFlowLayout: UICollectionViewFlowLayout { 14 | 15 | let kDistanceToProjectionPlane: CGFloat = 500.0 16 | var maxCoverDegree: CGFloat = 30.0 17 | var coverDensity: CGFloat = 0.25 18 | 19 | 20 | 21 | //当collection view的bounds改变时,布局需要告诉collection view是否需要重新计算布局。 22 | override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool { 23 | return true 24 | } 25 | 26 | //设置整体Attributes 27 | override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? { 28 | let indexPaths = indexPathsOfItemsInRect(rect) 29 | 30 | var resultingAttributes = [UICollectionViewLayoutAttributes]() 31 | 32 | for indexPath in indexPaths { 33 | //设置每个Cell的尺寸&位置 34 | let attributes = layoutAttributesForItemAtIndexPath(indexPath)! 35 | resultingAttributes.append(attributes) 36 | } 37 | 38 | 39 | 40 | return resultingAttributes 41 | } 42 | 43 | //设置每一个Cell的Attributes 44 | override func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? { 45 | let attributes = UICollectionViewLayoutAttributes(forCellWithIndexPath: indexPath) 46 | 47 | 48 | attributes.size = CGSizeMake(collectionView!.bounds.size.width*0.4225, collectionView!.bounds.size.width*0.293) 49 | attributes.center = CGPoint(x: collectionView!.bounds.size.width * CGFloat(indexPath.row) + collectionView!.bounds.size.width, y: collectionView!.bounds.size.height*0.435) 50 | //设置间距信息 51 | interpolateAttributes(attributes, forOffset: collectionView!.contentOffset.x) 52 | 53 | return attributes 54 | } 55 | 56 | override func collectionViewContentSize() -> CGSize { 57 | return CGSize(width: collectionView!.bounds.width * CGFloat(collectionView!.numberOfItemsInSection(0)), height: collectionView!.bounds.height) 58 | } 59 | } 60 | 61 | 62 | // MARK: - private method 63 | private extension CoverFlowLayout { 64 | 65 | //根据Cell的Invisible来获取IndexPath 66 | func indexPathsOfItemsInRect(rect: CGRect) -> [NSIndexPath] { 67 | if collectionView!.numberOfItemsInSection(0) == 0 { 68 | return [NSIndexPath]() 69 | } 70 | //下一个max与上一个min 71 | var minRow: Int = max(Int(rect.origin.x / collectionView!.bounds.width), 0) 72 | var maxRow: Int = Int(CGRectGetMaxX(rect) / collectionView!.bounds.width) 73 | 74 | 75 | 76 | let candidateMinRow = max(minRow - 1, 0) 77 | if maxXForRow(candidateMinRow) >= rect.origin.x { 78 | minRow = candidateMinRow 79 | } 80 | 81 | let candidateMaxRow = min(maxRow + 1, collectionView!.numberOfItemsInSection(0) - 1) 82 | if minXForRow(candidateMaxRow) <= CGRectGetMaxX(rect) { 83 | maxRow = candidateMaxRow 84 | } 85 | 86 | var resultingInexPaths = [NSIndexPath]() 87 | 88 | for i in Int(minRow) ..< Int(maxRow) + 1 { 89 | resultingInexPaths.append(NSIndexPath(forRow: i, inSection: 0)) 90 | } 91 | 92 | return resultingInexPaths 93 | } 94 | 95 | func minXForRow(row: Int) -> CGFloat { 96 | return itemCenterForRow(row - 1).x + (1 / 2 - coverDensity) * itemSize.width 97 | } 98 | 99 | func maxXForRow(row: Int) -> CGFloat { 100 | return itemCenterForRow(row + 1).x - (1 / 2 - coverDensity) * itemSize.width 101 | } 102 | 103 | func minXCenterForRow(row: Int) -> CGFloat { 104 | let halfWidth = itemSize.width / 2 105 | let maxRads = maxCoverDegree * CGFloat(M_PI) / 180 106 | let center = itemCenterForRow(row - 1).x 107 | let prevItemRightEdge = center + halfWidth 108 | let projectedLeftEdgeLocal = halfWidth * cos(maxRads) * kDistanceToProjectionPlane / (kDistanceToProjectionPlane + halfWidth * sin(maxRads)) 109 | return prevItemRightEdge - coverDensity * itemSize.width + projectedLeftEdgeLocal 110 | } 111 | 112 | func maxXCenterForRow(row: Int) -> CGFloat { 113 | let halfWidth = itemSize.width / 2 114 | let maxRads = maxCoverDegree * CGFloat(M_PI) / 180 115 | let center = itemCenterForRow(row + 1).x 116 | let nextItemLeftEdge = center - halfWidth 117 | let projectedRightEdgeLocal = fabs(halfWidth * cos(maxRads) * kDistanceToProjectionPlane / (-halfWidth * sin(maxRads) - kDistanceToProjectionPlane)) 118 | return nextItemLeftEdge + coverDensity * itemSize.width - projectedRightEdgeLocal 119 | } 120 | 121 | func itemCenterForRow(row: Int) -> CGPoint { 122 | let collectionViewSize = collectionView!.bounds.size 123 | return CGPoint(x: CGFloat(row) * collectionViewSize.width + collectionViewSize.width / 2, y: collectionViewSize.height / 2) 124 | } 125 | 126 | 127 | 128 | 129 | //间距设置 130 | func interpolateAttributes(attributes: UICollectionViewLayoutAttributes, forOffset offset: CGFloat) { 131 | let attributesPath = attributes.indexPath 132 | 133 | //间距 134 | let minInterval = CGFloat(Double(attributesPath.row - 1) - 0.5) * collectionView!.bounds.width 135 | let maxInterval = CGFloat(Double(attributesPath.row + 1) + 0.5) * collectionView!.bounds.width 136 | 137 | let minX = minXCenterForRow(attributesPath.row) 138 | let maxX = maxXCenterForRow(attributesPath.row) 139 | 140 | let interpolatedX = min(max(minX + (((maxX - minX) / (maxInterval - minInterval)) * (offset - minInterval)), minX), maxX) 141 | 142 | //MARK: CollectionView XY Position 143 | attributes.center = CGPoint(x: interpolatedX, y: attributes.center.y) 144 | 145 | //Rotation Part 146 | let angle = -maxCoverDegree + (interpolatedX - minX) * 2 * maxCoverDegree / (maxX - minX) 147 | //print(angle) 148 | attributes.transform3D = CATransform3DMakeScale((100-abs(angle)*2)/100, (100-abs(angle)*2)/100, (100-abs(angle)*2)/100) 149 | attributes.alpha = (60 - abs(angle)*2)/20 150 | 151 | vinylMoveValue = 0.1635 - abs(angle) * 0.007325 152 | 153 | 154 | 155 | } 156 | 157 | } 158 | -------------------------------------------------------------------------------- /mtTVPlayer/DIN-Bold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinRGB/MTMusicPlayer/e263038c3743215cc94b1940a307ef541a537dce/mtTVPlayer/DIN-Bold.otf -------------------------------------------------------------------------------- /mtTVPlayer/DIN-BoldItalic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinRGB/MTMusicPlayer/e263038c3743215cc94b1940a307ef541a537dce/mtTVPlayer/DIN-BoldItalic.otf -------------------------------------------------------------------------------- /mtTVPlayer/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 | UIAppFonts 26 | 27 | DIN-BoldItalic.otf 28 | DIN-Bold.otf 29 | 30 | UILaunchStoryboardName 31 | LaunchScreen 32 | UIMainStoryboardFile 33 | Main 34 | UIRequiredDeviceCapabilities 35 | 36 | armv7 37 | 38 | UISupportedInterfaceOrientations 39 | 40 | UIInterfaceOrientationLandscapeLeft 41 | UIInterfaceOrientationLandscapeRight 42 | 43 | UISupportedInterfaceOrientations~ipad 44 | 45 | UIInterfaceOrientationLandscapeLeft 46 | UIInterfaceOrientationLandscapeRight 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /mtTVPlayer/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // 4 | // Created by MartinRGB on 15/12/02. 5 | // Copyright © 2015年 Broccoli. All rights reserved. 6 | // 7 | 8 | import UIKit 9 | import AVFoundation 10 | 11 | //MARK:DATA 12 | 13 | struct AlbumModel { 14 | let title:String 15 | let image:UIImage! 16 | let songurl:NSURL! 17 | 18 | } 19 | 20 | let albumData = [ 21 | AlbumModel(title:"LEFT TO OUR OWN DEVICES",image:UIImage(named:"album1"),songurl:NSBundle.mainBundle().URLForResource("song6", withExtension: "mp3")!), 22 | AlbumModel(title:"ANDREW MCMAHON IN THE WILDERNESS",image:UIImage(named:"album2"),songurl:NSBundle.mainBundle().URLForResource("song7", withExtension: "mp3")!), 23 | AlbumModel(title:"CONTRAST",image:UIImage(named:"album3"),songurl:NSBundle.mainBundle().URLForResource("song6", withExtension: "mp3")!), 24 | AlbumModel(title:"GLASS BOYS",image:UIImage(named:"album4"),songurl:NSBundle.mainBundle().URLForResource("song7", withExtension: "mp3")!), 25 | AlbumModel(title:"HOW TO RUN AWAY",image:UIImage(named:"album5"),songurl:NSBundle.mainBundle().URLForResource("song6", withExtension: "mp3")!), 26 | AlbumModel(title:"LA BRONZE",image:UIImage(named:"album6"),songurl:NSBundle.mainBundle().URLForResource("song7", withExtension: "mp3")!), 27 | AlbumModel(title:"PEOPLE UNDER THE STAIRS",image:UIImage(named:"album7"),songurl:NSBundle.mainBundle().URLForResource("song6", withExtension: "mp3")!), 28 | AlbumModel(title:"POEMSS",image:UIImage(named:"album8"),songurl:NSBundle.mainBundle().URLForResource("song7", withExtension: "mp3")!), 29 | AlbumModel(title:"SWIM TEAM",image:UIImage(named:"album9"),songurl:NSBundle.mainBundle().URLForResource("song6", withExtension: "mp3")!), 30 | AlbumModel(title:"THE PAINS OF BEING PURE AT HEART",image:UIImage(named:"album10"),songurl:NSBundle.mainBundle().URLForResource("song7", withExtension: "mp3")!) 31 | ] 32 | 33 | //MARK:Controller 34 | class ViewController: UICollectionViewController { 35 | 36 | private var scrollIndex:Int = 0 37 | private let atitleView:UIView = UIView() 38 | private let atitleLabel:UILabel = UILabel() 39 | private let atitleLabel2:UILabel = UILabel() 40 | private let CellIdentifier = "CollectionCell" 41 | private let AVView:UIView = UIView() 42 | private var player:AVPlayer! = AVPlayer() 43 | private var playerLayer:AVPlayerLayer! = AVPlayerLayer() 44 | private var playerImageView:UIImageView! = UIImageView() 45 | private var vinylView:UIView! = UIView() 46 | private var vinylView2:UIView! = UIView() 47 | private var vinylImageView:UIImageView! = UIImageView() 48 | private var vinylImageView2:UIImageView! = UIImageView() 49 | private var scrollViewBeforeScroll:CGFloat = 0 50 | 51 | private var timeMaker1:UILabel! = UILabel() 52 | 53 | private var playPauseImageView:UIImageView! = UIImageView() 54 | private let tapRec:UITapGestureRecognizer = UITapGestureRecognizer() 55 | 56 | private var secondObserver: AnyObject! 57 | private var durationObserver:AnyObject! 58 | private var sliderObserver:AnyObject! 59 | 60 | private var secondMinute:String! = "00" 61 | private var secondSecond:String! = "00" 62 | private var totalMinute:String! = "03" 63 | private var totalSecond:String! = "11" 64 | private var totalValue:Double = 191.0 65 | private var secondValue:Double! = 0.0 66 | 67 | private let customSlider:UISlider! = UISlider() 68 | private var sliderNowValue:Float = 0.0 69 | private var sliderIsDragging = false; 70 | 71 | //MARK:ViewDidLoad 72 | 73 | override func viewDidLoad() { 74 | super.viewDidLoad() 75 | 76 | let bgImageView = UIImageView(frame: CGRectMake(0,0,self.view.bounds.width,self.view.bounds.height)) 77 | self.view.insertSubview(bgImageView, belowSubview: collectionView!) 78 | bgImageView.image = UIImage(named: "tvBG") 79 | self.collectionView!.backgroundColor = UIColor.clearColor() 80 | 81 | addTitleLabel() 82 | addAlbumTitleLabel() 83 | addAV() 84 | addVinyl() 85 | updateTimetoTimeMarker() 86 | } 87 | 88 | //MARK:初始化与布局调整 89 | 90 | //MARK:Landscape 91 | override func shouldAutorotate() -> Bool { 92 | return true 93 | } 94 | 95 | 96 | override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask { 97 | return [UIInterfaceOrientationMask.LandscapeLeft,UIInterfaceOrientationMask.LandscapeRight] 98 | } 99 | 100 | //MARK:Top Title 101 | private func addTitleLabel() { 102 | let titleLabel = UILabel(frame: CGRectMake(self.view.bounds.width/2-widthfortitle().width/2,self.view.bounds.height * 0.111,widthfortitle().width,widthfortitle().height)) 103 | titleLabel.text = "MY MUSIC" 104 | titleLabel.font = UIFont(name: "DIN-Bold", size: 24) 105 | titleLabel.textColor = UIColor.blackColor() 106 | titleLabel.textAlignment = NSTextAlignment.Center 107 | titleLabel.alpha = 0.5 108 | self.view.addSubview(titleLabel) 109 | } 110 | 111 | private func widthfortitle() -> CGSize { 112 | let titleString = NSMutableAttributedString( 113 | string:"My MUSIC", 114 | attributes: [NSFontAttributeName:UIFont( 115 | name: "DIN-Bold", 116 | size: 26)!]) 117 | 118 | return titleString.size() 119 | 120 | } 121 | 122 | //MARK:Title Label:Add the title Label & 滑动效果的开始效果 123 | func addAlbumTitleLabel(){ 124 | self.view.addSubview(atitleView) 125 | atitleView.backgroundColor = UIColor(red: 252/255, green: 212/255, blue: 24/255, alpha: 1.0) 126 | atitleView.frame = CGRectMake(self.view.bounds.width/2 - (self.sizeForLabel(self.scrollIndex).width + 40)/2,self.view.bounds.height * 0.592,self.sizeForLabel(self.scrollIndex).width + 40,self.view.bounds.size.width * 0.293/5) 127 | 128 | atitleLabel.frame = CGRectMake(self.atitleView.frame.size.width/2 - self.sizeForLabel(self.scrollIndex).width/2,self.atitleView.frame.size.height/2 - self.sizeForLabel(self.scrollIndex).height/2,self.sizeForLabel(self.scrollIndex).width,self.sizeForLabel(self.scrollIndex).height) 129 | 130 | atitleLabel.text = albumData[self.scrollIndex].title 131 | atitleLabel.font = UIFont(name: "DIN-Bold", size: 24) 132 | atitleLabel.textColor = UIColor.blackColor() 133 | atitleLabel.textAlignment = NSTextAlignment.Center 134 | 135 | atitleLabel2.frame = CGRectMake((self.atitleView.frame.size.width/2 - self.sizeForLabel(self.scrollIndex+1).width/2) + self.view.bounds.width/3 ,(self.atitleView.frame.size.height/2 - self.sizeForLabel(self.scrollIndex+1).height/2) - self.view.bounds.height/3,self.sizeForLabel(self.scrollIndex+1).width,self.sizeForLabel(self.scrollIndex+1).height) 136 | 137 | atitleLabel2.text = albumData[self.scrollIndex+1].title 138 | atitleLabel2.font = UIFont(name: "DIN-Bold", size: 24) 139 | atitleLabel2.textColor = UIColor.blackColor() 140 | atitleLabel2.textAlignment = NSTextAlignment.Center 141 | 142 | atitleView.addSubview(atitleLabel) 143 | atitleView.addSubview(atitleLabel2) 144 | atitleView.clipsToBounds = true 145 | } 146 | 147 | //MARK:Title Label:Calcuate the size of text 148 | func sizeForLabel(indexNumber:Int) -> CGSize 149 | { 150 | let labelString = NSMutableAttributedString( 151 | string: albumData[indexNumber].title, 152 | attributes: [NSFontAttributeName:UIFont( 153 | name: "DIN-Bold", 154 | size: 24)!]) 155 | 156 | return labelString.size() 157 | } 158 | 159 | //MARK:Vinyl 160 | func addVinyl(){ 161 | //add the vinyl 162 | vinylImageView.image = UIImage(named: "Vinyl") 163 | vinylImageView2.image = UIImage(named: "Vinyl") 164 | vinylView.addSubview(vinylImageView) 165 | vinylView2.addSubview(vinylImageView2) 166 | 167 | 168 | self.view.insertSubview(vinylView, belowSubview: collectionView!) 169 | self.view.insertSubview(vinylView2, belowSubview: collectionView!) 170 | 171 | vinylView.frame = CGRectMake(collectionView!.bounds.size.width * 0.3935 + 60, collectionView!.bounds.size.width * (0.197), collectionView!.bounds.size.width*0.259 , collectionView!.bounds.size.width*0.259) 172 | vinylImageView.frame = CGRectMake(0, 0, vinylView.frame.size.width, vinylView.frame.size.height) 173 | vinylView.transform = CGAffineTransformMakeScale(1 , 1 ) 174 | 175 | vinylView2.frame = CGRectMake(collectionView!.bounds.size.width * (0.7215) + 60 , collectionView!.bounds.size.width * (0.197), collectionView!.bounds.size.width*0.259 , collectionView!.bounds.size.width*0.259) 176 | vinylImageView2.frame = CGRectMake(0, 0, vinylView2.frame.size.width, vinylView2.frame.size.height) 177 | vinylView2.transform = CGAffineTransformMakeScale(0.6, 0.6) 178 | 179 | } 180 | 181 | //MARK:AVPlayer AVView 182 | func addAV(){ 183 | 184 | //add AVView 185 | AVView.frame = CGRectMake(0, self.view.bounds.height * 0.852, self.view.bounds.width, self.view.bounds.height*0.148) 186 | AVView.backgroundColor = UIColor.clearColor() 187 | self.view.addSubview(AVView) 188 | 189 | 190 | 191 | //add bottom Left Image 192 | playerImageView.frame = CGRectMake(0, self.view.bounds.height * 0.836, self.view.bounds.height * 0.164, self.view.bounds.height * 0.164) 193 | playerImageView.image = albumData[scrollIndex].image 194 | self.view.addSubview(playerImageView) 195 | 196 | let playerImageBackgroundView = UIView() 197 | playerImageBackgroundView.frame = CGRectMake(0, self.view.bounds.height * 0.836, self.view.bounds.height * 0.164, self.view.bounds.height * 0.164) 198 | playerImageBackgroundView.backgroundColor = UIColor.blackColor() 199 | playerImageBackgroundView.alpha = 0.7 200 | self.view.addSubview(playerImageBackgroundView) 201 | 202 | //Play & Pause Button 203 | let containerViewForPP = UIView() 204 | containerViewForPP.frame = CGRectMake(self.view.bounds.height * (0.164-0.049)/2,self.view.bounds.height * ((0.164-0.054)/2 + 0.838),self.view.bounds.height * 0.049,self.view.bounds.height * 0.054) 205 | 206 | self.view.addSubview(containerViewForPP) 207 | 208 | 209 | 210 | playPauseImageView.frame = CGRectMake(0,0,self.view.bounds.height * 0.049,self.view.bounds.height * 0.054) 211 | playPauseImageView.image = UIImage(named: "pause") 212 | 213 | 214 | containerViewForPP.addSubview(playPauseImageView) 215 | containerViewForPP.addGestureRecognizer(tapRec) 216 | tapRec.addTarget(self, action: Selector("tappedPP:")) 217 | 218 | //Add the timemarker Label 219 | timeMaker1.frame = CGRectMake(self.view.bounds.width * 0.834 , self.view.bounds.height * 0.9, self.view.bounds.height * 0.194, self.view.bounds.height * 0.056) 220 | self.timerWatch() 221 | 222 | 223 | timeMaker1.font = UIFont(name: "DIN-Bold", size: 24) 224 | timeMaker1.textColor = UIColor.blackColor() 225 | timeMaker1.textAlignment = NSTextAlignment.Center 226 | 227 | self.view.addSubview(timeMaker1) 228 | 229 | //Add Slider 230 | customSlider.frame = CGRectMake(self.view.bounds.height * 0.194, self.view.bounds.height * 0.888, self.view.bounds.height * 0.9, self.view.bounds.height * 0.083) 231 | customSlider.backgroundColor = UIColor.clearColor() 232 | customSlider.setMaximumTrackImage(UIImage(named: "min"), forState: .Normal) 233 | customSlider.setMinimumTrackImage(UIImage(named: "max"), forState: .Normal) 234 | 235 | customSlider.addTarget(self, action: "sliderValueDidChange:", forControlEvents: .ValueChanged) 236 | customSlider.addTarget(self, action: "sliderTouchDragEnter:", forControlEvents: .TouchDown) 237 | customSlider.addTarget(self, action: "sliderTouchDragExit:", forControlEvents: .TouchUpInside) 238 | customSlider.addTarget(self, action: "sliderTouchDragExit:", forControlEvents: .TouchUpOutside) 239 | customSlider.addTarget(self, action: "sliderTouchDragExit:", forControlEvents: .TouchCancel) 240 | 241 | self.view.addSubview(customSlider) 242 | 243 | 244 | //Add End Observer 245 | NSNotificationCenter.defaultCenter().addObserver(self, 246 | selector: "playerItemDidReachEnd:", 247 | name: AVPlayerItemDidPlayToEndTimeNotification, 248 | object:nil) 249 | 250 | //Add AVPlayer 251 | do{ 252 | playItemAtUrl(albumData[self.scrollIndex].songurl) 253 | player.pause() 254 | playPauseImageView.image = UIImage(named: "Play") 255 | 256 | try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback) 257 | try AVAudioSession.sharedInstance().setActive(true) 258 | }catch { 259 | print("Error getting the audio file") 260 | } 261 | 262 | 263 | 264 | } 265 | 266 | 267 | 268 | //MARK:AVPlayer AVPlayerLayer 269 | func playItemAtUrl(url: NSURL) { 270 | 271 | player = AVPlayer(URL: url) 272 | playerLayer = AVPlayerLayer(player: player) 273 | player.currentItem?.canPlayReverse 274 | player.currentItem?.canPlayFastReverse 275 | player.currentItem?.canPlayFastForward 276 | playerLayer.backgroundColor = UIColor.redColor().CGColor 277 | playerLayer.frame = AVView.frame 278 | AVView.layer.addSublayer(playerLayer) 279 | 280 | } 281 | 282 | //MARK:AVPlayer PlayReachEnd Notification 283 | func playerItemDidReachEnd(notif: NSNotification) { 284 | 285 | print("playerItemDidReachEnd") 286 | 287 | } 288 | 289 | //MARK:CollectionView DataSource 290 | override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 291 | return 10 292 | } 293 | 294 | override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { 295 | 296 | let cell = collectionView.dequeueReusableCellWithReuseIdentifier(CellIdentifier, forIndexPath: indexPath) 297 | cell.backgroundColor = UIColor.clearColor() 298 | cell.layer.allowsEdgeAntialiasing = true 299 | 300 | 301 | 302 | let cellImageView = UIImageView(frame: CGRectMake(0, 0, collectionView.bounds.size.width*0.293, collectionView.bounds.size.width*0.293)) 303 | cellImageView.image = albumData[indexPath.item].image 304 | cell.contentView.addSubview(cellImageView) 305 | 306 | 307 | 308 | return cell 309 | } 310 | 311 | //MARK:CollectionView Delegate 312 | override func scrollViewDidEndDecelerating(scrollView: UIScrollView) { 313 | 314 | scrollIndex = 0 + Int(collectionView!.contentOffset.x/self.view.bounds.width) 315 | 316 | self.playerImageView.image = albumData[self.scrollIndex].image 317 | 318 | //Player Control Part 319 | player.pause() 320 | playPauseImageView.image = UIImage(named: "pause") 321 | playItemAtUrl(albumData[self.scrollIndex].songurl) 322 | player.play() 323 | updateTimetoTimeMarker() 324 | 325 | //获得清零计数累加 326 | scrollViewBeforeScroll = (collectionView?.contentOffset.x)! 327 | //解决连续滑动bug 328 | scrollView.userInteractionEnabled = true 329 | 330 | sliderNowValue = 0 331 | 332 | } 333 | 334 | //MARK:CollectionView Delegate 335 | override func scrollViewDidScroll(scrollView: UIScrollView) { 336 | 337 | self.view.insertSubview(vinylView, belowSubview: collectionView!) 338 | self.view.insertSubview(vinylView2, belowSubview: collectionView!) 339 | 340 | //到头后,去掉一张盘,防止露馅 341 | if scrollView.contentOffset.x >= 9216{ 342 | vinylView.removeFromSuperview() 343 | } 344 | 345 | if scrollView.contentOffset.x <= 0{ 346 | vinylView2.removeFromSuperview() 347 | } 348 | 349 | let scrollProgress = (scrollView.contentOffset.x - scrollViewBeforeScroll)/self.view.bounds.width 350 | 351 | //范围 352 | if(scrollView.contentOffset.x > 0 && scrollView.contentOffset.x < 9216){ 353 | //左滑 354 | if (scrollProgress > 0){ 355 | //Vinyl Progress动画 356 | vinylView2.transform = CGAffineTransformMakeScale(0.6, 0.6) 357 | vinylView.transform = CGAffineTransformMakeScale(1, 1) 358 | 359 | vinylView.frame = CGRectMake(collectionView!.bounds.size.width * (0.3955 - (0.57 * scrollProgress)) + 60, collectionView!.bounds.size.width * 0.197 , collectionView!.bounds.size.width*0.259 , collectionView!.bounds.size.width*0.259) 360 | vinylImageView.frame = CGRectMake(0, 0, vinylView.frame.size.width, vinylView.frame.size.height) 361 | vinylView.transform = CGAffineTransformMakeScale(1 - 0.4 * scrollProgress, 1 - 0.4 * scrollProgress) 362 | 363 | vinylView2.frame = CGRectMake(collectionView!.bounds.size.width * (0.7715 - (0.290 * scrollProgress)) + 60, collectionView!.bounds.size.width * (0.25 + 0.035 * scrollProgress), collectionView!.bounds.size.width*0.259 , collectionView!.bounds.size.width*0.259) 364 | vinylImageView2.frame = CGRectMake(0, 0, vinylView2.frame.size.width, vinylView2.frame.size.height) 365 | vinylView2.transform = CGAffineTransformMakeScale(0.6 + 0.4 * scrollProgress, 0.6 + 0.4 * scrollProgress) 366 | 367 | //黄色LabelProgress动画 368 | let atitleVieworiginx = self.view.bounds.width/2 - (self.sizeForLabel(self.scrollIndex).width + 40)/2 369 | let atitleVieworiginw = self.sizeForLabel(self.scrollIndex).width + 40 370 | let atitleViewchangedx = (self.sizeForLabel(self.scrollIndex).width + 40)/2 - (self.sizeForLabel(self.scrollIndex + 1).width + 40)/2 371 | let atitleViewchangedw = self.sizeForLabel(self.scrollIndex).width - self.sizeForLabel(self.scrollIndex + 1).width 372 | 373 | self.atitleView.frame = CGRectMake(atitleVieworiginx + scrollProgress * atitleViewchangedx,self.view.bounds.height * 0.592,atitleVieworiginw - atitleViewchangedw * scrollProgress,self.view.bounds.size.width * 0.293/5) 374 | 375 | //文本LabelProgress动画 376 | atitleLabel.frame = CGRectMake((self.atitleView.frame.size.width/2 - self.sizeForLabel(self.scrollIndex).width/2) - self.view.bounds.width/3 * scrollProgress,(self.atitleView.frame.size.height/2 - self.sizeForLabel(self.scrollIndex).height/2) + self.view.bounds.height/3 * -scrollProgress ,self.sizeForLabel(self.scrollIndex).width,self.sizeForLabel(self.scrollIndex).height) 377 | atitleLabel.text = albumData[self.scrollIndex].title 378 | atitleLabel.alpha = 1 - 4 * scrollProgress 379 | 380 | atitleLabel2.frame = CGRectMake((self.atitleView.frame.size.width/2 - self.sizeForLabel(self.scrollIndex+1).width/2) + self.view.bounds.width/3 * (1-scrollProgress) ,(self.atitleView.frame.size.height/2 - self.sizeForLabel(self.scrollIndex+1).height/2) - self.view.bounds.height/3 * (1-scrollProgress),self.sizeForLabel(self.scrollIndex+1).width,self.sizeForLabel(self.scrollIndex+1).height) 381 | atitleLabel2.text = albumData[self.scrollIndex+1].title 382 | atitleLabel2.alpha = scrollProgress*10 - 9 383 | 384 | 385 | 386 | scrollView.userInteractionEnabled = false 387 | } 388 | //右滑 389 | else{ 390 | //Vinyl Progress动画 391 | vinylView2.transform = CGAffineTransformMakeScale(0.6, 0.6) 392 | vinylView.transform = CGAffineTransformMakeScale(1, 1) 393 | 394 | vinylView.frame = CGRectMake(collectionView!.bounds.size.width * ( -0.1765 - (0.57 * scrollProgress)) + 60, collectionView!.bounds.size.width * 0.197, collectionView!.bounds.size.width*0.259 , collectionView!.bounds.size.width*0.259) 395 | vinylImageView.frame = CGRectMake(0, 0, vinylView.frame.size.width, vinylView.frame.size.height) 396 | vinylView.transform = CGAffineTransformMakeScale(0.6 - 0.4 * scrollProgress, 0.6 - 0.4 * scrollProgress) 397 | 398 | vinylView2.frame = CGRectMake(collectionView!.bounds.size.width * (0.4815 - (0.290 * scrollProgress)) + 60 , collectionView!.bounds.size.width * (0.285 + 0.035 * scrollProgress), collectionView!.bounds.size.width*0.259 , collectionView!.bounds.size.width*0.259) 399 | vinylImageView2.frame = CGRectMake(0, 0, vinylView2.frame.size.width, vinylView2.frame.size.height) 400 | vinylView2.transform = CGAffineTransformMakeScale(1 + 0.4 * scrollProgress, 1 + 0.4 * scrollProgress) 401 | 402 | //黄色LabelProgress动画 403 | 404 | 405 | let atitleVieworiginx = self.view.bounds.width/2 - (self.sizeForLabel(self.scrollIndex).width + 40)/2 406 | let atitleVieworiginw = self.sizeForLabel(self.scrollIndex).width + 40 407 | let atitleViewchangedx = (self.sizeForLabel(self.scrollIndex).width + 40)/2 - (self.sizeForLabel(self.scrollIndex - 1).width + 40)/2 408 | let atitleViewchangedw = self.sizeForLabel(self.scrollIndex).width - self.sizeForLabel(self.scrollIndex - 1).width 409 | 410 | self.atitleView.frame = CGRectMake(atitleVieworiginx - scrollProgress * atitleViewchangedx,self.view.bounds.height * 0.592,atitleVieworiginw + atitleViewchangedw * scrollProgress,self.view.bounds.size.width * 0.293/5) 411 | 412 | //文本LabelProgress动画 413 | atitleLabel.frame = CGRectMake((self.atitleView.frame.size.width/2 - self.sizeForLabel(self.scrollIndex - 1).width/2) + self.view.bounds.width/3 * (-1 - scrollProgress),(self.atitleView.frame.size.height/2 - self.sizeForLabel(self.scrollIndex - 1).height/2) + self.view.bounds.height/3 * (-1 - scrollProgress) ,self.sizeForLabel(self.scrollIndex - 1).width,self.sizeForLabel(self.scrollIndex - 1).height) 414 | atitleLabel.text = albumData[self.scrollIndex - 1].title 415 | atitleLabel.alpha = -scrollProgress*10 - 9 416 | 417 | atitleLabel2.frame = CGRectMake((self.atitleView.frame.size.width/2 - self.sizeForLabel(self.scrollIndex).width/2) - self.view.bounds.width/3 * (scrollProgress) ,(self.atitleView.frame.size.height/2 - self.sizeForLabel(self.scrollIndex).height/2) + self.view.bounds.height/3 * (scrollProgress),self.sizeForLabel(self.scrollIndex).width,self.sizeForLabel(self.scrollIndex).height) 418 | atitleLabel2.text = albumData[self.scrollIndex].title 419 | atitleLabel2.alpha = 1 + scrollProgress * 4 420 | 421 | 422 | scrollView.userInteractionEnabled = false 423 | 424 | } 425 | 426 | } 427 | 428 | } 429 | 430 | 431 | //MARK:***AVPlayer 间隔观察 432 | func updateTimetoTimeMarker(){ 433 | 434 | //右下角当前时间 & 滑块观察 435 | secondObserver = player.addPeriodicTimeObserverForInterval(CMTimeMake(60,60), queue: nil) { (time:CMTime) -> Void in 436 | 437 | 438 | let asset = AVURLAsset(URL: albumData[self.scrollIndex].songurl) 439 | let audioDuration = asset.duration 440 | let audioDurationSeconds = CMTimeGetSeconds(audioDuration) 441 | let value2 = Double(audioDurationSeconds) 442 | 443 | //let nowtime = self.player.currentTime() 444 | 445 | if self.sliderNowValue == 0{ 446 | 447 | if self.sliderIsDragging == false{ 448 | 449 | let floatnowtime = Float(CMTimeGetSeconds(self.player.currentTime())) 450 | let floatalltime = Float(CMTimeGetSeconds(audioDuration)) 451 | let slidershouldbe = floatnowtime / floatalltime; 452 | 453 | self.secondValue = Double(slidershouldbe) * value2 454 | self.customSlider.value = slidershouldbe 455 | //// 可以解开注释看看效果 456 | // UIView.animateWithDuration(1, delay: 0, options: UIViewAnimationOptions.CurveLinear, animations: { 457 | // 458 | // () -> Void in 459 | // 460 | // self.customSlider.setValue(slidershouldbe, animated: true) 461 | // }, completion: { (finished) -> Void in 462 | // }) 463 | } 464 | } 465 | 466 | self.timerWatch() 467 | 468 | } 469 | 470 | //总时间 471 | durationObserver = player.addPeriodicTimeObserverForInterval(CMTimeMake(60,60), queue: nil) { (time:CMTime) -> Void in 472 | 473 | //print(self.player.currentItem?.duration.value) 474 | 475 | let asset = AVURLAsset(URL: albumData[self.scrollIndex].songurl) 476 | let audioDuration = asset.duration 477 | let audioDurationSeconds = CMTimeGetSeconds(audioDuration) 478 | 479 | self.totalValue = Double(audioDurationSeconds) 480 | self.player.removeTimeObserver(self.durationObserver) 481 | } 482 | 483 | } 484 | 485 | //MARK:AVPlayer 秒表 486 | func timerWatch(){ 487 | 488 | if secondValue < 0{ 489 | secondValue = 0 490 | } 491 | 492 | 493 | if Int(floor(self.secondValue - 60 * floor(self.secondValue/60))) < 10{ 494 | secondSecond = String("0\(Int(floor(self.secondValue - 60 * floor(self.secondValue/60))))") 495 | } 496 | else{ 497 | secondSecond = String(Int(floor(self.secondValue - 60 * floor(self.secondValue/60)))) 498 | } 499 | 500 | secondMinute = String(Int(floor(self.secondValue/60))) 501 | 502 | if Int(floor(self.totalValue - 60 * floor(self.totalValue/60))) < 10{ 503 | totalSecond = String("0\(Int(floor(self.totalValue - 60 * floor(self.totalValue/60))))") 504 | } 505 | else{ 506 | totalSecond = String(Int(floor(self.totalValue - 60 * floor(self.totalValue/60)))) 507 | } 508 | 509 | totalMinute = String(Int(floor(self.totalValue/60))) 510 | 511 | self.timeMaker1.text = "0\(secondMinute):\(secondSecond)/0\(totalMinute):\(totalSecond)" 512 | } 513 | 514 | //MARK:AVPlaye Play Pause Btn Action 515 | func tappedPP(sender:UITapGestureRecognizer){ 516 | if player.rate == 1.0 { 517 | player.pause() 518 | playPauseImageView.image = UIImage(named: "Play") 519 | } 520 | else{ 521 | player.play() 522 | playPauseImageView.image = UIImage(named: "pause") 523 | } 524 | } 525 | 526 | //MARK:AVPlaye Slider Action 527 | func sliderValueDidChange(sender:UISlider!) 528 | { 529 | 530 | } 531 | 532 | func sliderTouchDragEnter(sender:UISlider!){ 533 | self.sliderIsDragging = true 534 | } 535 | 536 | func sliderTouchDragExit(sender:UISlider!){ 537 | self.sliderIsDragging = false 538 | 539 | sliderNowValue = sender.value 540 | if self.sliderNowValue != 0{ 541 | 542 | self.player.seekToTime(CMTimeMake(Int64(self.sliderNowValue * Float(self.totalValue)) , 1), toleranceBefore: kCMTimeZero, toleranceAfter: kCMTimeZero, completionHandler: { (Bool) -> Void in 543 | self.player.play() 544 | self.playPauseImageView.image = UIImage(named: "pause") 545 | self.sliderNowValue = 0 546 | 547 | }) 548 | } 549 | } 550 | 551 | 552 | 553 | 554 | } -------------------------------------------------------------------------------- /mtTVPlayer/song6.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinRGB/MTMusicPlayer/e263038c3743215cc94b1940a307ef541a537dce/mtTVPlayer/song6.mp3 -------------------------------------------------------------------------------- /mtTVPlayer/song7.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MartinRGB/MTMusicPlayer/e263038c3743215cc94b1940a307ef541a537dce/mtTVPlayer/song7.mp3 --------------------------------------------------------------------------------