Browse Source

no message

HF_Q 4 years ago
parent
commit
cf5b6ece9c
100 changed files with 9738 additions and 2346 deletions
  1. 13 1
      Podfile.lock
  2. 13 1
      Pods/Manifest.lock
  3. 2749 2332
      Pods/Pods.xcodeproj/project.pbxproj
  4. 60 0
      Pods/Pods.xcodeproj/xcuserdata/niuzhen.xcuserdatad/xcschemes/ZFPlayer.xcscheme
  5. 5 0
      Pods/Pods.xcodeproj/xcuserdata/niuzhen.xcuserdatad/xcschemes/xcschememanagement.plist
  6. 23 0
      Pods/Target Support Files/Pods-smartRhino/Pods-smartRhino-acknowledgements.markdown
  7. 29 0
      Pods/Target Support Files/Pods-smartRhino/Pods-smartRhino-acknowledgements.plist
  8. 2 1
      Pods/Target Support Files/Pods-smartRhino/Pods-smartRhino-resources-Debug-input-files.xcfilelist
  9. 2 1
      Pods/Target Support Files/Pods-smartRhino/Pods-smartRhino-resources-Debug-output-files.xcfilelist
  10. 2 1
      Pods/Target Support Files/Pods-smartRhino/Pods-smartRhino-resources-Release-input-files.xcfilelist
  11. 2 1
      Pods/Target Support Files/Pods-smartRhino/Pods-smartRhino-resources-Release-output-files.xcfilelist
  12. 2 0
      Pods/Target Support Files/Pods-smartRhino/Pods-smartRhino-resources.sh
  13. 4 4
      Pods/Target Support Files/Pods-smartRhino/Pods-smartRhino.debug.xcconfig
  14. 4 4
      Pods/Target Support Files/Pods-smartRhino/Pods-smartRhino.release.xcconfig
  15. 26 0
      Pods/Target Support Files/ZFPlayer/ZFPlayer-Info.plist
  16. 5 0
      Pods/Target Support Files/ZFPlayer/ZFPlayer-dummy.m
  17. 12 0
      Pods/Target Support Files/ZFPlayer/ZFPlayer-prefix.pch
  18. 42 0
      Pods/Target Support Files/ZFPlayer/ZFPlayer-umbrella.h
  19. 6 0
      Pods/Target Support Files/ZFPlayer/ZFPlayer.modulemap
  20. 9 0
      Pods/Target Support Files/ZFPlayer/ZFPlayer.xcconfig
  21. 19 0
      Pods/ZFPlayer/LICENSE
  22. 131 0
      Pods/ZFPlayer/README.md
  23. 42 0
      Pods/ZFPlayer/ZFPlayer/Classes/AVPlayer/ZFAVPlayerManager.h
  24. 490 0
      Pods/ZFPlayer/ZFPlayer/Classes/AVPlayer/ZFAVPlayerManager.m
  25. 127 0
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/UIImageView+ZFCache.h
  26. 420 0
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/UIImageView+ZFCache.m
  27. 45 0
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/UIView+ZFFrame.h
  28. 149 0
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/UIView+ZFFrame.m
  29. 117 0
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFLandScapeControlView.h
  30. 452 0
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFLandScapeControlView.m
  31. 66 0
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFLoadingView.h
  32. 183 0
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFLoadingView.m
  33. 39 0
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFNetworkSpeedMonitor.h
  34. 161 0
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFNetworkSpeedMonitor.m
  35. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_back_full@2x.png
  36. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_back_full@3x.png
  37. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_bottom_shadow.png
  38. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_brightness_high@2x.png
  39. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_brightness_high@3x.png
  40. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_brightness_low@2x.png
  41. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_brightness_low@3x.png
  42. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_close@2x.png
  43. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_close@3x.png
  44. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_closeWatch@2x.png
  45. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_closeWatch@3x.png
  46. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_fast_backward@2x.png
  47. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_fast_backward@3x.png
  48. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_fast_forward@2x.png
  49. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_fast_forward@3x.png
  50. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_fullscreen@2x.png
  51. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_fullscreen@3x.png
  52. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_lock-nor@2x.png
  53. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_lock-nor@3x.png
  54. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_muted@2x.png
  55. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_muted@3x.png
  56. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_next@2x.png
  57. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_next@3x.png
  58. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_pause@2x.png
  59. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_pause@3x.png
  60. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_play@2x.png
  61. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_play@3x.png
  62. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_shrinkscreen@2x.png
  63. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_shrinkscreen@3x.png
  64. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_slider.png
  65. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_slider@2x.png
  66. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_slider@3x.png
  67. BIN
      smartRhino/Project/Other/Third/BaiduAIBD/BDSResource/defaultFullScreenTheme.bundle/dividing_line@3x.png
  68. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_unlock-nor@2x.png
  69. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_unlock-nor@3x.png
  70. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_volume_high@2x.png
  71. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_volume_high@3x.png
  72. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_volume_low@2x.png
  73. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_volume_low@3x.png
  74. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/new_allPause_44x44_@2x.png
  75. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/new_allPause_44x44_@3x.png
  76. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/new_allPlay_44x44_@2x.png
  77. BIN
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/new_allPlay_44x44_@3x.png
  78. 149 0
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayerControlView.h
  79. 840 0
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayerControlView.m
  80. 108 0
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPortraitControlView.h
  81. 380 0
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPortraitControlView.m
  82. 118 0
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFSliderView.h
  83. 426 0
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFSliderView.m
  84. 31 0
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFSmallFloatControlView.h
  85. 72 0
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFSmallFloatControlView.m
  86. 27 0
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFSpeedLoadingView.h
  87. 122 0
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFSpeedLoadingView.m
  88. 47 0
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFUtilities.h
  89. 74 0
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFUtilities.m
  90. 46 0
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFVolumeBrightnessView.h
  91. 167 0
      Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFVolumeBrightnessView.m
  92. 203 0
      Pods/ZFPlayer/ZFPlayer/Classes/Core/UIScrollView+ZFPlayer.h
  93. 917 0
      Pods/ZFPlayer/ZFPlayer/Classes/Core/UIScrollView+ZFPlayer.m
  94. 126 0
      Pods/ZFPlayer/ZFPlayer/Classes/Core/UIViewController+ZFPlayerRotation.m
  95. 35 0
      Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFFloatView.h
  96. 85 0
      Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFFloatView.m
  97. 40 0
      Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFKVOController.h
  98. 143 0
      Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFKVOController.m
  99. 131 0
      Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFOrientationObserver.h
  100. 0 0
      Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFOrientationObserver.m

+ 13 - 1
Podfile.lock

@@ -67,6 +67,13 @@ PODS:
   - WechatOpenSDK (1.8.7.1)
   - WMZPageController (1.1.7)
   - YYModel (1.0.4)
+  - ZFPlayer (3.3.1):
+    - ZFPlayer/Core (= 3.3.1)
+  - ZFPlayer/AVPlayer (3.3.1):
+    - ZFPlayer/Core
+  - ZFPlayer/ControlView (3.3.1):
+    - ZFPlayer/Core
+  - ZFPlayer/Core (3.3.1)
 
 DEPENDENCIES:
   - AFNetworking
@@ -94,6 +101,9 @@ DEPENDENCIES:
   - WechatOpenSDK
   - WMZPageController
   - YYModel
+  - ZFPlayer
+  - ZFPlayer/AVPlayer
+  - ZFPlayer/ControlView
 
 SPEC REPOS:
   https://github.com/CocoaPods/Specs.git:
@@ -122,6 +132,7 @@ SPEC REPOS:
     - WechatOpenSDK
     - WMZPageController
     - YYModel
+    - ZFPlayer
 
 SPEC CHECKSUMS:
   AFNetworking: 7864c38297c79aaca1500c33288e429c3451fdce
@@ -149,7 +160,8 @@ SPEC CHECKSUMS:
   WechatOpenSDK: 6a4d1436c15b3b5fe2a0bd383f3046010186da44
   WMZPageController: fc76f3634a3bf2271d173cf4ba025e98b1cd76eb
   YYModel: 2a7fdd96aaa4b86a824e26d0c517de8928c04b30
+  ZFPlayer: 8a6021a3c45e281f2abd24dca5c88915af770a7e
 
-PODFILE CHECKSUM: 12bbd06aa1a59e99bda6807fbcf98653e08b0eb9
+PODFILE CHECKSUM: 5bb1dc9126facddf5df052597180631ec6302cee
 
 COCOAPODS: 1.8.4

+ 13 - 1
Pods/Manifest.lock

@@ -67,6 +67,13 @@ PODS:
   - WechatOpenSDK (1.8.7.1)
   - WMZPageController (1.1.7)
   - YYModel (1.0.4)
+  - ZFPlayer (3.3.1):
+    - ZFPlayer/Core (= 3.3.1)
+  - ZFPlayer/AVPlayer (3.3.1):
+    - ZFPlayer/Core
+  - ZFPlayer/ControlView (3.3.1):
+    - ZFPlayer/Core
+  - ZFPlayer/Core (3.3.1)
 
 DEPENDENCIES:
   - AFNetworking
@@ -94,6 +101,9 @@ DEPENDENCIES:
   - WechatOpenSDK
   - WMZPageController
   - YYModel
+  - ZFPlayer
+  - ZFPlayer/AVPlayer
+  - ZFPlayer/ControlView
 
 SPEC REPOS:
   https://github.com/CocoaPods/Specs.git:
@@ -122,6 +132,7 @@ SPEC REPOS:
     - WechatOpenSDK
     - WMZPageController
     - YYModel
+    - ZFPlayer
 
 SPEC CHECKSUMS:
   AFNetworking: 7864c38297c79aaca1500c33288e429c3451fdce
@@ -149,7 +160,8 @@ SPEC CHECKSUMS:
   WechatOpenSDK: 6a4d1436c15b3b5fe2a0bd383f3046010186da44
   WMZPageController: fc76f3634a3bf2271d173cf4ba025e98b1cd76eb
   YYModel: 2a7fdd96aaa4b86a824e26d0c517de8928c04b30
+  ZFPlayer: 8a6021a3c45e281f2abd24dca5c88915af770a7e
 
-PODFILE CHECKSUM: 12bbd06aa1a59e99bda6807fbcf98653e08b0eb9
+PODFILE CHECKSUM: 5bb1dc9126facddf5df052597180631ec6302cee
 
 COCOAPODS: 1.8.4

File diff suppressed because it is too large
+ 2749 - 2332
Pods/Pods.xcodeproj/project.pbxproj


+ 60 - 0
Pods/Pods.xcodeproj/xcuserdata/niuzhen.xcuserdatad/xcschemes/ZFPlayer.xcscheme

@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "1100"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForAnalyzing = "YES"
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "93FD1F93E0C30B2749BD8A6EC148F233"
+               BuildableName = "ZFPlayer.framework"
+               BlueprintName = "ZFPlayer"
+               ReferencedContainer = "container:Pods.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      buildConfiguration = "Debug">
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </TestAction>
+   <LaunchAction
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      buildConfiguration = "Debug"
+      allowLocationSimulation = "YES">
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES"
+      buildConfiguration = "Release"
+      shouldUseLaunchSchemeArgsEnv = "YES">
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>

+ 5 - 0
Pods/Pods.xcodeproj/xcuserdata/niuzhen.xcuserdatad/xcschemes/xcschememanagement.plist

@@ -139,6 +139,11 @@
 			<key>isShown</key>
 			<false/>
 		</dict>
+		<key>ZFPlayer.xcscheme</key>
+		<dict>
+			<key>isShown</key>
+			<false/>
+		</dict>
 	</dict>
 	<key>SuppressBuildableAutocreation</key>
 	<dict/>

+ 23 - 0
Pods/Target Support Files/Pods-smartRhino/Pods-smartRhino-acknowledgements.markdown

@@ -481,4 +481,27 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 
 
+
+## ZFPlayer
+
+Copyright (c) 2018 renzifeng <zifeng1300@gmail.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
 Generated by CocoaPods - https://cocoapods.org

+ 29 - 0
Pods/Target Support Files/Pods-smartRhino/Pods-smartRhino-acknowledgements.plist

@@ -645,6 +645,35 @@ SOFTWARE.
 		</dict>
 		<dict>
 			<key>FooterText</key>
+			<string>Copyright (c) 2018 renzifeng &lt;zifeng1300@gmail.com&gt;
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+</string>
+			<key>License</key>
+			<string>MIT</string>
+			<key>Title</key>
+			<string>ZFPlayer</string>
+			<key>Type</key>
+			<string>PSGroupSpecifier</string>
+		</dict>
+		<dict>
+			<key>FooterText</key>
 			<string>Generated by CocoaPods - https://cocoapods.org</string>
 			<key>Title</key>
 			<string></string>

+ 2 - 1
Pods/Target Support Files/Pods-smartRhino/Pods-smartRhino-resources-Debug-input-files.xcfilelist

@@ -1,2 +1,3 @@
 ${PODS_ROOT}/Target Support Files/Pods-smartRhino/Pods-smartRhino-resources.sh
-${PODS_ROOT}/UMCShare/UMShare/SocialLibraries/Sina/SinaSDK/WeiboSDK.bundle
+${PODS_ROOT}/UMCShare/UMShare/SocialLibraries/Sina/SinaSDK/WeiboSDK.bundle
+${PODS_ROOT}/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle

+ 2 - 1
Pods/Target Support Files/Pods-smartRhino/Pods-smartRhino-resources-Debug-output-files.xcfilelist

@@ -1 +1,2 @@
-${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/WeiboSDK.bundle
+${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/WeiboSDK.bundle
+${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ZFPlayer.bundle

+ 2 - 1
Pods/Target Support Files/Pods-smartRhino/Pods-smartRhino-resources-Release-input-files.xcfilelist

@@ -1,2 +1,3 @@
 ${PODS_ROOT}/Target Support Files/Pods-smartRhino/Pods-smartRhino-resources.sh
-${PODS_ROOT}/UMCShare/UMShare/SocialLibraries/Sina/SinaSDK/WeiboSDK.bundle
+${PODS_ROOT}/UMCShare/UMShare/SocialLibraries/Sina/SinaSDK/WeiboSDK.bundle
+${PODS_ROOT}/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle

+ 2 - 1
Pods/Target Support Files/Pods-smartRhino/Pods-smartRhino-resources-Release-output-files.xcfilelist

@@ -1 +1,2 @@
-${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/WeiboSDK.bundle
+${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/WeiboSDK.bundle
+${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ZFPlayer.bundle

+ 2 - 0
Pods/Target Support Files/Pods-smartRhino/Pods-smartRhino-resources.sh

@@ -98,9 +98,11 @@ EOM
 }
 if [[ "$CONFIGURATION" == "Debug" ]]; then
   install_resource "${PODS_ROOT}/UMCShare/UMShare/SocialLibraries/Sina/SinaSDK/WeiboSDK.bundle"
+  install_resource "${PODS_ROOT}/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle"
 fi
 if [[ "$CONFIGURATION" == "Release" ]]; then
   install_resource "${PODS_ROOT}/UMCShare/UMShare/SocialLibraries/Sina/SinaSDK/WeiboSDK.bundle"
+  install_resource "${PODS_ROOT}/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle"
 fi
 
 mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"

File diff suppressed because it is too large
+ 4 - 4
Pods/Target Support Files/Pods-smartRhino/Pods-smartRhino.debug.xcconfig


File diff suppressed because it is too large
+ 4 - 4
Pods/Target Support Files/Pods-smartRhino/Pods-smartRhino.release.xcconfig


+ 26 - 0
Pods/Target Support Files/ZFPlayer/ZFPlayer-Info.plist

@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+  <key>CFBundleDevelopmentRegion</key>
+  <string>en</string>
+  <key>CFBundleExecutable</key>
+  <string>${EXECUTABLE_NAME}</string>
+  <key>CFBundleIdentifier</key>
+  <string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
+  <key>CFBundleInfoDictionaryVersion</key>
+  <string>6.0</string>
+  <key>CFBundleName</key>
+  <string>${PRODUCT_NAME}</string>
+  <key>CFBundlePackageType</key>
+  <string>FMWK</string>
+  <key>CFBundleShortVersionString</key>
+  <string>3.3.1</string>
+  <key>CFBundleSignature</key>
+  <string>????</string>
+  <key>CFBundleVersion</key>
+  <string>${CURRENT_PROJECT_VERSION}</string>
+  <key>NSPrincipalClass</key>
+  <string></string>
+</dict>
+</plist>

+ 5 - 0
Pods/Target Support Files/ZFPlayer/ZFPlayer-dummy.m

@@ -0,0 +1,5 @@
+#import <Foundation/Foundation.h>
+@interface PodsDummy_ZFPlayer : NSObject
+@end
+@implementation PodsDummy_ZFPlayer
+@end

+ 12 - 0
Pods/Target Support Files/ZFPlayer/ZFPlayer-prefix.pch

@@ -0,0 +1,12 @@
+#ifdef __OBJC__
+#import <UIKit/UIKit.h>
+#else
+#ifndef FOUNDATION_EXPORT
+#if defined(__cplusplus)
+#define FOUNDATION_EXPORT extern "C"
+#else
+#define FOUNDATION_EXPORT extern
+#endif
+#endif
+#endif
+

+ 42 - 0
Pods/Target Support Files/ZFPlayer/ZFPlayer-umbrella.h

@@ -0,0 +1,42 @@
+#ifdef __OBJC__
+#import <UIKit/UIKit.h>
+#else
+#ifndef FOUNDATION_EXPORT
+#if defined(__cplusplus)
+#define FOUNDATION_EXPORT extern "C"
+#else
+#define FOUNDATION_EXPORT extern
+#endif
+#endif
+#endif
+
+#import "ZFAVPlayerManager.h"
+#import "UIImageView+ZFCache.h"
+#import "UIView+ZFFrame.h"
+#import "ZFLandScapeControlView.h"
+#import "ZFLoadingView.h"
+#import "ZFNetworkSpeedMonitor.h"
+#import "ZFPlayerControlView.h"
+#import "ZFPortraitControlView.h"
+#import "ZFSliderView.h"
+#import "ZFSmallFloatControlView.h"
+#import "ZFSpeedLoadingView.h"
+#import "ZFUtilities.h"
+#import "ZFVolumeBrightnessView.h"
+#import "UIScrollView+ZFPlayer.h"
+#import "ZFFloatView.h"
+#import "ZFKVOController.h"
+#import "ZFOrientationObserver.h"
+#import "ZFPlayer.h"
+#import "ZFPlayerController.h"
+#import "ZFPlayerGestureControl.h"
+#import "ZFPlayerLogManager.h"
+#import "ZFPlayerMediaControl.h"
+#import "ZFPlayerMediaPlayback.h"
+#import "ZFPlayerNotification.h"
+#import "ZFPlayerView.h"
+#import "ZFReachabilityManager.h"
+
+FOUNDATION_EXPORT double ZFPlayerVersionNumber;
+FOUNDATION_EXPORT const unsigned char ZFPlayerVersionString[];
+

+ 6 - 0
Pods/Target Support Files/ZFPlayer/ZFPlayer.modulemap

@@ -0,0 +1,6 @@
+framework module ZFPlayer {
+  umbrella header "ZFPlayer-umbrella.h"
+
+  export *
+  module * { export * }
+}

+ 9 - 0
Pods/Target Support Files/ZFPlayer/ZFPlayer.xcconfig

@@ -0,0 +1,9 @@
+CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/ZFPlayer
+GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
+PODS_BUILD_DIR = ${BUILD_DIR}
+PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
+PODS_ROOT = ${SRCROOT}
+PODS_TARGET_SRCROOT = ${PODS_ROOT}/ZFPlayer
+PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
+SKIP_INSTALL = YES
+USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES

+ 19 - 0
Pods/ZFPlayer/LICENSE

@@ -0,0 +1,19 @@
+Copyright (c) 2018 renzifeng <zifeng1300@gmail.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

+ 131 - 0
Pods/ZFPlayer/README.md

@@ -0,0 +1,131 @@
+
+<p align="center">
+<img src="https://upload-images.jianshu.io/upload_images/635942-092427e571756309.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="ZFPlayer" title="ZFPlayer" width="557"/>
+</p>
+
+<p align="center">
+<a href="https://img.shields.io/cocoapods/v/ZFPlayer.svg"><img src="https://img.shields.io/cocoapods/v/ZFPlayer.svg"></a>
+<a href="https://img.shields.io/github/license/renzifeng/ZFPlayer.svg?style=flat"><img src="https://img.shields.io/github/license/renzifeng/ZFPlayer.svg?style=flat"></a>
+<a href="https://img.shields.io/cocoapods/dt/ZFPlayer.svg?maxAge=2592000"><img src="https://img.shields.io/cocoapods/dt/ZFPlayer.svg?maxAge=2592000"></a>
+<a href="https://img.shields.io/cocoapods/at/ZFPlayer.svg?maxAge=2592000"><img src="https://img.shields.io/cocoapods/at/ZFPlayer.svg?maxAge=2592000"></a>
+<a href="http://cocoadocs.org/docsets/ZFPlayer"><img src="https://img.shields.io/cocoapods/p/ZFPlayer.svg?style=flat"></a>
+<a href="http://weibo.com/zifeng1300"><img src="https://img.shields.io/badge/weibo-@%E4%BB%BB%E5%AD%90%E4%B8%B0-yellow.svg?style=flat"></a>
+</p>
+
+[中文说明](https://www.jianshu.com/p/90e55deb4d51)
+
+Before this, you used ZFPlayer, are you worried about encapsulating avplayer instead of using or modifying the source code to support other players, the control layer is not easy to customize, and so on? In order to solve these problems, I have wrote this player template, for player SDK you can conform the `ZFPlayerMediaPlayback` protocol, for control view you can conform the `ZFPlayerMediaControl` protocol, can custom the player and control view.
+
+在3.X之前,是不是在烦恼播放器SDK自定义、控制层自定义等问题。作者公司多个项目分别使用不同播放器SDK以及每个项目控制层都不一样,但是为了统一管理、统一调用,我特意写了这个播放器壳子。播放器SDK只要遵守`ZFPlayerMediaPlayback`协议,控制层只要遵守`ZFPlayerMediaControl`协议,完全可以实现自定义播放器和控制层。
+
+![ZFPlayer思维导图](https://upload-images.jianshu.io/upload_images/635942-e99d76498cb01afb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
+
+## Requirements
+
+- iOS 7+
+- Xcode 8+
+
+## Installation
+
+ZFPlayer is available through [CocoaPods](https://cocoapods.org). To install it,use player template simply add the following line to your Podfile:
+
+```objc
+pod 'ZFPlayer', '~> 3.0'
+```
+
+Use default controlView simply add the following line to your Podfile:
+
+```objc
+pod 'ZFPlayer/ControlView', '~> 3.0'
+```
+Use AVPlayer simply add the following line to your Podfile:
+
+```objc
+pod 'ZFPlayer/AVPlayer', '~> 3.0'
+```
+如果使用AVPlayer边下边播可以参考使用[KTVHTTPCache](https://github.com/ChangbaDevs/KTVHTTPCache)
+
+Use ijkplayer simply add the following line to your Podfile:
+
+```objc
+pod 'ZFPlayer/ijkplayer', '~> 3.0'
+```
+[IJKMediaFramework SDK](https://gitee.com/renzifeng/IJKMediaFramework) support cocoapods
+
+Use KSYMediaPlayer simply add the following line to your Podfile:
+
+```objc
+pod 'ZFPlayer/KSYMediaPlayer', '~> 3.0'
+```
+[KSYMediaPlayer SDK](https://github.com/ksvc/KSYMediaPlayer_iOS) support cocoapods
+
+## Usage introduce
+
+####  ZFPlayerController
+Main classes,normal style initialization and list style initialization (tableView, collection,scrollView)
+
+Normal style initialization 
+
+```objc
+ZFPlayerController *player = [ZFPlayerController playerWithPlayerManager:playerManager containerView:containerView];
+ZFPlayerController *player = [[ZFPlayerController alloc] initwithPlayerManager:playerManager containerView:containerView];
+```
+
+List style initialization
+
+```objc
+ZFPlayerController *player = [ZFPlayerController playerWithScrollView:tableView playerManager:playerManager containerViewTag:containerViewTag];
+ZFPlayerController *player = [ZFPlayerController alloc] initWithScrollView:tableView playerManager:playerManager containerViewTag:containerViewTag];
+ZFPlayerController *player = [ZFPlayerController playerWithScrollView:scrollView playerManager:playerManager containerView:containerView];
+ZFPlayerController *player = [ZFPlayerController alloc] initWithScrollView:tableView playerManager:playerManager containerView:containerView];
+```
+
+#### ZFPlayerMediaPlayback
+For the playerMnager,you must conform `ZFPlayerMediaPlayback` protocol,custom playermanager can supports any player SDK,such as `AVPlayer`,`MPMoviePlayerController`,`ijkplayer`,`vlc`,`PLPlayerKit`,`KSYMediaPlayer`and so on,you can reference the `ZFAVPlayerManager`class.
+
+```objc
+Class<ZFPlayerMediaPlayback> *playerManager = ...;
+```
+
+#### ZFPlayerMediaControl
+This class is used to display the control layer, and you must conform the ZFPlayerMediaControl protocol, you can reference the `ZFPlayerControlView` class.
+
+```objc
+UIView<ZFPlayerMediaControl> *controlView = ...;
+player.controlView = controlView;
+```
+
+
+## Picture demonstration
+
+![Picture effect](https://upload-images.jianshu.io/upload_images/635942-1b0e23b7f5eabd9e.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
+
+
+## Author
+
+- Weibo: [@任子丰](https://weibo.com/zifeng1300)
+- Email: zifeng1300@gmail.com
+- QQ群: 123449304
+
+![](https://upload-images.jianshu.io/upload_images/635942-a9fbbb2710de8eff.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
+
+## Contributors
+
+林界:https://github.com/GeekLee609
+
+
+## 寻求志同道合的小伙伴
+
+- 因本人工作忙,没有太多时间去维护ZFPlayer,在此向广大框架使用者说声:非常抱歉!😞
+- 现寻求志同道合的小伙伴一起维护此框架,有兴趣的小伙伴可以[发邮件](zifeng1300@gmail.com)给我,非常感谢😊
+- 如果一切OK,我将开放框架维护权限(github、pod等)
+- 目前已经找到1位小伙伴 
+
+## 打赏作者
+
+如果ZFPlayer在开发中有帮助到你、如果你需要技术支持或者你需要定制功能,都可以拼命打赏我!
+
+![支付.jpg](https://upload-images.jianshu.io/upload_images/635942-b9b836cfbb7a5e44.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
+
+
+

+ 42 - 0
Pods/ZFPlayer/ZFPlayer/Classes/AVPlayer/ZFAVPlayerManager.h

@@ -0,0 +1,42 @@
+//
+//  ZFAVPlayerManager.h
+//  ZFPlayer
+//
+// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import <Foundation/Foundation.h>
+#import <AVFoundation/AVFoundation.h>
+#if __has_include(<ZFPlayer/ZFPlayerMediaPlayback.h>)
+#import <ZFPlayer/ZFPlayerMediaPlayback.h>
+#else
+#import "ZFPlayerMediaPlayback.h"
+#endif
+
+@interface ZFAVPlayerManager : NSObject <ZFPlayerMediaPlayback>
+
+@property (nonatomic, strong, readonly) AVURLAsset *asset;
+@property (nonatomic, strong, readonly) AVPlayerItem *playerItem;
+@property (nonatomic, strong, readonly) AVPlayer *player;
+@property (nonatomic, assign) NSTimeInterval timeRefreshInterval;
+/// 视频请求头
+@property (nonatomic, strong) NSDictionary *requestHeader;
+
+@end

+ 490 - 0
Pods/ZFPlayer/ZFPlayer/Classes/AVPlayer/ZFAVPlayerManager.m

@@ -0,0 +1,490 @@
+//
+//  ZFAVPlayerManager.m
+//  ZFPlayer
+//
+// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import "ZFAVPlayerManager.h"
+#import <UIKit/UIKit.h>
+#if __has_include(<ZFPlayer/ZFPlayer.h>)
+#import <ZFPlayer/ZFPlayer.h>
+#import <ZFPlayer/ZFReachabilityManager.h>
+#else
+#import "ZFPlayer.h"
+#import "ZFReachabilityManager.h"
+#endif
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored"-Wdeprecated-declarations"
+
+/*!
+ *  Refresh interval for timed observations of AVPlayer
+ */
+static NSString *const kStatus                   = @"status";
+static NSString *const kLoadedTimeRanges         = @"loadedTimeRanges";
+static NSString *const kPlaybackBufferEmpty      = @"playbackBufferEmpty";
+static NSString *const kPlaybackLikelyToKeepUp   = @"playbackLikelyToKeepUp";
+static NSString *const kPresentationSize         = @"presentationSize";
+
+@interface ZFPlayerPresentView : ZFPlayerView
+
+@property (nonatomic, strong) AVPlayer *player;
+/// default is AVLayerVideoGravityResizeAspect.
+@property (nonatomic, strong) AVLayerVideoGravity videoGravity;
+
+@end
+
+@implementation ZFPlayerPresentView
+
++ (Class)layerClass {
+    return [AVPlayerLayer class];
+}
+
+- (AVPlayerLayer *)avLayer {
+    return (AVPlayerLayer *)self.layer;
+}
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    self = [super initWithFrame:frame];
+    if (self) {
+        self.backgroundColor = [UIColor blackColor];
+    }
+    return self;
+}
+
+- (void)setPlayer:(AVPlayer *)player {
+    if (player == _player) return;
+    self.avLayer.player = player;
+}
+
+- (void)setVideoGravity:(AVLayerVideoGravity)videoGravity {
+    if (videoGravity == self.videoGravity) return;
+    [self avLayer].videoGravity = videoGravity;
+}
+
+- (AVLayerVideoGravity)videoGravity {
+    return [self avLayer].videoGravity;
+}
+
+@end
+
+@interface ZFAVPlayerManager () {
+    id _timeObserver;
+    id _itemEndObserver;
+    ZFKVOController *_playerItemKVO;
+}
+@property (nonatomic, strong) AVPlayerLayer *playerLayer;
+@property (nonatomic, assign) BOOL isBuffering;
+@property (nonatomic, assign) BOOL isReadyToPlay;
+
+@end
+
+@implementation ZFAVPlayerManager
+
+@synthesize view                           = _view;
+@synthesize currentTime                    = _currentTime;
+@synthesize totalTime                      = _totalTime;
+@synthesize playerPlayTimeChanged          = _playerPlayTimeChanged;
+@synthesize playerBufferTimeChanged        = _playerBufferTimeChanged;
+@synthesize playerDidToEnd                 = _playerDidToEnd;
+@synthesize bufferTime                     = _bufferTime;
+@synthesize playState                      = _playState;
+@synthesize loadState                      = _loadState;
+@synthesize assetURL                       = _assetURL;
+@synthesize playerPrepareToPlay            = _playerPrepareToPlay;
+@synthesize playerReadyToPlay              = _playerReadyToPlay;
+@synthesize playerPlayStateChanged         = _playerPlayStateChanged;
+@synthesize playerLoadStateChanged         = _playerLoadStateChanged;
+@synthesize seekTime                       = _seekTime;
+@synthesize muted                          = _muted;
+@synthesize volume                         = _volume;
+@synthesize presentationSize               = _presentationSize;
+@synthesize isPlaying                      = _isPlaying;
+@synthesize rate                           = _rate;
+@synthesize isPreparedToPlay               = _isPreparedToPlay;
+@synthesize shouldAutoPlay                 = _shouldAutoPlay;
+@synthesize scalingMode                    = _scalingMode;
+@synthesize playerPlayFailed               = _playerPlayFailed;
+@synthesize presentationSizeChanged        = _presentationSizeChanged;
+
+- (instancetype)init {
+    self = [super init];
+    if (self) {
+        _scalingMode = ZFPlayerScalingModeAspectFit;
+        _shouldAutoPlay = YES;
+    }
+    return self;
+}
+
+- (void)prepareToPlay {
+    if (!_assetURL) return;
+    _isPreparedToPlay = YES;
+    [self initializePlayer];
+    if (self.shouldAutoPlay) {
+        [self play];
+    }
+    self.loadState = ZFPlayerLoadStatePrepare;
+    if (self.playerPrepareToPlay) self.playerPrepareToPlay(self, self.assetURL);
+}
+
+- (void)reloadPlayer {
+    self.seekTime = self.currentTime;
+    [self prepareToPlay];
+}
+
+- (void)play {
+    if (!_isPreparedToPlay) {
+        [self prepareToPlay];
+    } else {
+        [self.player play];
+        self.player.rate = self.rate;
+        self->_isPlaying = YES;
+        self.playState = ZFPlayerPlayStatePlaying;
+    }
+}
+
+- (void)pause {
+    [self.player pause];
+    self->_isPlaying = NO;
+    self.playState = ZFPlayerPlayStatePaused;
+    [_playerItem cancelPendingSeeks];
+    [_asset cancelLoading];
+}
+
+- (void)stop {
+    [_playerItemKVO safelyRemoveAllObservers];
+    self.loadState = ZFPlayerLoadStateUnknown;
+    self.playState = ZFPlayerPlayStatePlayStopped;
+    if (self.player.rate != 0) [self.player pause];
+    [self.player removeTimeObserver:_timeObserver];
+    [self.player replaceCurrentItemWithPlayerItem:nil];
+    _timeObserver = nil;
+    [[NSNotificationCenter defaultCenter] removeObserver:_itemEndObserver name:AVPlayerItemDidPlayToEndTimeNotification object:self.playerItem];
+    _itemEndObserver = nil;
+    _isPlaying = NO;
+    _player = nil;
+    _assetURL = nil;
+    _playerItem = nil;
+    _isPreparedToPlay = NO;
+    self->_currentTime = 0;
+    self->_totalTime = 0;
+    self->_bufferTime = 0;
+    self.isReadyToPlay = NO;
+}
+
+- (void)replay {
+    @weakify(self)
+    [self seekToTime:0 completionHandler:^(BOOL finished) {
+        @strongify(self)
+        [self play];
+    }];
+}
+
+- (void)seekToTime:(NSTimeInterval)time completionHandler:(void (^ __nullable)(BOOL finished))completionHandler {
+    if (self.totalTime > 0) {
+        CMTime seekTime = CMTimeMake(time, 1);
+        [_player seekToTime:seekTime toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero completionHandler:completionHandler];
+    } else {
+        self.seekTime = time;
+    }
+}
+
+- (UIImage *)thumbnailImageAtCurrentTime {
+    AVAssetImageGenerator *imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:_asset];
+    CMTime expectedTime = _playerItem.currentTime;
+    CGImageRef cgImage = NULL;
+    
+    imageGenerator.requestedTimeToleranceBefore = kCMTimeZero;
+    imageGenerator.requestedTimeToleranceAfter = kCMTimeZero;
+    cgImage = [imageGenerator copyCGImageAtTime:expectedTime actualTime:NULL error:NULL];
+    
+    if (!cgImage) {
+        imageGenerator.requestedTimeToleranceBefore = kCMTimePositiveInfinity;
+        imageGenerator.requestedTimeToleranceAfter = kCMTimePositiveInfinity;
+        cgImage = [imageGenerator copyCGImageAtTime:expectedTime actualTime:NULL error:NULL];
+    }
+    
+    UIImage *image = [UIImage imageWithCGImage:cgImage];
+    return image;
+}
+
+#pragma mark - private method
+
+/// Calculate buffer progress
+- (NSTimeInterval)availableDuration {
+    NSArray *timeRangeArray = _playerItem.loadedTimeRanges;
+    CMTime currentTime = [_player currentTime];
+    BOOL foundRange = NO;
+    CMTimeRange aTimeRange = {0};
+    if (timeRangeArray.count) {
+        aTimeRange = [[timeRangeArray objectAtIndex:0] CMTimeRangeValue];
+        if (CMTimeRangeContainsTime(aTimeRange, currentTime)) {
+            foundRange = YES;
+        }
+    }
+    
+    if (foundRange) {
+        CMTime maxTime = CMTimeRangeGetEnd(aTimeRange);
+        NSTimeInterval playableDuration = CMTimeGetSeconds(maxTime);
+        if (playableDuration > 0) {
+            return playableDuration;
+        }
+    }
+    return 0;
+}
+
+- (void)initializePlayer {
+    _asset = [AVURLAsset URLAssetWithURL:self.assetURL options:self.requestHeader];
+    _playerItem = [AVPlayerItem playerItemWithAsset:_asset];
+    _player = [AVPlayer playerWithPlayerItem:_playerItem];
+    [self enableAudioTracks:YES inPlayerItem:_playerItem];
+    
+    ZFPlayerPresentView *presentView = (ZFPlayerPresentView *)self.view;
+    presentView.player = _player;
+    self.scalingMode = _scalingMode;
+    if (@available(iOS 9.0, *)) {
+        _playerItem.canUseNetworkResourcesForLiveStreamingWhilePaused = NO;
+    }
+    if (@available(iOS 10.0, *)) {
+        _playerItem.preferredForwardBufferDuration = 5;
+        _player.automaticallyWaitsToMinimizeStalling = NO;
+    }
+    [self itemObserving];
+}
+
+/// Playback speed switching method
+- (void)enableAudioTracks:(BOOL)enable inPlayerItem:(AVPlayerItem*)playerItem {
+    for (AVPlayerItemTrack *track in playerItem.tracks){
+        if ([track.assetTrack.mediaType isEqual:AVMediaTypeVideo]) {
+            track.enabled = enable;
+        }
+    }
+}
+
+/**
+ *  缓冲较差时候回调这里
+ */
+- (void)bufferingSomeSecond {
+    // playbackBufferEmpty会反复进入,因此在bufferingOneSecond延时播放执行完之前再调用bufferingSomeSecond都忽略
+    if (self.isBuffering || self.playState == ZFPlayerPlayStatePlayStopped) return;
+    /// 没有网络
+    if ([ZFReachabilityManager sharedManager].networkReachabilityStatus == ZFReachabilityStatusNotReachable) return;
+    self.isBuffering = YES;
+    
+    // 需要先暂停一小会之后再播放,否则网络状况不好的时候时间在走,声音播放不出来
+    [self.player pause];
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+        // 如果此时用户已经暂停了,则不再需要开启播放了
+        if (!self.isPlaying && self.loadState == ZFPlayerLoadStateStalled) {
+            self.isBuffering = NO;
+            return;
+        }
+        [self play];
+        // 如果执行了play还是没有播放则说明还没有缓存好,则再次缓存一段时间
+        self.isBuffering = NO;
+        if (!self.playerItem.isPlaybackLikelyToKeepUp) [self bufferingSomeSecond];
+    });
+}
+
+- (void)itemObserving {
+    [_playerItemKVO safelyRemoveAllObservers];
+    _playerItemKVO = [[ZFKVOController alloc] initWithTarget:_playerItem];
+    [_playerItemKVO safelyAddObserver:self
+                           forKeyPath:kStatus
+                              options:NSKeyValueObservingOptionNew
+                              context:nil];
+    [_playerItemKVO safelyAddObserver:self
+                           forKeyPath:kPlaybackBufferEmpty
+                              options:NSKeyValueObservingOptionNew
+                              context:nil];
+    [_playerItemKVO safelyAddObserver:self
+                           forKeyPath:kPlaybackLikelyToKeepUp
+                              options:NSKeyValueObservingOptionNew
+                              context:nil];
+    [_playerItemKVO safelyAddObserver:self
+                           forKeyPath:kLoadedTimeRanges
+                              options:NSKeyValueObservingOptionNew
+                              context:nil];
+    [_playerItemKVO safelyAddObserver:self
+                           forKeyPath:kPresentationSize
+                              options:NSKeyValueObservingOptionNew
+                              context:nil];
+    
+    CMTime interval = CMTimeMakeWithSeconds(self.timeRefreshInterval > 0 ? self.timeRefreshInterval : 0.1, NSEC_PER_SEC);
+    @weakify(self)
+    _timeObserver = [self.player addPeriodicTimeObserverForInterval:interval queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
+        @strongify(self)
+        if (!self) return;
+        NSArray *loadedRanges = self.playerItem.seekableTimeRanges;
+        if (self.isPlaying && self.loadState == ZFPlayerLoadStateStalled) self.player.rate = self.rate;
+        if (loadedRanges.count > 0) {
+            if (self.playerPlayTimeChanged) self.playerPlayTimeChanged(self, self.currentTime, self.totalTime);
+        }
+    }];
+    
+    _itemEndObserver = [[NSNotificationCenter defaultCenter] addObserverForName:AVPlayerItemDidPlayToEndTimeNotification object:self.playerItem queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
+        @strongify(self)
+        if (!self) return;
+        self.playState = ZFPlayerPlayStatePlayStopped;
+        if (self.playerDidToEnd) self.playerDidToEnd(self);
+    }];
+}
+
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
+    dispatch_async(dispatch_get_main_queue(), ^{
+        if ([keyPath isEqualToString:kStatus]) {
+            if (self.player.currentItem.status == AVPlayerItemStatusReadyToPlay) {
+                if (!self.isReadyToPlay) {
+                    self.isReadyToPlay = YES;
+                    self.loadState = ZFPlayerLoadStatePlaythroughOK;
+                    if (self.playerReadyToPlay) self.playerReadyToPlay(self, self.assetURL);
+                }
+                if (self.seekTime) {
+                    [self seekToTime:self.seekTime completionHandler:nil];
+                    self.seekTime = 0;
+                }
+                if (self.isPlaying) [self play];
+                self.player.muted = self.muted;
+                NSArray *loadedRanges = self.playerItem.seekableTimeRanges;
+                if (loadedRanges.count > 0) {
+                    /// Fix https://github.com/renzifeng/ZFPlayer/issues/475
+                    if (self.playerPlayTimeChanged) self.playerPlayTimeChanged(self, self.currentTime, self.totalTime);
+                }
+            } else if (self.player.currentItem.status == AVPlayerItemStatusFailed) {
+                self.playState = ZFPlayerPlayStatePlayFailed;
+                NSError *error = self.player.currentItem.error;
+                if (self.playerPlayFailed) self.playerPlayFailed(self, error);
+            }
+        } else if ([keyPath isEqualToString:kPlaybackBufferEmpty]) {
+            // When the buffer is empty
+            if (self.playerItem.playbackBufferEmpty) {
+                self.loadState = ZFPlayerLoadStateStalled;
+                [self bufferingSomeSecond];
+            }
+        } else if ([keyPath isEqualToString:kPlaybackLikelyToKeepUp]) {
+            // When the buffer is good
+            if (self.playerItem.playbackLikelyToKeepUp) {
+                self.loadState = ZFPlayerLoadStatePlayable;
+                if (self.isPlaying) [self.player play];
+            }
+        } else if ([keyPath isEqualToString:kLoadedTimeRanges]) {
+            NSTimeInterval bufferTime = [self availableDuration];
+            self->_bufferTime = bufferTime;
+            if (self.playerBufferTimeChanged) self.playerBufferTimeChanged(self, bufferTime);
+        } else if ([keyPath isEqualToString:kPresentationSize]) {
+            self->_presentationSize = self.playerItem.presentationSize;
+            if (self.presentationSizeChanged) {
+                self.presentationSizeChanged(self, self->_presentationSize);
+            }
+        } else {
+            [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
+        }
+    });
+}
+
+#pragma mark - getter
+
+- (UIView *)view {
+    if (!_view) {
+        _view = [[ZFPlayerPresentView alloc] init];
+    }
+    return _view;
+}
+
+- (float)rate {
+    return _rate == 0 ?1:_rate;
+}
+
+- (NSTimeInterval)totalTime {
+    NSTimeInterval sec = CMTimeGetSeconds(self.player.currentItem.duration);
+    if (isnan(sec)) {
+        return 0;
+    }
+    return sec;
+}
+
+- (NSTimeInterval)currentTime {
+    NSTimeInterval sec = CMTimeGetSeconds(self.playerItem.currentTime);
+    if (isnan(sec) || sec < 0) {
+        return 0;
+    }
+    return sec;
+}
+
+#pragma mark - setter
+
+- (void)setPlayState:(ZFPlayerPlaybackState)playState {
+    _playState = playState;
+    if (self.playerPlayStateChanged) self.playerPlayStateChanged(self, playState);
+}
+
+- (void)setLoadState:(ZFPlayerLoadState)loadState {
+    _loadState = loadState;
+    if (self.playerLoadStateChanged) self.playerLoadStateChanged(self, loadState);
+}
+
+- (void)setAssetURL:(NSURL *)assetURL {
+    if (self.player) [self stop];
+    _assetURL = assetURL;
+    [self prepareToPlay];
+}
+
+- (void)setRate:(float)rate {
+    _rate = rate;
+    if (self.player && fabsf(_player.rate) > 0.00001f) {
+        self.player.rate = rate;
+    }
+}
+
+- (void)setMuted:(BOOL)muted {
+    _muted = muted;
+    self.player.muted = muted;
+}
+
+- (void)setScalingMode:(ZFPlayerScalingMode)scalingMode {
+    _scalingMode = scalingMode;
+    ZFPlayerPresentView *presentView = (ZFPlayerPresentView *)self.view;
+    switch (scalingMode) {
+        case ZFPlayerScalingModeNone:
+            presentView.videoGravity = AVLayerVideoGravityResizeAspect;
+            break;
+        case ZFPlayerScalingModeAspectFit:
+            presentView.videoGravity = AVLayerVideoGravityResizeAspect;
+            break;
+        case ZFPlayerScalingModeAspectFill:
+            presentView.videoGravity = AVLayerVideoGravityResizeAspectFill;
+            break;
+        case ZFPlayerScalingModeFill:
+            presentView.videoGravity = AVLayerVideoGravityResize;
+            break;
+        default:
+            break;
+    }
+}
+
+- (void)setVolume:(float)volume {
+    _volume = MIN(MAX(0, volume), 1);
+    self.player.volume = volume;
+}
+
+@end
+
+#pragma clang diagnostic pop

+ 127 - 0
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/UIImageView+ZFCache.h

@@ -0,0 +1,127 @@
+//
+//  UIImageView+ZFCache.h
+//  ZFPlayer
+//
+// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import <UIKit/UIKit.h>
+
+typedef void (^ZFDownLoadDataCallBack)(NSData *data, NSError *error);
+typedef void (^ZFDownloadProgressBlock)(unsigned long long total, unsigned long long current);
+
+@interface ZFImageDownloader : NSObject<NSURLSessionDownloadDelegate>
+
+@property (nonatomic, strong) NSURLSession *session;
+@property (nonatomic, strong) NSURLSessionDownloadTask *task;
+
+@property (nonatomic, assign) unsigned long long totalLength;
+@property (nonatomic, assign) unsigned long long currentLength;
+
+@property (nonatomic, copy) ZFDownloadProgressBlock progressBlock;
+@property (nonatomic, copy) ZFDownLoadDataCallBack callbackOnFinished;
+
+- (void)startDownloadImageWithUrl:(NSString *)url
+                         progress:(ZFDownloadProgressBlock)progress
+                         finished:(ZFDownLoadDataCallBack)finished;
+
+@end
+
+typedef void (^ZFImageBlock)(UIImage *image);
+
+@interface UIImageView (ZFCache)
+
+/**
+ *  Get/Set the callback block when download the image finished.
+ *
+ *  The image object from network or from disk.
+ */
+@property (nonatomic, copy) ZFImageBlock completion;
+
+/**
+ *  Image downloader
+ */
+@property (nonatomic, strong) ZFImageDownloader *imageDownloader;
+
+/**
+ *	Specify the URL to download images fails, the number of retries, the default is 2
+ */
+@property (nonatomic, assign) NSUInteger attemptToReloadTimesForFailedURL;
+
+/**
+ *	Will automatically download to cutting for UIImageView size of image.The default value is NO.
+ *  If set to YES, then the download after a successful store only after cutting the image
+ */
+@property (nonatomic, assign) BOOL shouldAutoClipImageToViewSize;
+
+/**
+ * Set the imageView `image` with an `url` and a placeholder.
+ *
+ * The download is asynchronous and cached.
+ *
+ * @param url         The url for the image.
+ * @param placeholderImageName The image name to be set initially, until the image request finishes.
+ */
+- (void)setImageWithURLString:(NSString *)url placeholderImageName:(NSString *)placeholderImageName;
+
+/**
+ * Set the imageView `image` with an `url` and a placeholder.
+ *
+ * The download is asynchronous and cached.
+ *
+ * @param url              The url for the image.
+ * @param placeholderImage The image to be set initially, until the image request finishes.
+ */
+- (void)setImageWithURLString:(NSString *)url placeholder:(UIImage *)placeholderImage;
+
+/**
+ * Set the imageView `image` with an `url`, placeholder.
+ *
+ * The download is asynchronous and cached.
+ *
+ * @param url               The url for the image.
+ * @param placeholderImage  The image to be set initially, until the image request finishes.
+ * @param completion        A block called when operation has been completed. This block has no return value
+ *                          and takes the requested UIImage as first parameter. In case of error the image parameter
+ *                          is nil and the second parameter may contain an NSError. The third parameter is a Boolean
+ *                          indicating if the image was retrieved from the local cache or from the network.
+ *                          The fourth parameter is the original image url.
+ */
+- (void)setImageWithURLString:(NSString *)url
+                  placeholder:(UIImage *)placeholderImage
+                   completion:(void (^)(UIImage *image))completion;
+
+/**
+ * Set the imageView `image` with an `url`, placeholder.
+ *
+ * The download is asynchronous and cached.
+ *
+ * @param url            The url for the image.
+ * @param placeholderImageName    The image name to be set initially, until the image request finishes.
+ * @param completion     A block called when operation has been completed. This block has no return value
+ *                       and takes the requested UIImage as first parameter. In case of error the image parameter
+ *                       is nil and the second parameter may contain an NSError. The third parameter is a Boolean
+ *                       indicating if the image was retrieved from the local cache or from the network.
+ *                       The fourth parameter is the original image url.
+ */
+- (void)setImageWithURLString:(NSString *)url
+         placeholderImageName:(NSString *)placeholderImageName
+                   completion:(void (^)(UIImage *image))completion;
+@end

+ 420 - 0
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/UIImageView+ZFCache.m

@@ -0,0 +1,420 @@
+//
+//  UIImageView+ZFCache.m
+//  ZFPlayer
+//
+// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import "UIImageView+ZFCache.h"
+#import <objc/runtime.h>
+#import <CommonCrypto/CommonDigest.h>
+
+@implementation ZFImageDownloader
+
+- (void)startDownloadImageWithUrl:(NSString *)url
+                         progress:(ZFDownloadProgressBlock)progress
+                         finished:(ZFDownLoadDataCallBack)finished {
+    self.progressBlock = progress;
+    self.callbackOnFinished = finished;
+    
+    if ([NSURL URLWithString:url] == nil) {
+        if (finished) { finished(nil, nil); }
+        return;
+    }
+    
+    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]
+                                                           cachePolicy:NSURLRequestReturnCacheDataElseLoad
+                                                       timeoutInterval:60];
+    [request addValue:@"image/*" forHTTPHeaderField:@"Accept"];
+    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
+    NSOperationQueue *queue = [[NSOperationQueue alloc]init];
+    self.session = [NSURLSession sessionWithConfiguration:config
+                                                 delegate:self
+                                            delegateQueue:queue];
+    NSURLSessionDownloadTask *task = [self.session downloadTaskWithRequest:request];
+    [task resume];
+    self.task = task;
+}
+
+- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {
+    NSData *data = [NSData dataWithContentsOfURL:location];
+    
+    if (self.progressBlock) {
+        self.progressBlock(self.totalLength, self.currentLength);
+    }
+    
+    if (self.callbackOnFinished) {
+        self.callbackOnFinished(data, nil);
+        
+        // 防止重复调用
+        self.callbackOnFinished = nil;
+    }
+}
+
+- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
+    self.currentLength = totalBytesWritten;
+    self.totalLength = totalBytesExpectedToWrite;
+    
+    if (self.progressBlock) {
+        self.progressBlock(self.totalLength, self.currentLength);
+    }
+}
+
+- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
+    if ([error code] != NSURLErrorCancelled) {
+        if (self.callbackOnFinished) {
+            self.callbackOnFinished(nil, error);
+        }
+        self.callbackOnFinished = nil;
+    }
+}
+
+@end
+
+@interface NSString (md5)
+
++ (NSString *)cachedFileNameForKey:(NSString *)key;
++ (NSString *)zf_cachePath;
++ (NSString *)zf_keyForRequest:(NSURLRequest *)request;
+
+@end
+
+@implementation NSString (md5)
+
++ (NSString *)zf_keyForRequest:(NSURLRequest *)request{
+    return request.URL.absoluteString;
+}
+
++ (NSString *)zf_cachePath {
+    NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
+    NSString *directoryPath = [NSString stringWithFormat:@"%@/%@/%@",cachePath,@"default",@"com.hackemist.SDWebImageCache.default"];
+    return directoryPath;
+}
+
++ (NSString *)cachedFileNameForKey:(NSString *)key {
+    const char *str = [key UTF8String];
+    if (str == NULL) {
+        str = "";
+    }
+    unsigned char r[CC_MD5_DIGEST_LENGTH];
+    CC_MD5(str, (CC_LONG)strlen(str), r);
+    NSString *filename = [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%@",
+                          r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7], r[8], r[9], r[10],
+                          r[11], r[12], r[13], r[14], r[15], [[key pathExtension] isEqualToString:@""] ? @"" : [NSString stringWithFormat:@".%@", [key pathExtension]]];
+    
+    return filename;
+}
+
+@end
+
+@interface UIApplication (ZFCacheImage)
+
+@property (nonatomic, strong, readonly) NSMutableDictionary *zf_cacheFaileTimes;
+
+- (UIImage *)zf_cacheImageForRequest:(NSURLRequest *)request;
+- (void)zf_cacheImage:(UIImage *)image forRequest:(NSURLRequest *)request;
+- (void)zf_cacheFailRequest:(NSURLRequest *)request;
+- (NSUInteger)zf_failTimesForRequest:(NSURLRequest *)request;
+
+@end
+
+@implementation UIApplication (ZFCacheImage)
+
+- (NSMutableDictionary *)zf_cacheFaileTimes {
+    NSMutableDictionary *dict = objc_getAssociatedObject(self, _cmd);
+    if (!dict) {
+        dict = [[NSMutableDictionary alloc] init];
+    }
+    return dict;
+}
+
+- (void)setZf_cacheFaileTimes:(NSMutableDictionary *)zf_cacheFaileTimes {
+    objc_setAssociatedObject(self, @selector(zf_cacheFaileTimes), zf_cacheFaileTimes, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+- (void)zf_clearCache {
+    [self.zf_cacheFaileTimes removeAllObjects];
+    self.zf_cacheFaileTimes = nil;
+}
+
+- (void)zf_clearDiskCaches {
+    NSString *directoryPath = [NSString zf_cachePath];
+    if ([[NSFileManager defaultManager] fileExistsAtPath:directoryPath isDirectory:nil]) {
+        dispatch_queue_t ioQueue = dispatch_queue_create("com.hackemist.SDWebImageCache", DISPATCH_QUEUE_SERIAL);
+        dispatch_async(ioQueue, ^{
+            NSError *error = nil;
+            [[NSFileManager defaultManager] removeItemAtPath:directoryPath error:&error];
+            [[NSFileManager defaultManager] createDirectoryAtPath:directoryPath
+                                      withIntermediateDirectories:YES
+                                                       attributes:nil
+                                                            error:nil];
+        });
+    }
+    [self zf_clearCache];
+}
+
+- (UIImage *)zf_cacheImageForRequest:(NSURLRequest *)request {
+    if (request) {
+        NSString *directoryPath = [NSString zf_cachePath];
+        NSString *path = [NSString stringWithFormat:@"%@/%@", directoryPath, [NSString cachedFileNameForKey:[NSString zf_keyForRequest:request]]];
+        return [UIImage imageWithContentsOfFile:path];
+    }
+    return nil;
+}
+
+- (NSUInteger)zf_failTimesForRequest:(NSURLRequest *)request {
+    NSNumber *faileTimes = [self.zf_cacheFaileTimes objectForKey:[NSString cachedFileNameForKey:[NSString zf_keyForRequest:request]]];
+    if (faileTimes && [faileTimes respondsToSelector:@selector(integerValue)]) {
+        return faileTimes.integerValue;
+    }
+    return 0;
+}
+
+- (void)zf_cacheFailRequest:(NSURLRequest *)request {
+    NSNumber *faileTimes = [self.zf_cacheFaileTimes objectForKey:[NSString cachedFileNameForKey:[NSString zf_keyForRequest:request]]];
+    NSUInteger times = 0;
+    if (faileTimes && [faileTimes respondsToSelector:@selector(integerValue)]) {
+        times = [faileTimes integerValue];
+    }
+    
+    times++;
+    
+    [self.zf_cacheFaileTimes setObject:@(times) forKey:[NSString cachedFileNameForKey:[NSString zf_keyForRequest:request]]];
+}
+
+- (void)zf_cacheImage:(UIImage *)image forRequest:(NSURLRequest *)request {
+    if (!image || !request) { return; }
+    
+    NSString *directoryPath = [NSString zf_cachePath];
+    
+    if (![[NSFileManager defaultManager] fileExistsAtPath:directoryPath isDirectory:nil]) {
+        NSError *error = nil;
+        [[NSFileManager defaultManager] createDirectoryAtPath:directoryPath
+                                  withIntermediateDirectories:YES
+                                                   attributes:nil
+                                                        error:&error];
+        if (error) { return; }
+    }
+    
+    NSString *path = [NSString stringWithFormat:@"%@/%@", directoryPath, [NSString cachedFileNameForKey:[NSString zf_keyForRequest:request]]];
+    NSData *data = UIImagePNGRepresentation(image);
+    if (data) {
+        [[NSFileManager defaultManager] createFileAtPath:path contents:data attributes:nil];
+    }
+}
+
+@end
+
+
+@implementation UIImageView (ZFCache)
+
+#pragma mark - getter
+
+- (ZFImageBlock)completion
+{
+    return objc_getAssociatedObject(self, _cmd);
+}
+
+- (ZFImageDownloader *)imageDownloader
+{
+    return objc_getAssociatedObject(self, _cmd);
+}
+
+- (NSUInteger)attemptToReloadTimesForFailedURL
+{
+    NSUInteger count = [objc_getAssociatedObject(self, _cmd) integerValue];
+    if (count == 0) {  count = 2; }
+    return count;
+}
+
+- (BOOL)shouldAutoClipImageToViewSize
+{
+    return [objc_getAssociatedObject(self, _cmd) boolValue];
+}
+
+#pragma mark - setter
+
+- (void)setCompletion:(ZFImageBlock)completion
+{
+    objc_setAssociatedObject(self, @selector(completion), completion, OBJC_ASSOCIATION_COPY_NONATOMIC);
+}
+
+- (void)setImageDownloader:(ZFImageDownloader *)imageDownloader
+{
+    objc_setAssociatedObject(self, @selector(imageDownloader), imageDownloader, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+- (void)setAttemptToReloadTimesForFailedURL:(NSUInteger)attemptToReloadTimesForFailedURL
+{
+    objc_setAssociatedObject(self, @selector(attemptToReloadTimesForFailedURL), @(attemptToReloadTimesForFailedURL), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+- (void)setShouldAutoClipImageToViewSize:(BOOL)shouldAutoClipImageToViewSize
+{
+    objc_setAssociatedObject(self, @selector(shouldAutoClipImageToViewSize), @(shouldAutoClipImageToViewSize), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+#pragma mark - public method
+
+- (void)setImageWithURLString:(NSString *)url
+         placeholderImageName:(NSString *)placeholderImageName {
+    return [self setImageWithURLString:url placeholderImageName:placeholderImageName completion:nil];
+}
+
+- (void)setImageWithURLString:(NSString *)url placeholder:(UIImage *)placeholderImage {
+    return [self setImageWithURLString:url placeholder:placeholderImage completion:nil];
+}
+
+- (void)setImageWithURLString:(NSString *)url
+         placeholderImageName:(NSString *)placeholderImage
+                   completion:(void (^)(UIImage *image))completion {
+    NSString *path = [[NSBundle mainBundle] pathForResource:placeholderImage ofType:nil];
+    UIImage *image = [UIImage imageWithContentsOfFile:path];
+    if (image == nil) { image = [UIImage imageNamed:placeholderImage]; }
+    
+    [self setImageWithURLString:url placeholder:image completion:completion];
+}
+
+- (void)setImageWithURLString:(NSString *)url
+                  placeholder:(UIImage *)placeholderImageName
+                   completion:(void (^)(UIImage *image))completion {
+    [self.layer removeAllAnimations];
+    self.completion = completion;
+    
+    if (url == nil || [url isKindOfClass:[NSNull class]] || (![url hasPrefix:@"http://"] && ![url hasPrefix:@"https://"])) {
+        [self setImage:placeholderImageName isFromCache:YES];
+        
+        if (completion) {
+            self.completion(self.image);
+        }
+        return;
+    }
+    
+    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
+    [self downloadWithReqeust:request holder:placeholderImageName];
+}
+
+#pragma mark - private method
+
+- (void)downloadWithReqeust:(NSURLRequest *)theRequest holder:(UIImage *)holder {
+    UIImage *cachedImage = [[UIApplication sharedApplication] zf_cacheImageForRequest:theRequest];
+    
+    if (cachedImage) {
+        [self setImage:cachedImage isFromCache:YES];
+        if (self.completion) {
+            self.completion(cachedImage);
+        }
+        return;
+    }
+    
+    [self setImage:holder isFromCache:YES];
+    
+    if ([[UIApplication sharedApplication] zf_failTimesForRequest:theRequest] >= self.attemptToReloadTimesForFailedURL) {
+        return;
+    }
+    
+    [self cancelRequest];
+    self.imageDownloader = nil;
+    
+    __weak __typeof(self) weakSelf = self;
+    
+    self.imageDownloader = [[ZFImageDownloader alloc] init];
+    [self.imageDownloader startDownloadImageWithUrl:theRequest.URL.absoluteString progress:nil finished:^(NSData *data, NSError *error) {
+        // success
+        if (data != nil && error == nil) {
+            dispatch_async(dispatch_get_global_queue(0, 0), ^{
+                UIImage *image = [UIImage imageWithData:data];
+                UIImage *finalImage = image;
+                
+                if (image) {
+                    if (weakSelf.shouldAutoClipImageToViewSize) {
+                        // cutting
+                        if (fabs(weakSelf.frame.size.width - image.size.width) != 0
+                            && fabs(weakSelf.frame.size.height - image.size.height) != 0) {
+                            finalImage = [self clipImage:image toSize:weakSelf.frame.size isScaleToMax:YES];
+                        }
+                    }
+                    
+                    [[UIApplication sharedApplication] zf_cacheImage:finalImage forRequest:theRequest];
+                } else {
+                    [[UIApplication sharedApplication] zf_cacheFailRequest:theRequest];
+                }
+                
+                dispatch_async(dispatch_get_main_queue(), ^{
+                    if (finalImage) {
+                        [weakSelf setImage:finalImage isFromCache:NO];
+                        
+                        if (weakSelf.completion) {
+                            weakSelf.completion(weakSelf.image);
+                        }
+                    } else {// error data
+                        if (weakSelf.completion) {
+                            weakSelf.completion(weakSelf.image);
+                        }
+                    }
+                });
+            });
+        } else { // error
+            [[UIApplication sharedApplication] zf_cacheFailRequest:theRequest];
+            
+            if (weakSelf.completion) {
+                weakSelf.completion(weakSelf.image);
+            }
+        }
+    }];
+}
+
+- (void)setImage:(UIImage *)image isFromCache:(BOOL)isFromCache {
+    self.image = image;
+    if (!isFromCache) {
+        CATransition *animation = [CATransition animation];
+        [animation setDuration:0.6f];
+        [animation setType:kCATransitionFade];
+        animation.removedOnCompletion = YES;
+        [self.layer addAnimation:animation forKey:@"transition"];
+    }
+}
+
+- (void)cancelRequest {
+    [self.imageDownloader.task cancel];
+}
+
+- (UIImage *)clipImage:(UIImage *)image toSize:(CGSize)size isScaleToMax:(BOOL)isScaleToMax {
+    CGFloat scale =  [UIScreen mainScreen].scale;
+    
+    UIGraphicsBeginImageContextWithOptions(size, NO, scale);
+    
+    CGSize aspectFitSize = CGSizeZero;
+    if (image.size.width != 0 && image.size.height != 0) {
+        CGFloat rateWidth = size.width / image.size.width;
+        CGFloat rateHeight = size.height / image.size.height;
+        
+        CGFloat rate = isScaleToMax ? MAX(rateHeight, rateWidth) : MIN(rateHeight, rateWidth);
+        aspectFitSize = CGSizeMake(image.size.width * rate, image.size.height * rate);
+    }
+    
+    [image drawInRect:CGRectMake(0, 0, aspectFitSize.width, aspectFitSize.height)];
+    UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();
+    UIGraphicsEndImageContext();
+    
+    return finalImage;
+}
+
+@end

+ 45 - 0
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/UIView+ZFFrame.h

@@ -0,0 +1,45 @@
+//
+//  UIView+ZFFrame.h
+//  ZFPlayer
+//
+// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import <UIKit/UIKit.h>
+
+@interface UIView (ZFFrame)
+
+@property (nonatomic) CGFloat zf_x;
+@property (nonatomic) CGFloat zf_y;
+@property (nonatomic) CGFloat zf_width;
+@property (nonatomic) CGFloat zf_height;
+
+@property (nonatomic) CGFloat zf_top;
+@property (nonatomic) CGFloat zf_bottom;
+@property (nonatomic) CGFloat zf_left;
+@property (nonatomic) CGFloat zf_right;
+
+@property (nonatomic) CGFloat zf_centerX;
+@property (nonatomic) CGFloat zf_centerY;
+
+@property (nonatomic) CGPoint zf_origin;
+@property (nonatomic) CGSize  zf_size;
+
+@end

+ 149 - 0
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/UIView+ZFFrame.m

@@ -0,0 +1,149 @@
+//
+//  UIView+ZFFrame.m
+//  ZFPlayer
+//
+// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import "UIView+ZFFrame.h"
+
+@implementation UIView (ZFFrame)
+
+- (CGFloat)zf_x {
+    return self.frame.origin.x;
+}
+
+- (void)setZf_x:(CGFloat)zf_x {
+    CGRect newFrame   = self.frame;
+    newFrame.origin.x = zf_x;
+    self.frame        = newFrame;
+}
+
+- (CGFloat)zf_y {
+    return self.frame.origin.y;
+}
+
+- (void)setZf_y:(CGFloat)zf_y {
+    CGRect newFrame   = self.frame;
+    newFrame.origin.y = zf_y;
+    self.frame        = newFrame;
+}
+
+- (CGFloat)zf_width {
+    return CGRectGetWidth(self.bounds);
+}
+
+- (void)setZf_width:(CGFloat)zf_width {
+    CGRect newFrame     = self.frame;
+    newFrame.size.width = zf_width;
+    self.frame          = newFrame;
+}
+
+- (CGFloat)zf_height {
+    return CGRectGetHeight(self.bounds);
+}
+
+- (void)setZf_height:(CGFloat)zf_height {
+    CGRect newFrame      = self.frame;
+    newFrame.size.height = zf_height;
+    self.frame           = newFrame;
+}
+
+- (CGFloat)zf_top {
+    return self.frame.origin.y;
+}
+
+- (void)setZf_top:(CGFloat)zf_top {
+    CGRect newFrame   = self.frame;
+    newFrame.origin.y = zf_top;
+    self.frame        = newFrame;
+}
+
+- (CGFloat)zf_bottom {
+    return self.frame.origin.y + self.frame.size.height;
+}
+
+- (void)setZf_bottom:(CGFloat)zf_bottom {
+    CGRect newFrame   = self.frame;
+    newFrame.origin.y = zf_bottom - self.frame.size.height;
+    self.frame        = newFrame;
+}
+
+- (CGFloat)zf_left {
+    return self.frame.origin.x;
+}
+
+- (void)setZf_left:(CGFloat)zf_left {
+    CGRect newFrame   = self.frame;
+    newFrame.origin.x = zf_left;
+    self.frame        = newFrame;
+}
+
+- (CGFloat)zf_right {
+    return self.frame.origin.x + self.frame.size.width;
+}
+
+- (void)setZf_right:(CGFloat)zf_right {
+    CGRect newFrame   = self.frame;
+    newFrame.origin.x = zf_right - self.frame.size.width;
+    self.frame        = newFrame;
+}
+
+- (CGFloat)zf_centerX {
+    return self.center.x;
+}
+
+- (void)setZf_centerX:(CGFloat)zf_centerX {
+    CGPoint newCenter = self.center;
+    newCenter.x       = zf_centerX;
+    self.center       = newCenter;
+}
+
+- (CGFloat)zf_centerY {
+    return self.center.y;
+}
+
+- (void)setZf_centerY:(CGFloat)zf_centerY {
+    CGPoint newCenter = self.center;
+    newCenter.y       = zf_centerY;
+    self.center       = newCenter;
+}
+
+- (CGPoint)zf_origin {
+    return self.frame.origin;
+}
+
+- (void)setZf_origin:(CGPoint)zf_origin {
+    CGRect newFrame = self.frame;
+    newFrame.origin = zf_origin;
+    self.frame      = newFrame;
+}
+
+- (CGSize)zf_size {
+    return self.frame.size;
+}
+
+- (void)setZf_size:(CGSize)zf_size {
+    CGRect newFrame = self.frame;
+    newFrame.size   = zf_size;
+    self.frame      = newFrame;
+}
+
+@end

+ 117 - 0
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFLandScapeControlView.h

@@ -0,0 +1,117 @@
+//
+//  ZFLandScapeControlView.h
+//  ZFPlayer
+//
+// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import <UIKit/UIKit.h>
+#import "ZFSliderView.h"
+#if __has_include(<ZFPlayer/ZFPlayerController.h>)
+#import <ZFPlayer/ZFPlayerController.h>
+#else
+#import "ZFPlayerController.h"
+#endif
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface ZFLandScapeControlView : UIView
+
+/// 顶部工具栏
+@property (nonatomic, strong, readonly) UIView *topToolView;
+
+/// 返回按钮
+@property (nonatomic, strong, readonly) UIButton *backBtn;
+
+/// 标题
+@property (nonatomic, strong, readonly) UILabel *titleLabel;
+
+/// 底部工具栏
+@property (nonatomic, strong, readonly) UIView *bottomToolView;
+
+/// 播放或暂停按钮 
+@property (nonatomic, strong, readonly) UIButton *playOrPauseBtn;
+
+/// 播放的当前时间
+@property (nonatomic, strong, readonly) UILabel *currentTimeLabel;
+
+/// 滑杆
+@property (nonatomic, strong, readonly) ZFSliderView *slider;
+
+/// 视频总时间
+@property (nonatomic, strong, readonly) UILabel *totalTimeLabel;
+
+/// 锁定屏幕按钮
+@property (nonatomic, strong, readonly) UIButton *lockBtn;
+
+/// 播放器
+@property (nonatomic, weak) ZFPlayerController *player;
+
+/// slider滑动中
+@property (nonatomic, copy, nullable) void(^sliderValueChanging)(CGFloat value,BOOL forward);
+
+/// slider滑动结束
+@property (nonatomic, copy, nullable) void(^sliderValueChanged)(CGFloat value);
+
+/// 返回按钮点击回调
+@property (nonatomic, copy) void(^backBtnClickCallback)(void);
+
+/// 如果是暂停状态,seek完是否播放,默认YES
+@property (nonatomic, assign) BOOL seekToPlay;
+
+/// 重置控制层
+- (void)resetControlView;
+
+/// 显示控制层
+- (void)showControlView;
+
+/// 隐藏控制层
+- (void)hideControlView;
+
+/// 设置播放时间
+- (void)videoPlayer:(ZFPlayerController *)videoPlayer currentTime:(NSTimeInterval)currentTime totalTime:(NSTimeInterval)totalTime;
+
+/// 设置缓冲时间
+- (void)videoPlayer:(ZFPlayerController *)videoPlayer bufferTime:(NSTimeInterval)bufferTime;
+
+/// 是否响应该手势
+- (BOOL)shouldResponseGestureWithPoint:(CGPoint)point withGestureType:(ZFPlayerGestureType)type touch:(nonnull UITouch *)touch;
+
+/// 视频尺寸改变
+- (void)videoPlayer:(ZFPlayerController *)videoPlayer presentationSizeChanged:(CGSize)size;
+
+/// 标题和全屏模式
+- (void)showTitle:(NSString *_Nullable)title fullScreenMode:(ZFFullScreenMode)fullScreenMode;
+
+/// 根据当前播放状态取反
+- (void)playOrPause;
+
+/// 播放按钮状态
+- (void)playBtnSelectedState:(BOOL)selected;
+
+/// 调节播放进度slider和当前时间更新
+- (void)sliderValueChanged:(CGFloat)value currentTimeString:(NSString *)timeString;
+
+/// 滑杆结束滑动
+- (void)sliderChangeEnded;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 452 - 0
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFLandScapeControlView.m

@@ -0,0 +1,452 @@
+//
+//  ZFLandScapeControlView.m
+//  ZFPlayer
+//
+// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import "ZFLandScapeControlView.h"
+#import "UIView+ZFFrame.h"
+#import "ZFUtilities.h"
+#if __has_include(<ZFPlayer/ZFPlayer.h>)
+#import <ZFPlayer/ZFPlayer.h>
+#else
+#import "ZFPlayer.h"
+#endif
+
+@interface ZFLandScapeControlView () <ZFSliderViewDelegate>
+/// 顶部工具栏
+@property (nonatomic, strong) UIView *topToolView;
+/// 返回按钮
+@property (nonatomic, strong) UIButton *backBtn;
+/// 标题
+@property (nonatomic, strong) UILabel *titleLabel;
+/// 底部工具栏
+@property (nonatomic, strong) UIView *bottomToolView;
+/// 播放或暂停按钮
+@property (nonatomic, strong) UIButton *playOrPauseBtn;
+/// 播放的当前时间 
+@property (nonatomic, strong) UILabel *currentTimeLabel;
+/// 滑杆
+@property (nonatomic, strong) ZFSliderView *slider;
+/// 视频总时间
+@property (nonatomic, strong) UILabel *totalTimeLabel;
+/// 锁定屏幕按钮
+@property (nonatomic, strong) UIButton *lockBtn;
+
+@property (nonatomic, assign) BOOL isShow;
+
+@end
+
+@implementation ZFLandScapeControlView
+
+- (void)dealloc {
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidChangeStatusBarFrameNotification object:nil];
+}
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    if (self = [super initWithFrame:frame]) {
+        [self addSubview:self.topToolView];
+        [self.topToolView addSubview:self.backBtn];
+        [self.topToolView addSubview:self.titleLabel];
+        [self addSubview:self.bottomToolView];
+        [self.bottomToolView addSubview:self.playOrPauseBtn];
+        [self.bottomToolView addSubview:self.currentTimeLabel];
+        
+        [self.bottomToolView addSubview:self.slider];
+        [self.bottomToolView addSubview:self.totalTimeLabel];
+        [self addSubview:self.lockBtn];
+        
+        // 设置子控件的响应事件
+        [self makeSubViewsAction];
+        [self resetControlView];
+        
+        /// statusBarFrame changed
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(layoutControllerViews) name:UIApplicationDidChangeStatusBarFrameNotification object:nil];
+    }
+    return self;
+}
+
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    CGFloat min_x = 0;
+    CGFloat min_y = 0;
+    CGFloat min_w = 0;
+    CGFloat min_h = 0;
+    CGFloat min_view_w = self.bounds.size.width;
+    CGFloat min_view_h = self.bounds.size.height;
+    
+    CGFloat min_margin = 9; 
+    
+    min_x = 0;
+    min_y = 0;
+    min_w = min_view_w;
+    min_h = iPhoneX ? 110 : 80;
+    self.topToolView.frame = CGRectMake(min_x, min_y, min_w, min_h);
+
+    min_x = (iPhoneX && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) ? 44: 15;
+    if (@available(iOS 13.0, *)) {
+        min_y = UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation) ? 10 : (iPhoneX ? 40 : 20);
+    } else {
+        min_y = (iPhoneX && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) ? 10: (iPhoneX ? 40 : 20);
+    }
+    min_w = 40;
+    min_h = 40;
+    self.backBtn.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    
+    min_x = self.backBtn.zf_right + 5;
+    min_y = 0;
+    min_w = min_view_w - min_x - 15 ;
+    min_h = 30;
+    self.titleLabel.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    self.titleLabel.zf_centerY = self.backBtn.zf_centerY;
+    
+    min_h = iPhoneX ? 100 : 73;
+    min_x = 0;
+    min_y = min_view_h - min_h;
+    min_w = min_view_w;
+    self.bottomToolView.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    
+    min_x = (iPhoneX && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) ? 44: 15;
+    min_y = 32;
+    min_w = 30;
+    min_h = 30;
+    self.playOrPauseBtn.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    
+    min_x = self.playOrPauseBtn.zf_right + 4;
+    min_y = 0;
+    min_w = 62;
+    min_h = 30;
+    self.currentTimeLabel.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    self.currentTimeLabel.zf_centerY = self.playOrPauseBtn.zf_centerY;
+    
+    min_w = 62;
+    min_x = self.bottomToolView.zf_width - min_w - ((iPhoneX && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) ? 44: min_margin);
+    min_y = 0;
+    min_h = 30;
+    self.totalTimeLabel.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    self.totalTimeLabel.zf_centerY = self.playOrPauseBtn.zf_centerY;
+    
+    min_x = self.currentTimeLabel.zf_right + 4;
+    min_y = 0;
+    min_w = self.totalTimeLabel.zf_left - min_x - 4;
+    min_h = 30;
+    self.slider.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    self.slider.zf_centerY = self.playOrPauseBtn.zf_centerY;
+    
+    min_x = (iPhoneX && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) ? 50: 18;
+    min_y = 0;
+    min_w = 40;
+    min_h = 40;
+    self.lockBtn.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    self.lockBtn.zf_centerY = self.zf_centerY;
+    
+    if (!self.isShow) {
+        self.topToolView.zf_y = -self.topToolView.zf_height;
+        self.bottomToolView.zf_y = self.zf_height;
+    } else {
+        if (self.player.isLockedScreen) {
+            self.topToolView.zf_y = -self.topToolView.zf_height;
+            self.bottomToolView.zf_y = self.zf_height;
+        } else {
+            self.topToolView.zf_y = 0;
+            self.bottomToolView.zf_y = self.zf_height - self.bottomToolView.zf_height;
+        }
+    }
+}
+
+- (void)makeSubViewsAction {
+    [self.backBtn addTarget:self action:@selector(backBtnClickAction:) forControlEvents:UIControlEventTouchUpInside];
+    [self.playOrPauseBtn addTarget:self action:@selector(playPauseButtonClickAction:) forControlEvents:UIControlEventTouchUpInside];
+    [self.lockBtn addTarget:self action:@selector(lockButtonClickAction:) forControlEvents:UIControlEventTouchUpInside];
+}
+
+#pragma mark - action
+
+- (void)layoutControllerViews {
+    [self layoutIfNeeded];
+    [self setNeedsLayout];
+}
+
+- (void)backBtnClickAction:(UIButton *)sender {
+    self.lockBtn.selected = NO;
+    self.player.lockedScreen = NO;
+    self.lockBtn.selected = NO;
+    if (self.player.orientationObserver.supportInterfaceOrientation & ZFInterfaceOrientationMaskPortrait) {
+        [self.player enterFullScreen:NO animated:YES];
+    }
+    if (self.backBtnClickCallback) {
+        self.backBtnClickCallback();
+    }
+}
+
+- (void)playPauseButtonClickAction:(UIButton *)sender {
+    [self playOrPause];
+}
+
+/// 根据当前播放状态取反
+- (void)playOrPause {
+    self.playOrPauseBtn.selected = !self.playOrPauseBtn.isSelected;
+    self.playOrPauseBtn.isSelected? [self.player.currentPlayerManager play]: [self.player.currentPlayerManager pause];
+}
+
+- (void)playBtnSelectedState:(BOOL)selected {
+    self.playOrPauseBtn.selected = selected;
+}
+
+- (void)lockButtonClickAction:(UIButton *)sender {
+    sender.selected = !sender.selected;
+    self.player.lockedScreen = sender.selected;
+}
+
+#pragma mark - ZFSliderViewDelegate
+
+- (void)sliderTouchBegan:(float)value {
+    self.slider.isdragging = YES;
+}
+
+- (void)sliderTouchEnded:(float)value {
+    if (self.player.totalTime > 0) {
+        self.slider.isdragging = YES;
+        if (self.sliderValueChanging) self.sliderValueChanging(value, self.slider.isForward);
+        @weakify(self)
+        [self.player seekToTime:self.player.totalTime*value completionHandler:^(BOOL finished) {
+            @strongify(self)
+            if (finished) {
+                self.slider.isdragging = NO;
+                if (self.sliderValueChanged) self.sliderValueChanged(value);
+                if (self.seekToPlay) {
+                    [self.player.currentPlayerManager play];
+                }
+            }
+        }];
+    } else {
+        self.slider.isdragging = NO;
+        self.slider.value = 0;
+    }
+}
+
+- (void)sliderValueChanged:(float)value {
+    if (self.player.totalTime == 0) {
+        self.slider.value = 0;
+        return;
+    }
+    self.slider.isdragging = YES;
+    NSString *currentTimeString = [ZFUtilities convertTimeSecond:self.player.totalTime*value];
+    self.currentTimeLabel.text = currentTimeString;
+    if (self.sliderValueChanging) self.sliderValueChanging(value,self.slider.isForward);
+}
+
+- (void)sliderTapped:(float)value {
+    [self sliderTouchEnded:value];
+    NSString *currentTimeString = [ZFUtilities convertTimeSecond:self.player.totalTime*value];
+    self.currentTimeLabel.text = currentTimeString;
+}
+
+#pragma mark - public method
+
+/// 重置ControlView
+- (void)resetControlView {
+    self.slider.value                = 0;
+    self.slider.bufferValue          = 0;
+    self.currentTimeLabel.text       = @"00:00";
+    self.totalTimeLabel.text         = @"00:00";
+    self.backgroundColor             = [UIColor clearColor];
+    self.playOrPauseBtn.selected     = YES;
+    self.titleLabel.text             = @"";
+    self.topToolView.alpha           = 1;
+    self.bottomToolView.alpha        = 1;
+    self.isShow                      = NO;
+}
+
+- (void)showControlView {
+    self.lockBtn.alpha               = 1;
+    self.isShow                      = YES;
+    if (self.player.isLockedScreen) {
+        self.topToolView.zf_y        = -self.topToolView.zf_height;
+        self.bottomToolView.zf_y     = self.zf_height;
+    } else {
+        self.topToolView.zf_y        = 0;
+        self.bottomToolView.zf_y     = self.zf_height - self.bottomToolView.zf_height;
+    }
+    self.lockBtn.zf_left             = iPhoneX ? 50: 18;
+    self.player.statusBarHidden      = NO;
+    if (self.player.isLockedScreen) {
+        self.topToolView.alpha       = 0;
+        self.bottomToolView.alpha    = 0;
+    } else {
+        self.topToolView.alpha       = 1;
+        self.bottomToolView.alpha    = 1;
+    }
+}
+
+- (void)hideControlView {
+    self.isShow                      = NO;
+    self.topToolView.zf_y            = -self.topToolView.zf_height;
+    self.bottomToolView.zf_y         = self.zf_height;
+    self.lockBtn.zf_left             = iPhoneX ? -82: -47;
+    self.player.statusBarHidden      = YES;
+    self.topToolView.alpha           = 0;
+    self.bottomToolView.alpha        = 0;
+    self.lockBtn.alpha               = 0;
+}
+
+- (BOOL)shouldResponseGestureWithPoint:(CGPoint)point withGestureType:(ZFPlayerGestureType)type touch:(nonnull UITouch *)touch {
+    CGRect sliderRect = [self.bottomToolView convertRect:self.slider.frame toView:self];
+    if (CGRectContainsPoint(sliderRect, point)) {
+        return NO;
+    }
+    if (self.player.isLockedScreen && type != ZFPlayerGestureTypeSingleTap) { // 锁定屏幕方向后只相应tap手势
+        return NO;
+    }
+    return YES;
+}
+
+- (void)videoPlayer:(ZFPlayerController *)videoPlayer presentationSizeChanged:(CGSize)size {
+    self.lockBtn.hidden = self.player.orientationObserver.fullScreenMode == ZFFullScreenModePortrait;
+}
+
+- (void)videoPlayer:(ZFPlayerController *)videoPlayer currentTime:(NSTimeInterval)currentTime totalTime:(NSTimeInterval)totalTime {
+    if (!self.slider.isdragging) {
+        NSString *currentTimeString = [ZFUtilities convertTimeSecond:currentTime];
+        self.currentTimeLabel.text = currentTimeString;
+        NSString *totalTimeString = [ZFUtilities convertTimeSecond:totalTime];
+        self.totalTimeLabel.text = totalTimeString;
+        self.slider.value = videoPlayer.progress;
+    }
+}
+
+- (void)videoPlayer:(ZFPlayerController *)videoPlayer bufferTime:(NSTimeInterval)bufferTime {
+    self.slider.bufferValue = videoPlayer.bufferProgress;
+}
+
+- (void)showTitle:(NSString *)title fullScreenMode:(ZFFullScreenMode)fullScreenMode {
+    self.titleLabel.text = title;
+    self.player.orientationObserver.fullScreenMode = fullScreenMode;
+    self.lockBtn.hidden = fullScreenMode == ZFFullScreenModePortrait;
+}
+
+/// 调节播放进度slider和当前时间更新
+- (void)sliderValueChanged:(CGFloat)value currentTimeString:(NSString *)timeString {
+    self.slider.value = value;
+    self.currentTimeLabel.text = timeString;
+    self.slider.isdragging = YES;
+    [UIView animateWithDuration:0.3 animations:^{
+        self.slider.sliderBtn.transform = CGAffineTransformMakeScale(1.2, 1.2);
+    }];
+}
+
+/// 滑杆结束滑动
+- (void)sliderChangeEnded {
+    self.slider.isdragging = NO;
+    [UIView animateWithDuration:0.3 animations:^{
+        self.slider.sliderBtn.transform = CGAffineTransformIdentity;
+    }];
+}
+
+#pragma mark - getter
+
+- (UIView *)topToolView {
+    if (!_topToolView) {
+        _topToolView = [[UIView alloc] init];
+        UIImage *image = ZFPlayer_Image(@"ZFPlayer_top_shadow");
+        _topToolView.layer.contents = (id)image.CGImage;
+    }
+    return _topToolView;
+}
+
+- (UIButton *)backBtn {
+    if (!_backBtn) {
+        _backBtn = [UIButton buttonWithType:UIButtonTypeCustom];
+        [_backBtn setImage:ZFPlayer_Image(@"ZFPlayer_back_full") forState:UIControlStateNormal];
+    }
+    return _backBtn;
+}
+
+- (UILabel *)titleLabel {
+    if (!_titleLabel) {
+        _titleLabel = [[UILabel alloc] init];
+        _titleLabel.textColor = [UIColor whiteColor];
+        _titleLabel.font = [UIFont systemFontOfSize:15.0];
+    }
+    return _titleLabel;
+}
+
+- (UIView *)bottomToolView {
+    if (!_bottomToolView) {
+        _bottomToolView = [[UIView alloc] init];
+        UIImage *image = ZFPlayer_Image(@"ZFPlayer_bottom_shadow");
+        _bottomToolView.layer.contents = (id)image.CGImage;
+    }
+    return _bottomToolView;
+}
+
+- (UIButton *)playOrPauseBtn {
+    if (!_playOrPauseBtn) {
+        _playOrPauseBtn = [UIButton buttonWithType:UIButtonTypeCustom];
+        [_playOrPauseBtn setImage:ZFPlayer_Image(@"ZFPlayer_play") forState:UIControlStateNormal];
+        [_playOrPauseBtn setImage:ZFPlayer_Image(@"ZFPlayer_pause") forState:UIControlStateSelected];
+    }
+    return _playOrPauseBtn;
+}
+
+- (UILabel *)currentTimeLabel {
+    if (!_currentTimeLabel) {
+        _currentTimeLabel = [[UILabel alloc] init];
+        _currentTimeLabel.textColor = [UIColor whiteColor];
+        _currentTimeLabel.font = [UIFont systemFontOfSize:14.0f];
+        _currentTimeLabel.textAlignment = NSTextAlignmentCenter;
+    }
+    return _currentTimeLabel;
+}
+
+- (ZFSliderView *)slider {
+    if (!_slider) {
+        _slider = [[ZFSliderView alloc] init];
+        _slider.delegate = self;
+        _slider.maximumTrackTintColor = [UIColor colorWithRed:0.5 green:0.5 blue:0.5 alpha:0.8];
+        _slider.bufferTrackTintColor  = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.5];
+        _slider.minimumTrackTintColor = [UIColor whiteColor];
+        [_slider setThumbImage:ZFPlayer_Image(@"ZFPlayer_slider") forState:UIControlStateNormal];
+        _slider.sliderHeight = 2;
+    }
+    return _slider;
+}
+
+- (UILabel *)totalTimeLabel {
+    if (!_totalTimeLabel) {
+        _totalTimeLabel = [[UILabel alloc] init];
+        _totalTimeLabel.textColor = [UIColor whiteColor];
+        _totalTimeLabel.font = [UIFont systemFontOfSize:14.0f];
+        _totalTimeLabel.textAlignment = NSTextAlignmentCenter;
+    }
+    return _totalTimeLabel;
+}
+
+- (UIButton *)lockBtn {
+    if (!_lockBtn) {
+        _lockBtn = [UIButton buttonWithType:UIButtonTypeCustom];
+        [_lockBtn setImage:ZFPlayer_Image(@"ZFPlayer_unlock-nor") forState:UIControlStateNormal];
+        [_lockBtn setImage:ZFPlayer_Image(@"ZFPlayer_lock-nor") forState:UIControlStateSelected];
+    }
+    return _lockBtn;
+}
+
+@end

+ 66 - 0
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFLoadingView.h

@@ -0,0 +1,66 @@
+//
+//  ZFLoadingView.h
+//  ZFPlayer
+//
+// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+typedef NS_ENUM(NSUInteger, ZFLoadingType) {
+    ZFLoadingTypeKeep,
+    ZFLoadingTypeFadeOut,
+};
+
+@interface ZFLoadingView : UIView
+
+/// default is ZFLoadingTypeKeep.
+@property (nonatomic, assign) ZFLoadingType animType;
+
+/// default is whiteColor.
+@property (nonatomic, strong, null_resettable) UIColor *lineColor;
+
+/// Sets the line width of the spinner's circle.
+@property (nonatomic) CGFloat lineWidth;
+
+/// Sets whether the view is hidden when not animating.
+@property (nonatomic) BOOL hidesWhenStopped;
+
+/// Property indicating the duration of the animation, default is 1.5s.
+@property (nonatomic, readwrite) NSTimeInterval duration;
+
+/// anima state
+@property (nonatomic, assign, readonly, getter=isAnimating) BOOL animating;
+
+/**
+ *  Starts animation of the spinner.
+ */
+- (void)startAnimating;
+
+/**
+ *  Stops animation of the spinnner.
+ */
+- (void)stopAnimating;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 183 - 0
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFLoadingView.m

@@ -0,0 +1,183 @@
+//
+//  ZFLoadingView.m
+//  ZFPlayer
+//
+// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import "ZFLoadingView.h"
+
+@interface ZFLoadingView ()
+
+@property (nonatomic, strong, readonly) CAShapeLayer *shapeLayer;
+@property (nonatomic, assign, getter=isAnimating) BOOL animating;
+@property (nonatomic, assign) BOOL strokeShow;
+
+@end
+
+@implementation ZFLoadingView
+
+@synthesize lineColor = _lineColor;
+@synthesize shapeLayer = _shapeLayer;
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    self = [super initWithFrame:frame];
+    if (self) {
+        [self initialize];
+    }
+    return self;
+}
+
+- (instancetype)initWithCoder:(NSCoder *)aDecoder {
+    if (self = [super initWithCoder:aDecoder]) {
+        [self initialize];
+    }
+    return self;
+}
+
+- (void)awakeFromNib {
+    [super awakeFromNib];
+    [self initialize];
+}
+
+- (void)initialize {
+    [self.layer addSublayer:self.shapeLayer];
+    self.duration = 1;
+    self.lineWidth = 1;
+    self.lineColor = [UIColor whiteColor];
+    self.userInteractionEnabled = NO;
+}
+
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    CGFloat width = MIN(self.bounds.size.width, self.bounds.size.height);
+    CGFloat height = width;
+    self.shapeLayer.frame = CGRectMake(0, 0, width, height);
+    
+    CGPoint center = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
+    CGFloat radius = MIN(CGRectGetWidth(self.bounds) / 2, CGRectGetHeight(self.bounds) / 2) - self.shapeLayer.lineWidth / 2;
+    CGFloat startAngle = (CGFloat)(0);
+    CGFloat endAngle = (CGFloat)(2*M_PI);
+    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];
+    self.shapeLayer.path = path.CGPath;
+}
+
+- (void)startAnimating {
+    if (self.animating) return;
+    self.animating = YES;
+    if (self.animType == ZFLoadingTypeFadeOut) [self fadeOutShow];
+    CABasicAnimation *rotationAnim = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
+    rotationAnim.toValue = [NSNumber numberWithFloat:2 * M_PI];
+    rotationAnim.duration = self.duration;
+    rotationAnim.repeatCount = CGFLOAT_MAX;
+    rotationAnim.removedOnCompletion = NO;
+    [self.shapeLayer addAnimation:rotationAnim forKey:@"rotation"];
+    if (self.hidesWhenStopped) {
+        self.hidden = NO;
+    }
+}
+
+- (void)stopAnimating {
+    if (!self.animating) return;
+    self.animating = NO;
+    [self.shapeLayer removeAllAnimations];
+    if (self.hidesWhenStopped) {
+        self.hidden = YES;
+    }
+}
+
+- (void)fadeOutShow {
+    CABasicAnimation *headAnimation = [CABasicAnimation animation];
+    headAnimation.keyPath = @"strokeStart";
+    headAnimation.duration = self.duration / 1.5f;
+    headAnimation.fromValue = @(0.f);
+    headAnimation.toValue = @(0.25f);
+    
+    CABasicAnimation *tailAnimation = [CABasicAnimation animation];
+    tailAnimation.keyPath = @"strokeEnd";
+    tailAnimation.duration = self.duration / 1.5f;
+    tailAnimation.fromValue = @(0.f);
+    tailAnimation.toValue = @(1.f);
+    
+    CABasicAnimation *endHeadAnimation = [CABasicAnimation animation];
+    endHeadAnimation.keyPath = @"strokeStart";
+    endHeadAnimation.beginTime = self.duration / 1.5f;
+    endHeadAnimation.duration = self.duration / 3.0f;
+    endHeadAnimation.fromValue = @(0.25f);
+    endHeadAnimation.toValue = @(1.f);
+    
+    CABasicAnimation *endTailAnimation = [CABasicAnimation animation];
+    endTailAnimation.keyPath = @"strokeEnd";
+    endTailAnimation.beginTime = self.duration / 1.5f;
+    endTailAnimation.duration = self.duration / 3.0f;
+    endTailAnimation.fromValue = @(1.f);
+    endTailAnimation.toValue = @(1.f);
+    
+    CAAnimationGroup *animations = [CAAnimationGroup animation];
+    [animations setDuration:self.duration];
+    [animations setAnimations:@[headAnimation, tailAnimation, endHeadAnimation, endTailAnimation]];
+    animations.repeatCount = INFINITY;
+    animations.removedOnCompletion = NO;
+    [self.shapeLayer addAnimation:animations forKey:@"strokeAnim"];
+    
+    if (self.hidesWhenStopped) {
+        self.hidden = NO;
+    }
+}
+
+#pragma mark - setter and getter
+
+- (CAShapeLayer *)shapeLayer {
+    if (!_shapeLayer) {
+        _shapeLayer = [CAShapeLayer layer];
+        _shapeLayer.strokeColor = self.lineColor.CGColor;
+        _shapeLayer.fillColor = [UIColor clearColor].CGColor;
+        _shapeLayer.strokeStart = 0.1;
+        _shapeLayer.strokeEnd = 1;
+        _shapeLayer.lineCap = @"round";
+        _shapeLayer.anchorPoint = CGPointMake(0.5, 0.5);
+    }
+    return _shapeLayer;
+}
+
+- (UIColor *)lineColor {
+    if (!_lineColor) {
+        return [UIColor whiteColor];
+    }
+    return _lineColor;
+}
+
+- (void)setLineWidth:(CGFloat)lineWidth {
+    _lineWidth = lineWidth;
+    self.shapeLayer.lineWidth = lineWidth;
+}
+
+- (void)setLineColor:(UIColor *)lineColor {
+    if (!lineColor) return;
+    _lineColor = lineColor;
+    self.shapeLayer.strokeColor = lineColor.CGColor;
+}
+
+- (void)setHidesWhenStopped:(BOOL)hidesWhenStopped {
+    _hidesWhenStopped = hidesWhenStopped;
+    self.hidden = !self.isAnimating && hidesWhenStopped;
+}
+
+@end

+ 39 - 0
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFNetworkSpeedMonitor.h

@@ -0,0 +1,39 @@
+//
+//  ZFNetworkSpeedMonitor.h
+//  ZFPlayer
+//
+// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import <Foundation/Foundation.h>
+
+extern NSString *const ZFDownloadNetworkSpeedNotificationKey;
+extern NSString *const ZFUploadNetworkSpeedNotificationKey;
+extern NSString *const ZFNetworkSpeedNotificationKey;
+
+@interface ZFNetworkSpeedMonitor : NSObject
+
+@property (nonatomic, copy, readonly) NSString *downloadNetworkSpeed;
+@property (nonatomic, copy, readonly) NSString *uploadNetworkSpeed;
+
+- (void)startNetworkSpeedMonitor;
+- (void)stopNetworkSpeedMonitor;
+
+@end

+ 161 - 0
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFNetworkSpeedMonitor.m

@@ -0,0 +1,161 @@
+//
+//  ZFNetworkSpeedMonitor.m
+//  ZFPlayer
+//
+// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import "ZFNetworkSpeedMonitor.h"
+#if __has_include(<ZFPlayer/ZFPlayerLogManager.h>)
+#import <ZFPlayer/ZFPlayerLogManager.h>
+#else
+#import "ZFPlayerLogManager.h"
+#endif
+#include <arpa/inet.h>
+#include <ifaddrs.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+
+NSString *const ZFDownloadNetworkSpeedNotificationKey = @"ZFDownloadNetworkSpeedNotificationKey";
+NSString *const ZFUploadNetworkSpeedNotificationKey   = @"ZFUploadNetworkSpeedNotificationKey";
+NSString *const ZFNetworkSpeedNotificationKey         = @"ZFNetworkSpeedNotificationKey";
+
+@interface ZFNetworkSpeedMonitor () {
+    // 总网速
+    uint32_t _iBytes;
+    uint32_t _oBytes;
+    uint32_t _allFlow;
+    
+    // wifi网速
+    uint32_t _wifiIBytes;
+    uint32_t _wifiOBytes;
+    uint32_t _wifiFlow;
+    
+    // 3G网速
+    uint32_t _wwanIBytes;
+    uint32_t _wwanOBytes;
+    uint32_t _wwanFlow;
+}
+
+@property (nonatomic, strong) NSTimer *timer;
+
+@end
+
+@implementation ZFNetworkSpeedMonitor
+
+- (instancetype)init {
+    if (self = [super init]) {
+        _iBytes = _oBytes = _allFlow = _wifiIBytes = _wifiOBytes = _wifiFlow = _wwanIBytes = _wwanOBytes = _wwanFlow = 0;
+    }
+    return self;
+}
+
+// 开始监听网速
+- (void)startNetworkSpeedMonitor {
+    if (!_timer) {
+        _timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(checkNetworkSpeed) userInfo:nil repeats:YES];
+        [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
+        [_timer fire];
+    }
+}
+
+// 停止监听网速
+- (void)stopNetworkSpeedMonitor {
+    if ([_timer isValid]) {
+        [_timer invalidate];
+        _timer = nil;
+    }
+}
+
+- (NSString *)stringWithbytes:(int)bytes {
+    if (bytes < 1024) { // B
+        return [NSString stringWithFormat:@"%dB", bytes];
+    } else if (bytes >= 1024 && bytes < 1024 * 1024) { // KB
+        return [NSString stringWithFormat:@"%.0fKB", (double)bytes / 1024];
+    } else if (bytes >= 1024 * 1024 && bytes < 1024 * 1024 * 1024) { // MB
+        return [NSString stringWithFormat:@"%.1fMB", (double)bytes / (1024 * 1024)];
+    } else { // GB
+        return [NSString stringWithFormat:@"%.1fGB", (double)bytes / (1024 * 1024 * 1024)];
+    }
+}
+
+- (void)checkNetworkSpeed {
+    struct ifaddrs *ifa_list = 0, *ifa;
+    if (getifaddrs(&ifa_list) == -1) return;
+    
+    uint32_t iBytes = 0;
+    uint32_t oBytes = 0;
+    uint32_t allFlow = 0;
+    uint32_t wifiIBytes = 0;
+    uint32_t wifiOBytes = 0;
+    uint32_t wifiFlow = 0;
+    uint32_t wwanIBytes = 0;
+    uint32_t wwanOBytes = 0;
+    uint32_t wwanFlow = 0;
+    
+    for (ifa = ifa_list; ifa; ifa = ifa->ifa_next) {
+        if (AF_LINK != ifa->ifa_addr->sa_family) continue;
+        if (!(ifa->ifa_flags & IFF_UP) && !(ifa->ifa_flags & IFF_RUNNING)) continue;
+        if (ifa->ifa_data == 0) continue;
+        
+        // network
+        if (strncmp(ifa->ifa_name, "lo", 2)) {
+            struct if_data* if_data = (struct if_data*)ifa->ifa_data;
+            iBytes += if_data->ifi_ibytes;
+            oBytes += if_data->ifi_obytes;
+            allFlow = iBytes + oBytes;
+        }
+        
+        //wifi
+        if (!strcmp(ifa->ifa_name, "en0")) {
+            struct if_data* if_data = (struct if_data*)ifa->ifa_data;
+            wifiIBytes += if_data->ifi_ibytes;
+            wifiOBytes += if_data->ifi_obytes;
+            wifiFlow = wifiIBytes + wifiOBytes;
+        }
+        
+        //3G or gprs
+        if (!strcmp(ifa->ifa_name, "pdp_ip0")) {
+            struct if_data* if_data = (struct if_data*)ifa->ifa_data;
+            wwanIBytes += if_data->ifi_ibytes;
+            wwanOBytes += if_data->ifi_obytes;
+            wwanFlow = wwanIBytes + wwanOBytes;
+        }
+    }
+    
+    freeifaddrs(ifa_list);
+    if (_iBytes != 0) {
+        _downloadNetworkSpeed = [[self stringWithbytes:iBytes - _iBytes] stringByAppendingString:@"/s"];
+        [[NSNotificationCenter defaultCenter] postNotificationName:ZFDownloadNetworkSpeedNotificationKey object:nil userInfo:@{ZFNetworkSpeedNotificationKey:_downloadNetworkSpeed}];
+        ZFPlayerLog(@"downloadNetworkSpeed : %@",_downloadNetworkSpeed);
+    }
+    
+    _iBytes = iBytes;
+    
+    if (_oBytes != 0) {
+        _uploadNetworkSpeed = [[self stringWithbytes:oBytes - _oBytes] stringByAppendingString:@"/s"];
+        [[NSNotificationCenter defaultCenter] postNotificationName:ZFUploadNetworkSpeedNotificationKey object:nil userInfo:@{ZFNetworkSpeedNotificationKey:_uploadNetworkSpeed}];
+        ZFPlayerLog(@"uploadNetworkSpeed :%@",_uploadNetworkSpeed);
+    }
+    
+    _oBytes = oBytes;
+}
+
+@end

BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_back_full@2x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_back_full@3x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_bottom_shadow.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_brightness_high@2x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_brightness_high@3x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_brightness_low@2x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_brightness_low@3x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_close@2x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_close@3x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_closeWatch@2x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_closeWatch@3x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_fast_backward@2x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_fast_backward@3x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_fast_forward@2x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_fast_forward@3x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_fullscreen@2x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_fullscreen@3x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_lock-nor@2x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_lock-nor@3x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_muted@2x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_muted@3x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_next@2x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_next@3x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_pause@2x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_pause@3x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_play@2x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_play@3x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_shrinkscreen@2x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_shrinkscreen@3x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_slider.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_slider@2x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_slider@3x.png


BIN
smartRhino/Project/Other/Third/BaiduAIBD/BDSResource/defaultFullScreenTheme.bundle/dividing_line@3x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_unlock-nor@2x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_unlock-nor@3x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_volume_high@2x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_volume_high@3x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_volume_low@2x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_volume_low@3x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/new_allPause_44x44_@2x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/new_allPause_44x44_@3x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/new_allPlay_44x44_@2x.png


BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/new_allPlay_44x44_@3x.png


+ 149 - 0
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayerControlView.h

@@ -0,0 +1,149 @@
+//
+//  ZFPlayerControlView.h
+//  ZFPlayer
+//
+// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import <UIKit/UIKit.h>
+#import "ZFPortraitControlView.h"
+#import "ZFLandScapeControlView.h"
+#import "ZFSpeedLoadingView.h"
+#import "ZFSmallFloatControlView.h"
+#if __has_include(<ZFPlayer/ZFPlayerMediaControl.h>)
+#import <ZFPlayer/ZFPlayerMediaControl.h>
+#else
+#import "ZFPlayerMediaControl.h"
+#endif
+
+@interface ZFPlayerControlView : UIView <ZFPlayerMediaControl>
+
+/// 竖屏控制层的View
+@property (nonatomic, strong, readonly) ZFPortraitControlView *portraitControlView;
+
+/// 横屏控制层的View
+@property (nonatomic, strong, readonly) ZFLandScapeControlView *landScapeControlView;
+
+/// 加载loading
+@property (nonatomic, strong, readonly) ZFSpeedLoadingView *activity;
+
+/// 快进快退View
+@property (nonatomic, strong, readonly) UIView *fastView;
+
+/// 快进快退进度progress
+@property (nonatomic, strong, readonly) ZFSliderView *fastProgressView;
+
+/// 快进快退时间
+@property (nonatomic, strong, readonly) UILabel *fastTimeLabel;
+
+/// 快进快退ImageView
+@property (nonatomic, strong, readonly) UIImageView *fastImageView;
+
+/// 加载失败按钮
+@property (nonatomic, strong, readonly) UIButton *failBtn;
+
+/// 底部播放进度
+@property (nonatomic, strong, readonly) ZFSliderView *bottomPgrogress;
+
+/// 封面图
+@property (nonatomic, strong, readonly) UIImageView *coverImageView;
+
+/// 高斯模糊的背景图
+@property (nonatomic, strong, readonly) UIImageView *bgImgView;
+
+/// 高斯模糊视图
+@property (nonatomic, strong, readonly) UIView *effectView;
+
+/// 小窗口控制层
+@property (nonatomic, strong, readonly) ZFSmallFloatControlView *floatControlView;
+
+/// 快进视图是否显示动画,默认NO.
+@property (nonatomic, assign) BOOL fastViewAnimated;
+
+/// 视频之外区域是否高斯模糊显示,默认YES.
+@property (nonatomic, assign) BOOL effectViewShow;
+
+/// 直接进入全屏模式,只支持全屏模式
+@property (nonatomic, assign) BOOL fullScreenOnly;
+
+/// 如果是暂停状态,seek完是否播放,默认YES
+@property (nonatomic, assign) BOOL seekToPlay;
+
+/// 返回按钮点击回调
+@property (nonatomic, copy) void(^backBtnClickCallback)(void);
+
+/// 控制层显示或者隐藏
+@property (nonatomic, readonly) BOOL controlViewAppeared;
+
+/// 控制层显示或者隐藏的回调
+@property (nonatomic, copy) void(^controlViewAppearedCallback)(BOOL appeared);
+
+/// 控制层自动隐藏的时间,默认2.5秒
+@property (nonatomic, assign) NSTimeInterval autoHiddenTimeInterval;
+
+/// 控制层显示、隐藏动画的时长,默认0.25秒
+@property (nonatomic, assign) NSTimeInterval autoFadeTimeInterval;
+
+/// 横向滑动控制播放进度时是否显示控制层,默认 YES.
+@property (nonatomic, assign) BOOL horizontalPanShowControlView;
+
+/// prepare时候是否显示控制层,默认 NO.
+@property (nonatomic, assign) BOOL prepareShowControlView;
+
+/// prepare时候是否显示loading,默认 NO.
+@property (nonatomic, assign) BOOL prepareShowLoading;
+
+/// 是否自定义禁止pan手势,默认 NO.
+@property (nonatomic, assign) BOOL customDisablePanMovingDirection;
+
+/**
+ 设置标题、封面、全屏模式
+
+ @param title 视频的标题
+ @param coverUrl 视频的封面,占位图默认是灰色的
+ @param fullScreenMode 全屏模式
+ */
+- (void)showTitle:(NSString *)title coverURLString:(NSString *)coverUrl fullScreenMode:(ZFFullScreenMode)fullScreenMode;
+
+/**
+ 设置标题、封面、默认占位图、全屏模式
+
+ @param title 视频的标题
+ @param coverUrl 视频的封面
+ @param placeholder 指定封面的placeholder
+ @param fullScreenMode 全屏模式
+ */
+- (void)showTitle:(NSString *)title coverURLString:(NSString *)coverUrl placeholderImage:(UIImage *)placeholder fullScreenMode:(ZFFullScreenMode)fullScreenMode;
+
+/**
+ 设置标题、UIImage封面、全屏模式
+
+ @param title 视频的标题
+ @param image 视频的封面UIImage
+ @param fullScreenMode 全屏模式
+ */
+- (void)showTitle:(NSString *)title coverImage:(UIImage *)image fullScreenMode:(ZFFullScreenMode)fullScreenMode;
+
+/**
+ 重置控制层
+ */
+- (void)resetControlView;
+
+@end

+ 840 - 0
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayerControlView.m

@@ -0,0 +1,840 @@
+//
+//  ZFPlayerControlView.m
+//  ZFPlayer
+//
+// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import "ZFPlayerControlView.h"
+#import <AVKit/AVKit.h>
+#import <AVFoundation/AVFoundation.h>
+#import "UIView+ZFFrame.h"
+#import "ZFSliderView.h"
+#import "ZFUtilities.h"
+#import "UIImageView+ZFCache.h"
+#import <MediaPlayer/MediaPlayer.h>
+#import "ZFVolumeBrightnessView.h"
+#if __has_include(<ZFPlayer/ZFPlayer.h>)
+#import <ZFPlayer/ZFPlayer.h>
+#else
+#import "ZFPlayer.h"
+#endif
+
+@interface ZFPlayerControlView () <ZFSliderViewDelegate>
+/// 竖屏控制层的View
+@property (nonatomic, strong) ZFPortraitControlView *portraitControlView;
+/// 横屏控制层的View
+@property (nonatomic, strong) ZFLandScapeControlView *landScapeControlView;
+/// 加载loading
+@property (nonatomic, strong) ZFSpeedLoadingView *activity;
+/// 快进快退View
+@property (nonatomic, strong) UIView *fastView;
+/// 快进快退进度progress
+@property (nonatomic, strong) ZFSliderView *fastProgressView;
+/// 快进快退时间
+@property (nonatomic, strong) UILabel *fastTimeLabel;
+/// 快进快退ImageView
+@property (nonatomic, strong) UIImageView *fastImageView;
+/// 加载失败按钮
+@property (nonatomic, strong) UIButton *failBtn;
+/// 底部播放进度
+@property (nonatomic, strong) ZFSliderView *bottomPgrogress;
+/// 封面图
+@property (nonatomic, strong) UIImageView *coverImageView;
+/// 是否显示了控制层
+@property (nonatomic, assign, getter=isShowing) BOOL showing;
+/// 是否播放结束
+@property (nonatomic, assign, getter=isPlayEnd) BOOL playeEnd;
+
+@property (nonatomic, assign) BOOL controlViewAppeared;
+
+@property (nonatomic, assign) NSTimeInterval sumTime;
+
+@property (nonatomic, strong) dispatch_block_t afterBlock;
+
+@property (nonatomic, strong) ZFSmallFloatControlView *floatControlView;
+
+@property (nonatomic, strong) ZFVolumeBrightnessView *volumeBrightnessView;
+
+@property (nonatomic, strong) UIImageView *bgImgView;
+
+@property (nonatomic, strong) UIView *effectView;
+
+@end
+
+@implementation ZFPlayerControlView
+@synthesize player = _player;
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    self = [super initWithFrame:frame];
+    if (self) {
+        [self addAllSubViews];
+        self.landScapeControlView.hidden = YES;
+        self.floatControlView.hidden = YES;
+        self.seekToPlay = YES;
+        self.effectViewShow = YES;
+        self.horizontalPanShowControlView = YES;
+        self.autoFadeTimeInterval = 0.25;
+        self.autoHiddenTimeInterval = 2.5;
+        [[NSNotificationCenter defaultCenter] addObserver:self
+                                                 selector:@selector(volumeChanged:)
+                                                     name:@"AVSystemController_SystemVolumeDidChangeNotification"
+                                                   object:nil];
+    }
+    return self;
+}
+
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    CGFloat min_x = 0;
+    CGFloat min_y = 0;
+    CGFloat min_w = 0;
+    CGFloat min_h = 0;
+    CGFloat min_view_w = self.zf_width;
+    CGFloat min_view_h = self.zf_height;
+    
+    self.portraitControlView.frame = self.bounds;
+    self.landScapeControlView.frame = self.bounds;
+    self.floatControlView.frame = self.bounds;
+    self.coverImageView.frame = self.bounds;
+    self.bgImgView.frame = self.bounds;
+    self.effectView.frame = self.bounds;
+    
+    min_w = 80;
+    min_h = 80;
+    self.activity.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    self.activity.zf_centerX = self.zf_centerX;
+    self.activity.zf_centerY = self.zf_centerY + 10;
+    
+    min_w = 150;
+    min_h = 30;
+    self.failBtn.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    self.failBtn.center = self.center;
+    
+    min_w = 140;
+    min_h = 80;
+    self.fastView.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    self.fastView.center = self.center;
+    
+    min_w = 32;
+    min_x = (self.fastView.zf_width - min_w) / 2;
+    min_y = 5;
+    min_h = 32;
+    self.fastImageView.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    
+    min_x = 0;
+    min_y = self.fastImageView.zf_bottom + 2;
+    min_w = self.fastView.zf_width;
+    min_h = 20;
+    self.fastTimeLabel.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    
+    min_x = 12;
+    min_y = self.fastTimeLabel.zf_bottom + 5;
+    min_w = self.fastView.zf_width - 2 * min_x;
+    min_h = 10;
+    self.fastProgressView.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    
+    min_x = 0;
+    min_y = min_view_h - 1;
+    min_w = min_view_w;
+    min_h = 1;
+    self.bottomPgrogress.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    
+    min_x = 0;
+    min_y = iPhoneX ? 54 : 30;
+    min_w = 170;
+    min_h = 35;
+    self.volumeBrightnessView.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    self.volumeBrightnessView.zf_centerX = self.zf_centerX;
+}
+
+- (void)dealloc {
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"AVSystemController_SystemVolumeDidChangeNotification" object:nil];
+    [self cancelAutoFadeOutControlView];
+}
+
+/// 添加所有子控件
+- (void)addAllSubViews {
+    [self addSubview:self.portraitControlView];
+    [self addSubview:self.landScapeControlView];
+    [self addSubview:self.floatControlView];
+    [self addSubview:self.activity];
+    [self addSubview:self.failBtn];
+    [self addSubview:self.fastView];
+    [self.fastView addSubview:self.fastImageView];
+    [self.fastView addSubview:self.fastTimeLabel];
+    [self.fastView addSubview:self.fastProgressView];
+    [self addSubview:self.bottomPgrogress];
+    [self addSubview:self.volumeBrightnessView];
+}
+
+- (void)autoFadeOutControlView {
+    self.controlViewAppeared = YES;
+    [self cancelAutoFadeOutControlView];
+    @weakify(self)
+    self.afterBlock = dispatch_block_create(0, ^{
+        @strongify(self)
+        [self hideControlViewWithAnimated:YES];
+    });
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.autoHiddenTimeInterval * NSEC_PER_SEC)), dispatch_get_main_queue(),self.afterBlock);
+}
+
+/// 取消延时隐藏controlView的方法
+- (void)cancelAutoFadeOutControlView {
+    if (self.afterBlock) {
+        dispatch_block_cancel(self.afterBlock);
+        self.afterBlock = nil;
+    }
+}
+
+/// 隐藏控制层
+- (void)hideControlViewWithAnimated:(BOOL)animated {
+    self.controlViewAppeared = NO;
+    if (self.controlViewAppearedCallback) {
+        self.controlViewAppearedCallback(NO);
+    }
+    [UIView animateWithDuration:animated ? self.autoFadeTimeInterval : 0 animations:^{
+        if (self.player.isFullScreen) {
+            [self.landScapeControlView hideControlView];
+        } else {
+            if (!self.player.isSmallFloatViewShow) {
+                [self.portraitControlView hideControlView];
+            }
+        }
+    } completion:^(BOOL finished) {
+        self.bottomPgrogress.hidden = NO;
+    }];
+}
+
+/// 显示控制层
+- (void)showControlViewWithAnimated:(BOOL)animated {
+    self.controlViewAppeared = YES;
+    if (self.controlViewAppearedCallback) {
+        self.controlViewAppearedCallback(YES);
+    }
+    [self autoFadeOutControlView];
+    [UIView animateWithDuration:animated ? self.autoFadeTimeInterval : 0 animations:^{
+        if (self.player.isFullScreen) {
+            [self.landScapeControlView showControlView];
+        } else {
+            if (!self.player.isSmallFloatViewShow) {
+                [self.portraitControlView showControlView];
+            }
+        }
+    } completion:^(BOOL finished) {
+        self.bottomPgrogress.hidden = YES;
+    }];
+}
+
+/// 音量改变的通知
+- (void)volumeChanged:(NSNotification *)notification {    
+    NSDictionary *userInfo = notification.userInfo;
+    NSString *reasonstr = userInfo[@"AVSystemController_AudioVolumeChangeReasonNotificationParameter"];
+    if ([reasonstr isEqualToString:@"ExplicitVolumeChange"]) {
+        float volume = [ userInfo[@"AVSystemController_AudioVolumeNotificationParameter"] floatValue];
+        if (self.player.isFullScreen) {
+            [self.volumeBrightnessView updateProgress:volume withVolumeBrightnessType:ZFVolumeBrightnessTypeVolume];
+        } else {
+            [self.volumeBrightnessView addSystemVolumeView];
+        }
+    }
+}
+
+#pragma mark - Public Method
+
+/// 重置控制层
+- (void)resetControlView {
+    [self.portraitControlView resetControlView];
+    [self.landScapeControlView resetControlView];
+    [self cancelAutoFadeOutControlView];
+    self.bottomPgrogress.value = 0;
+    self.bottomPgrogress.bufferValue = 0;
+    self.floatControlView.hidden = YES;
+    self.failBtn.hidden = YES;
+    self.volumeBrightnessView.hidden = YES;
+    self.portraitControlView.hidden = self.player.isFullScreen;
+    self.landScapeControlView.hidden = !self.player.isFullScreen;
+    if (self.controlViewAppeared) {
+        [self showControlViewWithAnimated:NO];
+    } else {
+        [self hideControlViewWithAnimated:NO];
+    }
+}
+
+/// 设置标题、封面、全屏模式
+- (void)showTitle:(NSString *)title coverURLString:(NSString *)coverUrl fullScreenMode:(ZFFullScreenMode)fullScreenMode {
+    UIImage *placeholder = [ZFUtilities imageWithColor:[UIColor colorWithRed:220/255.0 green:220/255.0 blue:220/255.0 alpha:1] size:self.bgImgView.bounds.size];
+    [self showTitle:title coverURLString:coverUrl placeholderImage:placeholder fullScreenMode:fullScreenMode];
+}
+
+/// 设置标题、封面、默认占位图、全屏模式
+- (void)showTitle:(NSString *)title coverURLString:(NSString *)coverUrl placeholderImage:(UIImage *)placeholder fullScreenMode:(ZFFullScreenMode)fullScreenMode {
+    [self resetControlView];
+    [self layoutIfNeeded];
+    [self setNeedsDisplay];
+    [self.portraitControlView showTitle:title fullScreenMode:fullScreenMode];
+    [self.landScapeControlView showTitle:title fullScreenMode:fullScreenMode];
+    [self.coverImageView setImageWithURLString:coverUrl placeholder:placeholder];
+    [self.bgImgView setImageWithURLString:coverUrl placeholder:placeholder];
+    if (self.prepareShowControlView) {
+        [self showControlViewWithAnimated:NO];
+    } else {
+        [self hideControlViewWithAnimated:NO];
+    }
+}
+
+/// 设置标题、UIImage封面、全屏模式
+- (void)showTitle:(NSString *)title coverImage:(UIImage *)image fullScreenMode:(ZFFullScreenMode)fullScreenMode {
+    [self resetControlView];
+    [self layoutIfNeeded];
+    [self setNeedsDisplay];
+    [self.portraitControlView showTitle:title fullScreenMode:fullScreenMode];
+    [self.landScapeControlView showTitle:title fullScreenMode:fullScreenMode];
+    self.coverImageView.image = image;
+    self.bgImgView.image = image;
+    if (self.prepareShowControlView) {
+        [self showControlViewWithAnimated:NO];
+    } else {
+        [self hideControlViewWithAnimated:NO];
+    }
+}
+
+#pragma mark - ZFPlayerControlViewDelegate
+
+/// 手势筛选,返回NO不响应该手势
+- (BOOL)gestureTriggerCondition:(ZFPlayerGestureControl *)gestureControl gestureType:(ZFPlayerGestureType)gestureType gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer touch:(nonnull UITouch *)touch {
+    CGPoint point = [touch locationInView:self];
+    if (self.player.isSmallFloatViewShow && !self.player.isFullScreen && gestureType != ZFPlayerGestureTypeSingleTap) {
+        return NO;
+    }
+    if (self.player.isFullScreen) {
+        if (!self.customDisablePanMovingDirection) {
+            /// 不禁用滑动方向
+            self.player.disablePanMovingDirection = ZFPlayerDisablePanMovingDirectionNone;
+        }
+        return [self.landScapeControlView shouldResponseGestureWithPoint:point withGestureType:gestureType touch:touch];
+    } else {
+        if (!self.customDisablePanMovingDirection) {
+            if (self.player.scrollView) {  /// 列表时候禁止上下滑动(防止和列表滑动冲突)
+                self.player.disablePanMovingDirection = ZFPlayerDisablePanMovingDirectionVertical;
+            } else { /// 不禁用滑动方向
+                self.player.disablePanMovingDirection = ZFPlayerDisablePanMovingDirectionNone;
+            }
+        }
+        return [self.portraitControlView shouldResponseGestureWithPoint:point withGestureType:gestureType touch:touch];
+    }
+}
+
+/// 单击手势事件
+- (void)gestureSingleTapped:(ZFPlayerGestureControl *)gestureControl {
+    if (!self.player) return;
+    if (self.player.isSmallFloatViewShow && !self.player.isFullScreen) {
+        [self.player enterFullScreen:YES animated:YES];
+    } else {
+        if (self.controlViewAppeared) {
+            [self hideControlViewWithAnimated:YES];
+        } else {
+            /// 显示之前先把控制层复位,先隐藏后显示
+            [self hideControlViewWithAnimated:NO];
+            [self showControlViewWithAnimated:YES];
+        }
+    }
+}
+
+/// 双击手势事件
+- (void)gestureDoubleTapped:(ZFPlayerGestureControl *)gestureControl {
+    if (self.player.isFullScreen) {
+        [self.landScapeControlView playOrPause];
+    } else {
+        [self.portraitControlView playOrPause];
+    }
+}
+
+/// 开始滑动手势事件
+- (void)gestureBeganPan:(ZFPlayerGestureControl *)gestureControl panDirection:(ZFPanDirection)direction panLocation:(ZFPanLocation)location {
+    if (direction == ZFPanDirectionH) {
+        self.sumTime = self.player.currentTime;
+    }
+}
+
+/// 滑动中手势事件
+- (void)gestureChangedPan:(ZFPlayerGestureControl *)gestureControl panDirection:(ZFPanDirection)direction panLocation:(ZFPanLocation)location withVelocity:(CGPoint)velocity {
+    if (direction == ZFPanDirectionH) {
+        // 每次滑动需要叠加时间
+        self.sumTime += velocity.x / 200;
+        // 需要限定sumTime的范围
+        NSTimeInterval totalMovieDuration = self.player.totalTime;
+        if (totalMovieDuration == 0) return;
+        if (self.sumTime > totalMovieDuration) self.sumTime = totalMovieDuration;
+        if (self.sumTime < 0) self.sumTime = 0;
+        BOOL style = NO;
+        if (velocity.x > 0) style = YES;
+        if (velocity.x < 0) style = NO;
+        if (velocity.x == 0) return;
+        [self sliderValueChangingValue:self.sumTime/totalMovieDuration isForward:style];
+    } else if (direction == ZFPanDirectionV) {
+        if (location == ZFPanLocationLeft) { /// 调节亮度
+            self.player.brightness -= (velocity.y) / 10000;
+            [self.volumeBrightnessView updateProgress:self.player.brightness withVolumeBrightnessType:ZFVolumeBrightnessTypeumeBrightness];
+        } else if (location == ZFPanLocationRight) { /// 调节声音
+            self.player.volume -= (velocity.y) / 10000;
+            if (self.player.isFullScreen) {
+                [self.volumeBrightnessView updateProgress:self.player.volume withVolumeBrightnessType:ZFVolumeBrightnessTypeVolume];
+            }
+        }
+    }
+}
+
+/// 滑动结束手势事件
+- (void)gestureEndedPan:(ZFPlayerGestureControl *)gestureControl panDirection:(ZFPanDirection)direction panLocation:(ZFPanLocation)location {
+    @weakify(self)
+    if (direction == ZFPanDirectionH && self.sumTime >= 0 && self.player.totalTime > 0) {
+        [self.player seekToTime:self.sumTime completionHandler:^(BOOL finished) {
+            @strongify(self)
+            /// 左右滑动调节播放进度
+            [self.portraitControlView sliderChangeEnded];
+            [self.landScapeControlView sliderChangeEnded];
+            self.bottomPgrogress.isdragging = NO;
+            if (self.controlViewAppeared) {
+                [self autoFadeOutControlView];
+            }
+        }];
+        if (self.seekToPlay) {
+            [self.player.currentPlayerManager play];
+        }
+        self.sumTime = 0;
+    }
+}
+
+/// 捏合手势事件,这里改变了视频的填充模式
+- (void)gesturePinched:(ZFPlayerGestureControl *)gestureControl scale:(float)scale {
+    if (scale > 1) {
+        self.player.currentPlayerManager.scalingMode = ZFPlayerScalingModeAspectFill;
+    } else {
+        self.player.currentPlayerManager.scalingMode = ZFPlayerScalingModeAspectFit;
+    }
+}
+
+/// 准备播放
+- (void)videoPlayer:(ZFPlayerController *)videoPlayer prepareToPlay:(NSURL *)assetURL {
+    [self hideControlViewWithAnimated:NO];
+}
+
+/// 播放状态改变
+- (void)videoPlayer:(ZFPlayerController *)videoPlayer playStateChanged:(ZFPlayerPlaybackState)state {
+    if (state == ZFPlayerPlayStatePlaying) {
+        [self.portraitControlView playBtnSelectedState:YES];
+        [self.landScapeControlView playBtnSelectedState:YES];
+        self.failBtn.hidden = YES;
+        /// 开始播放时候判断是否显示loading
+        if (videoPlayer.currentPlayerManager.loadState == ZFPlayerLoadStateStalled && !self.prepareShowLoading) {
+            [self.activity startAnimating];
+        } else if ((videoPlayer.currentPlayerManager.loadState == ZFPlayerLoadStateStalled || videoPlayer.currentPlayerManager.loadState == ZFPlayerLoadStatePrepare) && self.prepareShowLoading) {
+            [self.activity startAnimating];
+        }
+    } else if (state == ZFPlayerPlayStatePaused) {
+        [self.portraitControlView playBtnSelectedState:NO];
+        [self.landScapeControlView playBtnSelectedState:NO];
+        /// 暂停的时候隐藏loading
+        [self.activity stopAnimating];
+        self.failBtn.hidden = YES;
+    } else if (state == ZFPlayerPlayStatePlayFailed) {
+        self.failBtn.hidden = NO;
+        [self.activity stopAnimating];
+    }
+}
+
+/// 加载状态改变
+- (void)videoPlayer:(ZFPlayerController *)videoPlayer loadStateChanged:(ZFPlayerLoadState)state {
+    if (state == ZFPlayerLoadStatePrepare) {
+        self.coverImageView.hidden = NO;
+        [self.portraitControlView playBtnSelectedState:videoPlayer.currentPlayerManager.shouldAutoPlay];
+        [self.landScapeControlView playBtnSelectedState:videoPlayer.currentPlayerManager.shouldAutoPlay];
+    } else if (state == ZFPlayerLoadStatePlaythroughOK || state == ZFPlayerLoadStatePlayable) {
+        self.coverImageView.hidden = YES;
+        if (self.effectViewShow) {
+            self.effectView.hidden = NO;
+        } else {
+            self.effectView.hidden = YES;
+            self.player.currentPlayerManager.view.backgroundColor = [UIColor blackColor];
+        }
+    }
+    if (state == ZFPlayerLoadStateStalled && videoPlayer.currentPlayerManager.isPlaying && !self.prepareShowLoading) {
+        [self.activity startAnimating];
+    } else if ((state == ZFPlayerLoadStateStalled || state == ZFPlayerLoadStatePrepare) && videoPlayer.currentPlayerManager.isPlaying && self.prepareShowLoading) {
+        [self.activity startAnimating];
+    } else {
+        [self.activity stopAnimating];
+    }
+}
+
+/// 播放进度改变回调
+- (void)videoPlayer:(ZFPlayerController *)videoPlayer currentTime:(NSTimeInterval)currentTime totalTime:(NSTimeInterval)totalTime {
+    [self.portraitControlView videoPlayer:videoPlayer currentTime:currentTime totalTime:totalTime];
+    [self.landScapeControlView videoPlayer:videoPlayer currentTime:currentTime totalTime:totalTime];
+    if (!self.bottomPgrogress.isdragging) {
+        self.bottomPgrogress.value = videoPlayer.progress;
+    }
+}
+
+/// 缓冲改变回调
+- (void)videoPlayer:(ZFPlayerController *)videoPlayer bufferTime:(NSTimeInterval)bufferTime {
+    [self.portraitControlView videoPlayer:videoPlayer bufferTime:bufferTime];
+    [self.landScapeControlView videoPlayer:videoPlayer bufferTime:bufferTime];
+    self.bottomPgrogress.bufferValue = videoPlayer.bufferProgress;
+}
+
+- (void)videoPlayer:(ZFPlayerController *)videoPlayer presentationSizeChanged:(CGSize)size {
+    [self.landScapeControlView videoPlayer:videoPlayer presentationSizeChanged:size];
+}
+
+/// 视频view即将旋转
+- (void)videoPlayer:(ZFPlayerController *)videoPlayer orientationWillChange:(ZFOrientationObserver *)observer {
+    self.portraitControlView.hidden = observer.isFullScreen;
+    self.landScapeControlView.hidden = !observer.isFullScreen;
+    if (videoPlayer.isSmallFloatViewShow) {
+        self.floatControlView.hidden = observer.isFullScreen;
+        self.portraitControlView.hidden = YES;
+        if (observer.isFullScreen) {
+            self.controlViewAppeared = NO;
+            [self cancelAutoFadeOutControlView];
+        }
+    }
+    if (self.controlViewAppeared) {
+        [self showControlViewWithAnimated:NO];
+    } else {
+        [self hideControlViewWithAnimated:NO];
+    }
+    
+    if (observer.isFullScreen) {
+        [self.volumeBrightnessView removeSystemVolumeView];
+    } else {
+        [self.volumeBrightnessView addSystemVolumeView];
+    }
+}
+
+/// 视频view已经旋转
+- (void)videoPlayer:(ZFPlayerController *)videoPlayer orientationDidChanged:(ZFOrientationObserver *)observer {
+    if (self.controlViewAppeared) {
+        [self showControlViewWithAnimated:NO];
+    } else {
+        [self hideControlViewWithAnimated:NO];
+    }
+}
+
+/// 锁定旋转方向
+- (void)lockedVideoPlayer:(ZFPlayerController *)videoPlayer lockedScreen:(BOOL)locked {
+    [self showControlViewWithAnimated:YES];
+}
+
+/// 列表滑动时视频view已经显示
+- (void)playerDidAppearInScrollView:(ZFPlayerController *)videoPlayer {
+    if (!self.player.stopWhileNotVisible && !videoPlayer.isFullScreen) {
+        self.floatControlView.hidden = YES;
+        self.portraitControlView.hidden = NO;
+    }
+}
+
+/// 列表滑动时视频view已经消失
+- (void)playerDidDisappearInScrollView:(ZFPlayerController *)videoPlayer {
+    if (!self.player.stopWhileNotVisible && !videoPlayer.isFullScreen) {
+        self.floatControlView.hidden = NO;
+        self.portraitControlView.hidden = YES;
+    }
+}
+
+- (void)videoPlayer:(ZFPlayerController *)videoPlayer floatViewShow:(BOOL)show {
+    self.floatControlView.hidden = !show;
+    self.portraitControlView.hidden = show;
+}
+
+#pragma mark - Private Method
+
+- (void)sliderValueChangingValue:(CGFloat)value isForward:(BOOL)forward {
+    if (self.horizontalPanShowControlView) {
+        /// 显示控制层
+        [self showControlViewWithAnimated:NO];
+        [self cancelAutoFadeOutControlView];
+    }
+    
+    self.fastProgressView.value = value;
+    self.fastView.hidden = NO;
+    self.fastView.alpha = 1;
+    if (forward) {
+        self.fastImageView.image = ZFPlayer_Image(@"ZFPlayer_fast_forward");
+    } else {
+        self.fastImageView.image = ZFPlayer_Image(@"ZFPlayer_fast_backward");
+    }
+    NSString *draggedTime = [ZFUtilities convertTimeSecond:self.player.totalTime*value];
+    NSString *totalTime = [ZFUtilities convertTimeSecond:self.player.totalTime];
+    self.fastTimeLabel.text = [NSString stringWithFormat:@"%@ / %@",draggedTime,totalTime];
+    /// 更新滑杆
+    [self.portraitControlView sliderValueChanged:value currentTimeString:draggedTime];
+    [self.landScapeControlView sliderValueChanged:value currentTimeString:draggedTime];
+    self.bottomPgrogress.isdragging = YES;
+    self.bottomPgrogress.value = value;
+
+    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(hideFastView) object:nil];
+    [self performSelector:@selector(hideFastView) withObject:nil afterDelay:0.1];
+    
+    if (self.fastViewAnimated) {
+        [UIView animateWithDuration:0.4 animations:^{
+            self.fastView.transform = CGAffineTransformMakeTranslation(forward?8:-8, 0);
+        }];
+    }
+}
+
+/// 隐藏快进视图
+- (void)hideFastView {
+    [UIView animateWithDuration:0.4 animations:^{
+        self.fastView.transform = CGAffineTransformIdentity;
+        self.fastView.alpha = 0;
+    } completion:^(BOOL finished) {
+        self.fastView.hidden = YES;
+    }];
+}
+
+/// 加载失败
+- (void)failBtnClick:(UIButton *)sender {
+    [self.player.currentPlayerManager reloadPlayer];
+}
+
+#pragma mark - setter
+
+- (void)setPlayer:(ZFPlayerController *)player {
+    _player = player;
+    self.landScapeControlView.player = player;
+    self.portraitControlView.player = player;
+    /// 解决播放时候黑屏闪一下问题
+    [player.currentPlayerManager.view insertSubview:self.bgImgView atIndex:0];
+    [self.bgImgView addSubview:self.effectView];
+    [player.currentPlayerManager.view insertSubview:self.coverImageView atIndex:1];
+    self.coverImageView.frame = player.currentPlayerManager.view.bounds;
+    self.coverImageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+    self.bgImgView.frame = player.currentPlayerManager.view.bounds;
+    self.bgImgView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+    self.effectView.frame = self.bgImgView.bounds;
+    self.coverImageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+}
+
+- (void)setSeekToPlay:(BOOL)seekToPlay {
+    _seekToPlay = seekToPlay;
+    self.portraitControlView.seekToPlay = seekToPlay;
+    self.landScapeControlView.seekToPlay = seekToPlay;
+}
+
+- (void)setEffectViewShow:(BOOL)effectViewShow {
+    _effectViewShow = effectViewShow;
+    if (effectViewShow) {
+        self.bgImgView.hidden = NO;
+    } else {
+        self.bgImgView.hidden = YES;
+    }
+}
+
+#pragma mark - getter
+
+- (UIImageView *)bgImgView {
+    if (!_bgImgView) {
+        _bgImgView = [[UIImageView alloc] init];
+        _bgImgView.userInteractionEnabled = YES;
+    }
+    return _bgImgView;
+}
+
+- (UIView *)effectView {
+    if (!_effectView) {
+        if (@available(iOS 8.0, *)) {
+            UIBlurEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
+            _effectView = [[UIVisualEffectView alloc] initWithEffect:effect];
+        } else {
+            UIToolbar *effectView = [[UIToolbar alloc] init];
+            effectView.barStyle = UIBarStyleBlackTranslucent;
+            _effectView = effectView;
+        }
+    }
+    return _effectView;
+}
+
+- (ZFPortraitControlView *)portraitControlView {
+    if (!_portraitControlView) {
+        @weakify(self)
+        _portraitControlView = [[ZFPortraitControlView alloc] init];
+        _portraitControlView.sliderValueChanging = ^(CGFloat value, BOOL forward) {
+            @strongify(self)
+            NSString *draggedTime = [ZFUtilities convertTimeSecond:self.player.totalTime*value];
+            /// 更新滑杆和时间
+            [self.landScapeControlView sliderValueChanged:value currentTimeString:draggedTime];
+            self.fastProgressView.value = value;
+            self.bottomPgrogress.isdragging = YES;
+            self.bottomPgrogress.value = value;
+            [self cancelAutoFadeOutControlView];
+        };
+        _portraitControlView.sliderValueChanged = ^(CGFloat value) {
+            @strongify(self)
+            [self.landScapeControlView sliderChangeEnded];
+            self.fastProgressView.value = value;
+            self.bottomPgrogress.isdragging = NO;
+            self.bottomPgrogress.value = value;
+            [self autoFadeOutControlView];
+        };
+    }
+    return _portraitControlView;
+}
+
+- (ZFLandScapeControlView *)landScapeControlView {
+    if (!_landScapeControlView) {
+        @weakify(self)
+        _landScapeControlView = [[ZFLandScapeControlView alloc] init];
+        _landScapeControlView.sliderValueChanging = ^(CGFloat value, BOOL forward) {
+            @strongify(self)
+            NSString *draggedTime = [ZFUtilities convertTimeSecond:self.player.totalTime*value];
+            /// 更新滑杆和时间
+            [self.portraitControlView sliderValueChanged:value currentTimeString:draggedTime];
+            self.fastProgressView.value = value;
+            self.bottomPgrogress.isdragging = YES;
+            self.bottomPgrogress.value = value;
+            [self cancelAutoFadeOutControlView];
+        };
+        _landScapeControlView.sliderValueChanged = ^(CGFloat value) {
+            @strongify(self)
+            [self.portraitControlView sliderChangeEnded];
+            self.fastProgressView.value = value;
+            self.bottomPgrogress.isdragging = NO;
+            self.bottomPgrogress.value = value;
+            [self autoFadeOutControlView];
+        };
+    }
+    return _landScapeControlView;
+}
+
+- (ZFSpeedLoadingView *)activity {
+    if (!_activity) {
+        _activity = [[ZFSpeedLoadingView alloc] init];
+    }
+    return _activity;
+}
+
+- (UIView *)fastView {
+    if (!_fastView) {
+        _fastView = [[UIView alloc] init];
+        _fastView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.7];
+        _fastView.layer.cornerRadius = 4;
+        _fastView.layer.masksToBounds = YES;
+        _fastView.hidden = YES;
+    }
+    return _fastView;
+}
+
+- (UIImageView *)fastImageView {
+    if (!_fastImageView) {
+        _fastImageView = [[UIImageView alloc] init];
+    }
+    return _fastImageView;
+}
+
+- (UILabel *)fastTimeLabel {
+    if (!_fastTimeLabel) {
+        _fastTimeLabel = [[UILabel alloc] init];
+        _fastTimeLabel.textColor = [UIColor whiteColor];
+        _fastTimeLabel.textAlignment = NSTextAlignmentCenter;
+        _fastTimeLabel.font = [UIFont systemFontOfSize:14.0];
+        _fastTimeLabel.adjustsFontSizeToFitWidth = YES;
+    }
+    return _fastTimeLabel;
+}
+
+- (ZFSliderView *)fastProgressView {
+    if (!_fastProgressView) {
+        _fastProgressView = [[ZFSliderView alloc] init];
+        _fastProgressView.maximumTrackTintColor = [[UIColor lightGrayColor] colorWithAlphaComponent:0.4];
+        _fastProgressView.minimumTrackTintColor = [UIColor whiteColor];
+        _fastProgressView.sliderHeight = 2;
+        _fastProgressView.isHideSliderBlock = NO;
+    }
+    return _fastProgressView;
+}
+
+- (UIButton *)failBtn {
+    if (!_failBtn) {
+        _failBtn = [UIButton buttonWithType:UIButtonTypeSystem];
+        [_failBtn setTitle:@"加载失败,点击重试" forState:UIControlStateNormal];
+        [_failBtn addTarget:self action:@selector(failBtnClick:) forControlEvents:UIControlEventTouchUpInside];
+        [_failBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
+        _failBtn.titleLabel.font = [UIFont systemFontOfSize:14.0];
+        _failBtn.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.7];
+        _failBtn.hidden = YES;
+    }
+    return _failBtn;
+}
+
+- (ZFSliderView *)bottomPgrogress {
+    if (!_bottomPgrogress) {
+        _bottomPgrogress = [[ZFSliderView alloc] init];
+        _bottomPgrogress.maximumTrackTintColor = [UIColor clearColor];
+        _bottomPgrogress.minimumTrackTintColor = [UIColor whiteColor];
+        _bottomPgrogress.bufferTrackTintColor  = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.5];
+        _bottomPgrogress.sliderHeight = 1;
+        _bottomPgrogress.isHideSliderBlock = NO;
+    }
+    return _bottomPgrogress;
+}
+
+- (UIImageView *)coverImageView {
+    if (!_coverImageView) {
+        _coverImageView = [[UIImageView alloc] init];
+        _coverImageView.userInteractionEnabled = YES;
+        _coverImageView.contentMode = UIViewContentModeScaleAspectFit;
+    }
+    return _coverImageView;
+}
+
+- (ZFSmallFloatControlView *)floatControlView {
+    if (!_floatControlView) {
+        _floatControlView = [[ZFSmallFloatControlView alloc] init];
+        @weakify(self)
+        _floatControlView.closeClickCallback = ^{
+            @strongify(self)
+            if (self.player.containerType == ZFPlayerContainerTypeCell) {
+                [self.player stopCurrentPlayingCell];
+            } else if (self.player.containerType == ZFPlayerContainerTypeView) {
+                [self.player stopCurrentPlayingView];
+            }
+            [self resetControlView];
+        };
+    }
+    return _floatControlView;
+}
+
+- (ZFVolumeBrightnessView *)volumeBrightnessView {
+    if (!_volumeBrightnessView) {
+        _volumeBrightnessView = [[ZFVolumeBrightnessView alloc] init];
+        _volumeBrightnessView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.7];
+        _volumeBrightnessView.hidden = YES;
+    }
+    return _volumeBrightnessView;
+}
+
+- (void)setBackBtnClickCallback:(void (^)(void))backBtnClickCallback {
+    _backBtnClickCallback = [backBtnClickCallback copy];
+    self.landScapeControlView.backBtnClickCallback = _backBtnClickCallback;
+}
+
+@end

+ 108 - 0
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPortraitControlView.h

@@ -0,0 +1,108 @@
+//
+//  ZFPortraitControlView.h
+//  ZFPlayer
+//
+// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import <UIKit/UIKit.h>
+#import "ZFSliderView.h"
+#if __has_include(<ZFPlayer/ZFPlayerController.h>)
+#import <ZFPlayer/ZFPlayerController.h>
+#else
+#import "ZFPlayerController.h"
+#endif
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface ZFPortraitControlView : UIView
+
+/// 底部工具栏
+@property (nonatomic, strong, readonly) UIView *bottomToolView;
+
+/// 顶部工具栏
+@property (nonatomic, strong, readonly) UIView *topToolView;
+
+/// 标题
+@property (nonatomic, strong, readonly) UILabel *titleLabel;
+
+/// 播放或暂停按钮
+@property (nonatomic, strong, readonly) UIButton *playOrPauseBtn;
+
+/// 播放的当前时间 
+@property (nonatomic, strong, readonly) UILabel *currentTimeLabel;
+
+/// 滑杆
+@property (nonatomic, strong, readonly) ZFSliderView *slider;
+
+/// 视频总时间
+@property (nonatomic, strong, readonly) UILabel *totalTimeLabel;
+
+/// 全屏按钮
+@property (nonatomic, strong, readonly) UIButton *fullScreenBtn;
+
+/// 播放器
+@property (nonatomic, weak) ZFPlayerController *player;
+
+/// slider滑动中
+@property (nonatomic, copy, nullable) void(^sliderValueChanging)(CGFloat value,BOOL forward);
+
+/// slider滑动结束
+@property (nonatomic, copy, nullable) void(^sliderValueChanged)(CGFloat value);
+
+/// 如果是暂停状态,seek完是否播放,默认YES
+@property (nonatomic, assign) BOOL seekToPlay;
+
+/// 重置控制层
+- (void)resetControlView;
+
+/// 显示控制层
+- (void)showControlView;
+
+/// 隐藏控制层
+- (void)hideControlView;
+
+/// 设置播放时间
+- (void)videoPlayer:(ZFPlayerController *)videoPlayer currentTime:(NSTimeInterval)currentTime totalTime:(NSTimeInterval)totalTime;
+
+/// 设置缓冲时间
+- (void)videoPlayer:(ZFPlayerController *)videoPlayer bufferTime:(NSTimeInterval)bufferTime;
+
+/// 是否响应该手势
+- (BOOL)shouldResponseGestureWithPoint:(CGPoint)point withGestureType:(ZFPlayerGestureType)type touch:(nonnull UITouch *)touch;
+
+/// 标题和全屏模式
+- (void)showTitle:(NSString *_Nullable)title fullScreenMode:(ZFFullScreenMode)fullScreenMode;
+
+/// 根据当前播放状态取反
+- (void)playOrPause;
+
+/// 播放按钮状态
+- (void)playBtnSelectedState:(BOOL)selected;
+
+/// 调节播放进度slider和当前时间更新
+- (void)sliderValueChanged:(CGFloat)value currentTimeString:(NSString *)timeString;
+
+/// 滑杆结束滑动
+- (void)sliderChangeEnded;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 380 - 0
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPortraitControlView.m

@@ -0,0 +1,380 @@
+//
+//  ZFPortraitControlView.m
+//  ZFPlayer
+//
+// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import "ZFPortraitControlView.h"
+#import "UIView+ZFFrame.h"
+#import "ZFUtilities.h"
+#if __has_include(<ZFPlayer/ZFPlayer.h>)
+#import <ZFPlayer/ZFPlayer.h>
+#else
+#import "ZFPlayer.h"
+#endif
+
+@interface ZFPortraitControlView () <ZFSliderViewDelegate>
+/// 底部工具栏
+@property (nonatomic, strong) UIView *bottomToolView;
+/// 顶部工具栏
+@property (nonatomic, strong) UIView *topToolView;
+/// 标题
+@property (nonatomic, strong) UILabel *titleLabel;
+/// 播放或暂停按钮
+@property (nonatomic, strong) UIButton *playOrPauseBtn;
+/// 播放的当前时间 
+@property (nonatomic, strong) UILabel *currentTimeLabel;
+/// 滑杆
+@property (nonatomic, strong) ZFSliderView *slider;
+/// 视频总时间
+@property (nonatomic, strong) UILabel *totalTimeLabel;
+/// 全屏按钮
+@property (nonatomic, strong) UIButton *fullScreenBtn;
+
+@property (nonatomic, assign) BOOL isShow;
+
+@end
+
+@implementation ZFPortraitControlView
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    if (self = [super initWithFrame:frame]) {
+        // 添加子控件
+        [self addSubview:self.topToolView];
+        [self addSubview:self.bottomToolView];
+        [self addSubview:self.playOrPauseBtn];
+        [self.topToolView addSubview:self.titleLabel];
+        [self.bottomToolView addSubview:self.currentTimeLabel];
+        [self.bottomToolView addSubview:self.slider];
+        [self.bottomToolView addSubview:self.totalTimeLabel];
+        [self.bottomToolView addSubview:self.fullScreenBtn];
+        
+        // 设置子控件的响应事件
+        [self makeSubViewsAction];
+        
+        [self resetControlView];
+        self.clipsToBounds = YES;
+    }
+    return self;
+}
+
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    
+    CGFloat min_x = 0;
+    CGFloat min_y = 0;
+    CGFloat min_w = 0;
+    CGFloat min_h = 0;
+    CGFloat min_view_w = self.bounds.size.width;
+    CGFloat min_view_h = self.bounds.size.height;
+    CGFloat min_margin = 9;
+    
+    min_x = 0;
+    min_y = 0;
+    min_w = min_view_w;
+    min_h = 40;
+    self.topToolView.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    
+    min_x = 15;
+    min_y = 5;
+    min_w = min_view_w - min_x - 15;
+    min_h = 30;
+    self.titleLabel.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    
+    min_h = 40;
+    min_x = 0;
+    min_y = min_view_h - min_h;
+    min_w = min_view_w;
+    self.bottomToolView.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    
+    min_x = 0;
+    min_y = 0;
+    min_w = 44;
+    min_h = min_w;
+    self.playOrPauseBtn.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    self.playOrPauseBtn.center = self.center;
+    
+    min_x = min_margin;
+    min_w = 62;
+    min_h = 28;
+    min_y = (self.bottomToolView.zf_height - min_h)/2;
+    self.currentTimeLabel.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    
+    min_w = 28;
+    min_h = min_w;
+    min_x = self.bottomToolView.zf_width - min_w - min_margin;
+    min_y = 0;
+    self.fullScreenBtn.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    self.fullScreenBtn.zf_centerY = self.currentTimeLabel.zf_centerY;
+    
+    min_w = 62;
+    min_h = 28;
+    min_x = self.fullScreenBtn.zf_left - min_w - 4;
+    min_y = 0;
+    self.totalTimeLabel.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    self.totalTimeLabel.zf_centerY = self.currentTimeLabel.zf_centerY;
+    
+    min_x = self.currentTimeLabel.zf_right + 4;
+    min_y = 0;
+    min_w = self.totalTimeLabel.zf_left - min_x - 4;
+    min_h = 30;
+    self.slider.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    self.slider.zf_centerY = self.currentTimeLabel.zf_centerY;
+    
+    if (!self.isShow) {
+        self.topToolView.zf_y = -self.topToolView.zf_height;
+        self.bottomToolView.zf_y = self.zf_height;
+        self.playOrPauseBtn.alpha = 0;
+    } else {
+        self.topToolView.zf_y = 0;
+        self.bottomToolView.zf_y = self.zf_height - self.bottomToolView.zf_height;
+        self.playOrPauseBtn.alpha = 1;
+    }
+}
+
+- (void)makeSubViewsAction {
+    [self.playOrPauseBtn addTarget:self action:@selector(playPauseButtonClickAction:) forControlEvents:UIControlEventTouchUpInside];
+    [self.fullScreenBtn addTarget:self action:@selector(fullScreenButtonClickAction:) forControlEvents:UIControlEventTouchUpInside];
+}
+
+#pragma mark - action
+
+- (void)playPauseButtonClickAction:(UIButton *)sender {
+    [self playOrPause];
+}
+
+- (void)fullScreenButtonClickAction:(UIButton *)sender {
+    [self.player enterFullScreen:YES animated:YES];
+}
+
+/// 根据当前播放状态取反
+- (void)playOrPause {
+    self.playOrPauseBtn.selected = !self.playOrPauseBtn.isSelected;
+    self.playOrPauseBtn.isSelected? [self.player.currentPlayerManager play]: [self.player.currentPlayerManager pause];
+}
+
+- (void)playBtnSelectedState:(BOOL)selected {
+    self.playOrPauseBtn.selected = selected;
+}
+
+#pragma mark - ZFSliderViewDelegate
+
+- (void)sliderTouchBegan:(float)value {
+    self.slider.isdragging = YES;
+}
+
+- (void)sliderTouchEnded:(float)value {
+    if (self.player.totalTime > 0) {
+        self.slider.isdragging = YES;
+        if (self.sliderValueChanging) self.sliderValueChanging(value, self.slider.isForward);
+        @weakify(self)
+        [self.player seekToTime:self.player.totalTime*value completionHandler:^(BOOL finished) {
+            @strongify(self)
+            if (finished) {
+                self.slider.isdragging = NO;
+                if (self.sliderValueChanged) self.sliderValueChanged(value);
+            }
+        }];
+        if (self.seekToPlay) {
+            [self.player.currentPlayerManager play];
+        }
+    } else {
+        self.slider.isdragging = NO;
+        self.slider.value = 0;
+    }
+}
+
+- (void)sliderValueChanged:(float)value {
+    if (self.player.totalTime == 0) {
+        self.slider.value = 0;
+        return;
+    }
+    self.slider.isdragging = YES;
+    NSString *currentTimeString = [ZFUtilities convertTimeSecond:self.player.totalTime*value];
+    self.currentTimeLabel.text = currentTimeString;
+    if (self.sliderValueChanging) self.sliderValueChanging(value,self.slider.isForward);
+}
+
+- (void)sliderTapped:(float)value {
+    [self sliderTouchEnded:value];
+    NSString *currentTimeString = [ZFUtilities convertTimeSecond:self.player.totalTime*value];
+    self.currentTimeLabel.text = currentTimeString;
+}
+
+#pragma mark - public method 
+
+/** 重置ControlView */
+- (void)resetControlView {
+    self.bottomToolView.alpha        = 1;
+    self.slider.value                = 0;
+    self.slider.bufferValue          = 0;
+    self.currentTimeLabel.text       = @"00:00";
+    self.totalTimeLabel.text         = @"00:00";
+    self.backgroundColor             = [UIColor clearColor];
+    self.playOrPauseBtn.selected     = YES;
+    self.titleLabel.text             = @"";
+}
+
+- (void)showControlView {
+    self.topToolView.alpha           = 1;
+    self.bottomToolView.alpha        = 1;
+    self.isShow                      = YES;
+    self.topToolView.zf_y            = 0;
+    self.bottomToolView.zf_y         = self.zf_height - self.bottomToolView.zf_height;
+    self.playOrPauseBtn.alpha        = 1;
+    self.player.statusBarHidden      = NO;
+}
+
+- (void)hideControlView {
+    self.isShow                      = NO;
+    self.topToolView.zf_y            = -self.topToolView.zf_height;
+    self.bottomToolView.zf_y         = self.zf_height;
+    self.player.statusBarHidden      = NO;
+    self.playOrPauseBtn.alpha        = 0;
+    self.topToolView.alpha           = 0;
+    self.bottomToolView.alpha        = 0;
+}
+
+- (BOOL)shouldResponseGestureWithPoint:(CGPoint)point withGestureType:(ZFPlayerGestureType)type touch:(nonnull UITouch *)touch {
+    CGRect sliderRect = [self.bottomToolView convertRect:self.slider.frame toView:self];
+    if (CGRectContainsPoint(sliderRect, point)) {
+        return NO;
+    }
+    return YES;
+}
+
+- (void)videoPlayer:(ZFPlayerController *)videoPlayer currentTime:(NSTimeInterval)currentTime totalTime:(NSTimeInterval)totalTime {
+    if (!self.slider.isdragging) {
+        NSString *currentTimeString = [ZFUtilities convertTimeSecond:currentTime];
+        self.currentTimeLabel.text = currentTimeString;
+        NSString *totalTimeString = [ZFUtilities convertTimeSecond:totalTime];
+        self.totalTimeLabel.text = totalTimeString;
+        self.slider.value = videoPlayer.progress;
+    }
+}
+
+- (void)videoPlayer:(ZFPlayerController *)videoPlayer bufferTime:(NSTimeInterval)bufferTime {
+    self.slider.bufferValue = videoPlayer.bufferProgress;
+}
+
+- (void)showTitle:(NSString *)title fullScreenMode:(ZFFullScreenMode)fullScreenMode {
+    self.titleLabel.text = title;
+    self.player.orientationObserver.fullScreenMode = fullScreenMode;
+}
+
+/// 调节播放进度slider和当前时间更新
+- (void)sliderValueChanged:(CGFloat)value currentTimeString:(NSString *)timeString {
+    self.slider.value = value;
+    self.currentTimeLabel.text = timeString;
+    self.slider.isdragging = YES;
+    [UIView animateWithDuration:0.3 animations:^{
+        self.slider.sliderBtn.transform = CGAffineTransformMakeScale(1.2, 1.2);
+    }];
+}
+
+/// 滑杆结束滑动
+- (void)sliderChangeEnded {
+    self.slider.isdragging = NO;
+    [UIView animateWithDuration:0.3 animations:^{
+        self.slider.sliderBtn.transform = CGAffineTransformIdentity;
+    }];
+}
+
+#pragma mark - getter
+
+- (UIView *)topToolView {
+    if (!_topToolView) {
+        _topToolView = [[UIView alloc] init];
+        UIImage *image = ZFPlayer_Image(@"ZFPlayer_top_shadow");
+        _topToolView.layer.contents = (id)image.CGImage;
+    }
+    return _topToolView;
+}
+
+- (UILabel *)titleLabel {
+    if (!_titleLabel) {
+        _titleLabel = [[UILabel alloc] init];
+        _titleLabel.textColor = [UIColor whiteColor];
+        _titleLabel.font = [UIFont systemFontOfSize:15.0];
+    }
+    return _titleLabel;
+}
+
+- (UIView *)bottomToolView {
+    if (!_bottomToolView) {
+        _bottomToolView = [[UIView alloc] init];
+        UIImage *image = ZFPlayer_Image(@"ZFPlayer_bottom_shadow");
+        _bottomToolView.layer.contents = (id)image.CGImage;
+    }
+    return _bottomToolView;
+}
+
+- (UIButton *)playOrPauseBtn {
+    if (!_playOrPauseBtn) {
+        _playOrPauseBtn = [UIButton buttonWithType:UIButtonTypeCustom];
+        [_playOrPauseBtn setImage:ZFPlayer_Image(@"new_allPlay_44x44_") forState:UIControlStateNormal];
+        [_playOrPauseBtn setImage:ZFPlayer_Image(@"new_allPause_44x44_") forState:UIControlStateSelected];
+    }
+    return _playOrPauseBtn;
+}
+
+- (UILabel *)currentTimeLabel {
+    if (!_currentTimeLabel) {
+        _currentTimeLabel = [[UILabel alloc] init];
+        _currentTimeLabel.textColor = [UIColor whiteColor];
+        _currentTimeLabel.font = [UIFont systemFontOfSize:14.0f];
+        _currentTimeLabel.textAlignment = NSTextAlignmentCenter;
+    }
+    return _currentTimeLabel;
+}
+
+- (ZFSliderView *)slider {
+    if (!_slider) {
+        _slider = [[ZFSliderView alloc] init];
+        _slider.delegate = self;
+        _slider.maximumTrackTintColor = [UIColor colorWithRed:0.5 green:0.5 blue:0.5 alpha:0.8];
+        _slider.bufferTrackTintColor  = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.5];
+        _slider.minimumTrackTintColor = [UIColor whiteColor];
+        [_slider setThumbImage:ZFPlayer_Image(@"ZFPlayer_slider") forState:UIControlStateNormal];
+        _slider.sliderHeight = 2;
+    }
+    return _slider;
+}
+
+- (UILabel *)totalTimeLabel {
+    if (!_totalTimeLabel) {
+        _totalTimeLabel = [[UILabel alloc] init];
+        _totalTimeLabel.textColor = [UIColor whiteColor];
+        _totalTimeLabel.font = [UIFont systemFontOfSize:14.0f];
+        _totalTimeLabel.textAlignment = NSTextAlignmentCenter;
+    }
+    return _totalTimeLabel;
+}
+
+- (UIButton *)fullScreenBtn {
+    if (!_fullScreenBtn) {
+        _fullScreenBtn = [UIButton buttonWithType:UIButtonTypeCustom];
+        [_fullScreenBtn setImage:ZFPlayer_Image(@"ZFPlayer_fullscreen") forState:UIControlStateNormal];
+    }
+    return _fullScreenBtn;
+}
+
+@end

+ 118 - 0
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFSliderView.h

@@ -0,0 +1,118 @@
+//
+//  ZFSliderView.h
+//  ZFPlayer
+//
+// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import <UIKit/UIKit.h>
+
+@protocol ZFSliderViewDelegate <NSObject>
+
+@optional
+// 滑块滑动开始
+- (void)sliderTouchBegan:(float)value;
+// 滑块滑动中
+- (void)sliderValueChanged:(float)value;
+// 滑块滑动结束
+- (void)sliderTouchEnded:(float)value;
+// 滑杆点击
+- (void)sliderTapped:(float)value;
+
+@end
+
+@interface ZFSliderButton : UIButton
+
+@end
+
+@interface ZFSliderView : UIView
+
+@property (nonatomic, weak) id<ZFSliderViewDelegate> delegate;
+
+/** 滑块 */
+@property (nonatomic, strong, readonly) ZFSliderButton *sliderBtn;
+
+/** 默认滑杆的颜色 */
+@property (nonatomic, strong) UIColor *maximumTrackTintColor;
+
+/** 滑杆进度颜色 */
+@property (nonatomic, strong) UIColor *minimumTrackTintColor;
+
+/** 缓存进度颜色 */
+@property (nonatomic, strong) UIColor *bufferTrackTintColor;
+
+/** loading进度颜色 */
+@property (nonatomic, strong) UIColor *loadingTintColor;
+
+/** 默认滑杆的图片 */
+@property (nonatomic, strong) UIImage *maximumTrackImage;
+
+/** 滑杆进度的图片 */
+@property (nonatomic, strong) UIImage *minimumTrackImage;
+
+/** 缓存进度的图片 */
+@property (nonatomic, strong) UIImage *bufferTrackImage;
+
+/** 滑杆进度 */
+@property (nonatomic, assign) float value;
+
+/** 缓存进度 */
+@property (nonatomic, assign) float bufferValue;
+
+/** 是否允许点击,默认是YES */
+@property (nonatomic, assign) BOOL allowTapped;
+
+/** 是否允许点击,默认是YES */
+@property (nonatomic, assign) BOOL animate;
+
+/** 设置滑杆的高度 */
+@property (nonatomic, assign) CGFloat sliderHeight;
+
+/** 设置滑杆的圆角 */
+@property (nonatomic, assign) CGFloat sliderRadius;
+
+/** 是否隐藏滑块(默认为NO) */
+@property (nonatomic, assign) BOOL isHideSliderBlock;
+
+/// 是否正在拖动
+@property (nonatomic, assign) BOOL isdragging;
+
+/// 向前还是向后拖动
+@property (nonatomic, assign) BOOL isForward;
+
+@property (nonatomic, assign) CGSize thumbSize;
+
+/**
+ *  Starts animation of the spinner.
+ */
+- (void)startAnimating;
+
+/**
+ *  Stops animation of the spinnner.
+ */
+- (void)stopAnimating;
+
+// 设置滑块背景色
+- (void)setBackgroundImage:(UIImage *)image forState:(UIControlState)state;
+
+// 设置滑块图片
+- (void)setThumbImage:(UIImage *)image forState:(UIControlState)state;
+
+@end

+ 426 - 0
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFSliderView.m

@@ -0,0 +1,426 @@
+//
+//  ZFSliderView.m
+//  ZFPlayer
+//
+// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import "ZFSliderView.h"
+#import "UIView+ZFFrame.h"
+
+/** 滑块的大小 */
+static const CGFloat kSliderBtnWH = 19.0;
+/** 进度的高度 */
+static const CGFloat kProgressH = 1.0;
+/** 拖动slider动画的时间*/
+static const CGFloat kAnimate = 0.3;
+
+@implementation ZFSliderButton
+
+// 重写此方法将按钮的点击范围扩大
+- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
+    CGRect bounds = self.bounds;
+    // 扩大点击区域
+    bounds = CGRectInset(bounds, -20, -20);
+    // 若点击的点在新的bounds里面。就返回yes
+    return CGRectContainsPoint(bounds, point);
+}
+
+@end
+
+@interface ZFSliderView ()
+
+/** 进度背景 */
+@property (nonatomic, strong) UIImageView *bgProgressView;
+/** 缓存进度 */
+@property (nonatomic, strong) UIImageView *bufferProgressView;
+/** 滑动进度 */
+@property (nonatomic, strong) UIImageView *sliderProgressView;
+/** 滑块 */
+@property (nonatomic, strong) ZFSliderButton *sliderBtn;
+
+@property (nonatomic, strong) UIView *loadingBarView;
+
+@property (nonatomic, assign) BOOL isLoading;
+
+@property (nonatomic, strong) UITapGestureRecognizer *tapGesture;
+
+@end
+
+@implementation ZFSliderView
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    if (self = [super initWithFrame:frame]) {
+        self.allowTapped = YES;
+        self.animate = YES;
+        [self addSubViews];
+    }
+    return self;
+}
+
+- (void)awakeFromNib {
+    [super awakeFromNib];
+    self.allowTapped = YES;
+    self.animate = YES;
+    [self addSubViews];
+}
+
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    if (isnan(self.value) || isnan(self.bufferValue)) return;
+
+    CGFloat min_x = 0;
+    CGFloat min_y = 0;
+    CGFloat min_w = 0;
+    CGFloat min_h = 0;
+    CGFloat min_view_w = self.bounds.size.width;
+    CGFloat min_view_h = self.bounds.size.height;
+    
+    min_x = 0;
+    min_w = min_view_w;
+    min_y = 0;
+    min_h = self.sliderHeight;
+    self.bgProgressView.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    
+    min_x = 0;
+    min_y = 0;
+    min_w = self.thumbSize.width;
+    min_h = self.thumbSize.height;
+    self.sliderBtn.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    self.sliderBtn.zf_centerX = self.bgProgressView.zf_width * self.value;
+    
+    min_x = 0;
+    min_y = 0;
+    if (self.sliderBtn.hidden) {
+        min_w = self.bgProgressView.zf_width * self.value;
+    } else {
+        min_w = self.sliderBtn.zf_centerX;
+    }
+    min_h = self.sliderHeight;
+    self.sliderProgressView.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    
+    min_x = 0;
+    min_y = 0;
+    min_w = self.bgProgressView.zf_width * self.bufferValue;
+    min_h = self.sliderHeight;
+    self.bufferProgressView.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    
+    min_w = 0.1;
+    min_h = self.sliderHeight;
+    min_x = (min_view_w - min_w)/2;
+    min_y = (min_view_h - min_h)/2;
+    self.loadingBarView.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    
+    self.bgProgressView.zf_centerY     = min_view_h * 0.5;
+    self.bufferProgressView.zf_centerY = min_view_h * 0.5;
+    self.sliderProgressView.zf_centerY = min_view_h * 0.5;
+    self.sliderBtn.zf_centerY          = min_view_h * 0.5;
+}
+
+/**
+ 添加子视图
+ */
+- (void)addSubViews {
+    self.thumbSize = CGSizeMake(kSliderBtnWH, kSliderBtnWH);
+    self.sliderHeight = kProgressH;
+    self.backgroundColor = [UIColor clearColor];
+    [self addSubview:self.bgProgressView];
+    [self addSubview:self.bufferProgressView];
+    [self addSubview:self.sliderProgressView];
+    [self addSubview:self.sliderBtn];
+    [self addSubview:self.loadingBarView];
+    
+    // 添加点击手势
+    self.tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped:)];
+    [self addGestureRecognizer:self.tapGesture];
+    
+    // 添加滑动手势
+    UIPanGestureRecognizer *sliderGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(sliderGesture:)];
+    [self addGestureRecognizer:sliderGesture];
+}
+
+#pragma mark - Setter
+
+- (void)setMaximumTrackTintColor:(UIColor *)maximumTrackTintColor {
+    _maximumTrackTintColor = maximumTrackTintColor;
+    self.bgProgressView.backgroundColor = maximumTrackTintColor;
+}
+
+- (void)setMinimumTrackTintColor:(UIColor *)minimumTrackTintColor {
+    _minimumTrackTintColor = minimumTrackTintColor;
+    self.sliderProgressView.backgroundColor = minimumTrackTintColor;
+}
+
+- (void)setBufferTrackTintColor:(UIColor *)bufferTrackTintColor {
+    _bufferTrackTintColor = bufferTrackTintColor;
+    self.bufferProgressView.backgroundColor = bufferTrackTintColor;
+}
+
+- (void)setLoadingTintColor:(UIColor *)loadingTintColor {
+    _loadingTintColor = loadingTintColor;
+    self.loadingBarView.backgroundColor = loadingTintColor;
+}
+
+- (void)setMaximumTrackImage:(UIImage *)maximumTrackImage {
+    _maximumTrackImage = maximumTrackImage;
+    self.bgProgressView.image = maximumTrackImage;
+    self.maximumTrackTintColor = [UIColor clearColor];
+}
+
+- (void)setMinimumTrackImage:(UIImage *)minimumTrackImage {
+    _minimumTrackImage = minimumTrackImage;
+    self.sliderProgressView.image = minimumTrackImage;
+    self.minimumTrackTintColor = [UIColor clearColor];
+}
+
+- (void)setBufferTrackImage:(UIImage *)bufferTrackImage {
+    _bufferTrackImage = bufferTrackImage;
+    self.bufferProgressView.image = bufferTrackImage;
+    self.bufferTrackTintColor = [UIColor clearColor];
+}
+
+- (void)setBackgroundImage:(UIImage *)image forState:(UIControlState)state {
+    [self.sliderBtn setBackgroundImage:image forState:state];
+}
+
+- (void)setThumbImage:(UIImage *)image forState:(UIControlState)state {
+    [self.sliderBtn setImage:image forState:state];
+}
+
+- (void)setValue:(float)value {
+    if (isnan(value)) return;
+    value = MIN(1.0, value);
+    _value = value;
+    if (self.sliderBtn.hidden) {
+        self.sliderProgressView.zf_width = self.bgProgressView.zf_width * value;
+    } else {
+        self.sliderBtn.zf_centerX = self.bgProgressView.zf_width * value;
+        self.sliderProgressView.zf_width = self.sliderBtn.zf_centerX;
+    }
+}
+
+- (void)setBufferValue:(float)bufferValue {
+    if (isnan(bufferValue)) return;
+    bufferValue = MIN(1.0, bufferValue);
+    _bufferValue = bufferValue;
+    self.bufferProgressView.zf_width = self.bgProgressView.zf_width * bufferValue;
+}
+
+- (void)setAllowTapped:(BOOL)allowTapped {
+    _allowTapped = allowTapped;
+    if (!allowTapped) {
+        [self removeGestureRecognizer:self.tapGesture];
+    }
+}
+
+- (void)setSliderHeight:(CGFloat)sliderHeight {
+    if (isnan(sliderHeight)) return;
+    _sliderHeight = sliderHeight;
+    self.bgProgressView.zf_height     = sliderHeight;
+    self.bufferProgressView.zf_height = sliderHeight;
+    self.sliderProgressView.zf_height = sliderHeight;
+}
+
+- (void)setSliderRadius:(CGFloat)sliderRadius {
+    if (isnan(sliderRadius)) return;
+    _sliderRadius = sliderRadius;
+    self.bgProgressView.layer.cornerRadius      = sliderRadius;
+    self.bufferProgressView.layer.cornerRadius  = sliderRadius;
+    self.sliderProgressView.layer.cornerRadius  = sliderRadius;
+    self.bgProgressView.layer.masksToBounds     = YES;
+    self.bufferProgressView.layer.masksToBounds = YES;
+    self.sliderProgressView.layer.masksToBounds = YES;
+}
+
+- (void)setIsHideSliderBlock:(BOOL)isHideSliderBlock {
+    _isHideSliderBlock = isHideSliderBlock;
+    // 隐藏滑块,滑杆不可点击
+    if (isHideSliderBlock) {
+        self.sliderBtn.hidden = YES;
+        self.bgProgressView.zf_left     = 0;
+        self.bufferProgressView.zf_left = 0;
+        self.sliderProgressView.zf_left = 0;
+        self.allowTapped = NO;
+    }
+}
+
+/**
+ *  Starts animation of the spinner.
+ */
+- (void)startAnimating {
+    if (self.isLoading) return;
+    self.isLoading = YES;
+    self.bufferProgressView.hidden = YES;
+    self.sliderProgressView.hidden = YES;
+    self.sliderBtn.hidden = YES;
+    self.loadingBarView.hidden = NO;
+    
+    [self.loadingBarView.layer removeAllAnimations];
+    CAAnimationGroup *animationGroup = [[CAAnimationGroup alloc] init];
+    animationGroup.duration = 0.4;
+    animationGroup.beginTime = CACurrentMediaTime() + 0.4;
+    animationGroup.repeatCount = MAXFLOAT;
+    animationGroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
+    
+    CABasicAnimation *scaleAnimation = [CABasicAnimation animation];
+    scaleAnimation.keyPath = @"transform.scale.x";
+    scaleAnimation.fromValue = @(1000.0f);
+    scaleAnimation.toValue = @(self.zf_width * 10);
+    
+    CABasicAnimation *alphaAnimation = [CABasicAnimation animation];
+    alphaAnimation.keyPath = @"opacity";
+    alphaAnimation.fromValue = @(1.0f);
+    alphaAnimation.toValue = @(0.0f);
+    
+    [animationGroup setAnimations:@[scaleAnimation, alphaAnimation]];
+    [self.loadingBarView.layer addAnimation:animationGroup forKey:@"loading"];
+}
+
+/**
+ *  Stops animation of the spinnner.
+ */
+- (void)stopAnimating {
+    self.isLoading = NO;
+    self.bufferProgressView.hidden = NO;
+    self.sliderProgressView.hidden = NO;
+    self.sliderBtn.hidden = self.isHideSliderBlock;
+    self.loadingBarView.hidden = YES;
+    [self.loadingBarView.layer removeAllAnimations];
+}
+
+#pragma mark - User Action
+
+- (void)sliderGesture:(UIGestureRecognizer *)gesture {
+    switch (gesture.state) {
+        case UIGestureRecognizerStateBegan: {
+            [self sliderBtnTouchBegin:self.sliderBtn];
+        }
+            break;
+        case UIGestureRecognizerStateChanged: {
+            [self sliderBtnDragMoving:self.sliderBtn point:[gesture locationInView:self.bgProgressView]];
+        }
+            break;
+        case UIGestureRecognizerStateEnded: {
+            [self sliderBtnTouchEnded:self.sliderBtn];
+        }
+            break;
+        default:
+            break;
+    }
+}
+
+- (void)sliderBtnTouchBegin:(UIButton *)btn {
+    if ([self.delegate respondsToSelector:@selector(sliderTouchBegan:)]) {
+        [self.delegate sliderTouchBegan:self.value];
+    }
+    if (self.animate) {
+        [UIView animateWithDuration:kAnimate animations:^{
+            btn.transform = CGAffineTransformMakeScale(1.2, 1.2);
+        }];
+    }
+}
+
+- (void)sliderBtnTouchEnded:(UIButton *)btn {
+    if ([self.delegate respondsToSelector:@selector(sliderTouchEnded:)]) {
+        [self.delegate sliderTouchEnded:self.value];
+    }
+    if (self.animate) {
+        [UIView animateWithDuration:kAnimate animations:^{
+            btn.transform = CGAffineTransformIdentity;
+        }];
+    }
+}
+
+- (void)sliderBtnDragMoving:(UIButton *)btn point:(CGPoint)touchPoint {
+    // 点击的位置
+    CGPoint point = touchPoint;
+    // 获取进度值 由于btn是从 0-(self.width - btn.width)
+    CGFloat value = (point.x - btn.zf_width * 0.5) / self.bgProgressView.zf_width;
+    // value的值需在0-1之间
+    value = value >= 1.0 ? 1.0 : value <= 0.0 ? 0.0 : value;
+    if (self.value == value) return;
+    self.isForward = self.value < value;
+    self.value = value;
+    if ([self.delegate respondsToSelector:@selector(sliderValueChanged:)]) {
+        [self.delegate sliderValueChanged:value];
+    }
+}
+
+- (void)tapped:(UITapGestureRecognizer *)tap {
+    CGPoint point = [tap locationInView:self.bgProgressView];
+    // 获取进度
+    CGFloat value = (point.x - self.sliderBtn.zf_width * 0.5) * 1.0 / self.bgProgressView.zf_width;
+    value = value >= 1.0 ? 1.0 : value <= 0 ? 0 : value;
+    self.value = value;
+    if ([self.delegate respondsToSelector:@selector(sliderTapped:)]) {
+        [self.delegate sliderTapped:value];
+    }
+}
+
+#pragma mark - getter
+
+- (UIView *)bgProgressView {
+    if (!_bgProgressView) {
+        _bgProgressView = [UIImageView new];
+        _bgProgressView.backgroundColor = [UIColor grayColor];
+        _bgProgressView.contentMode = UIViewContentModeScaleAspectFill;
+        _bgProgressView.clipsToBounds = YES;
+    }
+    return _bgProgressView;
+}
+
+- (UIView *)bufferProgressView {
+    if (!_bufferProgressView) {
+        _bufferProgressView = [UIImageView new];
+        _bufferProgressView.backgroundColor = [UIColor whiteColor];
+        _bufferProgressView.contentMode = UIViewContentModeScaleAspectFill;
+        _bufferProgressView.clipsToBounds = YES;
+    }
+    return _bufferProgressView;
+}
+
+- (UIView *)sliderProgressView {
+    if (!_sliderProgressView) {
+        _sliderProgressView = [UIImageView new];
+        _sliderProgressView.backgroundColor = [UIColor redColor];
+        _sliderProgressView.contentMode = UIViewContentModeScaleAspectFill;
+        _sliderProgressView.clipsToBounds = YES;
+    }
+    return _sliderProgressView;
+}
+
+- (ZFSliderButton *)sliderBtn {
+    if (!_sliderBtn) {
+        _sliderBtn = [ZFSliderButton buttonWithType:UIButtonTypeCustom];
+        [_sliderBtn setAdjustsImageWhenHighlighted:NO];
+    }
+    return _sliderBtn;
+}
+
+- (UIView *)loadingBarView {
+    if (!_loadingBarView) {
+        _loadingBarView = [[UIView alloc] init];
+        _loadingBarView.backgroundColor = [UIColor whiteColor];
+        _loadingBarView.hidden = YES;
+    }
+    return _loadingBarView;
+}
+
+@end

+ 31 - 0
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFSmallFloatControlView.h

@@ -0,0 +1,31 @@
+//
+//  ZFSmallFloatControlView.h
+//  ZFPlayer
+//
+// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import <UIKit/UIKit.h>
+
+@interface ZFSmallFloatControlView : UIView
+
+@property (nonatomic, copy, nullable) void(^closeClickCallback)(void);
+
+@end

+ 72 - 0
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFSmallFloatControlView.m

@@ -0,0 +1,72 @@
+//
+//  ZFSmallFloatControlView.m
+//  ZFPlayer
+//
+// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import "ZFSmallFloatControlView.h"
+#import "ZFUtilities.h"
+
+@interface ZFSmallFloatControlView ()
+
+@property (nonatomic, strong) UIButton *closeBtn;
+
+@end
+
+@implementation ZFSmallFloatControlView
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    self = [super initWithFrame:frame];
+    if (self) {
+        [self addSubview:self.closeBtn];
+    }
+    return self;
+}
+
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    CGFloat min_x = 0;
+    CGFloat min_y = 0;
+    CGFloat min_w = 0;
+    CGFloat min_h = 0;
+    CGFloat min_view_w = self.bounds.size.width;
+    
+    min_x = min_view_w-20;
+    min_y = -10;
+    min_w = 30;
+    min_h = min_w;
+    self.closeBtn.frame = CGRectMake(min_x, min_y, min_w, min_h);
+}
+
+- (void)closeBtnClick:(UIButton *)sender {
+    if (self.closeClickCallback) self.closeClickCallback();
+}
+
+- (UIButton *)closeBtn {
+    if (!_closeBtn) {
+        _closeBtn = [UIButton buttonWithType:UIButtonTypeCustom];
+        [_closeBtn setImage:ZFPlayer_Image(@"ZFPlayer_close") forState:UIControlStateNormal];
+        [_closeBtn addTarget:self action:@selector(closeBtnClick:) forControlEvents:UIControlEventTouchUpInside];
+    }
+    return _closeBtn;
+}
+
+@end

+ 27 - 0
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFSpeedLoadingView.h

@@ -0,0 +1,27 @@
+//
+//  ZFSpeedLoadingView.h
+//  Pods-ZFPlayer_Example
+//
+//  Created by 紫枫 on 2018/6/27.
+//
+
+#import <UIKit/UIKit.h>
+#import "ZFLoadingView.h"
+
+@interface ZFSpeedLoadingView : UIView
+
+@property (nonatomic, strong) ZFLoadingView *loadingView;
+
+@property (nonatomic, strong) UILabel *speedTextLabel;
+
+/**
+ *  Starts animation of the spinner.
+ */
+- (void)startAnimating;
+
+/**
+ *  Stops animation of the spinnner.
+ */
+- (void)stopAnimating;
+
+@end

+ 122 - 0
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFSpeedLoadingView.m

@@ -0,0 +1,122 @@
+//
+//  ZFSpeedLoadingView.m
+//  Pods-ZFPlayer_Example
+//
+//  Created by 紫枫 on 2018/6/27.
+//
+
+#import "ZFSpeedLoadingView.h"
+#import "ZFNetworkSpeedMonitor.h"
+#import "UIView+ZFFrame.h"
+#if __has_include(<ZFPlayer/ZFPlayer.h>)
+#import <ZFPlayer/ZFPlayer.h>
+#else
+#import "ZFPlayer.h"
+#endif
+
+@interface ZFSpeedLoadingView ()
+
+@property (nonatomic, strong) ZFNetworkSpeedMonitor *speedMonitor;
+
+@end
+
+@implementation ZFSpeedLoadingView
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    self = [super initWithFrame:frame];
+    if (self) {
+        [self initialize];
+    }
+    return self;
+}
+
+- (instancetype)initWithCoder:(NSCoder *)aDecoder {
+    if (self = [super initWithCoder:aDecoder]) {
+        [self initialize];
+    }
+    return self;
+}
+
+- (void)awakeFromNib {
+    [super awakeFromNib];
+    [self initialize];
+}
+
+- (void)initialize {
+    self.userInteractionEnabled = NO;
+    [self addSubview:self.loadingView];
+    [self addSubview:self.speedTextLabel];
+    [self.speedMonitor startNetworkSpeedMonitor];
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkSpeedChanged:) name:ZFDownloadNetworkSpeedNotificationKey object:nil];
+}
+
+- (void)dealloc {
+    [self.speedMonitor stopNetworkSpeedMonitor];
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:ZFDownloadNetworkSpeedNotificationKey object:nil];
+}
+
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    CGFloat min_x = 0;
+    CGFloat min_y = 0;
+    CGFloat min_w = 0;
+    CGFloat min_h = 0;
+    CGFloat min_view_w = self.zf_width;
+    CGFloat min_view_h = self.zf_height;
+    
+    min_w = 44;
+    min_h = min_w;
+    min_x = (min_view_w - min_w) / 2;
+    min_y = (min_view_h - min_h) / 2 - 10;
+    self.loadingView.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    
+    min_x = 0;
+    min_y = self.loadingView.zf_bottom+5;
+    min_w = min_view_w;
+    min_h = 20;
+    self.speedTextLabel.frame = CGRectMake(min_x, min_y, min_w, min_h);
+}
+
+- (void)networkSpeedChanged:(NSNotification *)sender {
+    NSString *downloadSpped = [sender.userInfo objectForKey:ZFNetworkSpeedNotificationKey];
+    self.speedTextLabel.text = downloadSpped;
+}
+
+- (void)startAnimating {
+    [self.loadingView startAnimating];
+    self.hidden = NO;
+}
+
+- (void)stopAnimating {
+    [self.loadingView stopAnimating];
+    self.hidden = YES;
+}
+
+- (UILabel *)speedTextLabel {
+    if (!_speedTextLabel) {
+        _speedTextLabel = [UILabel new];
+        _speedTextLabel.textColor = [UIColor whiteColor];
+        _speedTextLabel.font = [UIFont systemFontOfSize:12.0];
+        _speedTextLabel.textAlignment = NSTextAlignmentCenter;
+    }
+    return _speedTextLabel;
+}
+
+- (ZFNetworkSpeedMonitor *)speedMonitor {
+    if (!_speedMonitor) {
+        _speedMonitor = [[ZFNetworkSpeedMonitor alloc] init];
+    }
+    return _speedMonitor;
+}
+
+- (ZFLoadingView *)loadingView {
+    if (!_loadingView) {
+        _loadingView = [[ZFLoadingView alloc] init];
+        _loadingView.lineWidth = 0.8;
+        _loadingView.duration = 1;
+        _loadingView.hidesWhenStopped = YES;
+    }
+    return _loadingView;
+}
+
+@end

+ 47 - 0
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFUtilities.h

@@ -0,0 +1,47 @@
+//
+//  ZFUtilities.m
+//  ZFPlayer
+//
+// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+/// iPhoneX  iPhoneXS  iPhoneXS Max  iPhoneXR 机型判断
+#define iPhoneX ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? ((NSInteger)(([[UIScreen mainScreen] currentMode].size.height/[[UIScreen mainScreen] currentMode].size.width)*100) == 216) : NO)
+
+#define ZFPlayer_Image(file)                 [ZFUtilities imageNamed:file]
+
+// 屏幕的宽
+#define ZFPlayer_ScreenWidth                 [[UIScreen mainScreen] bounds].size.width
+// 屏幕的高
+#define ZFPlayer_ScreenHeight                [[UIScreen mainScreen] bounds].size.height
+
+@interface ZFUtilities : NSObject
+
++ (NSString *)convertTimeSecond:(NSInteger)timeSecond;
+
++ (UIImage *)imageWithColor:(UIColor *)color size:(CGSize)size;
+
++ (UIImage *)imageNamed:(NSString *)name;
+
+@end
+

+ 74 - 0
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFUtilities.m

@@ -0,0 +1,74 @@
+//
+//  ZFUtilities.m
+//  ZFPlayer
+//
+// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import "ZFUtilities.h"
+
+@implementation ZFUtilities
+
++ (NSString *)convertTimeSecond:(NSInteger)timeSecond {
+    NSString *theLastTime = nil;
+    long second = timeSecond;
+    if (timeSecond < 60) {
+        theLastTime = [NSString stringWithFormat:@"00:%02zd", second];
+    } else if(timeSecond >= 60 && timeSecond < 3600){
+        theLastTime = [NSString stringWithFormat:@"%02zd:%02zd", second/60, second%60];
+    } else if(timeSecond >= 3600){
+        theLastTime = [NSString stringWithFormat:@"%02zd:%02zd:%02zd", second/3600, second%3600/60, second%60];
+    }
+    return theLastTime;
+}
+
++ (UIImage *)imageWithColor:(UIColor *)color size:(CGSize)size {
+    if (!color || size.width <= 0 || size.height <= 0) return nil;
+    CGRect rect = CGRectMake(0.0f, 0.0f, size.width, size.height);
+    UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0);
+    CGContextRef context = UIGraphicsGetCurrentContext();
+    CGContextSetFillColorWithColor(context, color.CGColor);
+    CGContextFillRect(context, rect);
+    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
+    UIGraphicsEndImageContext();
+    return image;
+}
+
++ (NSBundle *)bundle {
+    static NSBundle *bundle = nil;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        bundle = [NSBundle bundleWithPath:[[NSBundle bundleForClass:[self class]] pathForResource:@"ZFPlayer" ofType:@"bundle"]];
+    });
+    return bundle;
+}
+
++ (UIImage *)imageNamed:(NSString *)name {
+    if (name.length == 0) return nil;
+    int scale = (int)UIScreen.mainScreen.scale;
+    if (scale < 2) scale = 2;
+    else if (scale > 3) scale = 3;
+    NSString *n = [NSString stringWithFormat:@"%@@%dx", name, scale];
+    UIImage *image = [UIImage imageWithContentsOfFile:[self.bundle pathForResource:n ofType:@"png"]];
+    if (!image) image = [UIImage imageWithContentsOfFile:[self.bundle pathForResource:name ofType:@"png"]];
+    return image;
+}
+
+@end

+ 46 - 0
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFVolumeBrightnessView.h

@@ -0,0 +1,46 @@
+//
+//  ZFVolumeBrightnessView.h
+//  ZFPlayer
+//
+// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import <UIKit/UIKit.h>
+
+typedef NS_ENUM(NSInteger, ZFVolumeBrightnessType) {
+    ZFVolumeBrightnessTypeVolume,       // volume
+    ZFVolumeBrightnessTypeumeBrightness // brightness
+};
+
+@interface ZFVolumeBrightnessView : UIView
+
+@property (nonatomic, assign, readonly) ZFVolumeBrightnessType volumeBrightnessType;
+@property (nonatomic, strong, readonly) UIProgressView *progressView;
+@property (nonatomic, strong, readonly) UIImageView *iconImageView;
+
+- (void)updateProgress:(CGFloat)progress withVolumeBrightnessType:(ZFVolumeBrightnessType)volumeBrightnessType;
+
+/// 添加系统音量view
+- (void)addSystemVolumeView;
+
+/// 移除系统音量view
+- (void)removeSystemVolumeView;
+
+@end

+ 167 - 0
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFVolumeBrightnessView.m

@@ -0,0 +1,167 @@
+//
+//  ZFVolumeBrightnessView.m
+//  ZFPlayer
+//
+// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import "ZFVolumeBrightnessView.h"
+#import <MediaPlayer/MediaPlayer.h>
+#import "ZFUtilities.h"
+#if __has_include(<ZFPlayer/ZFPlayer.h>)
+#import <ZFPlayer/ZFPlayer.h>
+#else
+#import "ZFPlayer.h"
+#endif
+
+@interface ZFVolumeBrightnessView ()
+
+@property (nonatomic, strong) UIProgressView *progressView;
+@property (nonatomic, strong) UIImageView *iconImageView;
+@property (nonatomic, assign) ZFVolumeBrightnessType volumeBrightnessType;
+@property (nonatomic, strong) MPVolumeView *volumeView;
+
+@end
+
+@implementation ZFVolumeBrightnessView
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    self = [super initWithFrame:frame];
+    if (self) {
+        [self addSubview:self.iconImageView];
+        [self addSubview:self.progressView];
+        [self hideTipView];
+    }
+    return self;
+}
+
+- (void)dealloc {
+    [self addSystemVolumeView];
+}
+
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    CGFloat min_x = 0;
+    CGFloat min_y = 0;
+    CGFloat min_w = 0;
+    CGFloat min_h = 0;
+    CGFloat min_view_w = self.frame.size.width;
+    CGFloat min_view_h = self.frame.size.height;
+    CGFloat margin = 10;
+    
+    min_x = margin;
+    min_w = 20;
+    min_h = min_w;
+    min_y = (min_view_h-min_h)/2;
+    self.iconImageView.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    
+    min_x = CGRectGetMaxX(self.iconImageView.frame) + margin;
+    min_h = 2;
+    min_y = (min_view_h-min_h)/2;
+    min_w = min_view_w - min_x - margin;
+    self.progressView.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    
+    self.layer.cornerRadius = min_view_h/2;
+    self.layer.masksToBounds = YES;
+}
+
+- (void)hideTipView {
+    [UIView animateWithDuration:0.5 animations:^{
+        self.alpha = 0;
+    } completion:^(BOOL finished) {
+        self.hidden = YES;
+    }];
+}
+
+/// 添加系统音量view
+- (void)addSystemVolumeView {
+    [self.volumeView removeFromSuperview];
+}
+
+/// 移除系统音量view
+- (void)removeSystemVolumeView {
+    [[UIApplication sharedApplication].keyWindow addSubview:self.volumeView];
+}
+
+- (void)updateProgress:(CGFloat)progress withVolumeBrightnessType:(ZFVolumeBrightnessType)volumeBrightnessType {
+    if (progress >= 1) {
+        progress = 1;
+    } else if (progress <= 0) {
+        progress = 0;
+    }
+    self.progressView.progress = progress;
+    self.volumeBrightnessType = volumeBrightnessType;
+    UIImage *playerImage = nil;
+    if (volumeBrightnessType == ZFVolumeBrightnessTypeVolume) {
+        if (progress == 0) {
+            playerImage = ZFPlayer_Image(@"ZFPlayer_muted");
+        } else if (progress > 0 && progress < 0.5) {
+            playerImage = ZFPlayer_Image(@"ZFPlayer_volume_low");
+        } else {
+            playerImage = ZFPlayer_Image(@"ZFPlayer_volume_high");
+        }
+    } else if (volumeBrightnessType == ZFVolumeBrightnessTypeumeBrightness) {
+        if (progress >= 0 && progress < 0.5) {
+            playerImage = ZFPlayer_Image(@"ZFPlayer_brightness_low");
+        } else {
+            playerImage = ZFPlayer_Image(@"ZFPlayer_brightness_high");
+        }
+    }
+    self.iconImageView.image = playerImage;
+    self.hidden = NO;
+    self.alpha = 1;
+    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(hideTipView) object:nil];
+    [self performSelector:@selector(hideTipView) withObject:nil afterDelay:1.5];
+}
+
+- (void)setVolumeBrightnessType:(ZFVolumeBrightnessType)volumeBrightnessType {
+    _volumeBrightnessType = volumeBrightnessType;
+    if (volumeBrightnessType == ZFVolumeBrightnessTypeVolume) {
+        self.iconImageView.image = ZFPlayer_Image(@"ZFPlayer_volume");
+    } else {
+        self.iconImageView.image = ZFPlayer_Image(@"ZFPlayer_brightness");
+    }
+}
+
+- (UIProgressView *)progressView {
+    if (!_progressView) {
+        _progressView = [[UIProgressView alloc] init];
+        _progressView.progressTintColor = [UIColor whiteColor];
+        _progressView.trackTintColor = [[UIColor lightGrayColor] colorWithAlphaComponent:0.4];;
+    }
+    return _progressView;
+}
+
+- (UIImageView *)iconImageView {
+    if (!_iconImageView) {
+        _iconImageView = [UIImageView new];
+    }
+    return _iconImageView;
+}
+
+- (MPVolumeView *)volumeView {
+    if (!_volumeView) {
+        _volumeView = [[MPVolumeView alloc] init];
+        _volumeView.frame = CGRectMake(-1000, -1000, 100, 100);
+    }
+    return _volumeView;
+}
+
+@end

+ 203 - 0
Pods/ZFPlayer/ZFPlayer/Classes/Core/UIScrollView+ZFPlayer.h

@@ -0,0 +1,203 @@
+//
+//  UIScrollView+ZFPlayer.h
+//  ZFPlayer
+//
+// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/*
+ * The scroll direction of scrollView.
+ */
+typedef NS_ENUM(NSUInteger, ZFPlayerScrollDirection) {
+    ZFPlayerScrollDirectionNone,
+    ZFPlayerScrollDirectionUp,         // Scroll up
+    ZFPlayerScrollDirectionDown,       // Scroll Down
+    ZFPlayerScrollDirectionLeft,       // Scroll left
+    ZFPlayerScrollDirectionRight       // Scroll right
+};
+
+/*
+ * The scrollView direction.
+ */
+typedef NS_ENUM(NSInteger, ZFPlayerScrollViewDirection) {
+    ZFPlayerScrollViewDirectionVertical,
+    ZFPlayerScrollViewDirectionHorizontal
+};
+
+/*
+ * The player container type
+ */
+typedef NS_ENUM(NSInteger, ZFPlayerContainerType) {
+    ZFPlayerContainerTypeView,
+    ZFPlayerContainerTypeCell
+};
+
+@interface UIScrollView (ZFPlayer)
+
+/// When the ZFPlayerScrollViewDirection is ZFPlayerScrollViewDirectionVertical,the property has value.
+@property (nonatomic, readonly) CGFloat zf_lastOffsetY;
+
+/// When the ZFPlayerScrollViewDirection is ZFPlayerScrollViewDirectionHorizontal,the property has value.
+@property (nonatomic, readonly) CGFloat zf_lastOffsetX;
+
+/// The scrollView scroll direction, default is ZFPlayerScrollViewDirectionVertical.
+@property (nonatomic) ZFPlayerScrollViewDirection zf_scrollViewDirection;
+
+/// The scroll direction of scrollView while scrolling.
+/// When the ZFPlayerScrollViewDirection is ZFPlayerScrollViewDirectionVertical,this value can only be ZFPlayerScrollDirectionUp or ZFPlayerScrollDirectionDown.
+/// When the ZFPlayerScrollViewDirection is ZFPlayerScrollViewDirectionVertical,this value can only be ZFPlayerScrollDirectionLeft or ZFPlayerScrollDirectionRight.
+@property (nonatomic, readonly) ZFPlayerScrollDirection zf_scrollDirection;
+
+/// Get the cell according to indexPath.
+- (UIView *)zf_getCellForIndexPath:(NSIndexPath *)indexPath;
+
+/// Get the indexPath for cell.
+- (NSIndexPath *)zf_getIndexPathForCell:(UIView *)cell;
+
+/// Scroll to indexPath with animations.
+- (void)zf_scrollToRowAtIndexPath:(NSIndexPath *)indexPath completionHandler:(void (^ __nullable)(void))completionHandler;
+
+/// add in 3.2.4 version.
+/// Scroll to indexPath with animations.
+- (void)zf_scrollToRowAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated completionHandler:(void (^ __nullable)(void))completionHandler;
+
+/// add in 3.2.8 version.
+/// Scroll to indexPath with animations duration.
+- (void)zf_scrollToRowAtIndexPath:(NSIndexPath *)indexPath animateWithDuration:(NSTimeInterval)duration completionHandler:(void (^ __nullable)(void))completionHandler;
+
+///------------------------------------
+/// The following method must be implemented in UIScrollViewDelegate.
+///------------------------------------
+
+- (void)zf_scrollViewDidEndDecelerating;
+
+- (void)zf_scrollViewDidEndDraggingWillDecelerate:(BOOL)decelerate;
+
+- (void)zf_scrollViewDidScrollToTop;
+
+- (void)zf_scrollViewDidScroll;
+
+- (void)zf_scrollViewWillBeginDragging;
+
+///------------------------------------
+/// end
+///------------------------------------
+
+
+@end
+
+@interface UIScrollView (ZFPlayerCannotCalled)
+
+/// The block invoked When the player appearing.
+@property (nonatomic, copy, nullable) void(^zf_playerAppearingInScrollView)(NSIndexPath *indexPath, CGFloat playerApperaPercent);
+
+/// The block invoked When the player disappearing.
+@property (nonatomic, copy, nullable) void(^zf_playerDisappearingInScrollView)(NSIndexPath *indexPath, CGFloat playerDisapperaPercent);
+
+/// The block invoked When the player will appeared.
+@property (nonatomic, copy, nullable) void(^zf_playerWillAppearInScrollView)(NSIndexPath *indexPath);
+
+/// The block invoked When the player did appeared.
+@property (nonatomic, copy, nullable) void(^zf_playerDidAppearInScrollView)(NSIndexPath *indexPath);
+
+/// The block invoked When the player will disappear.
+@property (nonatomic, copy, nullable) void(^zf_playerWillDisappearInScrollView)(NSIndexPath *indexPath);
+
+/// The block invoked When the player did disappeared.
+@property (nonatomic, copy, nullable) void(^zf_playerDidDisappearInScrollView)(NSIndexPath *indexPath);
+
+/// The block invoked When the player did stop scroll.
+@property (nonatomic, copy, nullable) void(^zf_scrollViewDidEndScrollingCallback)(NSIndexPath *indexPath);
+
+/// The block invoked When the player did  scroll.
+@property (nonatomic, copy, nullable) void(^zf_scrollViewDidScrollCallback)(NSIndexPath *indexPath);
+
+/// The block invoked When the player should play.
+@property (nonatomic, copy, nullable) void(^zf_playerShouldPlayInScrollView)(NSIndexPath *indexPath);
+
+/// The current player scroll slides off the screen percent.
+/// the property used when the `stopWhileNotVisible` is YES, stop the current playing player.
+/// the property used when the `stopWhileNotVisible` is NO, the current playing player add to small container view.
+/// 0.0~1.0, defalut is 0.5.
+/// 0.0 is the player will disappear.
+/// 1.0 is the player did disappear.
+@property (nonatomic) CGFloat zf_playerDisapperaPercent;
+
+/// The current player scroll to the screen percent to play the video.
+/// 0.0~1.0, defalut is 0.0.
+/// 0.0 is the player will appear.
+/// 1.0 is the player did appear.
+@property (nonatomic) CGFloat zf_playerApperaPercent;
+
+/// The current player controller is disappear, not dealloc
+@property (nonatomic) BOOL zf_viewControllerDisappear;
+
+/// Has stopped playing
+@property (nonatomic, assign) BOOL zf_stopPlay;
+
+/// The currently playing cell stop playing when the cell has out off the screen,defalut is YES.
+@property (nonatomic, assign) BOOL zf_stopWhileNotVisible;
+
+/// The indexPath is playing.
+@property (nonatomic, nullable) NSIndexPath *zf_playingIndexPath;
+
+/// The indexPath should be play while scrolling.
+@property (nonatomic, nullable) NSIndexPath *zf_shouldPlayIndexPath;
+
+/// WWANA networks play automatically,default NO.
+@property (nonatomic, getter=zf_isWWANAutoPlay) BOOL zf_WWANAutoPlay;
+
+/// The player should auto player,default is YES.
+@property (nonatomic) BOOL zf_shouldAutoPlay;
+
+/// The view tag that the player display in scrollView.
+@property (nonatomic) NSInteger zf_containerViewTag;
+
+/// The video contrainerView in normal model.
+@property (nonatomic, strong) UIView *zf_containerView;
+
+
+/// The video contrainerView type.
+@property (nonatomic, assign) ZFPlayerContainerType zf_containerType;
+
+
+/// Filter the cell that should be played when the scroll is stopped (to play when the scroll is stopped).
+- (void)zf_filterShouldPlayCellWhileScrolled:(void (^ __nullable)(NSIndexPath *indexPath))handler;
+
+/// Filter the cell that should be played while scrolling (you can use this to filter the highlighted cell).
+- (void)zf_filterShouldPlayCellWhileScrolling:(void (^ __nullable)(NSIndexPath *indexPath))handler;
+
+@end
+
+@interface UIScrollView (ZFPlayerDeprecated)
+
+/// The block invoked When the player did stop scroll.
+@property (nonatomic, copy, nullable) void(^zf_scrollViewDidStopScrollCallback)(NSIndexPath *indexPath) __attribute__((deprecated("use `ZFPlayerController.zf_scrollViewDidEndScrollingCallback` instead.")));
+
+/// The block invoked When the player should play.
+@property (nonatomic, copy, nullable) void(^zf_shouldPlayIndexPathCallback)(NSIndexPath *indexPath) __attribute__((deprecated("use `ZFPlayerController.zf_playerShouldPlayInScrollView` instead.")));
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 917 - 0
Pods/ZFPlayer/ZFPlayer/Classes/Core/UIScrollView+ZFPlayer.m

@@ -0,0 +1,917 @@
+//
+//  UIScrollView+ZFPlayer.m
+//  ZFPlayer
+//
+// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import "UIScrollView+ZFPlayer.h"
+#import <objc/runtime.h>
+#import "ZFReachabilityManager.h"
+#import "ZFPlayer.h"
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored"-Wdeprecated-declarations"
+
+@interface UIScrollView ()
+
+@property (nonatomic) CGFloat zf_lastOffsetY;
+@property (nonatomic) CGFloat zf_lastOffsetX;
+@property (nonatomic) ZFPlayerScrollDirection zf_scrollDirection;
+
+@end
+
+@implementation UIScrollView (ZFPlayer)
+
++ (void)load {
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        SEL selectors[] = {
+            @selector(setContentOffset:)
+        };
+        
+        for (NSInteger index = 0; index < sizeof(selectors) / sizeof(SEL); ++index) {
+            SEL originalSelector = selectors[index];
+            SEL swizzledSelector = NSSelectorFromString([@"zf_" stringByAppendingString:NSStringFromSelector(originalSelector)]);
+            Method originalMethod = class_getInstanceMethod(self, originalSelector);
+            Method swizzledMethod = class_getInstanceMethod(self, swizzledSelector);
+            if (class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))) {
+                class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
+            } else {
+                method_exchangeImplementations(originalMethod, swizzledMethod);
+            }
+        }
+    });
+}
+
+- (void)zf_setContentOffset:(CGPoint)contentOffset {
+    if (self.zf_scrollViewDirection == ZFPlayerScrollViewDirectionVertical) {
+        [self _findCorrectCellWhenScrollViewDirectionVertical:nil];
+    } else {
+        [self _findCorrectCellWhenScrollViewDirectionHorizontal:nil];
+    }
+    [self zf_setContentOffset:contentOffset];
+}
+
+#pragma mark - private method
+
+- (void)_scrollViewDidStopScroll {
+    @weakify(self)
+    [self zf_filterShouldPlayCellWhileScrolled:^(NSIndexPath * _Nonnull indexPath) {
+        @strongify(self)
+        if (self.zf_scrollViewDidStopScrollCallback) self.zf_scrollViewDidStopScrollCallback(indexPath);
+        if (self.zf_scrollViewDidEndScrollingCallback) self.zf_scrollViewDidEndScrollingCallback(indexPath);
+    }];
+}
+
+- (void)_scrollViewBeginDragging {
+    if (self.zf_scrollViewDirection == ZFPlayerScrollViewDirectionVertical) {
+        self.zf_lastOffsetY = self.contentOffset.y;
+    } else {
+        self.zf_lastOffsetX = self.contentOffset.x;
+    }
+}
+
+/**
+  The percentage of scrolling processed in vertical scrolling.
+ */
+- (void)_scrollViewScrollingDirectionVertical {
+    CGFloat offsetY = self.contentOffset.y;
+    self.zf_scrollDirection = (offsetY - self.zf_lastOffsetY > 0) ? ZFPlayerScrollDirectionUp : ZFPlayerScrollDirectionDown;
+    self.zf_lastOffsetY = offsetY;
+    if (self.zf_stopPlay) return;
+    
+    UIView *playerView;
+    if (self.zf_containerType == ZFPlayerContainerTypeCell) {
+        // Avoid being paused the first time you play it.
+        if (self.contentOffset.y < 0) return;
+        if (!self.zf_playingIndexPath) return;
+        
+        UIView *cell = [self zf_getCellForIndexPath:self.zf_playingIndexPath];
+        if (!cell) {
+            if (self.zf_playerDidDisappearInScrollView) self.zf_playerDidDisappearInScrollView(self.zf_playingIndexPath);
+            return;
+        }
+        playerView = [cell viewWithTag:self.zf_containerViewTag];
+    } else if (self.zf_containerType == ZFPlayerContainerTypeView) {
+        if (!self.zf_containerView) return;
+        playerView = self.zf_containerView;
+    }
+    
+    CGRect rect1 = [playerView convertRect:playerView.frame toView:self];
+    CGRect rect = [self convertRect:rect1 toView:self.superview];
+    /// playerView top to scrollView top space.
+    CGFloat topSpacing = CGRectGetMinY(rect) - CGRectGetMinY(self.frame) - CGRectGetMinY(playerView.frame);
+    /// playerView bottom to scrollView bottom space.
+    CGFloat bottomSpacing = CGRectGetMaxY(self.frame) - CGRectGetMaxY(rect) + CGRectGetMinY(playerView.frame);
+    /// The height of the content area.
+    CGFloat contentInsetHeight = CGRectGetMaxY(self.frame) - CGRectGetMinY(self.frame);
+    
+    CGFloat playerDisapperaPercent = 0;
+    CGFloat playerApperaPercent = 0;
+    
+    if (self.zf_scrollDirection == ZFPlayerScrollDirectionUp) { /// Scroll up
+        /// Player is disappearing.
+        if (topSpacing <= 0 && CGRectGetHeight(rect) != 0) {
+            playerDisapperaPercent = -topSpacing/CGRectGetHeight(rect);
+            if (playerDisapperaPercent > 1.0) playerDisapperaPercent = 1.0;
+            if (self.zf_playerDisappearingInScrollView) self.zf_playerDisappearingInScrollView(self.zf_playingIndexPath, playerDisapperaPercent);
+        }
+        
+        /// Top area
+        if (topSpacing <= 0 && topSpacing > -CGRectGetHeight(rect)/2) {
+            /// When the player will disappear.
+            if (self.zf_playerWillDisappearInScrollView) self.zf_playerWillDisappearInScrollView(self.zf_playingIndexPath);
+        } else if (topSpacing <= -CGRectGetHeight(rect)) {
+            /// When the player did disappeared.
+            if (self.zf_playerDidDisappearInScrollView) self.zf_playerDidDisappearInScrollView(self.zf_playingIndexPath);
+        } else if (topSpacing > 0 && topSpacing <= contentInsetHeight) {
+            /// Player is appearing.
+            if (CGRectGetHeight(rect) != 0) {
+                playerApperaPercent = -(topSpacing-contentInsetHeight)/CGRectGetHeight(rect);
+                if (playerApperaPercent > 1.0) playerApperaPercent = 1.0;
+                if (self.zf_playerAppearingInScrollView) self.zf_playerAppearingInScrollView(self.zf_playingIndexPath, playerApperaPercent);
+            }
+            /// In visable area
+            if (topSpacing <= contentInsetHeight && topSpacing > contentInsetHeight-CGRectGetHeight(rect)/2) {
+                /// When the player will appear.
+                if (self.zf_playerWillAppearInScrollView) self.zf_playerWillAppearInScrollView(self.zf_playingIndexPath);
+            } else {
+                /// When the player did appeared.
+                if (self.zf_playerDidAppearInScrollView) self.zf_playerDidAppearInScrollView(self.zf_playingIndexPath);
+            }
+        }
+        
+    } else if (self.zf_scrollDirection == ZFPlayerScrollDirectionDown) { /// Scroll Down
+        /// Player is disappearing.
+        if (bottomSpacing <= 0 && CGRectGetHeight(rect) != 0) {
+            playerDisapperaPercent = -bottomSpacing/CGRectGetHeight(rect);
+            if (playerDisapperaPercent > 1.0) playerDisapperaPercent = 1.0;
+            if (self.zf_playerDisappearingInScrollView) self.zf_playerDisappearingInScrollView(self.zf_playingIndexPath, playerDisapperaPercent);
+        }
+        
+        /// Bottom area
+        if (bottomSpacing <= 0 && bottomSpacing > -CGRectGetHeight(rect)/2) {
+            /// When the player will disappear.
+            if (self.zf_playerWillDisappearInScrollView) self.zf_playerWillDisappearInScrollView(self.zf_playingIndexPath);
+        } else if (bottomSpacing <= -CGRectGetHeight(rect)) {
+            /// When the player did disappeared.
+            if (self.zf_playerDidDisappearInScrollView) self.zf_playerDidDisappearInScrollView(self.zf_playingIndexPath);
+        } else if (bottomSpacing > 0 && bottomSpacing <= contentInsetHeight) {
+            /// Player is appearing.
+            if (CGRectGetHeight(rect) != 0) {
+                playerApperaPercent = -(bottomSpacing-contentInsetHeight)/CGRectGetHeight(rect);
+                if (playerApperaPercent > 1.0) playerApperaPercent = 1.0;
+                if (self.zf_playerAppearingInScrollView) self.zf_playerAppearingInScrollView(self.zf_playingIndexPath, playerApperaPercent);
+            }
+            /// In visable area
+            if (bottomSpacing <= contentInsetHeight && bottomSpacing > contentInsetHeight-CGRectGetHeight(rect)/2) {
+                /// When the player will appear.
+                if (self.zf_playerWillAppearInScrollView) self.zf_playerWillAppearInScrollView(self.zf_playingIndexPath);
+            } else {
+                /// When the player did appeared.
+                if (self.zf_playerDidAppearInScrollView) self.zf_playerDidAppearInScrollView(self.zf_playingIndexPath);
+            }
+        }
+    }
+}
+
+/**
+ The percentage of scrolling processed in horizontal scrolling.
+ */
+- (void)_scrollViewScrollingDirectionHorizontal {
+    CGFloat offsetX = self.contentOffset.x;
+    self.zf_scrollDirection = (offsetX - self.zf_lastOffsetX > 0) ? ZFPlayerScrollDirectionLeft : ZFPlayerScrollDirectionRight;
+    self.zf_lastOffsetX = offsetX;
+    if (self.zf_stopPlay) return;
+    
+    UIView *playerView;
+    if (self.zf_containerType == ZFPlayerContainerTypeCell) {
+        // Avoid being paused the first time you play it.
+        if (self.contentOffset.x < 0) return;
+        if (!self.zf_playingIndexPath) return;
+        
+        UIView *cell = [self zf_getCellForIndexPath:self.zf_playingIndexPath];
+        if (!cell) {
+            if (self.zf_playerDidDisappearInScrollView) self.zf_playerDidDisappearInScrollView(self.zf_playingIndexPath);
+            return;
+        }
+       playerView = [cell viewWithTag:self.zf_containerViewTag];
+    } else if (self.zf_containerType == ZFPlayerContainerTypeView) {
+        if (!self.zf_containerView) return;
+        playerView = self.zf_containerView;
+    }
+    
+    CGRect rect1 = [playerView convertRect:playerView.frame toView:self];
+    CGRect rect = [self convertRect:rect1 toView:self.superview];
+    /// playerView left to scrollView left space.
+    CGFloat leftSpacing = CGRectGetMinX(rect) - CGRectGetMinX(self.frame) - CGRectGetMinX(playerView.frame);
+    /// playerView bottom to scrollView right space.
+    CGFloat rightSpacing = CGRectGetMaxX(self.frame) - CGRectGetMaxX(rect) + CGRectGetMinX(playerView.frame);
+    /// The height of the content area.
+    CGFloat contentInsetWidth = CGRectGetMaxX(self.frame) - CGRectGetMinX(self.frame);
+    
+    CGFloat playerDisapperaPercent = 0;
+    CGFloat playerApperaPercent = 0;
+    
+    if (self.zf_scrollDirection == ZFPlayerScrollDirectionLeft) { /// Scroll left
+        /// Player is disappearing.
+        if (leftSpacing <= 0 && CGRectGetWidth(rect) != 0) {
+            playerDisapperaPercent = -leftSpacing/CGRectGetWidth(rect);
+            if (playerDisapperaPercent > 1.0) playerDisapperaPercent = 1.0;
+            if (self.zf_playerDisappearingInScrollView) self.zf_playerDisappearingInScrollView(self.zf_playingIndexPath, playerDisapperaPercent);
+        }
+        
+        /// Top area
+        if (leftSpacing <= 0 && leftSpacing > -CGRectGetWidth(rect)/2) {
+            /// When the player will disappear.
+            if (self.zf_playerWillDisappearInScrollView) self.zf_playerWillDisappearInScrollView(self.zf_playingIndexPath);
+        } else if (leftSpacing <= -CGRectGetWidth(rect)) {
+            /// When the player did disappeared.
+            if (self.zf_playerDidDisappearInScrollView) self.zf_playerDidDisappearInScrollView(self.zf_playingIndexPath);
+        } else if (leftSpacing > 0 && leftSpacing <= contentInsetWidth) {
+            /// Player is appearing.
+            if (CGRectGetWidth(rect) != 0) {
+                playerApperaPercent = -(leftSpacing-contentInsetWidth)/CGRectGetWidth(rect);
+                if (playerApperaPercent > 1.0) playerApperaPercent = 1.0;
+                if (self.zf_playerAppearingInScrollView) self.zf_playerAppearingInScrollView(self.zf_playingIndexPath, playerApperaPercent);
+            }
+            /// In visable area
+            if (leftSpacing <= contentInsetWidth && leftSpacing > contentInsetWidth-CGRectGetWidth(rect)/2) {
+                /// When the player will appear.
+                if (self.zf_playerWillAppearInScrollView) self.zf_playerWillAppearInScrollView(self.zf_playingIndexPath);
+            } else {
+                /// When the player did appeared.
+                if (self.zf_playerDidAppearInScrollView) self.zf_playerDidAppearInScrollView(self.zf_playingIndexPath);
+            }
+        }
+        
+    } else if (self.zf_scrollDirection == ZFPlayerScrollDirectionRight) { /// Scroll right
+        /// Player is disappearing.
+        if (rightSpacing <= 0 && CGRectGetWidth(rect) != 0) {
+            playerDisapperaPercent = -rightSpacing/CGRectGetWidth(rect);
+            if (playerDisapperaPercent > 1.0) playerDisapperaPercent = 1.0;
+            if (self.zf_playerDisappearingInScrollView) self.zf_playerDisappearingInScrollView(self.zf_playingIndexPath, playerDisapperaPercent);
+        }
+        
+        /// Bottom area
+        if (rightSpacing <= 0 && rightSpacing > -CGRectGetWidth(rect)/2) {
+            /// When the player will disappear.
+            if (self.zf_playerWillDisappearInScrollView) self.zf_playerWillDisappearInScrollView(self.zf_playingIndexPath);
+        } else if (rightSpacing <= -CGRectGetWidth(rect)) {
+            /// When the player did disappeared.
+            if (self.zf_playerDidDisappearInScrollView) self.zf_playerDidDisappearInScrollView(self.zf_playingIndexPath);
+        } else if (rightSpacing > 0 && rightSpacing <= contentInsetWidth) {
+            /// Player is appearing.
+            if (CGRectGetWidth(rect) != 0) {
+                playerApperaPercent = -(rightSpacing-contentInsetWidth)/CGRectGetWidth(rect);
+                if (playerApperaPercent > 1.0) playerApperaPercent = 1.0;
+                if (self.zf_playerAppearingInScrollView) self.zf_playerAppearingInScrollView(self.zf_playingIndexPath, playerApperaPercent);
+            }
+            /// In visable area
+            if (rightSpacing <= contentInsetWidth && rightSpacing > contentInsetWidth-CGRectGetWidth(rect)/2) {
+                /// When the player will appear.
+                if (self.zf_playerWillAppearInScrollView) self.zf_playerWillAppearInScrollView(self.zf_playingIndexPath);
+            } else {
+                /// When the player did appeared.
+                if (self.zf_playerDidAppearInScrollView) self.zf_playerDidAppearInScrollView(self.zf_playingIndexPath);
+            }
+        }
+    }
+}
+
+/**
+ Find the playing cell while the scrollDirection is vertical.
+ */
+- (void)_findCorrectCellWhenScrollViewDirectionVertical:(void (^ __nullable)(NSIndexPath *indexPath))handler {
+    if (!self.zf_shouldAutoPlay) return;
+    if (self.zf_containerType == ZFPlayerContainerTypeView) return;
+
+    NSArray *visiableCells = nil;
+    NSIndexPath *indexPath = nil;
+    if ([self _isTableView]) {
+        UITableView *tableView = (UITableView *)self;
+        visiableCells = [tableView visibleCells];
+        // First visible cell indexPath
+        indexPath = tableView.indexPathsForVisibleRows.firstObject;
+        if (self.contentOffset.y <= 0 && (!self.zf_playingIndexPath || [indexPath compare:self.zf_playingIndexPath] == NSOrderedSame)) {
+            UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
+            UIView *playerView = [cell viewWithTag:self.zf_containerViewTag];
+            if (playerView) {
+                if (self.zf_scrollViewDidScrollCallback) self.zf_scrollViewDidScrollCallback(indexPath);
+                if (handler) handler(indexPath);
+                self.zf_shouldPlayIndexPath = indexPath;
+                return;
+            }
+        }
+        
+        // Last visible cell indexPath
+        indexPath = tableView.indexPathsForVisibleRows.lastObject;
+        if (self.contentOffset.y + self.frame.size.height >= self.contentSize.height && (!self.zf_playingIndexPath || [indexPath compare:self.zf_playingIndexPath] == NSOrderedSame)) {
+            UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
+            UIView *playerView = [cell viewWithTag:self.zf_containerViewTag];
+            if (playerView) {
+                if (self.zf_scrollViewDidScrollCallback) self.zf_scrollViewDidScrollCallback(indexPath);
+                if (handler) handler(indexPath);
+                self.zf_shouldPlayIndexPath = indexPath;
+                return;
+            }
+        }
+    } else if ([self _isCollectionView]) {
+        UICollectionView *collectionView = (UICollectionView *)self;
+        visiableCells = [collectionView visibleCells];
+        NSArray *sortedIndexPaths = [collectionView.indexPathsForVisibleItems sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
+            return [obj1 compare:obj2];
+        }];
+        
+        visiableCells = [visiableCells sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
+            NSIndexPath *path1 = (NSIndexPath *)[collectionView indexPathForCell:obj1];
+            NSIndexPath *path2 = (NSIndexPath *)[collectionView indexPathForCell:obj2];
+            return [path1 compare:path2];
+        }];
+        
+        // First visible cell indexPath
+        indexPath = sortedIndexPaths.firstObject;
+        if (self.contentOffset.y <= 0 && (!self.zf_playingIndexPath || [indexPath compare:self.zf_playingIndexPath] == NSOrderedSame)) {
+            UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
+            UIView *playerView = [cell viewWithTag:self.zf_containerViewTag];
+            if (playerView) {
+                if (self.zf_scrollViewDidScrollCallback) self.zf_scrollViewDidScrollCallback(indexPath);
+                if (handler) handler(indexPath);
+                self.zf_shouldPlayIndexPath = indexPath;
+                return;
+            }
+        }
+        
+        // Last visible cell indexPath
+        indexPath = sortedIndexPaths.lastObject;
+        if (self.contentOffset.y + self.frame.size.height >= self.contentSize.height && (!self.zf_playingIndexPath || [indexPath compare:self.zf_playingIndexPath] == NSOrderedSame)) {
+            UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
+            UIView *playerView = [cell viewWithTag:self.zf_containerViewTag];
+            if (playerView) {
+                if (self.zf_scrollViewDidScrollCallback) self.zf_scrollViewDidScrollCallback(indexPath);
+                if (handler) handler(indexPath);
+                self.zf_shouldPlayIndexPath = indexPath;
+                return;
+            }
+        }
+    }
+    
+    NSArray *cells = nil;
+    if (self.zf_scrollDirection == ZFPlayerScrollDirectionUp) {
+        cells = visiableCells;
+    } else {
+        cells = [visiableCells reverseObjectEnumerator].allObjects;
+    }
+    
+    /// Mid line.
+    CGFloat scrollViewMidY = CGRectGetHeight(self.frame)/2;
+    /// The final playing indexPath.
+    __block NSIndexPath *finalIndexPath = nil;
+    /// The final distance from the center line.
+    __block CGFloat finalSpace = 0;
+    @weakify(self)
+    [cells enumerateObjectsUsingBlock:^(UIView *cell, NSUInteger idx, BOOL * _Nonnull stop) {
+        @strongify(self)
+        UIView *playerView = [cell viewWithTag:self.zf_containerViewTag];
+        if (!playerView) return;
+        CGRect rect1 = [playerView convertRect:playerView.frame toView:self];
+        CGRect rect = [self convertRect:rect1 toView:self.superview];
+        /// playerView top to scrollView top space.
+        CGFloat topSpacing = CGRectGetMinY(rect) - CGRectGetMinY(self.frame) - CGRectGetMinY(playerView.frame);
+        /// playerView bottom to scrollView bottom space.
+        CGFloat bottomSpacing = CGRectGetMaxY(self.frame) - CGRectGetMaxY(rect) + CGRectGetMinY(playerView.frame);
+        CGFloat centerSpacing = ABS(scrollViewMidY - CGRectGetMidY(rect));
+        NSIndexPath *indexPath = [self zf_getIndexPathForCell:cell];
+        
+        /// Play when the video playback section is visible.
+        if ((topSpacing >= -(1 - self.zf_playerApperaPercent) * CGRectGetHeight(rect)) && (bottomSpacing >= -(1 - self.zf_playerApperaPercent) * CGRectGetHeight(rect))) {
+            /// If you have a cell that is playing, stop the traversal.
+            if (self.zf_playingIndexPath) {
+                indexPath = self.zf_playingIndexPath;
+                finalIndexPath = indexPath;
+                *stop = YES;
+                return;
+            }
+            if (!finalIndexPath || centerSpacing < finalSpace) {
+                finalIndexPath = indexPath;
+                finalSpace = centerSpacing;
+            }
+        }
+    }];
+    /// if find the playing indexPath.
+    if (finalIndexPath) {
+        if (self.zf_scrollViewDidScrollCallback) self.zf_scrollViewDidScrollCallback(indexPath);
+        if (handler) handler(finalIndexPath);
+    }
+    self.zf_shouldPlayIndexPath = finalIndexPath;
+}
+
+/**
+ Find the playing cell while the scrollDirection is horizontal.
+ */
+- (void)_findCorrectCellWhenScrollViewDirectionHorizontal:(void (^ __nullable)(NSIndexPath *indexPath))handler {
+    if (!self.zf_shouldAutoPlay) return;
+    if (self.zf_containerType == ZFPlayerContainerTypeView) return;
+    
+    NSArray *visiableCells = nil;
+    NSIndexPath *indexPath = nil;
+    if ([self _isTableView]) {
+        UITableView *tableView = (UITableView *)self;
+        visiableCells = [tableView visibleCells];
+        // First visible cell indexPath
+        indexPath = tableView.indexPathsForVisibleRows.firstObject;
+        if (self.contentOffset.x <= 0 && (!self.zf_playingIndexPath || [indexPath compare:self.zf_playingIndexPath] == NSOrderedSame)) {
+            UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
+            UIView *playerView = [cell viewWithTag:self.zf_containerViewTag];
+            if (playerView) {
+                if (self.zf_scrollViewDidScrollCallback) self.zf_scrollViewDidScrollCallback(indexPath);
+                if (handler) handler(indexPath);
+                self.zf_shouldPlayIndexPath = indexPath;
+                return;
+            }
+        }
+        
+        // Last visible cell indexPath
+        indexPath = tableView.indexPathsForVisibleRows.lastObject;
+        if (self.contentOffset.x + self.frame.size.width >= self.contentSize.width && (!self.zf_playingIndexPath || [indexPath compare:self.zf_playingIndexPath] == NSOrderedSame)) {
+            UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
+            UIView *playerView = [cell viewWithTag:self.zf_containerViewTag];
+            if (playerView) {
+                if (self.zf_scrollViewDidScrollCallback) self.zf_scrollViewDidScrollCallback(indexPath);
+                if (handler) handler(indexPath);
+                self.zf_shouldPlayIndexPath = indexPath;
+                return;
+            }
+        }
+    } else if ([self _isCollectionView]) {
+        UICollectionView *collectionView = (UICollectionView *)self;
+        visiableCells = [collectionView visibleCells];
+        NSArray *sortedIndexPaths = [collectionView.indexPathsForVisibleItems sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
+            return [obj1 compare:obj2];
+        }];
+        
+        visiableCells = [visiableCells sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
+            NSIndexPath *path1 = (NSIndexPath *)[collectionView indexPathForCell:obj1];
+            NSIndexPath *path2 = (NSIndexPath *)[collectionView indexPathForCell:obj2];
+            return [path1 compare:path2];
+        }];
+        
+        // First visible cell indexPath
+        indexPath = sortedIndexPaths.firstObject;
+        if (self.contentOffset.x <= 0 && (!self.zf_playingIndexPath || [indexPath compare:self.zf_playingIndexPath] == NSOrderedSame)) {
+            UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
+            UIView *playerView = [cell viewWithTag:self.zf_containerViewTag];
+            if (playerView) {
+                if (self.zf_scrollViewDidScrollCallback) self.zf_scrollViewDidScrollCallback(indexPath);
+                if (handler) handler(indexPath);
+                self.zf_shouldPlayIndexPath = indexPath;
+                return;
+            }
+        }
+        
+        // Last visible cell indexPath
+        indexPath = sortedIndexPaths.lastObject;
+        if (self.contentOffset.x + self.frame.size.width >= self.contentSize.width && (!self.zf_playingIndexPath || [indexPath compare:self.zf_playingIndexPath] == NSOrderedSame)) {
+            UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
+            UIView *playerView = [cell viewWithTag:self.zf_containerViewTag];
+            if (playerView) {
+                if (self.zf_scrollViewDidScrollCallback) self.zf_scrollViewDidScrollCallback(indexPath);
+                if (handler) handler(indexPath);
+                self.zf_shouldPlayIndexPath = indexPath;
+                return;
+            }
+        }
+    }
+    
+    NSArray *cells = nil;
+    if (self.zf_scrollDirection == ZFPlayerScrollDirectionUp) {
+        cells = visiableCells;
+    } else {
+        cells = [visiableCells reverseObjectEnumerator].allObjects;
+    }
+    
+    /// Mid line.
+    CGFloat scrollViewMidX = CGRectGetWidth(self.frame)/2;
+    /// The final playing indexPath.
+    __block NSIndexPath *finalIndexPath = nil;
+    /// The final distance from the center line.
+    __block CGFloat finalSpace = 0;
+    @weakify(self)
+    [cells enumerateObjectsUsingBlock:^(UIView *cell, NSUInteger idx, BOOL * _Nonnull stop) {
+        @strongify(self)
+        UIView *playerView = [cell viewWithTag:self.zf_containerViewTag];
+        if (!playerView) return;
+        CGRect rect1 = [playerView convertRect:playerView.frame toView:self];
+        CGRect rect = [self convertRect:rect1 toView:self.superview];
+        /// playerView left to scrollView top space.
+        CGFloat leftSpacing = CGRectGetMinX(rect) - CGRectGetMinX(self.frame) - CGRectGetMinX(playerView.frame);
+        /// playerView right to scrollView top space.
+        CGFloat rightSpacing = CGRectGetMaxX(self.frame) - CGRectGetMaxX(rect) + CGRectGetMinX(playerView.frame);
+        CGFloat centerSpacing = ABS(scrollViewMidX - CGRectGetMidX(rect));
+        NSIndexPath *indexPath = [self zf_getIndexPathForCell:cell];
+        
+        /// Play when the video playback section is visible.
+        if ((leftSpacing >= -(1 - self.zf_playerApperaPercent) * CGRectGetWidth(rect)) && (rightSpacing >= -(1 - self.zf_playerApperaPercent) * CGRectGetWidth(rect))) {
+            /// If you have a cell that is playing, stop the traversal.
+            if (self.zf_playingIndexPath) {
+                indexPath = self.zf_playingIndexPath;
+                finalIndexPath = indexPath;
+                *stop = YES;
+                return;
+            }
+            if (!finalIndexPath || centerSpacing < finalSpace) {
+                finalIndexPath = indexPath;
+                finalSpace = centerSpacing;
+            }
+        }
+    }];
+    /// if find the playing indexPath.
+    if (finalIndexPath) {
+        if (self.zf_scrollViewDidScrollCallback) self.zf_scrollViewDidScrollCallback(indexPath);
+        if (handler) handler(finalIndexPath);
+        self.zf_shouldPlayIndexPath = finalIndexPath;
+    }
+}
+
+- (BOOL)_isTableView {
+    return [self isKindOfClass:[UITableView class]];
+}
+
+- (BOOL)_isCollectionView {
+    return [self isKindOfClass:[UICollectionView class]];
+}
+
+#pragma mark - public method
+
+- (UIView *)zf_getCellForIndexPath:(NSIndexPath *)indexPath {
+    if ([self _isTableView]) {
+        UITableView *tableView = (UITableView *)self;
+        UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
+        return cell;
+    } else if ([self _isCollectionView]) {
+        UICollectionView *collectionView = (UICollectionView *)self;
+        UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
+        return cell;
+    }
+    return nil;
+}
+
+- (NSIndexPath *)zf_getIndexPathForCell:(UIView *)cell {
+    if ([self _isTableView]) {
+        UITableView *tableView = (UITableView *)self;
+        NSIndexPath *indexPath = [tableView indexPathForCell:(UITableViewCell *)cell];
+        return indexPath;
+    } else if ([self _isCollectionView]) {
+        UICollectionView *collectionView = (UICollectionView *)self;
+        NSIndexPath *indexPath = [collectionView indexPathForCell:(UICollectionViewCell *)cell];
+        return indexPath;
+    }
+    return nil;
+}
+
+- (void)zf_scrollToRowAtIndexPath:(NSIndexPath *)indexPath completionHandler:(void (^ __nullable)(void))completionHandler {
+    [self zf_scrollToRowAtIndexPath:indexPath animated:YES completionHandler:completionHandler];
+}
+
+- (void)zf_scrollToRowAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated completionHandler:(void (^ __nullable)(void))completionHandler {
+    [self zf_scrollToRowAtIndexPath:indexPath animateWithDuration:animated ? 0.4 : 0.0 completionHandler:completionHandler];
+}
+
+/// Scroll to indexPath with animations duration.
+- (void)zf_scrollToRowAtIndexPath:(NSIndexPath *)indexPath animateWithDuration:(NSTimeInterval)duration completionHandler:(void (^ __nullable)(void))completionHandler {
+    BOOL animated = duration > 0.0;
+    if ([self _isTableView]) {
+        UITableView *tableView = (UITableView *)self;
+        [tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:animated];
+    } else if ([self _isCollectionView]) {
+        UICollectionView *collectionView = (UICollectionView *)self;
+        [collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionTop animated:animated];
+    }
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+        if (completionHandler) completionHandler();
+    });
+}
+
+- (void)zf_scrollViewDidEndDecelerating {
+    BOOL scrollToScrollStop = !self.tracking && !self.dragging && !self.decelerating;
+    if (scrollToScrollStop) {
+        [self _scrollViewDidStopScroll];
+    }
+}
+
+- (void)zf_scrollViewDidEndDraggingWillDecelerate:(BOOL)decelerate {
+    if (!decelerate) {
+        BOOL dragToDragStop = self.tracking && !self.dragging && !self.decelerating;
+        if (dragToDragStop) {
+            [self _scrollViewDidStopScroll];
+        }
+    }
+}
+
+- (void)zf_scrollViewDidScrollToTop {
+    [self _scrollViewDidStopScroll];
+}
+
+- (void)zf_scrollViewDidScroll {
+    if (self.zf_scrollViewDirection == ZFPlayerScrollViewDirectionVertical) {
+        [self _scrollViewScrollingDirectionVertical];
+    } else {
+        [self _scrollViewScrollingDirectionHorizontal];
+    }
+}
+
+- (void)zf_scrollViewWillBeginDragging {
+    [self _scrollViewBeginDragging];
+}
+
+#pragma mark - getter
+
+- (ZFPlayerScrollDirection)zf_scrollDirection {
+    return [objc_getAssociatedObject(self, _cmd) integerValue];
+}
+
+- (ZFPlayerScrollViewDirection)zf_scrollViewDirection {
+    return [objc_getAssociatedObject(self, _cmd) integerValue];
+}
+
+- (CGFloat)zf_lastOffsetY {
+    return [objc_getAssociatedObject(self, _cmd) floatValue];
+}
+
+- (CGFloat)zf_lastOffsetX {
+    return [objc_getAssociatedObject(self, _cmd) floatValue];
+}
+
+#pragma mark - setter
+
+- (void)setZf_scrollDirection:(ZFPlayerScrollDirection)zf_scrollDirection {
+    objc_setAssociatedObject(self, @selector(zf_scrollDirection), @(zf_scrollDirection), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+- (void)setZf_scrollViewDirection:(ZFPlayerScrollViewDirection)zf_scrollViewDirection {
+    objc_setAssociatedObject(self, @selector(zf_scrollViewDirection), @(zf_scrollViewDirection), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+- (void)setZf_lastOffsetY:(CGFloat)zf_lastOffsetY {
+    objc_setAssociatedObject(self, @selector(zf_lastOffsetY), @(zf_lastOffsetY), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+- (void)setZf_lastOffsetX:(CGFloat)zf_lastOffsetX {
+    objc_setAssociatedObject(self, @selector(zf_lastOffsetX), @(zf_lastOffsetX), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+@end
+
+@implementation UIScrollView (ZFPlayerCannotCalled)
+
+- (void)zf_filterShouldPlayCellWhileScrolling:(void (^ __nullable)(NSIndexPath *indexPath))handler {
+    if (self.zf_scrollViewDirection == ZFPlayerScrollViewDirectionVertical) {
+        [self _findCorrectCellWhenScrollViewDirectionVertical:handler];
+    } else {
+        [self _findCorrectCellWhenScrollViewDirectionHorizontal:handler];
+    }
+}
+
+- (void)zf_filterShouldPlayCellWhileScrolled:(void (^ __nullable)(NSIndexPath *indexPath))handler {
+    if (!self.zf_shouldAutoPlay) return;
+    @weakify(self)
+    [self zf_filterShouldPlayCellWhileScrolling:^(NSIndexPath *indexPath) {
+        @strongify(self)
+        /// 如果当前控制器已经消失,直接return
+        if (self.zf_viewControllerDisappear) return;
+        if ([ZFReachabilityManager sharedManager].isReachableViaWWAN && !self.zf_WWANAutoPlay) {
+            /// 移动网络
+            self.zf_shouldPlayIndexPath = indexPath;
+            return;
+        }
+        if (handler) handler(indexPath);
+        self.zf_playingIndexPath = indexPath;
+    }];
+}
+
+#pragma mark - getter
+
+- (void (^)(NSIndexPath * _Nonnull, CGFloat))zf_playerDisappearingInScrollView {
+    return objc_getAssociatedObject(self, _cmd);
+}
+
+- (void (^)(NSIndexPath * _Nonnull, CGFloat))zf_playerAppearingInScrollView {
+    return objc_getAssociatedObject(self, _cmd);
+}
+
+- (void (^)(NSIndexPath * _Nonnull))zf_playerDidAppearInScrollView {
+    return objc_getAssociatedObject(self, _cmd);
+}
+
+- (void (^)(NSIndexPath * _Nonnull))zf_playerWillDisappearInScrollView {
+    return objc_getAssociatedObject(self, _cmd);
+}
+
+- (void (^)(NSIndexPath * _Nonnull))zf_playerWillAppearInScrollView {
+    return objc_getAssociatedObject(self, _cmd);
+}
+
+- (void (^)(NSIndexPath * _Nonnull))zf_playerDidDisappearInScrollView {
+    return objc_getAssociatedObject(self, _cmd);
+}
+
+- (void (^)(NSIndexPath * _Nonnull))zf_scrollViewDidEndScrollingCallback {
+    return objc_getAssociatedObject(self, _cmd);
+}
+
+- (void (^)(NSIndexPath * _Nonnull))zf_scrollViewDidScrollCallback {
+    return objc_getAssociatedObject(self, _cmd);
+}
+
+- (void (^)(NSIndexPath * _Nonnull))zf_playerShouldPlayInScrollView {
+    return objc_getAssociatedObject(self, _cmd);
+}
+
+- (CGFloat)zf_playerApperaPercent {
+    return [objc_getAssociatedObject(self, _cmd) floatValue];
+}
+
+- (CGFloat)zf_playerDisapperaPercent {
+    return [objc_getAssociatedObject(self, _cmd) floatValue];
+}
+
+- (BOOL)zf_viewControllerDisappear {
+    return [objc_getAssociatedObject(self, _cmd) boolValue];
+}
+
+- (BOOL)zf_stopPlay {
+    return [objc_getAssociatedObject(self, _cmd) boolValue];
+}
+
+- (BOOL)zf_stopWhileNotVisible {
+    return [objc_getAssociatedObject(self, _cmd) boolValue];
+}
+
+- (NSIndexPath *)zf_playingIndexPath {
+    return objc_getAssociatedObject(self, _cmd);
+}
+
+- (NSIndexPath *)zf_shouldPlayIndexPath {
+    return objc_getAssociatedObject(self, _cmd);
+}
+
+- (NSInteger)zf_containerViewTag {
+    return [objc_getAssociatedObject(self, _cmd) integerValue];
+}
+
+- (BOOL)zf_isWWANAutoPlay {
+    return [objc_getAssociatedObject(self, _cmd) boolValue];
+}
+
+- (BOOL)zf_shouldAutoPlay {
+    NSNumber *number = objc_getAssociatedObject(self, _cmd);
+    if (number) return number.boolValue;
+    self.zf_shouldAutoPlay = YES;
+    return YES;
+}
+
+- (ZFPlayerContainerType)zf_containerType {
+    return [objc_getAssociatedObject(self, _cmd) integerValue];
+}
+
+- (UIView *)zf_containerView {
+    return objc_getAssociatedObject(self, _cmd);
+}
+
+#pragma mark - setter
+
+- (void)setZf_playerDisappearingInScrollView:(void (^)(NSIndexPath * _Nonnull, CGFloat))zf_playerDisappearingInScrollView {
+    objc_setAssociatedObject(self, @selector(zf_playerDisappearingInScrollView), zf_playerDisappearingInScrollView, OBJC_ASSOCIATION_COPY_NONATOMIC);
+}
+
+- (void)setZf_playerAppearingInScrollView:(void (^)(NSIndexPath * _Nonnull, CGFloat))zf_playerAppearingInScrollView {
+    objc_setAssociatedObject(self, @selector(zf_playerAppearingInScrollView), zf_playerAppearingInScrollView, OBJC_ASSOCIATION_COPY_NONATOMIC);
+}
+
+- (void)setZf_playerDidAppearInScrollView:(void (^)(NSIndexPath * _Nonnull))zf_playerDidAppearInScrollView {
+    objc_setAssociatedObject(self, @selector(zf_playerDidAppearInScrollView), zf_playerDidAppearInScrollView, OBJC_ASSOCIATION_COPY_NONATOMIC);
+}
+
+- (void)setZf_playerWillDisappearInScrollView:(void (^)(NSIndexPath * _Nonnull))zf_playerWillDisappearInScrollView {
+    objc_setAssociatedObject(self, @selector(zf_playerWillDisappearInScrollView), zf_playerWillDisappearInScrollView, OBJC_ASSOCIATION_COPY_NONATOMIC);
+}
+
+- (void)setZf_playerWillAppearInScrollView:(void (^)(NSIndexPath * _Nonnull))zf_playerWillAppearInScrollView {
+    objc_setAssociatedObject(self, @selector(zf_playerWillAppearInScrollView), zf_playerWillAppearInScrollView, OBJC_ASSOCIATION_COPY_NONATOMIC);
+}
+
+- (void)setZf_playerDidDisappearInScrollView:(void (^)(NSIndexPath * _Nonnull))zf_playerDidDisappearInScrollView {
+    objc_setAssociatedObject(self, @selector(zf_playerDidDisappearInScrollView), zf_playerDidDisappearInScrollView, OBJC_ASSOCIATION_COPY_NONATOMIC);
+}
+
+- (void)setZf_scrollViewDidEndScrollingCallback:(void (^)(NSIndexPath * _Nonnull))zf_scrollViewDidEndScrollingCallback {
+    objc_setAssociatedObject(self, @selector(zf_scrollViewDidEndScrollingCallback), zf_scrollViewDidEndScrollingCallback, OBJC_ASSOCIATION_COPY_NONATOMIC);
+}
+
+- (void)setZf_scrollViewDidScrollCallback:(void (^)(NSIndexPath * _Nonnull))zf_scrollViewDidScrollCallback {
+    objc_setAssociatedObject(self, @selector(zf_scrollViewDidScrollCallback), zf_scrollViewDidScrollCallback, OBJC_ASSOCIATION_COPY_NONATOMIC);
+}
+
+- (void)setZf_playerShouldPlayInScrollView:(void (^)(NSIndexPath * _Nonnull))zf_playerShouldPlayInScrollView {
+    objc_setAssociatedObject(self, @selector(zf_playerShouldPlayInScrollView), zf_playerShouldPlayInScrollView, OBJC_ASSOCIATION_COPY_NONATOMIC);
+}
+
+- (void)setZf_playerApperaPercent:(CGFloat)zf_playerApperaPercent {
+    objc_setAssociatedObject(self, @selector(zf_playerApperaPercent), @(zf_playerApperaPercent), OBJC_ASSOCIATION_COPY_NONATOMIC);
+}
+
+- (void)setZf_playerDisapperaPercent:(CGFloat)zf_playerDisapperaPercent {
+    objc_setAssociatedObject(self, @selector(zf_playerDisapperaPercent), @(zf_playerDisapperaPercent), OBJC_ASSOCIATION_COPY_NONATOMIC);
+}
+
+- (void)setZf_viewControllerDisappear:(BOOL)zf_viewControllerDisappear {
+    objc_setAssociatedObject(self, @selector(zf_viewControllerDisappear), @(zf_viewControllerDisappear), OBJC_ASSOCIATION_COPY_NONATOMIC);
+}
+
+- (void)setZf_stopPlay:(BOOL)zf_stopPlay {
+    objc_setAssociatedObject(self, @selector(zf_stopPlay), @(zf_stopPlay), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+- (void)setZf_stopWhileNotVisible:(BOOL)zf_stopWhileNotVisible {
+    objc_setAssociatedObject(self, @selector(zf_stopWhileNotVisible), @(zf_stopWhileNotVisible), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+- (void)setZf_playingIndexPath:(NSIndexPath *)zf_playingIndexPath {
+    objc_setAssociatedObject(self, @selector(zf_playingIndexPath), zf_playingIndexPath, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+    if (zf_playingIndexPath && [zf_playingIndexPath compare:self.zf_shouldPlayIndexPath] != NSOrderedSame) {
+        self.zf_shouldPlayIndexPath = zf_playingIndexPath;
+    }
+}
+
+- (void)setZf_shouldPlayIndexPath:(NSIndexPath *)zf_shouldPlayIndexPath {
+    if (self.zf_playerShouldPlayInScrollView) self.zf_playerShouldPlayInScrollView(zf_shouldPlayIndexPath);
+    if (self.zf_shouldPlayIndexPathCallback) self.zf_shouldPlayIndexPathCallback(zf_shouldPlayIndexPath);
+    objc_setAssociatedObject(self, @selector(zf_shouldPlayIndexPath), zf_shouldPlayIndexPath, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+- (void)setZf_containerViewTag:(NSInteger)zf_containerViewTag {
+    objc_setAssociatedObject(self, @selector(zf_containerViewTag), @(zf_containerViewTag), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+- (void)setZf_containerType:(ZFPlayerContainerType)zf_containerType {
+    objc_setAssociatedObject(self, @selector(zf_containerType), @(zf_containerType), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+- (void)setZf_containerView:(UIView *)zf_containerView {
+    objc_setAssociatedObject(self, @selector(zf_containerView), zf_containerView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+- (void)setZf_shouldAutoPlay:(BOOL)zf_shouldAutoPlay {
+    objc_setAssociatedObject(self, @selector(zf_shouldAutoPlay), @(zf_shouldAutoPlay), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+- (void)setZf_WWANAutoPlay:(BOOL)zf_WWANAutoPlay {
+    objc_setAssociatedObject(self, @selector(zf_isWWANAutoPlay), @(zf_WWANAutoPlay), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+@end
+
+
+@implementation UIScrollView (ZFPlayerDeprecated)
+
+#pragma mark - getter
+
+- (void (^)(NSIndexPath * _Nonnull))zf_scrollViewDidStopScrollCallback {
+    return objc_getAssociatedObject(self, _cmd);
+}
+
+- (void (^)(NSIndexPath * _Nonnull))zf_shouldPlayIndexPathCallback {
+    return objc_getAssociatedObject(self, _cmd);
+}
+
+#pragma mark - setter
+
+- (void)setZf_scrollViewDidStopScrollCallback:(void (^)(NSIndexPath * _Nonnull))zf_scrollViewDidStopScrollCallback {
+    objc_setAssociatedObject(self, @selector(zf_scrollViewDidStopScrollCallback), zf_scrollViewDidStopScrollCallback, OBJC_ASSOCIATION_COPY_NONATOMIC);
+}
+
+- (void)setZf_shouldPlayIndexPathCallback:(void (^)(NSIndexPath * _Nonnull))zf_shouldPlayIndexPathCallback {
+    objc_setAssociatedObject(self, @selector(zf_shouldPlayIndexPathCallback), zf_shouldPlayIndexPathCallback, OBJC_ASSOCIATION_COPY_NONATOMIC);
+}
+
+@end
+
+#pragma clang diagnostic pop

+ 126 - 0
Pods/ZFPlayer/ZFPlayer/Classes/Core/UIViewController+ZFPlayerRotation.m

@@ -0,0 +1,126 @@
+//
+//  UIViewController+ZFPlayerRotation.m
+//
+// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import <UIKit/UIKit.h>
+#import <objc/runtime.h>
+
+@implementation UITabBarController (ZFPlayerRotation)
+
++ (void)load {
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        SEL selectors[] = {
+            @selector(selectedIndex)
+        };
+        
+        for (NSUInteger index = 0; index < sizeof(selectors) / sizeof(SEL); ++index) {
+            SEL originalSelector = selectors[index];
+            SEL swizzledSelector = NSSelectorFromString([@"zf_" stringByAppendingString:NSStringFromSelector(originalSelector)]);
+            Method originalMethod = class_getInstanceMethod(self, originalSelector);
+            Method swizzledMethod = class_getInstanceMethod(self, swizzledSelector);
+            if (class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))) {
+                class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
+            } else {
+                method_exchangeImplementations(originalMethod, swizzledMethod);
+            }
+        }
+    });
+}
+
+- (NSInteger)zf_selectedIndex {
+    NSInteger index = [self zf_selectedIndex];
+    if (index > self.viewControllers.count) return 0;
+    return index;
+}
+
+/**
+ * If the root view of the window is a UINavigationController, you call this Category first, and then UIViewController called.
+ * All you need to do is revisit the following three methods on a page that supports directions other than portrait.
+ */
+
+// Whether automatic screen rotation is supported.
+- (BOOL)shouldAutorotate {
+    UIViewController *vc = self.viewControllers[self.selectedIndex];
+    if ([vc isKindOfClass:[UINavigationController class]]) {
+        UINavigationController *nav = (UINavigationController *)vc;
+        return [nav.topViewController shouldAutorotate];
+    } else {
+        return [vc shouldAutorotate];
+    }
+}
+
+// Which screen directions are supported.
+- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
+    UIViewController *vc = self.viewControllers[self.selectedIndex];
+    if ([vc isKindOfClass:[UINavigationController class]]) {
+        UINavigationController *nav = (UINavigationController *)vc;
+        return [nav.topViewController supportedInterfaceOrientations];
+    } else {
+        return [vc supportedInterfaceOrientations];
+    }
+}
+
+// The default screen direction (the current ViewController must be represented by a modal UIViewController (which is not valid with modal navigation) to call this method).
+- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
+    UIViewController *vc = self.viewControllers[self.selectedIndex];
+    if ([vc isKindOfClass:[UINavigationController class]]) {
+        UINavigationController *nav = (UINavigationController *)vc;
+        return [nav.topViewController preferredInterfaceOrientationForPresentation];
+    } else {
+        return [vc preferredInterfaceOrientationForPresentation];
+    }
+}
+
+@end
+
+@implementation UINavigationController (ZFPlayerRotation)
+
+/**
+ * If the root view of the window is a UINavigationController, you call this Category first, and then UIViewController called.
+ * All you need to do is revisit the following three methods on a page that supports directions other than portrait.
+ */
+
+// Whether automatic screen rotation is supported
+- (BOOL)shouldAutorotate {
+    return [self.topViewController shouldAutorotate];
+}
+
+// Which screen directions are supported
+- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
+    return [self.topViewController supportedInterfaceOrientations];
+}
+
+// The default screen direction (the current ViewController must be represented by a modal UIViewController (which is not valid with modal navigation) to call this method).
+- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
+    return [self.topViewController preferredInterfaceOrientationForPresentation];
+}
+
+- (UIViewController *)childViewControllerForStatusBarStyle {
+    return self.topViewController;
+}
+
+- (UIViewController *)childViewControllerForStatusBarHidden {
+    return self.topViewController;
+}
+
+@end

+ 35 - 0
Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFFloatView.h

@@ -0,0 +1,35 @@
+//
+//  ZFFloatView.h
+//  ZFPlayer
+//
+// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import <UIKit/UIKit.h>
+
+@interface ZFFloatView : UIView
+
+/// The parent View
+@property(nonatomic, weak) UIView *parentView;
+
+/// Safe margins, mainly for those with Navbar and tabbar
+@property(nonatomic, assign) UIEdgeInsets safeInsets;
+
+@end

+ 85 - 0
Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFFloatView.m

@@ -0,0 +1,85 @@
+//
+//  ZFFloatView.m
+//  ZFPlayer
+//
+// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import "ZFFloatView.h"
+
+@implementation ZFFloatView
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    self = [super initWithFrame:frame];
+    if (self) {
+        [self initilize];
+    }
+    return self;
+}
+
+- (instancetype)initWithCoder:(NSCoder *)aDecoder{
+    self = [super initWithCoder:aDecoder];
+    if (self) {
+        [self initilize];
+    }
+    return self;
+}
+
+- (void)initilize {
+    self.safeInsets = UIEdgeInsetsMake(0, 0, 0, 0);
+    UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(doMoveAction:)];
+    [self addGestureRecognizer:panGestureRecognizer];
+}
+
+- (void)setParentView:(UIView *)parentView {
+    _parentView = parentView;
+    [parentView addSubview:self];
+}
+
+#pragma mark - Action
+
+- (void)doMoveAction:(UIPanGestureRecognizer *)recognizer {
+    /// The position where the gesture is moving in the self.view.
+    CGPoint translation = [recognizer translationInView:self.parentView];
+    CGPoint newCenter = CGPointMake(recognizer.view.center.x + translation.x,
+                                    recognizer.view.center.y + translation.y);
+    
+    // Limited screen range:
+    // Top margin limit.
+    newCenter.y = MAX(recognizer.view.frame.size.height/2 + self.safeInsets.top, newCenter.y);
+    
+    // Bottom margin limit.
+    newCenter.y = MIN(self.parentView.frame.size.height - self.safeInsets.bottom - recognizer.view.frame.size.height/2, newCenter.y);
+    
+    // Left margin limit.
+    newCenter.x = MAX(recognizer.view.frame.size.width/2, newCenter.x);
+    
+    // Right margin limit.
+    newCenter.x = MIN(self.parentView.frame.size.width - recognizer.view.frame.size.width/2,newCenter.x);
+    
+    // Set the center point.
+    recognizer.view.center = newCenter;
+    
+    // Set the gesture coordinates to 0, otherwise it will add up.
+    [recognizer setTranslation:CGPointZero inView:self.parentView];
+}
+
+
+@end

+ 40 - 0
Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFKVOController.h

@@ -0,0 +1,40 @@
+//
+//  UIScrollView+ZFPlayer.m
+//  ZFPlayer
+//
+// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import <Foundation/Foundation.h>
+
+@interface ZFKVOController : NSObject
+
+- (instancetype)initWithTarget:(NSObject *)target;
+
+- (void)safelyAddObserver:(NSObject *)observer
+               forKeyPath:(NSString *)keyPath
+                  options:(NSKeyValueObservingOptions)options
+                  context:(void *)context;
+- (void)safelyRemoveObserver:(NSObject *)observer
+                  forKeyPath:(NSString *)keyPath;
+
+- (void)safelyRemoveAllObservers;
+
+@end

+ 143 - 0
Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFKVOController.m

@@ -0,0 +1,143 @@
+//
+//  UIScrollView+ZFPlayer.m
+//  ZFPlayer
+//
+// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import "ZFKVOController.h"
+
+@interface ZFKVOEntry : NSObject
+@property (nonatomic, weak)   NSObject *observer;
+@property (nonatomic, strong) NSString *keyPath;
+
+@end
+
+@implementation ZFKVOEntry
+@synthesize observer;
+@synthesize keyPath;
+
+@end
+
+@interface ZFKVOController ()
+@property (nonatomic, weak) NSObject *target;
+@property (nonatomic, strong) NSMutableArray *observerArray;
+
+@end
+
+@implementation ZFKVOController
+
+- (instancetype)initWithTarget:(NSObject *)target {
+    self = [super init];
+    if (self) {
+        _target = target;
+        _observerArray = [[NSMutableArray alloc] init];
+    }
+    return self;
+}
+
+- (void)safelyAddObserver:(NSObject *)observer
+               forKeyPath:(NSString *)keyPath
+                  options:(NSKeyValueObservingOptions)options
+                  context:(void *)context {
+    NSObject *target = _target;
+    if (target == nil) return;
+    
+    BOOL removed = [self removeEntryOfObserver:observer forKeyPath:keyPath];
+    if (removed) {
+        // duplicated register
+        NSLog(@"duplicated observer");
+    }
+    
+    @try {
+        [target addObserver:observer
+                 forKeyPath:keyPath
+                    options:options
+                    context:context];
+        
+        ZFKVOEntry *entry = [[ZFKVOEntry alloc] init];
+        entry.observer = observer;
+        entry.keyPath  = keyPath;
+        [_observerArray addObject:entry];
+    } @catch (NSException *e) {
+        NSLog(@"ZFKVO: failed to add observer for %@\n", keyPath);
+    }
+}
+
+- (void)safelyRemoveObserver:(NSObject *)observer
+                  forKeyPath:(NSString *)keyPath {
+    NSObject *target = _target;
+    if (target == nil) return;
+    
+    BOOL removed = [self removeEntryOfObserver:observer forKeyPath:keyPath];
+    if (removed) {
+        // duplicated register
+        NSLog(@"duplicated observer");
+    }
+    
+    @try {
+        if (removed) {
+            [target removeObserver:observer
+                        forKeyPath:keyPath];
+        }
+    } @catch (NSException *e) {
+        NSLog(@"ZFKVO: failed to remove observer for %@\n", keyPath);
+    }
+}
+
+- (void)safelyRemoveAllObservers {
+    __block NSObject *target = _target;
+    if (target == nil) return;
+    [_observerArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
+        ZFKVOEntry *entry = obj;
+        if (entry == nil) return;
+        NSObject *observer = entry.observer;
+        if (observer == nil) return;
+        @try {
+            [target removeObserver:observer
+                        forKeyPath:entry.keyPath];
+        } @catch (NSException *e) {
+            NSLog(@"ZFKVO: failed to remove observer for %@\n", entry.keyPath);
+        }
+    }];
+    
+    [_observerArray removeAllObjects];
+}
+
+- (BOOL)removeEntryOfObserver:(NSObject *)observer
+                   forKeyPath:(NSString *)keyPath {
+    __block NSInteger foundIndex = -1;
+    [_observerArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
+        ZFKVOEntry *entry = (ZFKVOEntry *)obj;
+        if (entry.observer == observer &&
+            [entry.keyPath isEqualToString:keyPath]) {
+            foundIndex = idx;
+            *stop = YES;
+        }
+    }];
+    
+    if (foundIndex >= 0) {
+        [_observerArray removeObjectAtIndex:foundIndex];
+        return YES;
+    }
+    return NO;
+}
+
+@end

+ 131 - 0
Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFOrientationObserver.h

@@ -0,0 +1,131 @@
+//
+//  ZFOrentationObserver.h
+//  ZFPlayer
+//
+// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// Full screen mode
+typedef NS_ENUM(NSUInteger, ZFFullScreenMode) {
+    ZFFullScreenModeAutomatic,  // Determine full screen mode automatically
+    ZFFullScreenModeLandscape,  // Landscape full screen mode
+    ZFFullScreenModePortrait    // Portrait full screen Model
+};
+
+/// Full screen mode on the view
+typedef NS_ENUM(NSUInteger, ZFRotateType) {
+    ZFRotateTypeNormal,         // Normal
+    ZFRotateTypeCell,           // Cell
+    ZFRotateTypeCellOther       // Cell mode add to other view
+};
+
+/**
+ Rotation of support direction
+ */
+typedef NS_OPTIONS(NSUInteger, ZFInterfaceOrientationMask) {
+    ZFInterfaceOrientationMaskPortrait = (1 << 0),
+    ZFInterfaceOrientationMaskLandscapeLeft = (1 << 1),
+    ZFInterfaceOrientationMaskLandscapeRight = (1 << 2),
+    ZFInterfaceOrientationMaskPortraitUpsideDown = (1 << 3),
+    ZFInterfaceOrientationMaskLandscape = (ZFInterfaceOrientationMaskLandscapeLeft | ZFInterfaceOrientationMaskLandscapeRight),
+    ZFInterfaceOrientationMaskAll = (ZFInterfaceOrientationMaskPortrait | ZFInterfaceOrientationMaskLandscapeLeft | ZFInterfaceOrientationMaskLandscapeRight | ZFInterfaceOrientationMaskPortraitUpsideDown),
+    ZFInterfaceOrientationMaskAllButUpsideDown = (ZFInterfaceOrientationMaskPortrait | ZFInterfaceOrientationMaskLandscapeLeft | ZFInterfaceOrientationMaskLandscapeRight),
+};
+
+@interface ZFOrientationObserver : NSObject
+
+/// update the rotateView and containerView.
+- (void)updateRotateView:(UIView *)rotateView
+           containerView:(UIView *)containerView;
+
+/// list play
+- (void)cellModelRotateView:(UIView *)rotateView
+           rotateViewAtCell:(UIView *)cell
+              playerViewTag:(NSInteger)playerViewTag;
+
+/// cell other view rotation
+- (void)cellOtherModelRotateView:(UIView *)rotateView
+                   containerView:(UIView *)containerView;
+
+/// Container view of a full screen state player.
+@property (nonatomic, strong) UIView *fullScreenContainerView;
+
+/// Container view of a small screen state player.
+@property (nonatomic, weak) UIView *containerView;
+
+/// If the full screen.
+@property (nonatomic, readonly, getter=isFullScreen) BOOL fullScreen;
+
+/// Use device orientation, default NO.
+@property (nonatomic, assign) BOOL forceDeviceOrientation;
+
+/// Lock screen orientation
+@property (nonatomic, getter=isLockedScreen) BOOL lockedScreen;
+
+/// The block invoked When player will rotate.
+@property (nonatomic, copy, nullable) void(^orientationWillChange)(ZFOrientationObserver *observer, BOOL isFullScreen);
+
+/// The block invoked when player rotated.
+@property (nonatomic, copy, nullable) void(^orientationDidChanged)(ZFOrientationObserver *observer, BOOL isFullScreen);
+
+/// Full screen mode, the default landscape into full screen
+@property (nonatomic) ZFFullScreenMode fullScreenMode;
+
+/// rotate duration, default is 0.30
+@property (nonatomic) float duration;
+
+/// The statusbar hidden.
+@property (nonatomic, getter=isStatusBarHidden) BOOL statusBarHidden;
+
+/// The current orientation of the player.
+/// Default is UIInterfaceOrientationPortrait.
+@property (nonatomic, readonly) UIInterfaceOrientation currentOrientation;
+
+/// Whether allow the video orientation rotate.
+/// default is YES.
+@property (nonatomic) BOOL allowOrentitaionRotation;
+
+/// The support Interface Orientation,default is ZFInterfaceOrientationMaskAllButUpsideDown
+@property (nonatomic, assign) ZFInterfaceOrientationMask supportInterfaceOrientation;
+
+/// Add the device orientation observer.
+- (void)addDeviceOrientationObserver;
+
+/// Remove the device orientation observer.
+- (void)removeDeviceOrientationObserver;
+
+/// Enter the fullScreen while the ZFFullScreenMode is ZFFullScreenModeLandscape.
+- (void)enterLandscapeFullScreen:(UIInterfaceOrientation)orientation animated:(BOOL)animated;
+
+/// Enter the fullScreen while the ZFFullScreenMode is ZFFullScreenModePortrait.
+- (void)enterPortraitFullScreen:(BOOL)fullScreen animated:(BOOL)animated;
+
+/// Exit the fullScreen.
+- (void)exitFullScreenWithAnimated:(BOOL)animated;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+

+ 0 - 0
Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFOrientationObserver.m


Some files were not shown because too many files changed in this diff