├── README.md ├── ZXVideoPlayer.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── Shawn.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── Shawn.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── ZXVideoPlayer.xcscheme │ └── xcschememanagement.plist ├── ZXVideoPlayer ├── 150511_JiveBike.mov ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── BaseTabBarController.h ├── BaseTabBarController.m ├── Info.plist ├── VideoPlayViewController.h ├── VideoPlayViewController.m ├── ViewController.h ├── ViewController.m ├── ZXVideoPlayer │ ├── Assets │ │ ├── kr-video-player-close@2x.png │ │ ├── kr-video-player-close@3x.png │ │ ├── kr-video-player-fullscreen@2x.png │ │ ├── kr-video-player-fullscreen@3x.png │ │ ├── kr-video-player-pause@2x.png │ │ ├── kr-video-player-pause@3x.png │ │ ├── kr-video-player-play@2x.png │ │ ├── kr-video-player-play@3x.png │ │ ├── kr-video-player-point@2x.png │ │ ├── kr-video-player-point@3x.png │ │ ├── kr-video-player-shrinkscreen@2x.png │ │ ├── kr-video-player-shrinkscreen@3x.png │ │ ├── zx-video-banner-back.png │ │ ├── zx-video-banner-back@2x.png │ │ ├── zx-video-player-brightness@2x.png │ │ ├── zx-video-player-brightness@3x.png │ │ ├── zx-video-player-fastForward@2x.png │ │ ├── zx-video-player-fastForward@3x.png │ │ ├── zx-video-player-lock@2x.png │ │ ├── zx-video-player-lock@3x.png │ │ ├── zx-video-player-rewind@2x.png │ │ ├── zx-video-player-rewind@3x.png │ │ ├── zx-video-player-unlock@2x.png │ │ ├── zx-video-player-unlock@3x.png │ │ ├── zx-video-player-volume@2x.png │ │ ├── zx-video-player-volume@3x.png │ │ ├── zx-video-player-volumeMute@2x.png │ │ └── zx-video-player-volumeMute@3x.png │ ├── ZXVideo.h │ ├── ZXVideo.m │ ├── ZXVideoPlayerBatteryView.h │ ├── ZXVideoPlayerBatteryView.m │ ├── ZXVideoPlayerBrightnessView.h │ ├── ZXVideoPlayerBrightnessView.m │ ├── ZXVideoPlayerControlView.h │ ├── ZXVideoPlayerControlView.m │ ├── ZXVideoPlayerController.h │ ├── ZXVideoPlayerController.m │ ├── ZXVideoPlayerTimeIndicatorView.h │ ├── ZXVideoPlayerTimeIndicatorView.m │ ├── ZXVideoPlayerVolumeView.h │ └── ZXVideoPlayerVolumeView.m └── main.m ├── ZXVideoPlayerTests ├── Info.plist └── ZXVideoPlayerTests.m ├── ZXVideoPlayerUITests ├── Info.plist └── ZXVideoPlayerUITests.m ├── img1.jpg ├── img2.jpg └── img3.jpg /README.md: -------------------------------------------------------------------------------- 1 | # VideoPlayerDemo 2 | 根据[KRVideoPlayer](https://github.com/36Kr-Mobile/KRVideoPlayer)改编的视频播放器...呆哞,支持横竖屏旋转(90°&&180°),音量、亮度调节,左侧为亮度调节,右侧为音量调节,以及快进快退、加载进度(非缓存)、自定义电池条,锁屏等。可用于简单的网络视频播放。 3 | 4 | # Screenshot 5 | ![image](https://github.com/0summer0/VideoPlayerDemo/raw/master/img1.jpg) 6 | ![image](https://github.com/0summer0/VideoPlayerDemo/raw/master/img2.jpg) 7 | ![image](https://github.com/0summer0/VideoPlayerDemo/raw/master/img3.jpg) 8 | 9 | 10 | -------------------------------------------------------------------------------- /ZXVideoPlayer.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 296FA99F1CC7126C003FC0EA /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 296FA99E1CC7126C003FC0EA /* main.m */; }; 11 | 296FA9A21CC7126C003FC0EA /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 296FA9A11CC7126C003FC0EA /* AppDelegate.m */; }; 12 | 296FA9A51CC7126D003FC0EA /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 296FA9A41CC7126D003FC0EA /* ViewController.m */; }; 13 | 296FA9A81CC7126D003FC0EA /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 296FA9A61CC7126D003FC0EA /* Main.storyboard */; }; 14 | 296FA9AA1CC7126D003FC0EA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 296FA9A91CC7126D003FC0EA /* Assets.xcassets */; }; 15 | 296FA9AD1CC7126D003FC0EA /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 296FA9AB1CC7126D003FC0EA /* LaunchScreen.storyboard */; }; 16 | 296FA9B81CC7126D003FC0EA /* ZXVideoPlayerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 296FA9B71CC7126D003FC0EA /* ZXVideoPlayerTests.m */; }; 17 | 296FA9C31CC7126D003FC0EA /* ZXVideoPlayerUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 296FA9C21CC7126D003FC0EA /* ZXVideoPlayerUITests.m */; }; 18 | 296FAA841CC897BB003FC0EA /* 150511_JiveBike.mov in Resources */ = {isa = PBXBuildFile; fileRef = 296FAA831CC897BB003FC0EA /* 150511_JiveBike.mov */; }; 19 | 29A523861CD35A440097198F /* BaseTabBarController.m in Sources */ = {isa = PBXBuildFile; fileRef = 29A523851CD35A440097198F /* BaseTabBarController.m */; }; 20 | 29A523891CD35DC30097198F /* VideoPlayViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 29A523881CD35DC30097198F /* VideoPlayViewController.m */; }; 21 | 29BA1FDD1D1AB7AC0053D2F9 /* kr-video-player-close@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 29BA1FB51D1AB7AC0053D2F9 /* kr-video-player-close@2x.png */; }; 22 | 29BA1FDE1D1AB7AC0053D2F9 /* kr-video-player-close@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 29BA1FB61D1AB7AC0053D2F9 /* kr-video-player-close@3x.png */; }; 23 | 29BA1FDF1D1AB7AC0053D2F9 /* kr-video-player-fullscreen@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 29BA1FB71D1AB7AC0053D2F9 /* kr-video-player-fullscreen@2x.png */; }; 24 | 29BA1FE01D1AB7AC0053D2F9 /* kr-video-player-fullscreen@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 29BA1FB81D1AB7AC0053D2F9 /* kr-video-player-fullscreen@3x.png */; }; 25 | 29BA1FE11D1AB7AC0053D2F9 /* kr-video-player-pause@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 29BA1FB91D1AB7AC0053D2F9 /* kr-video-player-pause@2x.png */; }; 26 | 29BA1FE21D1AB7AC0053D2F9 /* kr-video-player-pause@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 29BA1FBA1D1AB7AC0053D2F9 /* kr-video-player-pause@3x.png */; }; 27 | 29BA1FE31D1AB7AC0053D2F9 /* kr-video-player-play@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 29BA1FBB1D1AB7AC0053D2F9 /* kr-video-player-play@2x.png */; }; 28 | 29BA1FE41D1AB7AC0053D2F9 /* kr-video-player-play@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 29BA1FBC1D1AB7AC0053D2F9 /* kr-video-player-play@3x.png */; }; 29 | 29BA1FE51D1AB7AC0053D2F9 /* kr-video-player-point@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 29BA1FBD1D1AB7AC0053D2F9 /* kr-video-player-point@2x.png */; }; 30 | 29BA1FE61D1AB7AC0053D2F9 /* kr-video-player-point@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 29BA1FBE1D1AB7AC0053D2F9 /* kr-video-player-point@3x.png */; }; 31 | 29BA1FE71D1AB7AC0053D2F9 /* kr-video-player-shrinkscreen@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 29BA1FBF1D1AB7AC0053D2F9 /* kr-video-player-shrinkscreen@2x.png */; }; 32 | 29BA1FE81D1AB7AC0053D2F9 /* kr-video-player-shrinkscreen@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 29BA1FC01D1AB7AC0053D2F9 /* kr-video-player-shrinkscreen@3x.png */; }; 33 | 29BA1FE91D1AB7AC0053D2F9 /* zx-video-banner-back.png in Resources */ = {isa = PBXBuildFile; fileRef = 29BA1FC11D1AB7AC0053D2F9 /* zx-video-banner-back.png */; }; 34 | 29BA1FEA1D1AB7AC0053D2F9 /* zx-video-banner-back@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 29BA1FC21D1AB7AC0053D2F9 /* zx-video-banner-back@2x.png */; }; 35 | 29BA1FEB1D1AB7AC0053D2F9 /* zx-video-player-brightness@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 29BA1FC31D1AB7AC0053D2F9 /* zx-video-player-brightness@2x.png */; }; 36 | 29BA1FEC1D1AB7AC0053D2F9 /* zx-video-player-brightness@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 29BA1FC41D1AB7AC0053D2F9 /* zx-video-player-brightness@3x.png */; }; 37 | 29BA1FED1D1AB7AC0053D2F9 /* zx-video-player-fastForward@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 29BA1FC51D1AB7AC0053D2F9 /* zx-video-player-fastForward@2x.png */; }; 38 | 29BA1FEE1D1AB7AC0053D2F9 /* zx-video-player-fastForward@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 29BA1FC61D1AB7AC0053D2F9 /* zx-video-player-fastForward@3x.png */; }; 39 | 29BA1FEF1D1AB7AC0053D2F9 /* zx-video-player-lock@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 29BA1FC71D1AB7AC0053D2F9 /* zx-video-player-lock@2x.png */; }; 40 | 29BA1FF01D1AB7AC0053D2F9 /* zx-video-player-lock@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 29BA1FC81D1AB7AC0053D2F9 /* zx-video-player-lock@3x.png */; }; 41 | 29BA1FF11D1AB7AC0053D2F9 /* zx-video-player-rewind@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 29BA1FC91D1AB7AC0053D2F9 /* zx-video-player-rewind@2x.png */; }; 42 | 29BA1FF21D1AB7AC0053D2F9 /* zx-video-player-rewind@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 29BA1FCA1D1AB7AC0053D2F9 /* zx-video-player-rewind@3x.png */; }; 43 | 29BA1FF31D1AB7AC0053D2F9 /* zx-video-player-unlock@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 29BA1FCB1D1AB7AC0053D2F9 /* zx-video-player-unlock@2x.png */; }; 44 | 29BA1FF41D1AB7AC0053D2F9 /* zx-video-player-unlock@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 29BA1FCC1D1AB7AC0053D2F9 /* zx-video-player-unlock@3x.png */; }; 45 | 29BA1FF51D1AB7AC0053D2F9 /* zx-video-player-volume@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 29BA1FCD1D1AB7AC0053D2F9 /* zx-video-player-volume@2x.png */; }; 46 | 29BA1FF61D1AB7AC0053D2F9 /* zx-video-player-volume@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 29BA1FCE1D1AB7AC0053D2F9 /* zx-video-player-volume@3x.png */; }; 47 | 29BA1FF71D1AB7AC0053D2F9 /* zx-video-player-volumeMute@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 29BA1FCF1D1AB7AC0053D2F9 /* zx-video-player-volumeMute@2x.png */; }; 48 | 29BA1FF81D1AB7AC0053D2F9 /* zx-video-player-volumeMute@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 29BA1FD01D1AB7AC0053D2F9 /* zx-video-player-volumeMute@3x.png */; }; 49 | 29BA1FF91D1AB7AC0053D2F9 /* ZXVideoPlayerBatteryView.m in Sources */ = {isa = PBXBuildFile; fileRef = 29BA1FD21D1AB7AC0053D2F9 /* ZXVideoPlayerBatteryView.m */; }; 50 | 29BA1FFA1D1AB7AC0053D2F9 /* ZXVideoPlayerBrightnessView.m in Sources */ = {isa = PBXBuildFile; fileRef = 29BA1FD41D1AB7AC0053D2F9 /* ZXVideoPlayerBrightnessView.m */; }; 51 | 29BA1FFB1D1AB7AC0053D2F9 /* ZXVideoPlayerController.m in Sources */ = {isa = PBXBuildFile; fileRef = 29BA1FD61D1AB7AC0053D2F9 /* ZXVideoPlayerController.m */; }; 52 | 29BA1FFC1D1AB7AC0053D2F9 /* ZXVideoPlayerControlView.m in Sources */ = {isa = PBXBuildFile; fileRef = 29BA1FD81D1AB7AC0053D2F9 /* ZXVideoPlayerControlView.m */; }; 53 | 29BA1FFD1D1AB7AC0053D2F9 /* ZXVideoPlayerTimeIndicatorView.m in Sources */ = {isa = PBXBuildFile; fileRef = 29BA1FDA1D1AB7AC0053D2F9 /* ZXVideoPlayerTimeIndicatorView.m */; }; 54 | 29BA1FFE1D1AB7AC0053D2F9 /* ZXVideoPlayerVolumeView.m in Sources */ = {isa = PBXBuildFile; fileRef = 29BA1FDC1D1AB7AC0053D2F9 /* ZXVideoPlayerVolumeView.m */; }; 55 | 29BA20041D1AB9040053D2F9 /* ZXVideo.m in Sources */ = {isa = PBXBuildFile; fileRef = 29BA20031D1AB9040053D2F9 /* ZXVideo.m */; }; 56 | /* End PBXBuildFile section */ 57 | 58 | /* Begin PBXContainerItemProxy section */ 59 | 296FA9B41CC7126D003FC0EA /* PBXContainerItemProxy */ = { 60 | isa = PBXContainerItemProxy; 61 | containerPortal = 296FA9921CC7126C003FC0EA /* Project object */; 62 | proxyType = 1; 63 | remoteGlobalIDString = 296FA9991CC7126C003FC0EA; 64 | remoteInfo = ZXVideoPlayer; 65 | }; 66 | 296FA9BF1CC7126D003FC0EA /* PBXContainerItemProxy */ = { 67 | isa = PBXContainerItemProxy; 68 | containerPortal = 296FA9921CC7126C003FC0EA /* Project object */; 69 | proxyType = 1; 70 | remoteGlobalIDString = 296FA9991CC7126C003FC0EA; 71 | remoteInfo = ZXVideoPlayer; 72 | }; 73 | /* End PBXContainerItemProxy section */ 74 | 75 | /* Begin PBXFileReference section */ 76 | 296FA99A1CC7126C003FC0EA /* ZXVideoPlayer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ZXVideoPlayer.app; sourceTree = BUILT_PRODUCTS_DIR; }; 77 | 296FA99E1CC7126C003FC0EA /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 78 | 296FA9A01CC7126C003FC0EA /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 79 | 296FA9A11CC7126C003FC0EA /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 80 | 296FA9A31CC7126D003FC0EA /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 81 | 296FA9A41CC7126D003FC0EA /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 82 | 296FA9A71CC7126D003FC0EA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 83 | 296FA9A91CC7126D003FC0EA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 84 | 296FA9AC1CC7126D003FC0EA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 85 | 296FA9AE1CC7126D003FC0EA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 86 | 296FA9B31CC7126D003FC0EA /* ZXVideoPlayerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ZXVideoPlayerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 87 | 296FA9B71CC7126D003FC0EA /* ZXVideoPlayerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ZXVideoPlayerTests.m; sourceTree = ""; }; 88 | 296FA9B91CC7126D003FC0EA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 89 | 296FA9BE1CC7126D003FC0EA /* ZXVideoPlayerUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ZXVideoPlayerUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 90 | 296FA9C21CC7126D003FC0EA /* ZXVideoPlayerUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ZXVideoPlayerUITests.m; sourceTree = ""; }; 91 | 296FA9C41CC7126D003FC0EA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 92 | 296FAA831CC897BB003FC0EA /* 150511_JiveBike.mov */ = {isa = PBXFileReference; lastKnownFileType = video.quicktime; path = 150511_JiveBike.mov; sourceTree = ""; }; 93 | 29A523841CD35A440097198F /* BaseTabBarController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BaseTabBarController.h; sourceTree = ""; }; 94 | 29A523851CD35A440097198F /* BaseTabBarController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BaseTabBarController.m; sourceTree = ""; }; 95 | 29A523871CD35DC30097198F /* VideoPlayViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VideoPlayViewController.h; sourceTree = ""; }; 96 | 29A523881CD35DC30097198F /* VideoPlayViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VideoPlayViewController.m; sourceTree = ""; }; 97 | 29BA1FB51D1AB7AC0053D2F9 /* kr-video-player-close@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "kr-video-player-close@2x.png"; sourceTree = ""; }; 98 | 29BA1FB61D1AB7AC0053D2F9 /* kr-video-player-close@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "kr-video-player-close@3x.png"; sourceTree = ""; }; 99 | 29BA1FB71D1AB7AC0053D2F9 /* kr-video-player-fullscreen@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "kr-video-player-fullscreen@2x.png"; sourceTree = ""; }; 100 | 29BA1FB81D1AB7AC0053D2F9 /* kr-video-player-fullscreen@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "kr-video-player-fullscreen@3x.png"; sourceTree = ""; }; 101 | 29BA1FB91D1AB7AC0053D2F9 /* kr-video-player-pause@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "kr-video-player-pause@2x.png"; sourceTree = ""; }; 102 | 29BA1FBA1D1AB7AC0053D2F9 /* kr-video-player-pause@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "kr-video-player-pause@3x.png"; sourceTree = ""; }; 103 | 29BA1FBB1D1AB7AC0053D2F9 /* kr-video-player-play@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "kr-video-player-play@2x.png"; sourceTree = ""; }; 104 | 29BA1FBC1D1AB7AC0053D2F9 /* kr-video-player-play@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "kr-video-player-play@3x.png"; sourceTree = ""; }; 105 | 29BA1FBD1D1AB7AC0053D2F9 /* kr-video-player-point@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "kr-video-player-point@2x.png"; sourceTree = ""; }; 106 | 29BA1FBE1D1AB7AC0053D2F9 /* kr-video-player-point@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "kr-video-player-point@3x.png"; sourceTree = ""; }; 107 | 29BA1FBF1D1AB7AC0053D2F9 /* kr-video-player-shrinkscreen@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "kr-video-player-shrinkscreen@2x.png"; sourceTree = ""; }; 108 | 29BA1FC01D1AB7AC0053D2F9 /* kr-video-player-shrinkscreen@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "kr-video-player-shrinkscreen@3x.png"; sourceTree = ""; }; 109 | 29BA1FC11D1AB7AC0053D2F9 /* zx-video-banner-back.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "zx-video-banner-back.png"; sourceTree = ""; }; 110 | 29BA1FC21D1AB7AC0053D2F9 /* zx-video-banner-back@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "zx-video-banner-back@2x.png"; sourceTree = ""; }; 111 | 29BA1FC31D1AB7AC0053D2F9 /* zx-video-player-brightness@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "zx-video-player-brightness@2x.png"; sourceTree = ""; }; 112 | 29BA1FC41D1AB7AC0053D2F9 /* zx-video-player-brightness@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "zx-video-player-brightness@3x.png"; sourceTree = ""; }; 113 | 29BA1FC51D1AB7AC0053D2F9 /* zx-video-player-fastForward@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "zx-video-player-fastForward@2x.png"; sourceTree = ""; }; 114 | 29BA1FC61D1AB7AC0053D2F9 /* zx-video-player-fastForward@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "zx-video-player-fastForward@3x.png"; sourceTree = ""; }; 115 | 29BA1FC71D1AB7AC0053D2F9 /* zx-video-player-lock@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "zx-video-player-lock@2x.png"; sourceTree = ""; }; 116 | 29BA1FC81D1AB7AC0053D2F9 /* zx-video-player-lock@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "zx-video-player-lock@3x.png"; sourceTree = ""; }; 117 | 29BA1FC91D1AB7AC0053D2F9 /* zx-video-player-rewind@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "zx-video-player-rewind@2x.png"; sourceTree = ""; }; 118 | 29BA1FCA1D1AB7AC0053D2F9 /* zx-video-player-rewind@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "zx-video-player-rewind@3x.png"; sourceTree = ""; }; 119 | 29BA1FCB1D1AB7AC0053D2F9 /* zx-video-player-unlock@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "zx-video-player-unlock@2x.png"; sourceTree = ""; }; 120 | 29BA1FCC1D1AB7AC0053D2F9 /* zx-video-player-unlock@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "zx-video-player-unlock@3x.png"; sourceTree = ""; }; 121 | 29BA1FCD1D1AB7AC0053D2F9 /* zx-video-player-volume@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "zx-video-player-volume@2x.png"; sourceTree = ""; }; 122 | 29BA1FCE1D1AB7AC0053D2F9 /* zx-video-player-volume@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "zx-video-player-volume@3x.png"; sourceTree = ""; }; 123 | 29BA1FCF1D1AB7AC0053D2F9 /* zx-video-player-volumeMute@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "zx-video-player-volumeMute@2x.png"; sourceTree = ""; }; 124 | 29BA1FD01D1AB7AC0053D2F9 /* zx-video-player-volumeMute@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "zx-video-player-volumeMute@3x.png"; sourceTree = ""; }; 125 | 29BA1FD11D1AB7AC0053D2F9 /* ZXVideoPlayerBatteryView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXVideoPlayerBatteryView.h; sourceTree = ""; }; 126 | 29BA1FD21D1AB7AC0053D2F9 /* ZXVideoPlayerBatteryView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXVideoPlayerBatteryView.m; sourceTree = ""; }; 127 | 29BA1FD31D1AB7AC0053D2F9 /* ZXVideoPlayerBrightnessView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXVideoPlayerBrightnessView.h; sourceTree = ""; }; 128 | 29BA1FD41D1AB7AC0053D2F9 /* ZXVideoPlayerBrightnessView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXVideoPlayerBrightnessView.m; sourceTree = ""; }; 129 | 29BA1FD51D1AB7AC0053D2F9 /* ZXVideoPlayerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXVideoPlayerController.h; sourceTree = ""; }; 130 | 29BA1FD61D1AB7AC0053D2F9 /* ZXVideoPlayerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXVideoPlayerController.m; sourceTree = ""; }; 131 | 29BA1FD71D1AB7AC0053D2F9 /* ZXVideoPlayerControlView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXVideoPlayerControlView.h; sourceTree = ""; }; 132 | 29BA1FD81D1AB7AC0053D2F9 /* ZXVideoPlayerControlView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXVideoPlayerControlView.m; sourceTree = ""; }; 133 | 29BA1FD91D1AB7AC0053D2F9 /* ZXVideoPlayerTimeIndicatorView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXVideoPlayerTimeIndicatorView.h; sourceTree = ""; }; 134 | 29BA1FDA1D1AB7AC0053D2F9 /* ZXVideoPlayerTimeIndicatorView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXVideoPlayerTimeIndicatorView.m; sourceTree = ""; }; 135 | 29BA1FDB1D1AB7AC0053D2F9 /* ZXVideoPlayerVolumeView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXVideoPlayerVolumeView.h; sourceTree = ""; }; 136 | 29BA1FDC1D1AB7AC0053D2F9 /* ZXVideoPlayerVolumeView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXVideoPlayerVolumeView.m; sourceTree = ""; }; 137 | 29BA20021D1AB9040053D2F9 /* ZXVideo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXVideo.h; sourceTree = ""; }; 138 | 29BA20031D1AB9040053D2F9 /* ZXVideo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXVideo.m; sourceTree = ""; }; 139 | /* End PBXFileReference section */ 140 | 141 | /* Begin PBXFrameworksBuildPhase section */ 142 | 296FA9971CC7126C003FC0EA /* Frameworks */ = { 143 | isa = PBXFrameworksBuildPhase; 144 | buildActionMask = 2147483647; 145 | files = ( 146 | ); 147 | runOnlyForDeploymentPostprocessing = 0; 148 | }; 149 | 296FA9B01CC7126D003FC0EA /* Frameworks */ = { 150 | isa = PBXFrameworksBuildPhase; 151 | buildActionMask = 2147483647; 152 | files = ( 153 | ); 154 | runOnlyForDeploymentPostprocessing = 0; 155 | }; 156 | 296FA9BB1CC7126D003FC0EA /* Frameworks */ = { 157 | isa = PBXFrameworksBuildPhase; 158 | buildActionMask = 2147483647; 159 | files = ( 160 | ); 161 | runOnlyForDeploymentPostprocessing = 0; 162 | }; 163 | /* End PBXFrameworksBuildPhase section */ 164 | 165 | /* Begin PBXGroup section */ 166 | 296FA9911CC7126C003FC0EA = { 167 | isa = PBXGroup; 168 | children = ( 169 | 296FA99C1CC7126C003FC0EA /* ZXVideoPlayer */, 170 | 296FA9B61CC7126D003FC0EA /* ZXVideoPlayerTests */, 171 | 296FA9C11CC7126D003FC0EA /* ZXVideoPlayerUITests */, 172 | 296FA99B1CC7126C003FC0EA /* Products */, 173 | ); 174 | sourceTree = ""; 175 | }; 176 | 296FA99B1CC7126C003FC0EA /* Products */ = { 177 | isa = PBXGroup; 178 | children = ( 179 | 296FA99A1CC7126C003FC0EA /* ZXVideoPlayer.app */, 180 | 296FA9B31CC7126D003FC0EA /* ZXVideoPlayerTests.xctest */, 181 | 296FA9BE1CC7126D003FC0EA /* ZXVideoPlayerUITests.xctest */, 182 | ); 183 | name = Products; 184 | sourceTree = ""; 185 | }; 186 | 296FA99C1CC7126C003FC0EA /* ZXVideoPlayer */ = { 187 | isa = PBXGroup; 188 | children = ( 189 | 29BA1FB31D1AB7AC0053D2F9 /* ZXVideoPlayer */, 190 | 296FA9A01CC7126C003FC0EA /* AppDelegate.h */, 191 | 296FA9A11CC7126C003FC0EA /* AppDelegate.m */, 192 | 29A523841CD35A440097198F /* BaseTabBarController.h */, 193 | 29A523851CD35A440097198F /* BaseTabBarController.m */, 194 | 296FA9A31CC7126D003FC0EA /* ViewController.h */, 195 | 296FA9A41CC7126D003FC0EA /* ViewController.m */, 196 | 29A523871CD35DC30097198F /* VideoPlayViewController.h */, 197 | 29A523881CD35DC30097198F /* VideoPlayViewController.m */, 198 | 296FA9A61CC7126D003FC0EA /* Main.storyboard */, 199 | 296FA9A91CC7126D003FC0EA /* Assets.xcassets */, 200 | 296FA9AB1CC7126D003FC0EA /* LaunchScreen.storyboard */, 201 | 296FA9AE1CC7126D003FC0EA /* Info.plist */, 202 | 296FA99D1CC7126C003FC0EA /* Supporting Files */, 203 | ); 204 | path = ZXVideoPlayer; 205 | sourceTree = ""; 206 | }; 207 | 296FA99D1CC7126C003FC0EA /* Supporting Files */ = { 208 | isa = PBXGroup; 209 | children = ( 210 | 296FAA831CC897BB003FC0EA /* 150511_JiveBike.mov */, 211 | 296FA99E1CC7126C003FC0EA /* main.m */, 212 | ); 213 | name = "Supporting Files"; 214 | sourceTree = ""; 215 | }; 216 | 296FA9B61CC7126D003FC0EA /* ZXVideoPlayerTests */ = { 217 | isa = PBXGroup; 218 | children = ( 219 | 296FA9B71CC7126D003FC0EA /* ZXVideoPlayerTests.m */, 220 | 296FA9B91CC7126D003FC0EA /* Info.plist */, 221 | ); 222 | path = ZXVideoPlayerTests; 223 | sourceTree = ""; 224 | }; 225 | 296FA9C11CC7126D003FC0EA /* ZXVideoPlayerUITests */ = { 226 | isa = PBXGroup; 227 | children = ( 228 | 296FA9C21CC7126D003FC0EA /* ZXVideoPlayerUITests.m */, 229 | 296FA9C41CC7126D003FC0EA /* Info.plist */, 230 | ); 231 | path = ZXVideoPlayerUITests; 232 | sourceTree = ""; 233 | }; 234 | 29BA1FB31D1AB7AC0053D2F9 /* ZXVideoPlayer */ = { 235 | isa = PBXGroup; 236 | children = ( 237 | 29BA1FB41D1AB7AC0053D2F9 /* Assets */, 238 | 29BA1FD11D1AB7AC0053D2F9 /* ZXVideoPlayerBatteryView.h */, 239 | 29BA1FD21D1AB7AC0053D2F9 /* ZXVideoPlayerBatteryView.m */, 240 | 29BA1FD31D1AB7AC0053D2F9 /* ZXVideoPlayerBrightnessView.h */, 241 | 29BA1FD41D1AB7AC0053D2F9 /* ZXVideoPlayerBrightnessView.m */, 242 | 29BA1FD51D1AB7AC0053D2F9 /* ZXVideoPlayerController.h */, 243 | 29BA1FD61D1AB7AC0053D2F9 /* ZXVideoPlayerController.m */, 244 | 29BA1FD71D1AB7AC0053D2F9 /* ZXVideoPlayerControlView.h */, 245 | 29BA1FD81D1AB7AC0053D2F9 /* ZXVideoPlayerControlView.m */, 246 | 29BA1FD91D1AB7AC0053D2F9 /* ZXVideoPlayerTimeIndicatorView.h */, 247 | 29BA1FDA1D1AB7AC0053D2F9 /* ZXVideoPlayerTimeIndicatorView.m */, 248 | 29BA1FDB1D1AB7AC0053D2F9 /* ZXVideoPlayerVolumeView.h */, 249 | 29BA1FDC1D1AB7AC0053D2F9 /* ZXVideoPlayerVolumeView.m */, 250 | 29BA20021D1AB9040053D2F9 /* ZXVideo.h */, 251 | 29BA20031D1AB9040053D2F9 /* ZXVideo.m */, 252 | ); 253 | path = ZXVideoPlayer; 254 | sourceTree = ""; 255 | }; 256 | 29BA1FB41D1AB7AC0053D2F9 /* Assets */ = { 257 | isa = PBXGroup; 258 | children = ( 259 | 29BA1FB51D1AB7AC0053D2F9 /* kr-video-player-close@2x.png */, 260 | 29BA1FB61D1AB7AC0053D2F9 /* kr-video-player-close@3x.png */, 261 | 29BA1FB71D1AB7AC0053D2F9 /* kr-video-player-fullscreen@2x.png */, 262 | 29BA1FB81D1AB7AC0053D2F9 /* kr-video-player-fullscreen@3x.png */, 263 | 29BA1FB91D1AB7AC0053D2F9 /* kr-video-player-pause@2x.png */, 264 | 29BA1FBA1D1AB7AC0053D2F9 /* kr-video-player-pause@3x.png */, 265 | 29BA1FBB1D1AB7AC0053D2F9 /* kr-video-player-play@2x.png */, 266 | 29BA1FBC1D1AB7AC0053D2F9 /* kr-video-player-play@3x.png */, 267 | 29BA1FBD1D1AB7AC0053D2F9 /* kr-video-player-point@2x.png */, 268 | 29BA1FBE1D1AB7AC0053D2F9 /* kr-video-player-point@3x.png */, 269 | 29BA1FBF1D1AB7AC0053D2F9 /* kr-video-player-shrinkscreen@2x.png */, 270 | 29BA1FC01D1AB7AC0053D2F9 /* kr-video-player-shrinkscreen@3x.png */, 271 | 29BA1FC11D1AB7AC0053D2F9 /* zx-video-banner-back.png */, 272 | 29BA1FC21D1AB7AC0053D2F9 /* zx-video-banner-back@2x.png */, 273 | 29BA1FC31D1AB7AC0053D2F9 /* zx-video-player-brightness@2x.png */, 274 | 29BA1FC41D1AB7AC0053D2F9 /* zx-video-player-brightness@3x.png */, 275 | 29BA1FC51D1AB7AC0053D2F9 /* zx-video-player-fastForward@2x.png */, 276 | 29BA1FC61D1AB7AC0053D2F9 /* zx-video-player-fastForward@3x.png */, 277 | 29BA1FC71D1AB7AC0053D2F9 /* zx-video-player-lock@2x.png */, 278 | 29BA1FC81D1AB7AC0053D2F9 /* zx-video-player-lock@3x.png */, 279 | 29BA1FC91D1AB7AC0053D2F9 /* zx-video-player-rewind@2x.png */, 280 | 29BA1FCA1D1AB7AC0053D2F9 /* zx-video-player-rewind@3x.png */, 281 | 29BA1FCB1D1AB7AC0053D2F9 /* zx-video-player-unlock@2x.png */, 282 | 29BA1FCC1D1AB7AC0053D2F9 /* zx-video-player-unlock@3x.png */, 283 | 29BA1FCD1D1AB7AC0053D2F9 /* zx-video-player-volume@2x.png */, 284 | 29BA1FCE1D1AB7AC0053D2F9 /* zx-video-player-volume@3x.png */, 285 | 29BA1FCF1D1AB7AC0053D2F9 /* zx-video-player-volumeMute@2x.png */, 286 | 29BA1FD01D1AB7AC0053D2F9 /* zx-video-player-volumeMute@3x.png */, 287 | ); 288 | path = Assets; 289 | sourceTree = ""; 290 | }; 291 | /* End PBXGroup section */ 292 | 293 | /* Begin PBXNativeTarget section */ 294 | 296FA9991CC7126C003FC0EA /* ZXVideoPlayer */ = { 295 | isa = PBXNativeTarget; 296 | buildConfigurationList = 296FA9C71CC7126D003FC0EA /* Build configuration list for PBXNativeTarget "ZXVideoPlayer" */; 297 | buildPhases = ( 298 | 296FA9961CC7126C003FC0EA /* Sources */, 299 | 296FA9971CC7126C003FC0EA /* Frameworks */, 300 | 296FA9981CC7126C003FC0EA /* Resources */, 301 | ); 302 | buildRules = ( 303 | ); 304 | dependencies = ( 305 | ); 306 | name = ZXVideoPlayer; 307 | productName = ZXVideoPlayer; 308 | productReference = 296FA99A1CC7126C003FC0EA /* ZXVideoPlayer.app */; 309 | productType = "com.apple.product-type.application"; 310 | }; 311 | 296FA9B21CC7126D003FC0EA /* ZXVideoPlayerTests */ = { 312 | isa = PBXNativeTarget; 313 | buildConfigurationList = 296FA9CA1CC7126D003FC0EA /* Build configuration list for PBXNativeTarget "ZXVideoPlayerTests" */; 314 | buildPhases = ( 315 | 296FA9AF1CC7126D003FC0EA /* Sources */, 316 | 296FA9B01CC7126D003FC0EA /* Frameworks */, 317 | 296FA9B11CC7126D003FC0EA /* Resources */, 318 | ); 319 | buildRules = ( 320 | ); 321 | dependencies = ( 322 | 296FA9B51CC7126D003FC0EA /* PBXTargetDependency */, 323 | ); 324 | name = ZXVideoPlayerTests; 325 | productName = ZXVideoPlayerTests; 326 | productReference = 296FA9B31CC7126D003FC0EA /* ZXVideoPlayerTests.xctest */; 327 | productType = "com.apple.product-type.bundle.unit-test"; 328 | }; 329 | 296FA9BD1CC7126D003FC0EA /* ZXVideoPlayerUITests */ = { 330 | isa = PBXNativeTarget; 331 | buildConfigurationList = 296FA9CD1CC7126D003FC0EA /* Build configuration list for PBXNativeTarget "ZXVideoPlayerUITests" */; 332 | buildPhases = ( 333 | 296FA9BA1CC7126D003FC0EA /* Sources */, 334 | 296FA9BB1CC7126D003FC0EA /* Frameworks */, 335 | 296FA9BC1CC7126D003FC0EA /* Resources */, 336 | ); 337 | buildRules = ( 338 | ); 339 | dependencies = ( 340 | 296FA9C01CC7126D003FC0EA /* PBXTargetDependency */, 341 | ); 342 | name = ZXVideoPlayerUITests; 343 | productName = ZXVideoPlayerUITests; 344 | productReference = 296FA9BE1CC7126D003FC0EA /* ZXVideoPlayerUITests.xctest */; 345 | productType = "com.apple.product-type.bundle.ui-testing"; 346 | }; 347 | /* End PBXNativeTarget section */ 348 | 349 | /* Begin PBXProject section */ 350 | 296FA9921CC7126C003FC0EA /* Project object */ = { 351 | isa = PBXProject; 352 | attributes = { 353 | LastUpgradeCheck = 0720; 354 | ORGANIZATIONNAME = Shawn; 355 | TargetAttributes = { 356 | 296FA9991CC7126C003FC0EA = { 357 | CreatedOnToolsVersion = 7.2; 358 | }; 359 | 296FA9B21CC7126D003FC0EA = { 360 | CreatedOnToolsVersion = 7.2; 361 | TestTargetID = 296FA9991CC7126C003FC0EA; 362 | }; 363 | 296FA9BD1CC7126D003FC0EA = { 364 | CreatedOnToolsVersion = 7.2; 365 | TestTargetID = 296FA9991CC7126C003FC0EA; 366 | }; 367 | }; 368 | }; 369 | buildConfigurationList = 296FA9951CC7126C003FC0EA /* Build configuration list for PBXProject "ZXVideoPlayer" */; 370 | compatibilityVersion = "Xcode 3.2"; 371 | developmentRegion = English; 372 | hasScannedForEncodings = 0; 373 | knownRegions = ( 374 | en, 375 | Base, 376 | ); 377 | mainGroup = 296FA9911CC7126C003FC0EA; 378 | productRefGroup = 296FA99B1CC7126C003FC0EA /* Products */; 379 | projectDirPath = ""; 380 | projectRoot = ""; 381 | targets = ( 382 | 296FA9991CC7126C003FC0EA /* ZXVideoPlayer */, 383 | 296FA9B21CC7126D003FC0EA /* ZXVideoPlayerTests */, 384 | 296FA9BD1CC7126D003FC0EA /* ZXVideoPlayerUITests */, 385 | ); 386 | }; 387 | /* End PBXProject section */ 388 | 389 | /* Begin PBXResourcesBuildPhase section */ 390 | 296FA9981CC7126C003FC0EA /* Resources */ = { 391 | isa = PBXResourcesBuildPhase; 392 | buildActionMask = 2147483647; 393 | files = ( 394 | 29BA1FEF1D1AB7AC0053D2F9 /* zx-video-player-lock@2x.png in Resources */, 395 | 29BA1FDD1D1AB7AC0053D2F9 /* kr-video-player-close@2x.png in Resources */, 396 | 29BA1FF71D1AB7AC0053D2F9 /* zx-video-player-volumeMute@2x.png in Resources */, 397 | 29BA1FE31D1AB7AC0053D2F9 /* kr-video-player-play@2x.png in Resources */, 398 | 29BA1FE61D1AB7AC0053D2F9 /* kr-video-player-point@3x.png in Resources */, 399 | 29BA1FEA1D1AB7AC0053D2F9 /* zx-video-banner-back@2x.png in Resources */, 400 | 29BA1FEE1D1AB7AC0053D2F9 /* zx-video-player-fastForward@3x.png in Resources */, 401 | 296FA9AD1CC7126D003FC0EA /* LaunchScreen.storyboard in Resources */, 402 | 29BA1FE41D1AB7AC0053D2F9 /* kr-video-player-play@3x.png in Resources */, 403 | 296FA9AA1CC7126D003FC0EA /* Assets.xcassets in Resources */, 404 | 29BA1FF21D1AB7AC0053D2F9 /* zx-video-player-rewind@3x.png in Resources */, 405 | 29BA1FEC1D1AB7AC0053D2F9 /* zx-video-player-brightness@3x.png in Resources */, 406 | 29BA1FDF1D1AB7AC0053D2F9 /* kr-video-player-fullscreen@2x.png in Resources */, 407 | 29BA1FF81D1AB7AC0053D2F9 /* zx-video-player-volumeMute@3x.png in Resources */, 408 | 29BA1FEB1D1AB7AC0053D2F9 /* zx-video-player-brightness@2x.png in Resources */, 409 | 29BA1FE21D1AB7AC0053D2F9 /* kr-video-player-pause@3x.png in Resources */, 410 | 29BA1FE81D1AB7AC0053D2F9 /* kr-video-player-shrinkscreen@3x.png in Resources */, 411 | 29BA1FF51D1AB7AC0053D2F9 /* zx-video-player-volume@2x.png in Resources */, 412 | 29BA1FE91D1AB7AC0053D2F9 /* zx-video-banner-back.png in Resources */, 413 | 29BA1FE71D1AB7AC0053D2F9 /* kr-video-player-shrinkscreen@2x.png in Resources */, 414 | 296FAA841CC897BB003FC0EA /* 150511_JiveBike.mov in Resources */, 415 | 29BA1FDE1D1AB7AC0053D2F9 /* kr-video-player-close@3x.png in Resources */, 416 | 29BA1FED1D1AB7AC0053D2F9 /* zx-video-player-fastForward@2x.png in Resources */, 417 | 29BA1FE11D1AB7AC0053D2F9 /* kr-video-player-pause@2x.png in Resources */, 418 | 29BA1FF11D1AB7AC0053D2F9 /* zx-video-player-rewind@2x.png in Resources */, 419 | 29BA1FE51D1AB7AC0053D2F9 /* kr-video-player-point@2x.png in Resources */, 420 | 29BA1FF61D1AB7AC0053D2F9 /* zx-video-player-volume@3x.png in Resources */, 421 | 29BA1FF31D1AB7AC0053D2F9 /* zx-video-player-unlock@2x.png in Resources */, 422 | 29BA1FF41D1AB7AC0053D2F9 /* zx-video-player-unlock@3x.png in Resources */, 423 | 29BA1FE01D1AB7AC0053D2F9 /* kr-video-player-fullscreen@3x.png in Resources */, 424 | 296FA9A81CC7126D003FC0EA /* Main.storyboard in Resources */, 425 | 29BA1FF01D1AB7AC0053D2F9 /* zx-video-player-lock@3x.png in Resources */, 426 | ); 427 | runOnlyForDeploymentPostprocessing = 0; 428 | }; 429 | 296FA9B11CC7126D003FC0EA /* Resources */ = { 430 | isa = PBXResourcesBuildPhase; 431 | buildActionMask = 2147483647; 432 | files = ( 433 | ); 434 | runOnlyForDeploymentPostprocessing = 0; 435 | }; 436 | 296FA9BC1CC7126D003FC0EA /* Resources */ = { 437 | isa = PBXResourcesBuildPhase; 438 | buildActionMask = 2147483647; 439 | files = ( 440 | ); 441 | runOnlyForDeploymentPostprocessing = 0; 442 | }; 443 | /* End PBXResourcesBuildPhase section */ 444 | 445 | /* Begin PBXSourcesBuildPhase section */ 446 | 296FA9961CC7126C003FC0EA /* Sources */ = { 447 | isa = PBXSourcesBuildPhase; 448 | buildActionMask = 2147483647; 449 | files = ( 450 | 29A523891CD35DC30097198F /* VideoPlayViewController.m in Sources */, 451 | 29A523861CD35A440097198F /* BaseTabBarController.m in Sources */, 452 | 29BA1FFE1D1AB7AC0053D2F9 /* ZXVideoPlayerVolumeView.m in Sources */, 453 | 29BA1FFD1D1AB7AC0053D2F9 /* ZXVideoPlayerTimeIndicatorView.m in Sources */, 454 | 29BA1FFA1D1AB7AC0053D2F9 /* ZXVideoPlayerBrightnessView.m in Sources */, 455 | 296FA9A51CC7126D003FC0EA /* ViewController.m in Sources */, 456 | 29BA1FF91D1AB7AC0053D2F9 /* ZXVideoPlayerBatteryView.m in Sources */, 457 | 29BA1FFC1D1AB7AC0053D2F9 /* ZXVideoPlayerControlView.m in Sources */, 458 | 296FA9A21CC7126C003FC0EA /* AppDelegate.m in Sources */, 459 | 29BA20041D1AB9040053D2F9 /* ZXVideo.m in Sources */, 460 | 29BA1FFB1D1AB7AC0053D2F9 /* ZXVideoPlayerController.m in Sources */, 461 | 296FA99F1CC7126C003FC0EA /* main.m in Sources */, 462 | ); 463 | runOnlyForDeploymentPostprocessing = 0; 464 | }; 465 | 296FA9AF1CC7126D003FC0EA /* Sources */ = { 466 | isa = PBXSourcesBuildPhase; 467 | buildActionMask = 2147483647; 468 | files = ( 469 | 296FA9B81CC7126D003FC0EA /* ZXVideoPlayerTests.m in Sources */, 470 | ); 471 | runOnlyForDeploymentPostprocessing = 0; 472 | }; 473 | 296FA9BA1CC7126D003FC0EA /* Sources */ = { 474 | isa = PBXSourcesBuildPhase; 475 | buildActionMask = 2147483647; 476 | files = ( 477 | 296FA9C31CC7126D003FC0EA /* ZXVideoPlayerUITests.m in Sources */, 478 | ); 479 | runOnlyForDeploymentPostprocessing = 0; 480 | }; 481 | /* End PBXSourcesBuildPhase section */ 482 | 483 | /* Begin PBXTargetDependency section */ 484 | 296FA9B51CC7126D003FC0EA /* PBXTargetDependency */ = { 485 | isa = PBXTargetDependency; 486 | target = 296FA9991CC7126C003FC0EA /* ZXVideoPlayer */; 487 | targetProxy = 296FA9B41CC7126D003FC0EA /* PBXContainerItemProxy */; 488 | }; 489 | 296FA9C01CC7126D003FC0EA /* PBXTargetDependency */ = { 490 | isa = PBXTargetDependency; 491 | target = 296FA9991CC7126C003FC0EA /* ZXVideoPlayer */; 492 | targetProxy = 296FA9BF1CC7126D003FC0EA /* PBXContainerItemProxy */; 493 | }; 494 | /* End PBXTargetDependency section */ 495 | 496 | /* Begin PBXVariantGroup section */ 497 | 296FA9A61CC7126D003FC0EA /* Main.storyboard */ = { 498 | isa = PBXVariantGroup; 499 | children = ( 500 | 296FA9A71CC7126D003FC0EA /* Base */, 501 | ); 502 | name = Main.storyboard; 503 | sourceTree = ""; 504 | }; 505 | 296FA9AB1CC7126D003FC0EA /* LaunchScreen.storyboard */ = { 506 | isa = PBXVariantGroup; 507 | children = ( 508 | 296FA9AC1CC7126D003FC0EA /* Base */, 509 | ); 510 | name = LaunchScreen.storyboard; 511 | sourceTree = ""; 512 | }; 513 | /* End PBXVariantGroup section */ 514 | 515 | /* Begin XCBuildConfiguration section */ 516 | 296FA9C51CC7126D003FC0EA /* Debug */ = { 517 | isa = XCBuildConfiguration; 518 | buildSettings = { 519 | ALWAYS_SEARCH_USER_PATHS = NO; 520 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 521 | CLANG_CXX_LIBRARY = "libc++"; 522 | CLANG_ENABLE_MODULES = YES; 523 | CLANG_ENABLE_OBJC_ARC = YES; 524 | CLANG_WARN_BOOL_CONVERSION = YES; 525 | CLANG_WARN_CONSTANT_CONVERSION = YES; 526 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 527 | CLANG_WARN_EMPTY_BODY = YES; 528 | CLANG_WARN_ENUM_CONVERSION = YES; 529 | CLANG_WARN_INT_CONVERSION = YES; 530 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 531 | CLANG_WARN_UNREACHABLE_CODE = YES; 532 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 533 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 534 | COPY_PHASE_STRIP = NO; 535 | DEBUG_INFORMATION_FORMAT = dwarf; 536 | ENABLE_STRICT_OBJC_MSGSEND = YES; 537 | ENABLE_TESTABILITY = YES; 538 | GCC_C_LANGUAGE_STANDARD = gnu99; 539 | GCC_DYNAMIC_NO_PIC = NO; 540 | GCC_NO_COMMON_BLOCKS = YES; 541 | GCC_OPTIMIZATION_LEVEL = 0; 542 | GCC_PREPROCESSOR_DEFINITIONS = ( 543 | "DEBUG=1", 544 | "$(inherited)", 545 | ); 546 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 547 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 548 | GCC_WARN_UNDECLARED_SELECTOR = YES; 549 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 550 | GCC_WARN_UNUSED_FUNCTION = YES; 551 | GCC_WARN_UNUSED_VARIABLE = YES; 552 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 553 | MTL_ENABLE_DEBUG_INFO = YES; 554 | ONLY_ACTIVE_ARCH = YES; 555 | SDKROOT = iphoneos; 556 | }; 557 | name = Debug; 558 | }; 559 | 296FA9C61CC7126D003FC0EA /* Release */ = { 560 | isa = XCBuildConfiguration; 561 | buildSettings = { 562 | ALWAYS_SEARCH_USER_PATHS = NO; 563 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 564 | CLANG_CXX_LIBRARY = "libc++"; 565 | CLANG_ENABLE_MODULES = YES; 566 | CLANG_ENABLE_OBJC_ARC = YES; 567 | CLANG_WARN_BOOL_CONVERSION = YES; 568 | CLANG_WARN_CONSTANT_CONVERSION = YES; 569 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 570 | CLANG_WARN_EMPTY_BODY = YES; 571 | CLANG_WARN_ENUM_CONVERSION = YES; 572 | CLANG_WARN_INT_CONVERSION = YES; 573 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 574 | CLANG_WARN_UNREACHABLE_CODE = YES; 575 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 576 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 577 | COPY_PHASE_STRIP = NO; 578 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 579 | ENABLE_NS_ASSERTIONS = NO; 580 | ENABLE_STRICT_OBJC_MSGSEND = YES; 581 | GCC_C_LANGUAGE_STANDARD = gnu99; 582 | GCC_NO_COMMON_BLOCKS = YES; 583 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 584 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 585 | GCC_WARN_UNDECLARED_SELECTOR = YES; 586 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 587 | GCC_WARN_UNUSED_FUNCTION = YES; 588 | GCC_WARN_UNUSED_VARIABLE = YES; 589 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 590 | MTL_ENABLE_DEBUG_INFO = NO; 591 | SDKROOT = iphoneos; 592 | VALIDATE_PRODUCT = YES; 593 | }; 594 | name = Release; 595 | }; 596 | 296FA9C81CC7126D003FC0EA /* Debug */ = { 597 | isa = XCBuildConfiguration; 598 | buildSettings = { 599 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 600 | INFOPLIST_FILE = ZXVideoPlayer/Info.plist; 601 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 602 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 603 | PRODUCT_BUNDLE_IDENTIFIER = com.shawn.ZXVideoPlayer; 604 | PRODUCT_NAME = "$(TARGET_NAME)"; 605 | }; 606 | name = Debug; 607 | }; 608 | 296FA9C91CC7126D003FC0EA /* Release */ = { 609 | isa = XCBuildConfiguration; 610 | buildSettings = { 611 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 612 | INFOPLIST_FILE = ZXVideoPlayer/Info.plist; 613 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 614 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 615 | PRODUCT_BUNDLE_IDENTIFIER = com.shawn.ZXVideoPlayer; 616 | PRODUCT_NAME = "$(TARGET_NAME)"; 617 | }; 618 | name = Release; 619 | }; 620 | 296FA9CB1CC7126D003FC0EA /* Debug */ = { 621 | isa = XCBuildConfiguration; 622 | buildSettings = { 623 | BUNDLE_LOADER = "$(TEST_HOST)"; 624 | INFOPLIST_FILE = ZXVideoPlayerTests/Info.plist; 625 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 626 | PRODUCT_BUNDLE_IDENTIFIER = com.shawn.ZXVideoPlayerTests; 627 | PRODUCT_NAME = "$(TARGET_NAME)"; 628 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ZXVideoPlayer.app/ZXVideoPlayer"; 629 | }; 630 | name = Debug; 631 | }; 632 | 296FA9CC1CC7126D003FC0EA /* Release */ = { 633 | isa = XCBuildConfiguration; 634 | buildSettings = { 635 | BUNDLE_LOADER = "$(TEST_HOST)"; 636 | INFOPLIST_FILE = ZXVideoPlayerTests/Info.plist; 637 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 638 | PRODUCT_BUNDLE_IDENTIFIER = com.shawn.ZXVideoPlayerTests; 639 | PRODUCT_NAME = "$(TARGET_NAME)"; 640 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ZXVideoPlayer.app/ZXVideoPlayer"; 641 | }; 642 | name = Release; 643 | }; 644 | 296FA9CE1CC7126D003FC0EA /* Debug */ = { 645 | isa = XCBuildConfiguration; 646 | buildSettings = { 647 | INFOPLIST_FILE = ZXVideoPlayerUITests/Info.plist; 648 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 649 | PRODUCT_BUNDLE_IDENTIFIER = com.shawn.ZXVideoPlayerUITests; 650 | PRODUCT_NAME = "$(TARGET_NAME)"; 651 | TEST_TARGET_NAME = ZXVideoPlayer; 652 | USES_XCTRUNNER = YES; 653 | }; 654 | name = Debug; 655 | }; 656 | 296FA9CF1CC7126D003FC0EA /* Release */ = { 657 | isa = XCBuildConfiguration; 658 | buildSettings = { 659 | INFOPLIST_FILE = ZXVideoPlayerUITests/Info.plist; 660 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 661 | PRODUCT_BUNDLE_IDENTIFIER = com.shawn.ZXVideoPlayerUITests; 662 | PRODUCT_NAME = "$(TARGET_NAME)"; 663 | TEST_TARGET_NAME = ZXVideoPlayer; 664 | USES_XCTRUNNER = YES; 665 | }; 666 | name = Release; 667 | }; 668 | /* End XCBuildConfiguration section */ 669 | 670 | /* Begin XCConfigurationList section */ 671 | 296FA9951CC7126C003FC0EA /* Build configuration list for PBXProject "ZXVideoPlayer" */ = { 672 | isa = XCConfigurationList; 673 | buildConfigurations = ( 674 | 296FA9C51CC7126D003FC0EA /* Debug */, 675 | 296FA9C61CC7126D003FC0EA /* Release */, 676 | ); 677 | defaultConfigurationIsVisible = 0; 678 | defaultConfigurationName = Release; 679 | }; 680 | 296FA9C71CC7126D003FC0EA /* Build configuration list for PBXNativeTarget "ZXVideoPlayer" */ = { 681 | isa = XCConfigurationList; 682 | buildConfigurations = ( 683 | 296FA9C81CC7126D003FC0EA /* Debug */, 684 | 296FA9C91CC7126D003FC0EA /* Release */, 685 | ); 686 | defaultConfigurationIsVisible = 0; 687 | defaultConfigurationName = Release; 688 | }; 689 | 296FA9CA1CC7126D003FC0EA /* Build configuration list for PBXNativeTarget "ZXVideoPlayerTests" */ = { 690 | isa = XCConfigurationList; 691 | buildConfigurations = ( 692 | 296FA9CB1CC7126D003FC0EA /* Debug */, 693 | 296FA9CC1CC7126D003FC0EA /* Release */, 694 | ); 695 | defaultConfigurationIsVisible = 0; 696 | defaultConfigurationName = Release; 697 | }; 698 | 296FA9CD1CC7126D003FC0EA /* Build configuration list for PBXNativeTarget "ZXVideoPlayerUITests" */ = { 699 | isa = XCConfigurationList; 700 | buildConfigurations = ( 701 | 296FA9CE1CC7126D003FC0EA /* Debug */, 702 | 296FA9CF1CC7126D003FC0EA /* Release */, 703 | ); 704 | defaultConfigurationIsVisible = 0; 705 | defaultConfigurationName = Release; 706 | }; 707 | /* End XCConfigurationList section */ 708 | }; 709 | rootObject = 296FA9921CC7126C003FC0EA /* Project object */; 710 | } 711 | -------------------------------------------------------------------------------- /ZXVideoPlayer.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ZXVideoPlayer.xcodeproj/project.xcworkspace/xcuserdata/Shawn.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0summer0/VideoPlayerDemo/6623b7fafc136f98dd3784b849c60f05ac5e15ce/ZXVideoPlayer.xcodeproj/project.xcworkspace/xcuserdata/Shawn.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /ZXVideoPlayer.xcodeproj/xcuserdata/Shawn.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /ZXVideoPlayer.xcodeproj/xcuserdata/Shawn.xcuserdatad/xcschemes/ZXVideoPlayer.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 74 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /ZXVideoPlayer.xcodeproj/xcuserdata/Shawn.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | ZXVideoPlayer.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 296FA9991CC7126C003FC0EA 16 | 17 | primary 18 | 19 | 20 | 296FA9B21CC7126D003FC0EA 21 | 22 | primary 23 | 24 | 25 | 296FA9BD1CC7126D003FC0EA 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /ZXVideoPlayer/150511_JiveBike.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0summer0/VideoPlayerDemo/6623b7fafc136f98dd3784b849c60f05ac5e15ce/ZXVideoPlayer/150511_JiveBike.mov -------------------------------------------------------------------------------- /ZXVideoPlayer/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // ZXVideoPlayer 4 | // 5 | // Created by Shawn on 16/4/20. 6 | // Copyright © 2016年 Shawn. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /ZXVideoPlayer/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // ZXVideoPlayer 4 | // 5 | // Created by Shawn on 16/4/20. 6 | // Copyright © 2016年 Shawn. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /ZXVideoPlayer/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 | } -------------------------------------------------------------------------------- /ZXVideoPlayer/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 | -------------------------------------------------------------------------------- /ZXVideoPlayer/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 27 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /ZXVideoPlayer/BaseTabBarController.h: -------------------------------------------------------------------------------- 1 | // 2 | // BaseTabBarController.h 3 | // ZXVideoPlayer 4 | // 5 | // Created by Shawn on 16/4/29. 6 | // Copyright © 2016年 Shawn. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface BaseTabBarController : UITabBarController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /ZXVideoPlayer/BaseTabBarController.m: -------------------------------------------------------------------------------- 1 | // 2 | // BaseTabBarController.m 3 | // ZXVideoPlayer 4 | // 5 | // Created by Shawn on 16/4/29. 6 | // Copyright © 2016年 Shawn. All rights reserved. 7 | // 8 | 9 | #import "BaseTabBarController.h" 10 | #import "ViewController.h" 11 | #import "VideoPlayViewController.h" 12 | 13 | @interface BaseTabBarController () 14 | 15 | @end 16 | 17 | @implementation BaseTabBarController 18 | 19 | - (void)viewDidLoad { 20 | [super viewDidLoad]; 21 | // Do any additional setup after loading the view. 22 | } 23 | 24 | - (BOOL)shouldAutorotate 25 | { 26 | UINavigationController *nav = self.viewControllers[0]; 27 | if ([nav.topViewController isKindOfClass:[VideoPlayViewController class]]) { 28 | return ![[[NSUserDefaults standardUserDefaults] objectForKey:@"ZXVideoPlayer_DidLockScreen"] boolValue]; 29 | } 30 | 31 | return YES; 32 | } 33 | 34 | - (UIInterfaceOrientationMask)supportedInterfaceOrientations 35 | { 36 | UINavigationController *nav = self.viewControllers[0]; 37 | if ([nav.topViewController isKindOfClass:[ViewController class]]) { 38 | return UIInterfaceOrientationMaskPortrait; 39 | } 40 | 41 | return UIInterfaceOrientationMaskAllButUpsideDown; 42 | } 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /ZXVideoPlayer/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 | NSAppTransportSecurity 26 | 27 | NSAllowsArbitraryLoads 28 | 29 | 30 | UILaunchStoryboardName 31 | LaunchScreen 32 | UIMainStoryboardFile 33 | Main 34 | UIRequiredDeviceCapabilities 35 | 36 | armv7 37 | 38 | UISupportedInterfaceOrientations 39 | 40 | UIInterfaceOrientationPortrait 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | UIViewControllerBasedStatusBarAppearance 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /ZXVideoPlayer/VideoPlayViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // VideoPlayViewController.h 3 | // ZXVideoPlayer 4 | // 5 | // Created by Shawn on 16/4/29. 6 | // Copyright © 2016年 Shawn. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class ZXVideo; 12 | @interface VideoPlayViewController : UIViewController 13 | 14 | @property (nonatomic, strong, readwrite) ZXVideo *video; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /ZXVideoPlayer/VideoPlayViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // VideoPlayViewController.m 3 | // ZXVideoPlayer 4 | // 5 | // Created by Shawn on 16/4/29. 6 | // Copyright © 2016年 Shawn. All rights reserved. 7 | // 8 | 9 | #import "VideoPlayViewController.h" 10 | #import "ZXVideoPlayerController.h" 11 | #import "ZXVideo.h" 12 | 13 | @interface VideoPlayViewController () 14 | 15 | @property (nonatomic, strong) ZXVideoPlayerController *videoController; 16 | 17 | @end 18 | 19 | @implementation VideoPlayViewController 20 | 21 | - (void)viewDidLoad { 22 | [super viewDidLoad]; 23 | 24 | [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent]; 25 | [self.navigationController setNavigationBarHidden:YES animated:YES]; 26 | 27 | self.view.backgroundColor = [UIColor lightGrayColor]; 28 | 29 | [self playVideo]; 30 | } 31 | 32 | - (void)playVideo 33 | { 34 | if (!self.videoController) { 35 | self.videoController = [[ZXVideoPlayerController alloc] initWithFrame:CGRectMake(0, 0, kZXVideoPlayerOriginalWidth, kZXVideoPlayerOriginalHeight)]; 36 | 37 | __weak typeof(self) weakSelf = self; 38 | self.videoController.videoPlayerGoBackBlock = ^{ 39 | __strong typeof(self) strongSelf = weakSelf; 40 | 41 | [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault]; 42 | 43 | [strongSelf.navigationController popViewControllerAnimated:YES]; 44 | [strongSelf.navigationController setNavigationBarHidden:NO animated:YES]; 45 | 46 | [[NSUserDefaults standardUserDefaults] setObject:@0 forKey:@"ZXVideoPlayer_DidLockScreen"]; 47 | 48 | strongSelf.videoController = nil; 49 | }; 50 | 51 | self.videoController.videoPlayerWillChangeToOriginalScreenModeBlock = ^(){ 52 | NSLog(@"切换为竖屏模式"); 53 | }; 54 | self.videoController.videoPlayerWillChangeToFullScreenModeBlock = ^(){ 55 | NSLog(@"切换为全屏模式"); 56 | }; 57 | 58 | [self.videoController showInView:self.view]; 59 | } 60 | 61 | self.videoController.video = self.video; 62 | } 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /ZXVideoPlayer/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // ZXVideoPlayer 4 | // 5 | // Created by Shawn on 16/4/20. 6 | // Copyright © 2016年 Shawn. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /ZXVideoPlayer/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // ZXVideoPlayer 4 | // 5 | // Created by Shawn on 16/4/20. 6 | // Copyright © 2016年 Shawn. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "VideoPlayViewController.h" 11 | #import "ZXVideo.h" 12 | 13 | @interface ViewController () 14 | 15 | @end 16 | 17 | @implementation ViewController 18 | 19 | - (void)viewDidLoad { 20 | [super viewDidLoad]; 21 | self.title = @"Home"; 22 | self.tabBarItem.title = @"Home"; 23 | } 24 | 25 | - (IBAction)playLocalVideo:(id)sender { 26 | 27 | NSURL *videoURL = [[NSBundle mainBundle] URLForResource:@"150511_JiveBike" withExtension:@"mov"]; 28 | ZXVideo *video = [[ZXVideo alloc] init]; 29 | video.playUrl = videoURL.absoluteString; 30 | video.title = @"Test"; 31 | 32 | VideoPlayViewController *vc = [[VideoPlayViewController alloc] init]; 33 | vc.video = video; 34 | vc.hidesBottomBarWhenPushed = YES; 35 | [self.navigationController pushViewController:vc animated:YES]; 36 | } 37 | 38 | - (IBAction)playRemoteVideo:(id)sender { 39 | 40 | ZXVideo *video = [[ZXVideo alloc] init]; 41 | video.playUrl = @"http://baobab.wdjcdn.com/1451897812703c.mp4"; 42 | video.title = @"Rollin'Wild 圆滚滚的"; 43 | 44 | VideoPlayViewController *vc = [[VideoPlayViewController alloc] init]; 45 | vc.video = video; 46 | vc.hidesBottomBarWhenPushed = YES; 47 | [self.navigationController pushViewController:vc animated:YES]; 48 | } 49 | 50 | 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/Assets/kr-video-player-close@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0summer0/VideoPlayerDemo/6623b7fafc136f98dd3784b849c60f05ac5e15ce/ZXVideoPlayer/ZXVideoPlayer/Assets/kr-video-player-close@2x.png -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/Assets/kr-video-player-close@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0summer0/VideoPlayerDemo/6623b7fafc136f98dd3784b849c60f05ac5e15ce/ZXVideoPlayer/ZXVideoPlayer/Assets/kr-video-player-close@3x.png -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/Assets/kr-video-player-fullscreen@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0summer0/VideoPlayerDemo/6623b7fafc136f98dd3784b849c60f05ac5e15ce/ZXVideoPlayer/ZXVideoPlayer/Assets/kr-video-player-fullscreen@2x.png -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/Assets/kr-video-player-fullscreen@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0summer0/VideoPlayerDemo/6623b7fafc136f98dd3784b849c60f05ac5e15ce/ZXVideoPlayer/ZXVideoPlayer/Assets/kr-video-player-fullscreen@3x.png -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/Assets/kr-video-player-pause@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0summer0/VideoPlayerDemo/6623b7fafc136f98dd3784b849c60f05ac5e15ce/ZXVideoPlayer/ZXVideoPlayer/Assets/kr-video-player-pause@2x.png -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/Assets/kr-video-player-pause@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0summer0/VideoPlayerDemo/6623b7fafc136f98dd3784b849c60f05ac5e15ce/ZXVideoPlayer/ZXVideoPlayer/Assets/kr-video-player-pause@3x.png -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/Assets/kr-video-player-play@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0summer0/VideoPlayerDemo/6623b7fafc136f98dd3784b849c60f05ac5e15ce/ZXVideoPlayer/ZXVideoPlayer/Assets/kr-video-player-play@2x.png -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/Assets/kr-video-player-play@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0summer0/VideoPlayerDemo/6623b7fafc136f98dd3784b849c60f05ac5e15ce/ZXVideoPlayer/ZXVideoPlayer/Assets/kr-video-player-play@3x.png -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/Assets/kr-video-player-point@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0summer0/VideoPlayerDemo/6623b7fafc136f98dd3784b849c60f05ac5e15ce/ZXVideoPlayer/ZXVideoPlayer/Assets/kr-video-player-point@2x.png -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/Assets/kr-video-player-point@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0summer0/VideoPlayerDemo/6623b7fafc136f98dd3784b849c60f05ac5e15ce/ZXVideoPlayer/ZXVideoPlayer/Assets/kr-video-player-point@3x.png -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/Assets/kr-video-player-shrinkscreen@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0summer0/VideoPlayerDemo/6623b7fafc136f98dd3784b849c60f05ac5e15ce/ZXVideoPlayer/ZXVideoPlayer/Assets/kr-video-player-shrinkscreen@2x.png -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/Assets/kr-video-player-shrinkscreen@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0summer0/VideoPlayerDemo/6623b7fafc136f98dd3784b849c60f05ac5e15ce/ZXVideoPlayer/ZXVideoPlayer/Assets/kr-video-player-shrinkscreen@3x.png -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/Assets/zx-video-banner-back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0summer0/VideoPlayerDemo/6623b7fafc136f98dd3784b849c60f05ac5e15ce/ZXVideoPlayer/ZXVideoPlayer/Assets/zx-video-banner-back.png -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/Assets/zx-video-banner-back@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0summer0/VideoPlayerDemo/6623b7fafc136f98dd3784b849c60f05ac5e15ce/ZXVideoPlayer/ZXVideoPlayer/Assets/zx-video-banner-back@2x.png -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/Assets/zx-video-player-brightness@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0summer0/VideoPlayerDemo/6623b7fafc136f98dd3784b849c60f05ac5e15ce/ZXVideoPlayer/ZXVideoPlayer/Assets/zx-video-player-brightness@2x.png -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/Assets/zx-video-player-brightness@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0summer0/VideoPlayerDemo/6623b7fafc136f98dd3784b849c60f05ac5e15ce/ZXVideoPlayer/ZXVideoPlayer/Assets/zx-video-player-brightness@3x.png -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/Assets/zx-video-player-fastForward@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0summer0/VideoPlayerDemo/6623b7fafc136f98dd3784b849c60f05ac5e15ce/ZXVideoPlayer/ZXVideoPlayer/Assets/zx-video-player-fastForward@2x.png -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/Assets/zx-video-player-fastForward@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0summer0/VideoPlayerDemo/6623b7fafc136f98dd3784b849c60f05ac5e15ce/ZXVideoPlayer/ZXVideoPlayer/Assets/zx-video-player-fastForward@3x.png -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/Assets/zx-video-player-lock@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0summer0/VideoPlayerDemo/6623b7fafc136f98dd3784b849c60f05ac5e15ce/ZXVideoPlayer/ZXVideoPlayer/Assets/zx-video-player-lock@2x.png -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/Assets/zx-video-player-lock@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0summer0/VideoPlayerDemo/6623b7fafc136f98dd3784b849c60f05ac5e15ce/ZXVideoPlayer/ZXVideoPlayer/Assets/zx-video-player-lock@3x.png -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/Assets/zx-video-player-rewind@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0summer0/VideoPlayerDemo/6623b7fafc136f98dd3784b849c60f05ac5e15ce/ZXVideoPlayer/ZXVideoPlayer/Assets/zx-video-player-rewind@2x.png -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/Assets/zx-video-player-rewind@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0summer0/VideoPlayerDemo/6623b7fafc136f98dd3784b849c60f05ac5e15ce/ZXVideoPlayer/ZXVideoPlayer/Assets/zx-video-player-rewind@3x.png -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/Assets/zx-video-player-unlock@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0summer0/VideoPlayerDemo/6623b7fafc136f98dd3784b849c60f05ac5e15ce/ZXVideoPlayer/ZXVideoPlayer/Assets/zx-video-player-unlock@2x.png -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/Assets/zx-video-player-unlock@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0summer0/VideoPlayerDemo/6623b7fafc136f98dd3784b849c60f05ac5e15ce/ZXVideoPlayer/ZXVideoPlayer/Assets/zx-video-player-unlock@3x.png -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/Assets/zx-video-player-volume@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0summer0/VideoPlayerDemo/6623b7fafc136f98dd3784b849c60f05ac5e15ce/ZXVideoPlayer/ZXVideoPlayer/Assets/zx-video-player-volume@2x.png -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/Assets/zx-video-player-volume@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0summer0/VideoPlayerDemo/6623b7fafc136f98dd3784b849c60f05ac5e15ce/ZXVideoPlayer/ZXVideoPlayer/Assets/zx-video-player-volume@3x.png -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/Assets/zx-video-player-volumeMute@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0summer0/VideoPlayerDemo/6623b7fafc136f98dd3784b849c60f05ac5e15ce/ZXVideoPlayer/ZXVideoPlayer/Assets/zx-video-player-volumeMute@2x.png -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/Assets/zx-video-player-volumeMute@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0summer0/VideoPlayerDemo/6623b7fafc136f98dd3784b849c60f05ac5e15ce/ZXVideoPlayer/ZXVideoPlayer/Assets/zx-video-player-volumeMute@3x.png -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/ZXVideo.h: -------------------------------------------------------------------------------- 1 | // 2 | // ZXVideo.h 3 | // ZXVideoPlayer 4 | // 5 | // Created by Shawn on 16/6/22. 6 | // Copyright © 2016年 Shawn. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface ZXVideo : NSObject 13 | 14 | /// 标题 15 | @property (nonatomic, copy, readwrite) NSString *title; 16 | /// 播放地址 17 | @property (nonatomic, copy, readwrite) NSString *playUrl; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/ZXVideo.m: -------------------------------------------------------------------------------- 1 | // 2 | // ZXVideo.m 3 | // ZXVideoPlayer 4 | // 5 | // Created by Shawn on 16/6/22. 6 | // Copyright © 2016年 Shawn. All rights reserved. 7 | // 8 | 9 | #import "ZXVideo.h" 10 | 11 | @implementation ZXVideo 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/ZXVideoPlayerBatteryView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ZXVideoPlayerBatteryView.h 3 | // ZXVideoPlayer 4 | // 5 | // Created by Shawn on 16/4/23. 6 | // Copyright © 2016年 Shawn. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | static const CGFloat kVideoBatteryViewWidth = 30.0; 12 | static const CGFloat kVideoBatteryViewHeight = 12.0; 13 | 14 | @interface ZXVideoPlayerBatteryView : UIView 15 | 16 | /// 设备电量 17 | @property (nonatomic, assign, readwrite) CGFloat batteryLevel; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/ZXVideoPlayerBatteryView.m: -------------------------------------------------------------------------------- 1 | // 2 | // ZXVideoPlayerBatteryView.m 3 | // ZXVideoPlayer 4 | // 5 | // Created by Shawn on 16/4/23. 6 | // Copyright © 2016年 Shawn. All rights reserved. 7 | // 8 | 9 | #import "ZXVideoPlayerBatteryView.h" 10 | 11 | @implementation ZXVideoPlayerBatteryView 12 | 13 | - (void)dealloc 14 | { 15 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 16 | } 17 | 18 | - (instancetype)initWithFrame:(CGRect)frame 19 | { 20 | self = [super initWithFrame:frame]; 21 | if (self) { 22 | self.backgroundColor = [UIColor clearColor]; 23 | [self setInitialBatteryLevel]; 24 | [self addBatteryObserver]; 25 | } 26 | return self; 27 | } 28 | 29 | - (void)drawRect:(CGRect)rect 30 | { 31 | CGFloat borderWidth = 1.0; // 边框线宽 32 | CGFloat margin = 1.0; // 电量填充rect距边框的距离 33 | CGFloat blockWidth = 2.0; 34 | CGFloat blockHeight = 6.0; 35 | 36 | [[UIColor whiteColor] set]; 37 | 38 | // 电池矩形框(self内边缘绘制边框) 39 | UIBezierPath *borderPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(borderWidth / 2, borderWidth / 2, CGRectGetWidth(self.bounds) - borderWidth - blockWidth, CGRectGetHeight(self.bounds) - borderWidth) cornerRadius:3]; 40 | borderPath.lineWidth = borderWidth; 41 | [borderPath stroke]; 42 | 43 | // 电池正极 (只有 topRight && bottomRight 两个角有圆角) 44 | UIBezierPath *blockPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(CGRectGetMaxX(borderPath.bounds) + borderWidth / 2, CGRectGetMidY(borderPath.bounds) - blockHeight / 2, blockWidth, blockHeight) byRoundingCorners:UIRectCornerTopRight | UIRectCornerBottomRight cornerRadii:CGSizeMake(blockWidth / 2, blockHeight / 2)]; 45 | blockPath.lineWidth = 0.01; 46 | [blockPath fill]; 47 | [blockPath stroke]; 48 | 49 | // 填充电量 (距离边框保留magin单位宽度) 50 | CGContextFillRect(UIGraphicsGetCurrentContext(), CGRectMake(borderWidth + margin, borderWidth + margin, ((CGRectGetWidth(borderPath.bounds) - borderWidth - margin) - margin) * self.batteryLevel, CGRectGetHeight(self.bounds) - (borderWidth + margin) * 2)); 51 | } 52 | 53 | - (void)setInitialBatteryLevel 54 | { 55 | [UIDevice currentDevice].batteryMonitoringEnabled = YES; 56 | self.batteryLevel = [UIDevice currentDevice].batteryLevel; 57 | } 58 | 59 | - (void)addBatteryObserver 60 | { 61 | // or use [[UIDevice currentDevice] addObserver:self forKeyPath:@"batteryLevel" options:NSKeyValueObservingOptionNew context:NULL]; 62 | // 以上方法调用次数相对较多,所以修改为仅当值改变时重绘 63 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onBatteryLevelChanged:) name:UIDeviceBatteryLevelDidChangeNotification object:nil]; 64 | } 65 | 66 | - (void)onBatteryLevelChanged:(NSNotification *)noti 67 | { 68 | self.batteryLevel = ((UIDevice *)noti.object).batteryLevel; 69 | [self setNeedsDisplay]; // redrawn battery view 70 | } 71 | 72 | @end 73 | -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/ZXVideoPlayerBrightnessView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ZXVideoPlayerBrightnessView.h 3 | // ZXVideoPlayer 4 | // 5 | // Created by Shawn on 16/4/21. 6 | // Copyright © 2016年 Shawn. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | static const CGFloat kVideoBrightnessIndicatorViewSide = 118.0; 12 | 13 | @interface ZXVideoPlayerBrightnessView : UIView 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/ZXVideoPlayerBrightnessView.m: -------------------------------------------------------------------------------- 1 | // 2 | // ZXVideoPlayerBrightnessView.m 3 | // ZXVideoPlayer 4 | // 5 | // Created by Shawn on 16/4/21. 6 | // Copyright © 2016年 Shawn. All rights reserved. 7 | // 8 | 9 | #import "ZXVideoPlayerBrightnessView.h" 10 | #import "ZXVideoPlayerControlView.h" 11 | 12 | static const CGFloat kViewSpacing = 21.0; 13 | static const CGFloat kBrightnessIndicatorAutoFadeOutTimeInterval = 1.0; 14 | 15 | @interface ZXVideoPlayerBrightnessView () 16 | 17 | @property (nonatomic, strong) NSMutableArray *blocksArray; 18 | 19 | @end 20 | 21 | @implementation ZXVideoPlayerBrightnessView 22 | 23 | - (void)dealloc 24 | { 25 | [[UIScreen mainScreen] removeObserver:self forKeyPath:@"brightness"]; 26 | } 27 | 28 | - (instancetype)initWithFrame:(CGRect)frame 29 | { 30 | self = [super initWithFrame:frame]; 31 | if (self) { 32 | self.hidden = YES; 33 | self.layer.cornerRadius = 5; 34 | self.layer.masksToBounds = YES; 35 | self.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.3]; 36 | 37 | [self createBrightnessIndicator]; 38 | [self configScreenBrightnessObserver]; 39 | } 40 | return self; 41 | } 42 | 43 | - (void)configScreenBrightnessObserver 44 | { 45 | [[UIScreen mainScreen] addObserver:self 46 | forKeyPath:@"brightness" 47 | options:NSKeyValueObservingOptionNew 48 | context:NULL]; 49 | } 50 | 51 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 52 | { 53 | CGFloat brightness = [change[@"new"] floatValue]; 54 | [self updateBrightnessIndicator:brightness]; 55 | } 56 | 57 | - (void)createBrightnessIndicator 58 | { 59 | // 亮度图标 60 | UIImageView *brightnessImageView = [[UIImageView alloc] initWithFrame:CGRectMake((kVideoBrightnessIndicatorViewSide - 50) / 2, kViewSpacing, 50, 50)]; 61 | [brightnessImageView setImage:[UIImage imageNamed:@"zx-video-player-brightness"]]; 62 | [self addSubview:brightnessImageView]; 63 | 64 | // 亮度条 65 | self.blocksArray = [NSMutableArray arrayWithCapacity:16]; 66 | 67 | UIView *blockBackgroundView = [[UIView alloc] initWithFrame:CGRectMake((kVideoVolumeIndicatorViewSide - 105) / 2, 50 + kViewSpacing * 2, 105, 2.75 + 2)]; 68 | blockBackgroundView.backgroundColor = [UIColor colorWithRed:0.25f green:0.22f blue:0.21f alpha:0.65]; 69 | [self addSubview:blockBackgroundView]; 70 | 71 | CGFloat margin = 1; 72 | CGFloat blockW = 5.5; 73 | CGFloat blockH = 2.75; 74 | 75 | for (int i = 0; i < 16; i++) { 76 | CGFloat locX = i * (blockW + margin) + margin; 77 | UIImageView *blockView = [[UIImageView alloc] init]; 78 | blockView.backgroundColor = [UIColor whiteColor]; 79 | blockView.frame = CGRectMake(locX, margin, blockW, blockH); 80 | 81 | [blockBackgroundView addSubview:blockView]; 82 | [self.blocksArray addObject:blockView]; 83 | } 84 | } 85 | 86 | - (void)updateBrightnessIndicator:(CGFloat)value 87 | { 88 | self.hidden = NO; 89 | 90 | // 防止重叠显示 91 | if (self.superview.accessibilityIdentifier) { 92 | ZXVideoPlayerControlView *playerView = (ZXVideoPlayerControlView *)self.superview; 93 | playerView.timeIndicatorView.hidden = YES; 94 | playerView.volumeIndicatorView.hidden = YES; 95 | } else { 96 | self.superview.accessibilityIdentifier = @""; 97 | } 98 | 99 | CGFloat stage = 1 / 16.0; 100 | NSInteger level = value / stage; 101 | 102 | for (NSInteger i=0; i 10 | #import "ZXVideoPlayerTimeIndicatorView.h" 11 | #import "ZXVideoPlayerBrightnessView.h" 12 | #import "ZXVideoPlayerVolumeView.h" 13 | #import "ZXVideoPlayerBatteryView.h" 14 | 15 | #define kZXPlayerControlViewHideNotification @"ZXPlayerControlViewHideNotification" 16 | 17 | @protocol ZXVideoPlayerControlViewDelegage 18 | 19 | @optional 20 | - (void)videoPlayerControlViewDidTapped; 21 | 22 | @end 23 | 24 | @interface ZXVideoPlayerControlView : UIView 25 | 26 | @property (nonatomic, assign, readwrite) id delegate; 27 | 28 | @property (nonatomic, strong, readonly) UIView *topBar; 29 | @property (nonatomic, strong, readonly) UIView *bottomBar; 30 | @property (nonatomic, strong, readonly) UIButton *playButton; 31 | @property (nonatomic, strong, readonly) UIButton *pauseButton; 32 | @property (nonatomic, strong, readonly) UIButton *fullScreenButton; 33 | @property (nonatomic, strong, readonly) UIButton *shrinkScreenButton; 34 | @property (nonatomic, strong, readonly) UISlider *progressSlider; 35 | @property (nonatomic, strong, readonly) UILabel *timeLabel; 36 | @property (nonatomic, strong, readonly) UIActivityIndicatorView *indicatorView; 37 | 38 | @property (nonatomic, assign, readonly) BOOL isBarShowing; 39 | /// 返回按钮 40 | @property (nonatomic, strong, readwrite) UIButton *backButton; 41 | /// 屏幕锁定按钮 42 | @property (nonatomic, strong, readwrite) UIButton *lockButton; 43 | /// 缓冲进度条 44 | @property (nonatomic, strong, readwrite) UIProgressView *bufferProgressView; 45 | /// 快进、快退指示器 46 | @property (nonatomic, strong, readwrite) ZXVideoPlayerTimeIndicatorView *timeIndicatorView; 47 | /// 亮度指示器 48 | @property (nonatomic, strong, readwrite) ZXVideoPlayerBrightnessView *brightnessIndicatorView; 49 | /// 音量指示器 50 | @property (nonatomic, strong, readwrite) ZXVideoPlayerVolumeView *volumeIndicatorView; 51 | /// 电池条 52 | @property (nonatomic, strong, readwrite) ZXVideoPlayerBatteryView *batteryView; 53 | /// 标题 54 | @property (nonatomic, strong, readwrite) UILabel *titleLabel; 55 | 56 | - (void)animateHide; 57 | - (void)animateShow; 58 | - (void)autoFadeOutControlBar; 59 | - (void)cancelAutoFadeOutControlBar; 60 | 61 | @end 62 | -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/ZXVideoPlayerControlView.m: -------------------------------------------------------------------------------- 1 | // 2 | // ZXVideoPlayerControlView.m 3 | // ZXVideoPlayer 4 | // 5 | // Created by Shawn on 16/4/21. 6 | // Copyright © 2016年 Shawn. All rights reserved. 7 | // 8 | 9 | #import "ZXVideoPlayerControlView.h" 10 | 11 | static const CGFloat kVideoControlBarHeight = 20.0 + 30.0; 12 | static const CGFloat kVideoControlAnimationTimeInterval = 0.3; 13 | static const CGFloat kVideoControlTimeLabelFontSize = 10.0; 14 | static const CGFloat kVideoControlBarAutoFadeOutTimeInterval = 5.0; 15 | 16 | @interface ZXVideoPlayerControlView () 17 | 18 | @property (nonatomic, strong) UIView *topBar; 19 | @property (nonatomic, strong) UIView *bottomBar; 20 | @property (nonatomic, strong) UIButton *playButton; 21 | @property (nonatomic, strong) UIButton *pauseButton; 22 | @property (nonatomic, strong) UIButton *fullScreenButton; 23 | @property (nonatomic, strong) UIButton *shrinkScreenButton; 24 | @property (nonatomic, strong) UISlider *progressSlider; 25 | @property (nonatomic, strong) UILabel *timeLabel; 26 | @property (nonatomic, assign) BOOL isBarShowing; 27 | @property (nonatomic, strong) UIActivityIndicatorView *indicatorView; 28 | 29 | @end 30 | 31 | @implementation ZXVideoPlayerControlView 32 | 33 | - (instancetype)initWithFrame:(CGRect)frame 34 | { 35 | self = [super initWithFrame:frame]; 36 | if (self) { 37 | self.backgroundColor = [UIColor clearColor]; 38 | [self addSubview:self.topBar]; 39 | [self addSubview:self.bottomBar]; 40 | [self.bottomBar addSubview:self.playButton]; 41 | [self.bottomBar addSubview:self.pauseButton]; 42 | self.pauseButton.hidden = YES; 43 | [self.bottomBar addSubview:self.fullScreenButton]; 44 | [self.bottomBar addSubview:self.shrinkScreenButton]; 45 | self.shrinkScreenButton.hidden = YES; 46 | [self.bottomBar addSubview:self.progressSlider]; 47 | [self.bottomBar addSubview:self.timeLabel]; 48 | [self addSubview:self.indicatorView]; 49 | 50 | // 返回按钮 51 | [self.topBar addSubview:self.backButton]; 52 | // 锁定按钮 53 | [self.topBar addSubview:self.lockButton]; 54 | // 缓冲进度条 55 | [self.bottomBar insertSubview:self.bufferProgressView belowSubview:self.progressSlider]; 56 | // 快进、快退指示器 57 | [self addSubview:self.timeIndicatorView]; 58 | // 亮度指示器 59 | [self addSubview:self.brightnessIndicatorView]; 60 | // 音量指示器 61 | [self addSubview:self.volumeIndicatorView]; 62 | // 电池条 63 | // [self.topBar addSubview:self.batteryView]; 64 | // 标题 65 | [self.topBar addSubview:self.titleLabel]; 66 | 67 | UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTap:)]; 68 | [self addGestureRecognizer:tapGesture]; 69 | 70 | } 71 | return self; 72 | } 73 | 74 | - (void)layoutSubviews 75 | { 76 | [super layoutSubviews]; 77 | 78 | self.topBar.frame = CGRectMake(CGRectGetMinX(self.bounds), CGRectGetMinY(self.bounds), CGRectGetWidth(self.bounds), kVideoControlBarHeight); 79 | 80 | self.bottomBar.frame = CGRectMake(CGRectGetMinX(self.bounds), CGRectGetHeight(self.bounds) - kVideoControlBarHeight, CGRectGetWidth(self.bounds), kVideoControlBarHeight); 81 | 82 | self.playButton.frame = CGRectMake(CGRectGetMinX(self.bottomBar.bounds), CGRectGetHeight(self.bottomBar.bounds)/2 - CGRectGetHeight(self.playButton.bounds)/2, CGRectGetWidth(self.playButton.bounds), CGRectGetHeight(self.playButton.bounds)); 83 | 84 | self.pauseButton.frame = self.playButton.frame; 85 | 86 | self.fullScreenButton.frame = CGRectMake(CGRectGetWidth(self.bottomBar.bounds) - CGRectGetWidth(self.fullScreenButton.bounds), CGRectGetHeight(self.bottomBar.bounds)/2 - CGRectGetHeight(self.fullScreenButton.bounds)/2, CGRectGetWidth(self.fullScreenButton.bounds), CGRectGetHeight(self.fullScreenButton.bounds)); 87 | 88 | self.shrinkScreenButton.frame = self.fullScreenButton.frame; 89 | 90 | self.progressSlider.frame = CGRectMake(CGRectGetMaxX(self.playButton.frame), 0, CGRectGetMinX(self.fullScreenButton.frame) - CGRectGetMaxX(self.playButton.frame), kVideoControlBarHeight); 91 | 92 | self.timeLabel.frame = CGRectMake(CGRectGetMidX(self.progressSlider.frame), CGRectGetHeight(self.bottomBar.bounds) - CGRectGetHeight(self.timeLabel.bounds) - 2.0, CGRectGetWidth(self.progressSlider.bounds)/2, CGRectGetHeight(self.timeLabel.bounds)); 93 | 94 | self.indicatorView.center = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds)); 95 | 96 | // 返回按钮 97 | self.backButton.frame = CGRectMake(CGRectGetMinX(self.topBar.bounds), CGRectGetHeight(self.topBar.bounds) - 40, 40, 40); 98 | // 锁定按钮 99 | self.lockButton.frame = CGRectMake(CGRectGetMaxX(self.topBar.bounds) - 40 - 10, CGRectGetHeight(self.topBar.bounds) - 40, 40, 40); 100 | // 缓冲进度条 101 | self.bufferProgressView.bounds = CGRectMake(0, 0, self.progressSlider.bounds.size.width - 7, self.progressSlider.bounds.size.height); 102 | self.bufferProgressView.center = CGPointMake(self.progressSlider.center.x + 2, self.progressSlider.center.y); 103 | // 快进、快退指示器 104 | self.timeIndicatorView.center = self.indicatorView.center; 105 | // 亮度指示器 106 | self.brightnessIndicatorView.center = self.indicatorView.center; 107 | // 音量指示器 108 | self.volumeIndicatorView.center = self.indicatorView.center; 109 | // 电池条 110 | // self.batteryView.frame = CGRectMake(CGRectGetMinX(self.lockButton.frame) - CGRectGetWidth(self.batteryView.bounds) - 10, CGRectGetMidY(self.topBar.bounds) - CGRectGetHeight(self.batteryView.bounds) / 2, CGRectGetWidth(self.batteryView.bounds), CGRectGetHeight(self.batteryView.bounds)); 111 | // 标题 112 | self.titleLabel.frame = CGRectMake(CGRectGetWidth(self.backButton.bounds), 20, CGRectGetWidth(self.topBar.bounds) - CGRectGetWidth(self.backButton.bounds) - CGRectGetWidth(self.lockButton.bounds), kVideoControlBarHeight - 20); 113 | } 114 | 115 | - (void)didMoveToSuperview 116 | { 117 | [super didMoveToSuperview]; 118 | self.isBarShowing = YES; 119 | } 120 | 121 | #pragma mark - Public Method 122 | 123 | - (void)animateHide 124 | { 125 | if (!self.isBarShowing) { 126 | return; 127 | } 128 | 129 | [[NSNotificationCenter defaultCenter] postNotificationName:kZXPlayerControlViewHideNotification object:nil]; 130 | 131 | [UIView animateWithDuration:kVideoControlAnimationTimeInterval animations:^{ 132 | self.topBar.alpha = 0.0; 133 | self.bottomBar.alpha = 0.0; 134 | } completion:^(BOOL finished) { 135 | self.isBarShowing = NO; 136 | }]; 137 | } 138 | 139 | - (void)animateShow 140 | { 141 | if (self.isBarShowing) { 142 | return; 143 | } 144 | [UIView animateWithDuration:kVideoControlAnimationTimeInterval animations:^{ 145 | self.topBar.alpha = 1.0; 146 | self.bottomBar.alpha = 1.0; 147 | } completion:^(BOOL finished) { 148 | self.isBarShowing = YES; 149 | [self autoFadeOutControlBar]; 150 | }]; 151 | } 152 | 153 | - (void)autoFadeOutControlBar 154 | { 155 | if (!self.isBarShowing) { 156 | return; 157 | } 158 | [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(animateHide) object:nil]; 159 | [self performSelector:@selector(animateHide) withObject:nil afterDelay:kVideoControlBarAutoFadeOutTimeInterval]; 160 | } 161 | 162 | - (void)cancelAutoFadeOutControlBar 163 | { 164 | [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(animateHide) object:nil]; 165 | } 166 | 167 | #pragma mark - Tap Detection 168 | 169 | - (void)onTap:(UITapGestureRecognizer *)gesture 170 | { 171 | if (gesture.state == UIGestureRecognizerStateRecognized) { 172 | if (self.isBarShowing) { 173 | [self animateHide]; 174 | } else { 175 | [self animateShow]; 176 | [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationFade]; 177 | } 178 | } 179 | } 180 | 181 | #pragma mark - getters 182 | 183 | - (UIView *)topBar 184 | { 185 | if (!_topBar) { 186 | _topBar = [UIView new]; 187 | _topBar.accessibilityIdentifier = @"TopBar"; 188 | _topBar.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.3]; 189 | } 190 | return _topBar; 191 | } 192 | 193 | - (UIView *)bottomBar 194 | { 195 | if (!_bottomBar) { 196 | _bottomBar = [UIView new]; 197 | _bottomBar.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.3]; 198 | } 199 | return _bottomBar; 200 | } 201 | 202 | - (UIButton *)playButton 203 | { 204 | if (!_playButton) { 205 | _playButton = [UIButton buttonWithType:UIButtonTypeCustom]; 206 | [_playButton setImage:[UIImage imageNamed:@"kr-video-player-play"] forState:UIControlStateNormal]; 207 | _playButton.bounds = CGRectMake(0, 0, kVideoControlBarHeight, kVideoControlBarHeight); 208 | } 209 | return _playButton; 210 | } 211 | 212 | - (UIButton *)pauseButton 213 | { 214 | if (!_pauseButton) { 215 | _pauseButton = [UIButton buttonWithType:UIButtonTypeCustom]; 216 | [_pauseButton setImage:[UIImage imageNamed:@"kr-video-player-pause"] forState:UIControlStateNormal]; 217 | _pauseButton.bounds = CGRectMake(0, 0, kVideoControlBarHeight, kVideoControlBarHeight); 218 | } 219 | return _pauseButton; 220 | } 221 | 222 | - (UIButton *)fullScreenButton 223 | { 224 | if (!_fullScreenButton) { 225 | _fullScreenButton = [UIButton buttonWithType:UIButtonTypeCustom]; 226 | [_fullScreenButton setImage:[UIImage imageNamed:@"kr-video-player-fullscreen"] forState:UIControlStateNormal]; 227 | _fullScreenButton.bounds = CGRectMake(0, 0, kVideoControlBarHeight, kVideoControlBarHeight); 228 | } 229 | return _fullScreenButton; 230 | } 231 | 232 | - (UIButton *)shrinkScreenButton 233 | { 234 | if (!_shrinkScreenButton) { 235 | _shrinkScreenButton = [UIButton buttonWithType:UIButtonTypeCustom]; 236 | [_shrinkScreenButton setImage:[UIImage imageNamed:@"kr-video-player-shrinkscreen"] forState:UIControlStateNormal]; 237 | _shrinkScreenButton.bounds = CGRectMake(0, 0, kVideoControlBarHeight, kVideoControlBarHeight); 238 | } 239 | return _shrinkScreenButton; 240 | } 241 | 242 | - (UISlider *)progressSlider 243 | { 244 | if (!_progressSlider) { 245 | _progressSlider = [[UISlider alloc] init]; 246 | [_progressSlider setThumbImage:[UIImage imageNamed:@"kr-video-player-point"] forState:UIControlStateNormal]; 247 | [_progressSlider setMinimumTrackTintColor:[UIColor whiteColor]]; 248 | [_progressSlider setMaximumTrackTintColor:[[UIColor lightGrayColor] colorWithAlphaComponent:0.4]]; 249 | _progressSlider.value = 0.f; 250 | _progressSlider.continuous = YES; 251 | } 252 | return _progressSlider; 253 | } 254 | 255 | - (UILabel *)timeLabel 256 | { 257 | if (!_timeLabel) { 258 | _timeLabel = [UILabel new]; 259 | _timeLabel.backgroundColor = [UIColor clearColor]; 260 | _timeLabel.font = [UIFont systemFontOfSize:kVideoControlTimeLabelFontSize]; 261 | _timeLabel.textColor = [UIColor whiteColor]; 262 | _timeLabel.textAlignment = NSTextAlignmentRight; 263 | _timeLabel.bounds = CGRectMake(0, 0, kVideoControlTimeLabelFontSize, kVideoControlTimeLabelFontSize); 264 | } 265 | return _timeLabel; 266 | } 267 | 268 | - (UIActivityIndicatorView *)indicatorView 269 | { 270 | if (!_indicatorView) { 271 | _indicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite]; 272 | [_indicatorView stopAnimating]; 273 | } 274 | return _indicatorView; 275 | } 276 | 277 | - (UIButton *)backButton 278 | { 279 | if (!_backButton) { 280 | _backButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, kVideoControlBarHeight , kVideoControlBarHeight)]; 281 | [_backButton setImage:[UIImage imageNamed:@"zx-video-banner-back"] forState:UIControlStateNormal]; 282 | _backButton.contentEdgeInsets = UIEdgeInsetsMake(5, 0, -5, 0); 283 | _backButton.imageEdgeInsets = UIEdgeInsetsMake(6, 6, 6, 6); 284 | } 285 | return _backButton; 286 | } 287 | 288 | - (UIButton *)lockButton 289 | { 290 | if (!_lockButton) { 291 | _lockButton =[[UIButton alloc] initWithFrame:CGRectMake(0, 0, kVideoControlBarHeight, kVideoControlBarHeight)]; 292 | [_lockButton setImage:[UIImage imageNamed:@"zx-video-player-unlock"] forState:UIControlStateNormal]; 293 | [_lockButton setImage:[UIImage imageNamed:@"zx-video-player-lock"] forState:UIControlStateHighlighted]; 294 | [_lockButton setImage:[UIImage imageNamed:@"zx-video-player-lock"] forState:UIControlStateSelected]; 295 | _lockButton.contentEdgeInsets = UIEdgeInsetsMake(5, 0, -5, 0); 296 | } 297 | return _lockButton; 298 | } 299 | 300 | - (UIProgressView *)bufferProgressView 301 | { 302 | if (!_bufferProgressView) { 303 | _bufferProgressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault]; 304 | _bufferProgressView.progressTintColor = [UIColor colorWithWhite:1 alpha:0.3]; 305 | _bufferProgressView.trackTintColor = [UIColor clearColor]; 306 | } 307 | return _bufferProgressView; 308 | } 309 | 310 | - (ZXVideoPlayerTimeIndicatorView *)timeIndicatorView 311 | { 312 | if (!_timeIndicatorView) { 313 | _timeIndicatorView = [[ZXVideoPlayerTimeIndicatorView alloc] initWithFrame:CGRectMake(0, 0, kVideoTimeIndicatorViewSide, kVideoTimeIndicatorViewSide)]; 314 | } 315 | return _timeIndicatorView; 316 | } 317 | 318 | - (ZXVideoPlayerBrightnessView *)brightnessIndicatorView 319 | { 320 | if (!_brightnessIndicatorView) { 321 | _brightnessIndicatorView = [[ZXVideoPlayerBrightnessView alloc] initWithFrame:CGRectMake(0, 0, kVideoBrightnessIndicatorViewSide, kVideoBrightnessIndicatorViewSide)]; 322 | } 323 | return _brightnessIndicatorView; 324 | } 325 | 326 | - (ZXVideoPlayerVolumeView *)volumeIndicatorView 327 | { 328 | if (!_volumeIndicatorView) { 329 | _volumeIndicatorView = [[ZXVideoPlayerVolumeView alloc] initWithFrame:CGRectMake(0, 0, kVideoVolumeIndicatorViewSide, kVideoVolumeIndicatorViewSide)]; 330 | } 331 | return _volumeIndicatorView; 332 | } 333 | 334 | - (ZXVideoPlayerBatteryView *)batteryView 335 | { 336 | if (!_batteryView) { 337 | _batteryView = [[ZXVideoPlayerBatteryView alloc] initWithFrame:CGRectMake(0, 0, kVideoBatteryViewWidth, kVideoBatteryViewHeight)]; 338 | } 339 | return _batteryView; 340 | } 341 | 342 | - (UILabel *)titleLabel 343 | { 344 | if (!_titleLabel) { 345 | _titleLabel = [[UILabel alloc] init]; 346 | _titleLabel.lineBreakMode = NSLineBreakByTruncatingTail; 347 | _titleLabel.textColor = [UIColor whiteColor]; 348 | _titleLabel.textAlignment = NSTextAlignmentCenter; 349 | } 350 | return _titleLabel; 351 | } 352 | 353 | @end 354 | -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/ZXVideoPlayerController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ZXVideoPlayerController.h 3 | // ZXVideoPlayer 4 | // 5 | // Created by Shawn on 16/4/21. 6 | // Copyright © 2016年 Shawn. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ZXVideo.h" 11 | @import MediaPlayer; 12 | 13 | #define kZXVideoPlayerOriginalWidth MIN([UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height) 14 | #define kZXVideoPlayerOriginalHeight (kZXVideoPlayerOriginalWidth * (11.0 / 16.0)) 15 | 16 | @interface ZXVideoPlayerController : MPMoviePlayerController 17 | 18 | @property (nonatomic, assign) CGRect frame; 19 | /// video model 20 | @property (nonatomic, strong, readwrite) ZXVideo *video; 21 | /// 竖屏模式下点击返回 22 | @property (nonatomic, copy) void(^videoPlayerGoBackBlock)(void); 23 | /// 将要切换到竖屏模式 24 | @property (nonatomic, copy) void(^videoPlayerWillChangeToOriginalScreenModeBlock)(); 25 | /// 将要切换到全屏模式 26 | @property (nonatomic, copy) void(^videoPlayerWillChangeToFullScreenModeBlock)(); 27 | 28 | - (instancetype)initWithFrame:(CGRect)frame; 29 | /// 展示播放器 30 | - (void)showInView:(UIView *)view; 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/ZXVideoPlayerController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ZXVideoPlayerController.m 3 | // ZXVideoPlayer 4 | // 5 | // Created by Shawn on 16/4/21. 6 | // Copyright © 2016年 Shawn. All rights reserved. 7 | // 8 | 9 | #import "ZXVideoPlayerController.h" 10 | #import "ZXVideoPlayerControlView.h" 11 | #import 12 | 13 | typedef NS_ENUM(NSInteger, ZXPanDirection){ 14 | ZXPanDirectionHorizontal, // 横向移动 15 | ZXPanDirectionVertical, // 纵向移动 16 | }; 17 | 18 | /// 播放器显示和消失的动画时长 19 | static const CGFloat kVideoPlayerControllerAnimationTimeInterval = 0.3f; 20 | 21 | @interface ZXVideoPlayerController () 22 | 23 | /// 播放器视图 24 | @property (nonatomic, strong) ZXVideoPlayerControlView *videoControl; 25 | /// 是否已经全屏模式 26 | @property (nonatomic, assign) BOOL isFullscreenMode; 27 | /// 是否锁定 28 | @property (nonatomic, assign) BOOL isLocked; 29 | /// 设备方向 30 | @property (nonatomic, assign, readonly, getter=getDeviceOrientation) UIDeviceOrientation deviceOrientation; 31 | /// player duration timer 32 | @property (nonatomic, strong) NSTimer *durationTimer; 33 | /// pan手势移动方向 34 | @property (nonatomic, assign) ZXPanDirection panDirection; 35 | /// 快进退的总时长 36 | @property (nonatomic, assign) CGFloat sumTime; 37 | /// 是否在调节音量 38 | @property (nonatomic, assign) BOOL isVolumeAdjust; 39 | /// 系统音量slider 40 | @property (nonatomic, strong) UISlider *volumeViewSlider; 41 | 42 | @end 43 | 44 | @implementation ZXVideoPlayerController 45 | 46 | #pragma mark - life cycle 47 | 48 | - (void)dealloc 49 | { 50 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 51 | } 52 | 53 | - (instancetype)initWithFrame:(CGRect)frame 54 | { 55 | self = [super init]; 56 | if (self) { 57 | self.view.frame = frame; 58 | self.view.backgroundColor = [UIColor blackColor]; 59 | self.controlStyle = MPMovieControlStyleNone; 60 | [self.view addSubview:self.videoControl]; 61 | self.videoControl.frame = self.view.bounds; 62 | 63 | UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(panDirection:)]; 64 | pan.delegate = self; 65 | [self.videoControl addGestureRecognizer:pan]; 66 | 67 | [self configObserver]; 68 | [self configControlAction]; 69 | [self configDeviceOrientationObserver]; 70 | [self configVolume]; 71 | } 72 | return self; 73 | } 74 | 75 | #pragma mark - 76 | #pragma mark - UIGestureRecognizerDelegate 77 | 78 | -(BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer shouldReceiveTouch:(UITouch*)touch 79 | { 80 | // UISlider & UIButton & topBar 不需要响应手势 81 | if([touch.view isKindOfClass:[UISlider class]] || [touch.view isKindOfClass:[UIButton class]] || [touch.view.accessibilityIdentifier isEqualToString:@"TopBar"]) { 82 | return NO; 83 | } else { 84 | return YES; 85 | } 86 | } 87 | 88 | #pragma mark - 89 | #pragma mark - Public Method 90 | 91 | /// 展示播放器 92 | - (void)showInView:(UIView *)view 93 | { 94 | if ([UIApplication sharedApplication].statusBarStyle != UIStatusBarStyleLightContent) { 95 | [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent]; 96 | } 97 | 98 | [view addSubview:self.view]; 99 | 100 | self.view.alpha = 0.0; 101 | [UIView animateWithDuration:kVideoPlayerControllerAnimationTimeInterval animations:^{ 102 | self.view.alpha = 1.0; 103 | } completion:^(BOOL finished) {}]; 104 | 105 | if (self.getDeviceOrientation == UIDeviceOrientationLandscapeLeft || self.getDeviceOrientation == UIDeviceOrientationLandscapeRight) { 106 | [self changeToOrientation:self.getDeviceOrientation]; 107 | } else { 108 | [self changeToOrientation:UIDeviceOrientationPortrait]; 109 | } 110 | } 111 | 112 | #pragma mark - 113 | #pragma mark - Private Method 114 | 115 | /// 控件点击事件 116 | - (void)configControlAction 117 | { 118 | [self.videoControl.playButton addTarget:self action:@selector(playButtonClick) forControlEvents:UIControlEventTouchUpInside]; 119 | [self.videoControl.pauseButton addTarget:self action:@selector(pauseButtonClick) forControlEvents:UIControlEventTouchUpInside]; 120 | [self.videoControl.fullScreenButton addTarget:self action:@selector(fullScreenButtonClick) forControlEvents:UIControlEventTouchUpInside]; 121 | [self.videoControl.shrinkScreenButton addTarget:self action:@selector(shrinkScreenButtonClick) forControlEvents:UIControlEventTouchUpInside]; 122 | [self.videoControl.lockButton addTarget:self action:@selector(lockButtonClick:) forControlEvents:UIControlEventTouchUpInside]; 123 | [self.videoControl.backButton addTarget:self action:@selector(backButtonClick) forControlEvents:UIControlEventTouchUpInside]; 124 | 125 | // slider 126 | [self.videoControl.progressSlider addTarget:self action:@selector(progressSliderValueChanged:) forControlEvents:UIControlEventValueChanged]; 127 | [self.videoControl.progressSlider addTarget:self action:@selector(progressSliderTouchBegan:) forControlEvents:UIControlEventTouchDown]; 128 | [self.videoControl.progressSlider addTarget:self action:@selector(progressSliderTouchEnded:) forControlEvents:UIControlEventTouchUpInside]; 129 | [self.videoControl.progressSlider addTarget:self action:@selector(progressSliderTouchEnded:) forControlEvents:UIControlEventTouchUpOutside]; 130 | [self.videoControl.progressSlider addTarget:self action:@selector(progressSliderTouchEnded:) forControlEvents:UIControlEventTouchCancel]; 131 | 132 | [self setProgressSliderMaxMinValues]; 133 | [self monitorVideoPlayback]; 134 | } 135 | 136 | /// 开始播放时根据视频文件长度设置slider最值 137 | - (void)setProgressSliderMaxMinValues 138 | { 139 | CGFloat duration = self.duration; 140 | self.videoControl.progressSlider.minimumValue = 0.f; 141 | self.videoControl.progressSlider.maximumValue = floor(duration); 142 | } 143 | 144 | /// 监听播放进度 145 | - (void)monitorVideoPlayback 146 | { 147 | double currentTime = floor(self.currentPlaybackTime); 148 | double totalTime = floor(self.duration); 149 | // 更新时间 150 | [self setTimeLabelValues:currentTime totalTime:totalTime]; 151 | // 更新播放进度 152 | self.videoControl.progressSlider.value = ceil(currentTime); 153 | // 更新缓冲进度 154 | self.videoControl.bufferProgressView.progress = self.playableDuration / self.duration; 155 | 156 | // if (self.duration == self.playableDuration && self.playableDuration != 0.0) { 157 | // NSLog(@"缓冲完成"); 158 | // } 159 | // int percentage = self.playableDuration / self.duration * 100; 160 | // NSLog(@"缓冲进度: %d%%", percentage); 161 | } 162 | 163 | /// 更新播放时间显示 164 | - (void)setTimeLabelValues:(double)currentTime totalTime:(double)totalTime { 165 | double minutesElapsed = floor(currentTime / 60.0); 166 | double secondsElapsed = fmod(currentTime, 60.0); 167 | NSString *timeElapsedString = [NSString stringWithFormat:@"%02.0f:%02.0f", minutesElapsed, secondsElapsed]; 168 | 169 | double minutesRemaining = floor(totalTime / 60.0); 170 | double secondsRemaining = floor(fmod(totalTime, 60.0)); 171 | NSString *timeRmainingString = [NSString stringWithFormat:@"%02.0f:%02.0f", minutesRemaining, secondsRemaining]; 172 | 173 | self.videoControl.timeLabel.text = [NSString stringWithFormat:@"%@/%@",timeElapsedString,timeRmainingString]; 174 | } 175 | 176 | /// 开启定时器 177 | - (void)startDurationTimer 178 | { 179 | if (self.durationTimer) { 180 | [self.durationTimer setFireDate:[NSDate date]]; 181 | } else { 182 | self.durationTimer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(monitorVideoPlayback) userInfo:nil repeats:YES]; 183 | [[NSRunLoop currentRunLoop] addTimer:self.durationTimer forMode:NSRunLoopCommonModes]; 184 | } 185 | } 186 | 187 | /// 暂停定时器 188 | - (void)stopDurationTimer 189 | { 190 | if (_durationTimer) { 191 | [self.durationTimer setFireDate:[NSDate distantFuture]]; 192 | } 193 | } 194 | 195 | /// MARK: 播放器状态通知 196 | 197 | /// 监听播放器状态通知 198 | - (void)configObserver 199 | { 200 | // 播放状态改变,可配合playbakcState属性获取具体状态 201 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onMPMoviePlayerPlaybackStateDidChangeNotification) name:MPMoviePlayerPlaybackStateDidChangeNotification object:nil]; 202 | 203 | // 媒体网络加载状态改变 204 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onMPMoviePlayerLoadStateDidChangeNotification) name:MPMoviePlayerLoadStateDidChangeNotification object:nil]; 205 | 206 | // 视频显示状态改变 207 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onMPMoviePlayerReadyForDisplayDidChangeNotification) name:MPMoviePlayerReadyForDisplayDidChangeNotification object:nil]; 208 | 209 | // 确定了媒体播放时长后 210 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onMPMovieDurationAvailableNotification) name:MPMovieDurationAvailableNotification object:nil]; 211 | 212 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onPayerControlViewHideNotification) name:kZXPlayerControlViewHideNotification object:nil]; 213 | } 214 | 215 | /// 播放状态改变, 可配合playbakcState属性获取具体状态 216 | - (void)onMPMoviePlayerPlaybackStateDidChangeNotification 217 | { 218 | NSLog(@"MPMoviePlayer PlaybackStateDidChange Notification"); 219 | 220 | if (self.playbackState == MPMoviePlaybackStatePlaying) { 221 | self.videoControl.pauseButton.hidden = NO; 222 | self.videoControl.playButton.hidden = YES; 223 | [self startDurationTimer]; 224 | 225 | [self.videoControl.indicatorView stopAnimating]; 226 | [self.videoControl autoFadeOutControlBar]; 227 | } else { 228 | self.videoControl.pauseButton.hidden = YES; 229 | self.videoControl.playButton.hidden = NO; 230 | [self stopDurationTimer]; 231 | if (self.playbackState == MPMoviePlaybackStateStopped) { 232 | [self.videoControl animateShow]; 233 | } 234 | } 235 | } 236 | 237 | /// 媒体网络加载状态改变 238 | - (void)onMPMoviePlayerLoadStateDidChangeNotification 239 | { 240 | NSLog(@"MPMoviePlayer LoadStateDidChange Notification"); 241 | 242 | if (self.loadState & MPMovieLoadStateStalled) { 243 | [self.videoControl.indicatorView startAnimating]; 244 | } 245 | } 246 | 247 | /// 视频显示状态改变 248 | - (void)onMPMoviePlayerReadyForDisplayDidChangeNotification 249 | { 250 | NSLog(@"MPMoviePlayer ReadyForDisplayDidChange Notification"); 251 | } 252 | 253 | /// 确定了媒体播放时长 254 | - (void)onMPMovieDurationAvailableNotification 255 | { 256 | NSLog(@"MPMovie DurationAvailable Notification"); 257 | [self startDurationTimer]; 258 | [self setProgressSliderMaxMinValues]; 259 | 260 | self.videoControl.fullScreenButton.hidden = NO; 261 | self.videoControl.shrinkScreenButton.hidden = YES; 262 | } 263 | 264 | /// 控制视图隐藏 265 | - (void)onPayerControlViewHideNotification 266 | { 267 | if (self.isFullscreenMode) { 268 | [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationFade]; 269 | } else { 270 | [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationFade]; 271 | } 272 | } 273 | 274 | /// MARK: pan手势处理 275 | 276 | /// pan手势触发 277 | - (void)panDirection:(UIPanGestureRecognizer *)pan 278 | { 279 | CGPoint locationPoint = [pan locationInView:self.videoControl]; 280 | CGPoint veloctyPoint = [pan velocityInView:self.videoControl]; 281 | 282 | switch (pan.state) { 283 | case UIGestureRecognizerStateBegan: { // 开始移动 284 | CGFloat x = fabs(veloctyPoint.x); 285 | CGFloat y = fabs(veloctyPoint.y); 286 | 287 | if (x > y) { // 水平移动 288 | self.panDirection = ZXPanDirectionHorizontal; 289 | self.sumTime = self.currentPlaybackTime; // sumTime初值 290 | [self pause]; 291 | [self stopDurationTimer]; 292 | } else if (x < y) { // 垂直移动 293 | self.panDirection = ZXPanDirectionVertical; 294 | if (locationPoint.x > self.view.bounds.size.width / 2) { // 音量调节 295 | self.isVolumeAdjust = YES; 296 | } else { // 亮度调节 297 | self.isVolumeAdjust = NO; 298 | } 299 | } 300 | } 301 | break; 302 | case UIGestureRecognizerStateChanged: { // 正在移动 303 | switch (self.panDirection) { 304 | case ZXPanDirectionHorizontal: { 305 | [self horizontalMoved:veloctyPoint.x]; 306 | } 307 | break; 308 | case ZXPanDirectionVertical: { 309 | [self verticalMoved:veloctyPoint.y]; 310 | } 311 | break; 312 | 313 | default: 314 | break; 315 | } 316 | } 317 | break; 318 | case UIGestureRecognizerStateEnded: { // 移动停止 319 | switch (self.panDirection) { 320 | case ZXPanDirectionHorizontal: { 321 | [self setCurrentPlaybackTime:floor(self.sumTime)]; 322 | [self play]; 323 | [self startDurationTimer]; 324 | [self.videoControl autoFadeOutControlBar]; 325 | } 326 | break; 327 | case ZXPanDirectionVertical: { 328 | break; 329 | } 330 | break; 331 | 332 | default: 333 | break; 334 | } 335 | } 336 | break; 337 | 338 | default: 339 | break; 340 | } 341 | } 342 | 343 | /// pan水平移动 344 | - (void)horizontalMoved:(CGFloat)value 345 | { 346 | // 每次滑动叠加时间 347 | self.sumTime += value / 200; 348 | 349 | // 容错处理 350 | if (self.sumTime > self.duration) { 351 | self.sumTime = self.duration; 352 | } else if (self.sumTime < 0) { 353 | self.sumTime = 0; 354 | } 355 | 356 | // 时间更新 357 | double currentTime = self.sumTime; 358 | double totalTime = self.duration; 359 | [self setTimeLabelValues:currentTime totalTime:totalTime]; 360 | // 提示视图 361 | self.videoControl.timeIndicatorView.labelText = self.videoControl.timeLabel.text; 362 | // 播放进度更新 363 | self.videoControl.progressSlider.value = self.sumTime; 364 | 365 | // 快进or后退 状态调整 366 | ZXTimeIndicatorPlayState playState = ZXTimeIndicatorPlayStateRewind; 367 | 368 | if (value < 0) { // left 369 | playState = ZXTimeIndicatorPlayStateRewind; 370 | } else if (value > 0) { // right 371 | playState = ZXTimeIndicatorPlayStateFastForward; 372 | } 373 | 374 | if (self.videoControl.timeIndicatorView.playState != playState) { 375 | if (value < 0) { // left 376 | NSLog(@"------fast rewind"); 377 | self.videoControl.timeIndicatorView.playState = ZXTimeIndicatorPlayStateRewind; 378 | [self.videoControl.timeIndicatorView setNeedsLayout]; 379 | } else if (value > 0) { // right 380 | NSLog(@"------fast forward"); 381 | self.videoControl.timeIndicatorView.playState = ZXTimeIndicatorPlayStateFastForward; 382 | [self.videoControl.timeIndicatorView setNeedsLayout]; 383 | } 384 | } 385 | } 386 | 387 | 388 | /// pan垂直移动 389 | - (void)verticalMoved:(CGFloat)value 390 | { 391 | if (self.isVolumeAdjust) { 392 | // 调节系统音量 393 | // [MPMusicPlayerController applicationMusicPlayer].volume 这种简单的方式调节音量也可以,只是CPU高一点点 394 | self.volumeViewSlider.value -= value / 10000; 395 | }else { 396 | // 亮度 397 | [UIScreen mainScreen].brightness -= value / 10000; 398 | } 399 | } 400 | 401 | /// MARK: 系统音量控件 402 | 403 | /// 获取系统音量控件 404 | - (void)configVolume 405 | { 406 | MPVolumeView *volumeView = [[MPVolumeView alloc] init]; 407 | volumeView.center = CGPointMake(-1000, 0); 408 | [self.view addSubview:volumeView]; 409 | 410 | _volumeViewSlider = nil; 411 | for (UIView *view in [volumeView subviews]){ 412 | if ([view.class.description isEqualToString:@"MPVolumeSlider"]){ 413 | _volumeViewSlider = (UISlider *)view; 414 | break; 415 | } 416 | } 417 | 418 | // 使用这个category的应用不会随着手机静音键打开而静音,可在手机静音下播放声音 419 | NSError *error = nil; 420 | BOOL success = [[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error: &error]; 421 | 422 | if (!success) {/* error */} 423 | 424 | // 监听耳机插入和拔掉通知 425 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioRouteChangeListenerCallback:) name:AVAudioSessionRouteChangeNotification object:nil]; 426 | } 427 | 428 | /// 耳机插入、拔出事件 429 | - (void)audioRouteChangeListenerCallback:(NSNotification*)notification 430 | { 431 | NSInteger routeChangeReason = [[notification.userInfo valueForKey:AVAudioSessionRouteChangeReasonKey] integerValue]; 432 | switch (routeChangeReason) { 433 | case AVAudioSessionRouteChangeReasonNewDeviceAvailable: 434 | NSLog(@"---耳机插入"); 435 | break; 436 | 437 | case AVAudioSessionRouteChangeReasonOldDeviceUnavailable: { 438 | NSLog(@"---耳机拔出"); 439 | // 拔掉耳机继续播放 440 | [self play]; 441 | } 442 | break; 443 | 444 | case AVAudioSessionRouteChangeReasonCategoryChange: 445 | // called at start - also when other audio wants to play 446 | NSLog(@"AVAudioSessionRouteChangeReasonCategoryChange"); 447 | break; 448 | 449 | default: 450 | break; 451 | } 452 | } 453 | 454 | /// MARK: 设备方向 455 | 456 | /// 设置监听设备旋转通知 457 | - (void)configDeviceOrientationObserver 458 | { 459 | [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; 460 | [[NSNotificationCenter defaultCenter] addObserver:self 461 | selector:@selector(onDeviceOrientationDidChange) 462 | name:UIDeviceOrientationDidChangeNotification 463 | object:nil]; 464 | } 465 | 466 | /// 设备旋转方向改变 467 | - (void)onDeviceOrientationDidChange 468 | { 469 | UIDeviceOrientation orientation = self.getDeviceOrientation; 470 | 471 | if (!self.isLocked) 472 | { 473 | switch (orientation) { 474 | case UIDeviceOrientationPortrait: { // Device oriented vertically, home button on the bottom 475 | NSLog(@"home键在 下"); 476 | [self restoreOriginalScreen]; 477 | } 478 | break; 479 | case UIDeviceOrientationPortraitUpsideDown: { // Device oriented vertically, home button on the top 480 | NSLog(@"home键在 上"); 481 | } 482 | break; 483 | case UIDeviceOrientationLandscapeLeft: { // Device oriented horizontally, home button on the right 484 | NSLog(@"home键在 右"); 485 | [self changeToFullScreenForOrientation:UIDeviceOrientationLandscapeLeft]; 486 | } 487 | break; 488 | case UIDeviceOrientationLandscapeRight: { // Device oriented horizontally, home button on the left 489 | NSLog(@"home键在 左"); 490 | [self changeToFullScreenForOrientation:UIDeviceOrientationLandscapeRight]; 491 | } 492 | break; 493 | 494 | default: 495 | break; 496 | } 497 | } 498 | } 499 | 500 | /// 切换到全屏模式 501 | - (void)changeToFullScreenForOrientation:(UIDeviceOrientation)orientation 502 | { 503 | if (self.isFullscreenMode) { 504 | return; 505 | } 506 | 507 | if (self.videoControl.isBarShowing) { 508 | [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationFade]; 509 | } else { 510 | [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationFade]; 511 | } 512 | 513 | if (self.videoPlayerWillChangeToFullScreenModeBlock) { 514 | self.videoPlayerWillChangeToFullScreenModeBlock(); 515 | } 516 | 517 | self.frame = [UIScreen mainScreen].bounds; 518 | 519 | self.isFullscreenMode = YES; 520 | self.videoControl.fullScreenButton.hidden = YES; 521 | self.videoControl.shrinkScreenButton.hidden = NO; 522 | } 523 | 524 | /// 切换到竖屏模式 525 | - (void)restoreOriginalScreen 526 | { 527 | if (!self.isFullscreenMode) { 528 | return; 529 | } 530 | 531 | if ([UIApplication sharedApplication].statusBarHidden) { 532 | [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationFade]; 533 | } 534 | 535 | if (self.videoPlayerWillChangeToOriginalScreenModeBlock) { 536 | self.videoPlayerWillChangeToOriginalScreenModeBlock(); 537 | } 538 | 539 | self.frame = CGRectMake(0, 0, kZXVideoPlayerOriginalWidth, kZXVideoPlayerOriginalHeight); 540 | 541 | self.isFullscreenMode = NO; 542 | self.videoControl.fullScreenButton.hidden = NO; 543 | self.videoControl.shrinkScreenButton.hidden = YES; 544 | } 545 | 546 | /// 手动切换设备方向 547 | - (void)changeToOrientation:(UIDeviceOrientation)orientation 548 | { 549 | if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) { 550 | SEL selector = NSSelectorFromString(@"setOrientation:"); 551 | NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDevice instanceMethodSignatureForSelector:selector]]; 552 | [invocation setSelector:selector]; 553 | [invocation setTarget:[UIDevice currentDevice]]; 554 | int val = orientation; 555 | [invocation setArgument:&val atIndex:2]; 556 | [invocation invoke]; 557 | } 558 | } 559 | 560 | #pragma mark - 561 | #pragma mark - Action Code 562 | 563 | /// 返回按钮点击 564 | - (void)backButtonClick 565 | { 566 | if (!self.isFullscreenMode) { // 如果是竖屏模式,返回关闭 567 | if (self) { 568 | [self.durationTimer invalidate]; 569 | [self stop]; 570 | [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone]; 571 | 572 | if (self.videoPlayerGoBackBlock) { 573 | [self.videoControl cancelAutoFadeOutControlBar]; 574 | self.videoPlayerGoBackBlock(); 575 | } 576 | } 577 | } else { // 全屏模式,返回到竖屏模式 578 | if (self.isLocked) { // 解锁 579 | [self lockButtonClick:self.videoControl.lockButton]; 580 | } 581 | [self changeToOrientation:UIDeviceOrientationPortrait]; 582 | } 583 | } 584 | 585 | /// 播放按钮点击 586 | - (void)playButtonClick 587 | { 588 | [self play]; 589 | self.videoControl.playButton.hidden = YES; 590 | self.videoControl.pauseButton.hidden = NO; 591 | } 592 | 593 | /// 暂停按钮点击 594 | - (void)pauseButtonClick 595 | { 596 | [self pause]; 597 | self.videoControl.playButton.hidden = NO; 598 | self.videoControl.pauseButton.hidden = YES; 599 | } 600 | 601 | /// 锁屏按钮点击 602 | - (void)lockButtonClick:(UIButton *)lockBtn 603 | { 604 | lockBtn.selected = !lockBtn.selected; 605 | 606 | if (lockBtn.selected) { // 锁定 607 | self.isLocked = YES; 608 | [[NSUserDefaults standardUserDefaults] setObject:@1 forKey:@"ZXVideoPlayer_DidLockScreen"]; 609 | } else { // 解除锁定 610 | self.isLocked = NO; 611 | [[NSUserDefaults standardUserDefaults] setObject:@0 forKey:@"ZXVideoPlayer_DidLockScreen"]; 612 | } 613 | } 614 | 615 | /// 全屏按钮点击 616 | - (void)fullScreenButtonClick 617 | { 618 | if (self.isFullscreenMode) { 619 | return; 620 | } 621 | 622 | if (self.isLocked) { // 解锁 623 | [self lockButtonClick:self.videoControl.lockButton]; 624 | } 625 | 626 | // FIXME: ? 627 | [self changeToOrientation:UIDeviceOrientationLandscapeLeft]; 628 | } 629 | 630 | /// 返回竖屏按钮点击 631 | - (void)shrinkScreenButtonClick 632 | { 633 | if (!self.isFullscreenMode) { 634 | return; 635 | } 636 | 637 | if (self.isLocked) { // 解锁 638 | [self lockButtonClick:self.videoControl.lockButton]; 639 | } 640 | 641 | [self changeToOrientation:UIDeviceOrientationPortrait]; 642 | } 643 | 644 | /// slider 按下事件 645 | - (void)progressSliderTouchBegan:(UISlider *)slider 646 | { 647 | [self pause]; 648 | [self stopDurationTimer]; 649 | [self.videoControl cancelAutoFadeOutControlBar]; 650 | } 651 | 652 | /// slider 松开事件 653 | - (void)progressSliderTouchEnded:(UISlider *)slider 654 | { 655 | [self setCurrentPlaybackTime:floor(slider.value)]; 656 | [self play]; 657 | [self startDurationTimer]; 658 | [self.videoControl autoFadeOutControlBar]; 659 | } 660 | 661 | /// slider value changed 662 | - (void)progressSliderValueChanged:(UISlider *)slider 663 | { 664 | double currentTime = floor(slider.value); 665 | double totalTime = floor(self.duration); 666 | [self setTimeLabelValues:currentTime totalTime:totalTime]; 667 | } 668 | 669 | #pragma mark - 670 | #pragma mark - getters and setters 671 | 672 | - (void)setContentURL:(NSURL *)contentURL 673 | { 674 | [self stop]; 675 | [super setContentURL:contentURL]; 676 | [self play]; 677 | } 678 | 679 | - (ZXVideoPlayerControlView *)videoControl 680 | { 681 | if (!_videoControl) { 682 | _videoControl = [[ZXVideoPlayerControlView alloc] init]; 683 | } 684 | return _videoControl; 685 | } 686 | 687 | - (void)setFrame:(CGRect)frame 688 | { 689 | [self.view setFrame:frame]; 690 | [self.videoControl setFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)]; 691 | [self.videoControl setNeedsLayout]; 692 | [self.videoControl layoutIfNeeded]; 693 | } 694 | 695 | - (UIDeviceOrientation)getDeviceOrientation 696 | { 697 | return [UIDevice currentDevice].orientation; 698 | } 699 | 700 | - (void)setVideo:(ZXVideo *)video 701 | { 702 | _video = video; 703 | 704 | // 标题 705 | self.videoControl.titleLabel.text = self.video.title; 706 | // play url 707 | self.contentURL = [NSURL URLWithString:self.video.playUrl]; 708 | } 709 | 710 | @end 711 | -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/ZXVideoPlayerTimeIndicatorView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ZXVideoPlayerTimeIndicatorView.h 3 | // ZXVideoPlayer 4 | // 5 | // Created by Shawn on 16/4/21. 6 | // Copyright © 2016年 Shawn. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef NS_ENUM(NSUInteger, ZXTimeIndicatorPlayState) { 12 | ZXTimeIndicatorPlayStateRewind, // rewind 13 | ZXTimeIndicatorPlayStateFastForward, // fast forward 14 | }; 15 | 16 | static const CGFloat kVideoTimeIndicatorViewSide = 96; 17 | 18 | @interface ZXVideoPlayerTimeIndicatorView : UIView 19 | 20 | @property (nonatomic, strong, readwrite) NSString *labelText; 21 | @property (nonatomic, assign, readwrite) ZXTimeIndicatorPlayState playState; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/ZXVideoPlayerTimeIndicatorView.m: -------------------------------------------------------------------------------- 1 | // 2 | // ZXVideoPlayerTimeIndicatorView.m 3 | // ZXVideoPlayer 4 | // 5 | // Created by Shawn on 16/4/21. 6 | // Copyright © 2016年 Shawn. All rights reserved. 7 | // 8 | 9 | #import "ZXVideoPlayerTimeIndicatorView.h" 10 | #import "ZXVideoPlayerControlView.h" 11 | 12 | static const CGFloat kViewSpacing = 15.0; 13 | static const CGFloat kTimeIndicatorAutoFadeOutTimeInterval = 1.0; 14 | 15 | @interface ZXVideoPlayerTimeIndicatorView () 16 | 17 | @property (nonatomic, strong, readwrite) UIImageView *arrowImageView; 18 | @property (nonatomic, strong, readwrite) UILabel *timeLabel; 19 | 20 | @end 21 | 22 | @implementation ZXVideoPlayerTimeIndicatorView 23 | 24 | - (instancetype)initWithFrame:(CGRect)frame 25 | { 26 | self = [super initWithFrame:frame]; 27 | if (self) { 28 | self.hidden = YES; 29 | self.layer.cornerRadius = 5; 30 | self.layer.masksToBounds = YES; 31 | self.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.3]; 32 | 33 | [self createTimeIndicator]; 34 | } 35 | return self; 36 | } 37 | 38 | - (void)setLabelText:(NSString *)labelText 39 | { 40 | // _labelText = [labelText copy]; 41 | self.hidden = NO; 42 | self.timeLabel.text = labelText; 43 | 44 | // 防止重叠显示 45 | if (self.superview.accessibilityIdentifier) { 46 | ZXVideoPlayerControlView *playerView = (ZXVideoPlayerControlView *)self.superview; 47 | playerView.brightnessIndicatorView.hidden = YES; 48 | playerView.volumeIndicatorView.hidden = YES; 49 | } else { 50 | self.superview.accessibilityIdentifier = @""; 51 | } 52 | 53 | [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(animateHide) object:nil]; 54 | [self performSelector:@selector(animateHide) withObject:nil afterDelay:kTimeIndicatorAutoFadeOutTimeInterval]; 55 | } 56 | 57 | - (void)layoutSubviews 58 | { 59 | [super layoutSubviews]; 60 | 61 | if (self.playState == ZXTimeIndicatorPlayStateRewind) { 62 | [self.arrowImageView setImage:[UIImage imageNamed:@"zx-video-player-rewind"]]; 63 | } else { 64 | [self.arrowImageView setImage:[UIImage imageNamed:@"zx-video-player-fastForward"]]; 65 | } 66 | } 67 | 68 | - (void)createTimeIndicator 69 | { 70 | CGFloat margin = (kVideoTimeIndicatorViewSide - 24 - 12 - kViewSpacing) / 2; 71 | _arrowImageView = [[UIImageView alloc] initWithFrame:CGRectMake((kVideoTimeIndicatorViewSide - 44) / 2, margin, 44, 24)]; 72 | [self addSubview:_arrowImageView]; 73 | 74 | _timeLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, margin + 24 + kViewSpacing, kVideoTimeIndicatorViewSide, 12)]; 75 | _timeLabel.textColor = [UIColor whiteColor]; 76 | _timeLabel.backgroundColor = [UIColor clearColor]; 77 | _timeLabel.font = [UIFont systemFontOfSize:12]; 78 | _timeLabel.textAlignment = NSTextAlignmentCenter; 79 | [self addSubview:_timeLabel]; 80 | } 81 | 82 | - (void)animateHide 83 | { 84 | [UIView animateWithDuration:.3 animations:^{ 85 | self.alpha = 0; 86 | } completion:^(BOOL finished) { 87 | self.hidden = YES; 88 | self.alpha = 1; 89 | self.superview.accessibilityIdentifier = nil; 90 | }]; 91 | } 92 | 93 | @end 94 | -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/ZXVideoPlayerVolumeView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ZXVideoPlayerVolumeView.h 3 | // ZXVideoPlayer 4 | // 5 | // Created by Shawn on 16/4/22. 6 | // Copyright © 2016年 Shawn. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | static const CGFloat kVideoVolumeIndicatorViewSide = 118.0; 12 | 13 | @interface ZXVideoPlayerVolumeView : UIView 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /ZXVideoPlayer/ZXVideoPlayer/ZXVideoPlayerVolumeView.m: -------------------------------------------------------------------------------- 1 | // 2 | // ZXVideoPlayerVolumeView.m 3 | // ZXVideoPlayer 4 | // 5 | // Created by Shawn on 16/4/22. 6 | // Copyright © 2016年 Shawn. All rights reserved. 7 | // 8 | 9 | #import "ZXVideoPlayerVolumeView.h" 10 | #import "ZXVideoPlayerControlView.h" 11 | 12 | static const CGFloat kViewSpacing = 21.0; 13 | static const CGFloat kVolumeIndicatorAutoFadeOutTimeInterval = 1.0; 14 | 15 | @interface ZXVideoPlayerVolumeView () 16 | 17 | @property (nonatomic, strong, readwrite) NSMutableArray *blocksArray; 18 | @property (nonatomic, strong, readwrite) UIImageView *volumeImageView; 19 | 20 | @end 21 | 22 | @implementation ZXVideoPlayerVolumeView 23 | 24 | - (void)dealloc 25 | { 26 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 27 | } 28 | 29 | - (instancetype)initWithFrame:(CGRect)frame 30 | { 31 | self = [super initWithFrame:frame]; 32 | if (self) { 33 | self.hidden = YES; 34 | self.layer.cornerRadius = 5; 35 | self.layer.masksToBounds = YES; 36 | self.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.3]; 37 | 38 | [self createVolumeIndicator]; 39 | [self configVolumeNotification]; 40 | } 41 | return self; 42 | } 43 | 44 | - (void)createVolumeIndicator 45 | { 46 | // 音量图标 47 | _volumeImageView = [[UIImageView alloc] initWithFrame:CGRectMake((kVideoVolumeIndicatorViewSide - 50) / 2, kViewSpacing, 50, 50)]; 48 | [_volumeImageView setImage:[UIImage imageNamed:@"zx-video-player-volume"]]; 49 | [self addSubview:_volumeImageView]; 50 | 51 | // 音量条 52 | self.blocksArray = [NSMutableArray arrayWithCapacity:16]; 53 | 54 | UIView *blockBackgroundView = [[UIView alloc] initWithFrame:CGRectMake((kVideoVolumeIndicatorViewSide - 105) / 2, 50 + kViewSpacing * 2, 105, 2.75 + 2)]; 55 | blockBackgroundView.backgroundColor = [UIColor colorWithRed:0.25f green:0.22f blue:0.21f alpha:0.65]; 56 | [self addSubview:blockBackgroundView]; 57 | 58 | CGFloat margin = 1; 59 | CGFloat blockW = 5.5; 60 | CGFloat blockH = 2.75; 61 | 62 | for (int i = 0; i < 16; i++) { 63 | CGFloat locX = i * (blockW + margin) + margin; 64 | UIImageView *blockView = [[UIImageView alloc] init]; 65 | blockView.backgroundColor = [UIColor whiteColor]; 66 | blockView.frame = CGRectMake(locX, margin, blockW, blockH); 67 | 68 | [blockBackgroundView addSubview:blockView]; 69 | [self.blocksArray addObject:blockView]; 70 | } 71 | } 72 | 73 | - (void)configVolumeNotification 74 | { 75 | // or use [[AVAudioSession sharedInstance] addObserver:self forKeyPath:@"outputVolume" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:(void *)[AVAudioSession sharedInstance]]; 76 | [[NSNotificationCenter defaultCenter] addObserver:self 77 | selector:@selector(volumeChanged:) 78 | name:@"AVSystemController_SystemVolumeDidChangeNotification" 79 | object:nil]; 80 | } 81 | 82 | - (void)volumeChanged:(NSNotification *)notification 83 | { 84 | float outputVolume = [[[notification userInfo] objectForKey:@"AVSystemController_AudioVolumeNotificationParameter"] floatValue]; 85 | [self updateVolumeIndicator:outputVolume]; 86 | } 87 | 88 | - (void)updateVolumeIndicator:(CGFloat)value 89 | { 90 | self.hidden = NO; 91 | 92 | // 防止重叠显示 93 | if (self.superview.accessibilityIdentifier) { 94 | ZXVideoPlayerControlView *playerView = (ZXVideoPlayerControlView *)self.superview; 95 | playerView.timeIndicatorView.hidden = YES; 96 | playerView.brightnessIndicatorView.hidden = YES; 97 | } else { 98 | self.superview.accessibilityIdentifier = @""; 99 | } 100 | 101 | CGFloat stage = 1 / 16.0; 102 | NSInteger level = value / stage; 103 | 104 | for (NSInteger i=0; i 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ZXVideoPlayerTests/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 | -------------------------------------------------------------------------------- /ZXVideoPlayerTests/ZXVideoPlayerTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // ZXVideoPlayerTests.m 3 | // ZXVideoPlayerTests 4 | // 5 | // Created by Shawn on 16/4/20. 6 | // Copyright © 2016年 Shawn. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ZXVideoPlayerTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation ZXVideoPlayerTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | // Use XCTAssert and related functions to verify your tests produce the correct results. 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /ZXVideoPlayerUITests/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 | -------------------------------------------------------------------------------- /ZXVideoPlayerUITests/ZXVideoPlayerUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // ZXVideoPlayerUITests.m 3 | // ZXVideoPlayerUITests 4 | // 5 | // Created by Shawn on 16/4/20. 6 | // Copyright © 2016年 Shawn. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ZXVideoPlayerUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation ZXVideoPlayerUITests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | 22 | // In UI tests it is usually best to stop immediately when a failure occurs. 23 | self.continueAfterFailure = NO; 24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 25 | [[[XCUIApplication alloc] init] launch]; 26 | 27 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 28 | } 29 | 30 | - (void)tearDown { 31 | // Put teardown code here. This method is called after the invocation of each test method in the class. 32 | [super tearDown]; 33 | } 34 | 35 | - (void)testExample { 36 | // Use recording to get started writing UI tests. 37 | // Use XCTAssert and related functions to verify your tests produce the correct results. 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /img1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0summer0/VideoPlayerDemo/6623b7fafc136f98dd3784b849c60f05ac5e15ce/img1.jpg -------------------------------------------------------------------------------- /img2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0summer0/VideoPlayerDemo/6623b7fafc136f98dd3784b849c60f05ac5e15ce/img2.jpg -------------------------------------------------------------------------------- /img3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0summer0/VideoPlayerDemo/6623b7fafc136f98dd3784b849c60f05ac5e15ce/img3.jpg --------------------------------------------------------------------------------