浏览代码

Goods 页面,banner 页面完成-wm

wangmeng 2 年之前
父节点
当前提交
2e227e1e56
共有 100 个文件被更改,包括 9272 次插入0 次删除
  1. 316 0
      Asteria.xcodeproj/project.pbxproj
  2. 12 0
      Asteria/Config/ProjectConfig.h
  3. 77 0
      Asteria/Fuction/Goods/M/GoodsInformationM.h
  4. 65 0
      Asteria/Fuction/Goods/M/GoodsInformationM.m
  5. 22 0
      Asteria/Fuction/Goods/V/Banner/GoodsBannerCollectionViewCell.h
  6. 45 0
      Asteria/Fuction/Goods/V/Banner/GoodsBannerCollectionViewCell.m
  7. 29 0
      Asteria/Fuction/Goods/V/Banner/GoodsVideoCollectionViewCell.h
  8. 132 0
      Asteria/Fuction/Goods/V/Banner/GoodsVideoCollectionViewCell.m
  9. 24 0
      Asteria/Fuction/Goods/V/Banner/M/GoodsBannerModel.h
  10. 24 0
      Asteria/Fuction/Goods/V/Banner/M/GoodsBannerModel.m
  11. 17 0
      Asteria/Fuction/Goods/V/Banner/SelectVCollectionViewCell.h
  12. 48 0
      Asteria/Fuction/Goods/V/Banner/SelectVCollectionViewCell.m
  13. 74 0
      Asteria/Fuction/Goods/V/Banner/TYCyclePagerView/TYCyclePagerTransformLayout.h
  14. 300 0
      Asteria/Fuction/Goods/V/Banner/TYCyclePagerView/TYCyclePagerTransformLayout.m
  15. 184 0
      Asteria/Fuction/Goods/V/Banner/TYCyclePagerView/TYCyclePagerView.h
  16. 609 0
      Asteria/Fuction/Goods/V/Banner/TYCyclePagerView/TYCyclePagerView.m
  17. 47 0
      Asteria/Fuction/Goods/V/Banner/TYCyclePagerView/TYPageControl.h
  18. 285 0
      Asteria/Fuction/Goods/V/Banner/TYCyclePagerView/TYPageControl.m
  19. 24 0
      Asteria/Fuction/Goods/V/Banner/WKM_goodsBanner.h
  20. 173 0
      Asteria/Fuction/Goods/V/Banner/WKM_goodsBanner.m
  21. 44 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/AVPlayer/ZFAVPlayerManager.h
  22. 527 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/AVPlayer/ZFAVPlayerManager.m
  23. 127 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/UIImageView+ZFCache.h
  24. 411 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/UIImageView+ZFCache.m
  25. 45 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/UIView+ZFFrame.h
  26. 149 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/UIView+ZFFrame.m
  27. 120 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFLandScapeControlView.h
  28. 462 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFLandScapeControlView.m
  29. 66 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFLoadingView.h
  30. 183 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFLoadingView.m
  31. 39 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFNetworkSpeedMonitor.h
  32. 167 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFNetworkSpeedMonitor.m
  33. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_back_full@2x.png
  34. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_back_full@3x.png
  35. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_bottom_shadow.png
  36. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_brightness_high@2x.png
  37. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_brightness_high@3x.png
  38. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_brightness_low@2x.png
  39. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_brightness_low@3x.png
  40. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_close@2x.png
  41. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_close@3x.png
  42. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_closeWatch@2x.png
  43. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_closeWatch@3x.png
  44. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_fast_backward@2x.png
  45. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_fast_backward@3x.png
  46. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_fast_forward@2x.png
  47. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_fast_forward@3x.png
  48. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_fullscreen@2x.png
  49. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_fullscreen@3x.png
  50. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_lock-nor@2x.png
  51. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_lock-nor@3x.png
  52. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_muted@2x.png
  53. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_muted@3x.png
  54. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_next@2x.png
  55. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_next@3x.png
  56. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_pause@2x.png
  57. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_pause@3x.png
  58. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_play@2x.png
  59. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_play@3x.png
  60. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_shrinkscreen@2x.png
  61. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_shrinkscreen@3x.png
  62. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_slider.png
  63. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_slider@2x.png
  64. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_slider@3x.png
  65. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_top_shadow.png
  66. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_unlock-nor@2x.png
  67. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_unlock-nor@3x.png
  68. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_volume_high@2x.png
  69. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_volume_high@3x.png
  70. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_volume_low@2x.png
  71. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_volume_low@3x.png
  72. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/new_allPause_44x44_@2x.png
  73. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/new_allPause_44x44_@3x.png
  74. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/new_allPlay_44x44_@2x.png
  75. 二进制
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/new_allPlay_44x44_@3x.png
  76. 151 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayerControlView.h
  77. 836 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayerControlView.m
  78. 116 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPortraitControlView.h
  79. 396 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPortraitControlView.m
  80. 118 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFSliderView.h
  81. 426 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFSliderView.m
  82. 31 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFSmallFloatControlView.h
  83. 72 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFSmallFloatControlView.m
  84. 27 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFSpeedLoadingView.h
  85. 117 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFSpeedLoadingView.m
  86. 47 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFUtilities.h
  87. 74 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFUtilities.m
  88. 46 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFVolumeBrightnessView.h
  89. 162 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFVolumeBrightnessView.m
  90. 244 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/Core/UIScrollView+ZFPlayer.h
  91. 915 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/Core/UIScrollView+ZFPlayer.m
  92. 120 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/Core/UIViewController+ZFPlayerRotation.m
  93. 35 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/Core/ZFFloatView.h
  94. 85 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/Core/ZFFloatView.m
  95. 40 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/Core/ZFKVOController.h
  96. 130 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/Core/ZFKVOController.m
  97. 65 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/Core/ZFLandscapeViewController.h
  98. 136 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/Core/ZFLandscapeViewController.m
  99. 36 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/Core/ZFLandscapeWindow.h
  100. 0 0
      Asteria/Fuction/Goods/V/Banner/ZFPlayer/Core/ZFLandscapeWindow.m

+ 316 - 0
Asteria.xcodeproj/project.pbxproj

@@ -25,6 +25,47 @@
 		9A337E3B2A04EE1A00D058A5 /* BViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A337E392A04EE1A00D058A5 /* BViewController.m */; };
 		9A337E4E2A04F46600D058A5 /* AViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A337E4D2A04F46600D058A5 /* AViewController.m */; };
 		9A788C442A08A663003E0025 /* Target_Goods.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A788C432A08A663003E0025 /* Target_Goods.m */; };
+		9AD3459E2A08D545005CA070 /* GoodsDetailSrcView.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD3459D2A08D545005CA070 /* GoodsDetailSrcView.m */; };
+		9AD345A72A08D571005CA070 /* TYPageControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345A32A08D571005CA070 /* TYPageControl.m */; };
+		9AD345A82A08D571005CA070 /* TYCyclePagerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345A42A08D571005CA070 /* TYCyclePagerView.m */; };
+		9AD345A92A08D571005CA070 /* TYCyclePagerTransformLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345A52A08D571005CA070 /* TYCyclePagerTransformLayout.m */; };
+		9AD345AC2A08D59A005CA070 /* WKM_goodsBanner.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345AB2A08D59A005CA070 /* WKM_goodsBanner.m */; };
+		9AD345B12A08D5ED005CA070 /* GoodsBannerCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345AE2A08D5EB005CA070 /* GoodsBannerCollectionViewCell.m */; };
+		9AD345B22A08D5ED005CA070 /* GoodsVideoCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345B02A08D5ED005CA070 /* GoodsVideoCollectionViewCell.m */; };
+		9AD345F82A08D60F005CA070 /* ZFPlayerGestureControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345B62A08D60F005CA070 /* ZFPlayerGestureControl.m */; };
+		9AD345F92A08D60F005CA070 /* ZFPlayerController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345B72A08D60F005CA070 /* ZFPlayerController.m */; };
+		9AD345FA2A08D60F005CA070 /* ZFLandscapeWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345BA2A08D60F005CA070 /* ZFLandscapeWindow.m */; };
+		9AD345FB2A08D60F005CA070 /* ZFOrientationObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345BD2A08D60F005CA070 /* ZFOrientationObserver.m */; };
+		9AD345FC2A08D60F005CA070 /* ZFPlayerLogManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345C02A08D60F005CA070 /* ZFPlayerLogManager.m */; };
+		9AD345FD2A08D60F005CA070 /* ZFPersentInteractiveTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345C22A08D60F005CA070 /* ZFPersentInteractiveTransition.m */; };
+		9AD345FE2A08D60F005CA070 /* UIScrollView+ZFPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345C42A08D60F005CA070 /* UIScrollView+ZFPlayer.m */; };
+		9AD345FF2A08D60F005CA070 /* ZFPlayerNotification.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345C72A08D60F005CA070 /* ZFPlayerNotification.m */; };
+		9AD346002A08D60F005CA070 /* ZFPresentTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345C82A08D60F005CA070 /* ZFPresentTransition.m */; };
+		9AD346012A08D60F005CA070 /* ZFFloatView.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345C92A08D60F005CA070 /* ZFFloatView.m */; };
+		9AD346022A08D60F005CA070 /* ZFPlayerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345CC2A08D60F005CA070 /* ZFPlayerView.m */; };
+		9AD346032A08D60F005CA070 /* ZFPortraitViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345CE2A08D60F005CA070 /* ZFPortraitViewController.m */; };
+		9AD346042A08D60F005CA070 /* ZFKVOController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345D12A08D60F005CA070 /* ZFKVOController.m */; };
+		9AD346052A08D60F005CA070 /* ZFLandscapeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345D22A08D60F005CA070 /* ZFLandscapeViewController.m */; };
+		9AD346062A08D60F005CA070 /* ZFReachabilityManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345D52A08D60F005CA070 /* ZFReachabilityManager.m */; };
+		9AD346072A08D60F005CA070 /* UIViewController+ZFPlayerRotation.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345D72A08D60F005CA070 /* UIViewController+ZFPlayerRotation.m */; };
+		9AD346082A08D60F005CA070 /* ZFIJKPlayerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345DA2A08D60F005CA070 /* ZFIJKPlayerManager.m */; };
+		9AD346092A08D60F005CA070 /* ZFAVPlayerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345DC2A08D60F005CA070 /* ZFAVPlayerManager.m */; };
+		9AD3460A2A08D60F005CA070 /* ZFUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345DF2A08D60F005CA070 /* ZFUtilities.m */; };
+		9AD3460B2A08D60F005CA070 /* UIView+ZFFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345E02A08D60F005CA070 /* UIView+ZFFrame.m */; };
+		9AD3460C2A08D60F005CA070 /* ZFVolumeBrightnessView.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345E42A08D60F005CA070 /* ZFVolumeBrightnessView.m */; };
+		9AD3460D2A08D60F005CA070 /* ZFLandScapeControlView.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345E72A08D60F005CA070 /* ZFLandScapeControlView.m */; };
+		9AD3460E2A08D60F005CA070 /* ZFNetworkSpeedMonitor.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345E82A08D60F005CA070 /* ZFNetworkSpeedMonitor.m */; };
+		9AD3460F2A08D60F005CA070 /* ZFPlayer.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 9AD345EB2A08D60F005CA070 /* ZFPlayer.bundle */; };
+		9AD346102A08D60F005CA070 /* ZFSliderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345EE2A08D60F005CA070 /* ZFSliderView.m */; };
+		9AD346112A08D60F005CA070 /* ZFPlayerControlView.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345EF2A08D60F005CA070 /* ZFPlayerControlView.m */; };
+		9AD346122A08D60F005CA070 /* ZFSmallFloatControlView.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345F02A08D60F005CA070 /* ZFSmallFloatControlView.m */; };
+		9AD346132A08D60F005CA070 /* ZFLoadingView.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345F12A08D60F005CA070 /* ZFLoadingView.m */; };
+		9AD346142A08D60F005CA070 /* ZFSpeedLoadingView.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345F22A08D60F005CA070 /* ZFSpeedLoadingView.m */; };
+		9AD346152A08D60F005CA070 /* ZFPortraitControlView.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345F42A08D60F005CA070 /* ZFPortraitControlView.m */; };
+		9AD346162A08D60F005CA070 /* UIImageView+ZFCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD345F52A08D60F005CA070 /* UIImageView+ZFCache.m */; };
+		9AD346192A08D679005CA070 /* GoodsBannerModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD346182A08D679005CA070 /* GoodsBannerModel.m */; };
+		9AD3461D2A08D6F0005CA070 /* GoodsInformationM.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD3461C2A08D6EF005CA070 /* GoodsInformationM.m */; };
+		9AD346202A08E30E005CA070 /* SelectVCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD3461F2A08E30E005CA070 /* SelectVCollectionViewCell.m */; };
 		9AD364C62A05E73E00452C7A /* AS_GoodsDetailsC.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD364C52A05E73E00452C7A /* AS_GoodsDetailsC.m */; };
 		9AD364D12A05EC7800452C7A /* AS_TabBarViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD364D02A05EC7800452C7A /* AS_TabBarViewController.m */; };
 /* End PBXBuildFile section */
@@ -93,6 +134,91 @@
 		9A337E4D2A04F46600D058A5 /* AViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AViewController.m; sourceTree = "<group>"; };
 		9A788C422A08A663003E0025 /* Target_Goods.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Target_Goods.h; sourceTree = "<group>"; };
 		9A788C432A08A663003E0025 /* Target_Goods.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Target_Goods.m; sourceTree = "<group>"; };
+		9AD3459C2A08D545005CA070 /* GoodsDetailSrcView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GoodsDetailSrcView.h; sourceTree = "<group>"; };
+		9AD3459D2A08D545005CA070 /* GoodsDetailSrcView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoodsDetailSrcView.m; sourceTree = "<group>"; };
+		9AD345A12A08D571005CA070 /* TYCyclePagerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TYCyclePagerView.h; sourceTree = "<group>"; };
+		9AD345A22A08D571005CA070 /* TYCyclePagerTransformLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TYCyclePagerTransformLayout.h; sourceTree = "<group>"; };
+		9AD345A32A08D571005CA070 /* TYPageControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TYPageControl.m; sourceTree = "<group>"; };
+		9AD345A42A08D571005CA070 /* TYCyclePagerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TYCyclePagerView.m; sourceTree = "<group>"; };
+		9AD345A52A08D571005CA070 /* TYCyclePagerTransformLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TYCyclePagerTransformLayout.m; sourceTree = "<group>"; };
+		9AD345A62A08D571005CA070 /* TYPageControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TYPageControl.h; sourceTree = "<group>"; };
+		9AD345AA2A08D59A005CA070 /* WKM_goodsBanner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKM_goodsBanner.h; sourceTree = "<group>"; };
+		9AD345AB2A08D59A005CA070 /* WKM_goodsBanner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WKM_goodsBanner.m; sourceTree = "<group>"; };
+		9AD345AD2A08D5EB005CA070 /* GoodsBannerCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GoodsBannerCollectionViewCell.h; sourceTree = "<group>"; };
+		9AD345AE2A08D5EB005CA070 /* GoodsBannerCollectionViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GoodsBannerCollectionViewCell.m; sourceTree = "<group>"; };
+		9AD345AF2A08D5EC005CA070 /* GoodsVideoCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GoodsVideoCollectionViewCell.h; sourceTree = "<group>"; };
+		9AD345B02A08D5ED005CA070 /* GoodsVideoCollectionViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GoodsVideoCollectionViewCell.m; sourceTree = "<group>"; };
+		9AD345B52A08D60F005CA070 /* ZFPlayerNotification.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFPlayerNotification.h; sourceTree = "<group>"; };
+		9AD345B62A08D60F005CA070 /* ZFPlayerGestureControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZFPlayerGestureControl.m; sourceTree = "<group>"; };
+		9AD345B72A08D60F005CA070 /* ZFPlayerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZFPlayerController.m; sourceTree = "<group>"; };
+		9AD345B82A08D60F005CA070 /* ZFFloatView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFFloatView.h; sourceTree = "<group>"; };
+		9AD345B92A08D60F005CA070 /* ZFPresentTransition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFPresentTransition.h; sourceTree = "<group>"; };
+		9AD345BA2A08D60F005CA070 /* ZFLandscapeWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZFLandscapeWindow.m; sourceTree = "<group>"; };
+		9AD345BB2A08D60F005CA070 /* ZFKVOController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFKVOController.h; sourceTree = "<group>"; };
+		9AD345BC2A08D60F005CA070 /* ZFLandscapeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFLandscapeViewController.h; sourceTree = "<group>"; };
+		9AD345BD2A08D60F005CA070 /* ZFOrientationObserver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZFOrientationObserver.m; sourceTree = "<group>"; };
+		9AD345BE2A08D60F005CA070 /* ZFPortraitViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFPortraitViewController.h; sourceTree = "<group>"; };
+		9AD345BF2A08D60F005CA070 /* ZFPlayerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFPlayerView.h; sourceTree = "<group>"; };
+		9AD345C02A08D60F005CA070 /* ZFPlayerLogManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZFPlayerLogManager.m; sourceTree = "<group>"; };
+		9AD345C12A08D60F005CA070 /* ZFPlayerMediaPlayback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFPlayerMediaPlayback.h; sourceTree = "<group>"; };
+		9AD345C22A08D60F005CA070 /* ZFPersentInteractiveTransition.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZFPersentInteractiveTransition.m; sourceTree = "<group>"; };
+		9AD345C32A08D60F005CA070 /* ZFReachabilityManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFReachabilityManager.h; sourceTree = "<group>"; };
+		9AD345C42A08D60F005CA070 /* UIScrollView+ZFPlayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIScrollView+ZFPlayer.m"; sourceTree = "<group>"; };
+		9AD345C52A08D60F005CA070 /* ZFPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFPlayer.h; sourceTree = "<group>"; };
+		9AD345C62A08D60F005CA070 /* ZFPlayerGestureControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFPlayerGestureControl.h; sourceTree = "<group>"; };
+		9AD345C72A08D60F005CA070 /* ZFPlayerNotification.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZFPlayerNotification.m; sourceTree = "<group>"; };
+		9AD345C82A08D60F005CA070 /* ZFPresentTransition.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZFPresentTransition.m; sourceTree = "<group>"; };
+		9AD345C92A08D60F005CA070 /* ZFFloatView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZFFloatView.m; sourceTree = "<group>"; };
+		9AD345CA2A08D60F005CA070 /* ZFPlayerMediaControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFPlayerMediaControl.h; sourceTree = "<group>"; };
+		9AD345CB2A08D60F005CA070 /* ZFPlayerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFPlayerController.h; sourceTree = "<group>"; };
+		9AD345CC2A08D60F005CA070 /* ZFPlayerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZFPlayerView.m; sourceTree = "<group>"; };
+		9AD345CD2A08D60F005CA070 /* ZFPlayerLogManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFPlayerLogManager.h; sourceTree = "<group>"; };
+		9AD345CE2A08D60F005CA070 /* ZFPortraitViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZFPortraitViewController.m; sourceTree = "<group>"; };
+		9AD345CF2A08D60F005CA070 /* ZFOrientationObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFOrientationObserver.h; sourceTree = "<group>"; };
+		9AD345D02A08D60F005CA070 /* ZFPlayerConst.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFPlayerConst.h; sourceTree = "<group>"; };
+		9AD345D12A08D60F005CA070 /* ZFKVOController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZFKVOController.m; sourceTree = "<group>"; };
+		9AD345D22A08D60F005CA070 /* ZFLandscapeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZFLandscapeViewController.m; sourceTree = "<group>"; };
+		9AD345D32A08D60F005CA070 /* ZFLandscapeWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFLandscapeWindow.h; sourceTree = "<group>"; };
+		9AD345D42A08D60F005CA070 /* UIScrollView+ZFPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIScrollView+ZFPlayer.h"; sourceTree = "<group>"; };
+		9AD345D52A08D60F005CA070 /* ZFReachabilityManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZFReachabilityManager.m; sourceTree = "<group>"; };
+		9AD345D62A08D60F005CA070 /* ZFPersentInteractiveTransition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFPersentInteractiveTransition.h; sourceTree = "<group>"; };
+		9AD345D72A08D60F005CA070 /* UIViewController+ZFPlayerRotation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIViewController+ZFPlayerRotation.m"; sourceTree = "<group>"; };
+		9AD345D92A08D60F005CA070 /* ZFIJKPlayerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFIJKPlayerManager.h; sourceTree = "<group>"; };
+		9AD345DA2A08D60F005CA070 /* ZFIJKPlayerManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZFIJKPlayerManager.m; sourceTree = "<group>"; };
+		9AD345DC2A08D60F005CA070 /* ZFAVPlayerManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZFAVPlayerManager.m; sourceTree = "<group>"; };
+		9AD345DD2A08D60F005CA070 /* ZFAVPlayerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFAVPlayerManager.h; sourceTree = "<group>"; };
+		9AD345DF2A08D60F005CA070 /* ZFUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZFUtilities.m; sourceTree = "<group>"; };
+		9AD345E02A08D60F005CA070 /* UIView+ZFFrame.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+ZFFrame.m"; sourceTree = "<group>"; };
+		9AD345E12A08D60F005CA070 /* ZFSmallFloatControlView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFSmallFloatControlView.h; sourceTree = "<group>"; };
+		9AD345E22A08D60F005CA070 /* ZFPlayerControlView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFPlayerControlView.h; sourceTree = "<group>"; };
+		9AD345E32A08D60F005CA070 /* ZFSliderView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFSliderView.h; sourceTree = "<group>"; };
+		9AD345E42A08D60F005CA070 /* ZFVolumeBrightnessView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZFVolumeBrightnessView.m; sourceTree = "<group>"; };
+		9AD345E52A08D60F005CA070 /* ZFSpeedLoadingView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFSpeedLoadingView.h; sourceTree = "<group>"; };
+		9AD345E62A08D60F005CA070 /* ZFLoadingView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFLoadingView.h; sourceTree = "<group>"; };
+		9AD345E72A08D60F005CA070 /* ZFLandScapeControlView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZFLandScapeControlView.m; sourceTree = "<group>"; };
+		9AD345E82A08D60F005CA070 /* ZFNetworkSpeedMonitor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZFNetworkSpeedMonitor.m; sourceTree = "<group>"; };
+		9AD345E92A08D60F005CA070 /* UIImageView+ZFCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImageView+ZFCache.h"; sourceTree = "<group>"; };
+		9AD345EA2A08D60F005CA070 /* ZFPortraitControlView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFPortraitControlView.h; sourceTree = "<group>"; };
+		9AD345EB2A08D60F005CA070 /* ZFPlayer.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = ZFPlayer.bundle; sourceTree = "<group>"; };
+		9AD345EC2A08D60F005CA070 /* UIView+ZFFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+ZFFrame.h"; sourceTree = "<group>"; };
+		9AD345ED2A08D60F005CA070 /* ZFUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFUtilities.h; sourceTree = "<group>"; };
+		9AD345EE2A08D60F005CA070 /* ZFSliderView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZFSliderView.m; sourceTree = "<group>"; };
+		9AD345EF2A08D60F005CA070 /* ZFPlayerControlView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZFPlayerControlView.m; sourceTree = "<group>"; };
+		9AD345F02A08D60F005CA070 /* ZFSmallFloatControlView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZFSmallFloatControlView.m; sourceTree = "<group>"; };
+		9AD345F12A08D60F005CA070 /* ZFLoadingView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZFLoadingView.m; sourceTree = "<group>"; };
+		9AD345F22A08D60F005CA070 /* ZFSpeedLoadingView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZFSpeedLoadingView.m; sourceTree = "<group>"; };
+		9AD345F32A08D60F005CA070 /* ZFVolumeBrightnessView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFVolumeBrightnessView.h; sourceTree = "<group>"; };
+		9AD345F42A08D60F005CA070 /* ZFPortraitControlView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZFPortraitControlView.m; sourceTree = "<group>"; };
+		9AD345F52A08D60F005CA070 /* UIImageView+ZFCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImageView+ZFCache.m"; sourceTree = "<group>"; };
+		9AD345F62A08D60F005CA070 /* ZFNetworkSpeedMonitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFNetworkSpeedMonitor.h; sourceTree = "<group>"; };
+		9AD345F72A08D60F005CA070 /* ZFLandScapeControlView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFLandScapeControlView.h; sourceTree = "<group>"; };
+		9AD346172A08D679005CA070 /* GoodsBannerModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GoodsBannerModel.h; sourceTree = "<group>"; };
+		9AD346182A08D679005CA070 /* GoodsBannerModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GoodsBannerModel.m; sourceTree = "<group>"; };
+		9AD3461B2A08D6EF005CA070 /* GoodsInformationM.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GoodsInformationM.h; sourceTree = "<group>"; };
+		9AD3461C2A08D6EF005CA070 /* GoodsInformationM.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GoodsInformationM.m; sourceTree = "<group>"; };
+		9AD3461E2A08E30E005CA070 /* SelectVCollectionViewCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SelectVCollectionViewCell.h; sourceTree = "<group>"; };
+		9AD3461F2A08E30E005CA070 /* SelectVCollectionViewCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SelectVCollectionViewCell.m; sourceTree = "<group>"; };
+		9AD346212A08E828005CA070 /* ProjectConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ProjectConfig.h; sourceTree = "<group>"; };
 		9AD364C42A05E73E00452C7A /* AS_GoodsDetailsC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AS_GoodsDetailsC.h; sourceTree = "<group>"; };
 		9AD364C52A05E73E00452C7A /* AS_GoodsDetailsC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AS_GoodsDetailsC.m; sourceTree = "<group>"; };
 		9AD364CF2A05EC7800452C7A /* AS_TabBarViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AS_TabBarViewController.h; sourceTree = "<group>"; };
@@ -243,6 +369,149 @@
 			path = Goods;
 			sourceTree = "<group>";
 		};
+		9AD3459F2A08D55D005CA070 /* Banner */ = {
+			isa = PBXGroup;
+			children = (
+				9AD3461E2A08E30E005CA070 /* SelectVCollectionViewCell.h */,
+				9AD3461F2A08E30E005CA070 /* SelectVCollectionViewCell.m */,
+				9AD3461A2A08D692005CA070 /* M */,
+				9AD345AA2A08D59A005CA070 /* WKM_goodsBanner.h */,
+				9AD345AB2A08D59A005CA070 /* WKM_goodsBanner.m */,
+				9AD345AD2A08D5EB005CA070 /* GoodsBannerCollectionViewCell.h */,
+				9AD345AE2A08D5EB005CA070 /* GoodsBannerCollectionViewCell.m */,
+				9AD345AF2A08D5EC005CA070 /* GoodsVideoCollectionViewCell.h */,
+				9AD345B02A08D5ED005CA070 /* GoodsVideoCollectionViewCell.m */,
+				9AD345B32A08D60F005CA070 /* ZFPlayer */,
+				9AD345A02A08D571005CA070 /* TYCyclePagerView */,
+			);
+			path = Banner;
+			sourceTree = "<group>";
+		};
+		9AD345A02A08D571005CA070 /* TYCyclePagerView */ = {
+			isa = PBXGroup;
+			children = (
+				9AD345A22A08D571005CA070 /* TYCyclePagerTransformLayout.h */,
+				9AD345A52A08D571005CA070 /* TYCyclePagerTransformLayout.m */,
+				9AD345A12A08D571005CA070 /* TYCyclePagerView.h */,
+				9AD345A42A08D571005CA070 /* TYCyclePagerView.m */,
+				9AD345A62A08D571005CA070 /* TYPageControl.h */,
+				9AD345A32A08D571005CA070 /* TYPageControl.m */,
+			);
+			path = TYCyclePagerView;
+			sourceTree = "<group>";
+		};
+		9AD345B32A08D60F005CA070 /* ZFPlayer */ = {
+			isa = PBXGroup;
+			children = (
+				9AD345B42A08D60F005CA070 /* Core */,
+				9AD345D82A08D60F005CA070 /* ijkplayer */,
+				9AD345DB2A08D60F005CA070 /* AVPlayer */,
+				9AD345DE2A08D60F005CA070 /* ControlView */,
+			);
+			path = ZFPlayer;
+			sourceTree = "<group>";
+		};
+		9AD345B42A08D60F005CA070 /* Core */ = {
+			isa = PBXGroup;
+			children = (
+				9AD345B52A08D60F005CA070 /* ZFPlayerNotification.h */,
+				9AD345B62A08D60F005CA070 /* ZFPlayerGestureControl.m */,
+				9AD345B72A08D60F005CA070 /* ZFPlayerController.m */,
+				9AD345B82A08D60F005CA070 /* ZFFloatView.h */,
+				9AD345B92A08D60F005CA070 /* ZFPresentTransition.h */,
+				9AD345BA2A08D60F005CA070 /* ZFLandscapeWindow.m */,
+				9AD345BB2A08D60F005CA070 /* ZFKVOController.h */,
+				9AD345BC2A08D60F005CA070 /* ZFLandscapeViewController.h */,
+				9AD345BD2A08D60F005CA070 /* ZFOrientationObserver.m */,
+				9AD345BE2A08D60F005CA070 /* ZFPortraitViewController.h */,
+				9AD345BF2A08D60F005CA070 /* ZFPlayerView.h */,
+				9AD345C02A08D60F005CA070 /* ZFPlayerLogManager.m */,
+				9AD345C12A08D60F005CA070 /* ZFPlayerMediaPlayback.h */,
+				9AD345C22A08D60F005CA070 /* ZFPersentInteractiveTransition.m */,
+				9AD345C32A08D60F005CA070 /* ZFReachabilityManager.h */,
+				9AD345C42A08D60F005CA070 /* UIScrollView+ZFPlayer.m */,
+				9AD345C52A08D60F005CA070 /* ZFPlayer.h */,
+				9AD345C62A08D60F005CA070 /* ZFPlayerGestureControl.h */,
+				9AD345C72A08D60F005CA070 /* ZFPlayerNotification.m */,
+				9AD345C82A08D60F005CA070 /* ZFPresentTransition.m */,
+				9AD345C92A08D60F005CA070 /* ZFFloatView.m */,
+				9AD345CA2A08D60F005CA070 /* ZFPlayerMediaControl.h */,
+				9AD345CB2A08D60F005CA070 /* ZFPlayerController.h */,
+				9AD345CC2A08D60F005CA070 /* ZFPlayerView.m */,
+				9AD345CD2A08D60F005CA070 /* ZFPlayerLogManager.h */,
+				9AD345CE2A08D60F005CA070 /* ZFPortraitViewController.m */,
+				9AD345CF2A08D60F005CA070 /* ZFOrientationObserver.h */,
+				9AD345D02A08D60F005CA070 /* ZFPlayerConst.h */,
+				9AD345D12A08D60F005CA070 /* ZFKVOController.m */,
+				9AD345D22A08D60F005CA070 /* ZFLandscapeViewController.m */,
+				9AD345D32A08D60F005CA070 /* ZFLandscapeWindow.h */,
+				9AD345D42A08D60F005CA070 /* UIScrollView+ZFPlayer.h */,
+				9AD345D52A08D60F005CA070 /* ZFReachabilityManager.m */,
+				9AD345D62A08D60F005CA070 /* ZFPersentInteractiveTransition.h */,
+				9AD345D72A08D60F005CA070 /* UIViewController+ZFPlayerRotation.m */,
+			);
+			path = Core;
+			sourceTree = "<group>";
+		};
+		9AD345D82A08D60F005CA070 /* ijkplayer */ = {
+			isa = PBXGroup;
+			children = (
+				9AD345D92A08D60F005CA070 /* ZFIJKPlayerManager.h */,
+				9AD345DA2A08D60F005CA070 /* ZFIJKPlayerManager.m */,
+			);
+			path = ijkplayer;
+			sourceTree = "<group>";
+		};
+		9AD345DB2A08D60F005CA070 /* AVPlayer */ = {
+			isa = PBXGroup;
+			children = (
+				9AD345DC2A08D60F005CA070 /* ZFAVPlayerManager.m */,
+				9AD345DD2A08D60F005CA070 /* ZFAVPlayerManager.h */,
+			);
+			path = AVPlayer;
+			sourceTree = "<group>";
+		};
+		9AD345DE2A08D60F005CA070 /* ControlView */ = {
+			isa = PBXGroup;
+			children = (
+				9AD345DF2A08D60F005CA070 /* ZFUtilities.m */,
+				9AD345E02A08D60F005CA070 /* UIView+ZFFrame.m */,
+				9AD345E12A08D60F005CA070 /* ZFSmallFloatControlView.h */,
+				9AD345E22A08D60F005CA070 /* ZFPlayerControlView.h */,
+				9AD345E32A08D60F005CA070 /* ZFSliderView.h */,
+				9AD345E42A08D60F005CA070 /* ZFVolumeBrightnessView.m */,
+				9AD345E52A08D60F005CA070 /* ZFSpeedLoadingView.h */,
+				9AD345E62A08D60F005CA070 /* ZFLoadingView.h */,
+				9AD345E72A08D60F005CA070 /* ZFLandScapeControlView.m */,
+				9AD345E82A08D60F005CA070 /* ZFNetworkSpeedMonitor.m */,
+				9AD345E92A08D60F005CA070 /* UIImageView+ZFCache.h */,
+				9AD345EA2A08D60F005CA070 /* ZFPortraitControlView.h */,
+				9AD345EB2A08D60F005CA070 /* ZFPlayer.bundle */,
+				9AD345EC2A08D60F005CA070 /* UIView+ZFFrame.h */,
+				9AD345ED2A08D60F005CA070 /* ZFUtilities.h */,
+				9AD345EE2A08D60F005CA070 /* ZFSliderView.m */,
+				9AD345EF2A08D60F005CA070 /* ZFPlayerControlView.m */,
+				9AD345F02A08D60F005CA070 /* ZFSmallFloatControlView.m */,
+				9AD345F12A08D60F005CA070 /* ZFLoadingView.m */,
+				9AD345F22A08D60F005CA070 /* ZFSpeedLoadingView.m */,
+				9AD345F32A08D60F005CA070 /* ZFVolumeBrightnessView.h */,
+				9AD345F42A08D60F005CA070 /* ZFPortraitControlView.m */,
+				9AD345F52A08D60F005CA070 /* UIImageView+ZFCache.m */,
+				9AD345F62A08D60F005CA070 /* ZFNetworkSpeedMonitor.h */,
+				9AD345F72A08D60F005CA070 /* ZFLandScapeControlView.h */,
+			);
+			path = ControlView;
+			sourceTree = "<group>";
+		};
+		9AD3461A2A08D692005CA070 /* M */ = {
+			isa = PBXGroup;
+			children = (
+				9AD346172A08D679005CA070 /* GoodsBannerModel.h */,
+				9AD346182A08D679005CA070 /* GoodsBannerModel.m */,
+			);
+			path = M;
+			sourceTree = "<group>";
+		};
 		9AD364BF2A05E68400452C7A /* Target */ = {
 			isa = PBXGroup;
 			children = (
@@ -264,6 +533,9 @@
 		9AD364C72A05E76D00452C7A /* V */ = {
 			isa = PBXGroup;
 			children = (
+				9AD3459F2A08D55D005CA070 /* Banner */,
+				9AD3459C2A08D545005CA070 /* GoodsDetailSrcView.h */,
+				9AD3459D2A08D545005CA070 /* GoodsDetailSrcView.m */,
 			);
 			path = V;
 			sourceTree = "<group>";
@@ -271,6 +543,8 @@
 		9AD364C82A05E77200452C7A /* M */ = {
 			isa = PBXGroup;
 			children = (
+				9AD3461B2A08D6EF005CA070 /* GoodsInformationM.h */,
+				9AD3461C2A08D6EF005CA070 /* GoodsInformationM.m */,
 			);
 			path = M;
 			sourceTree = "<group>";
@@ -289,6 +563,7 @@
 			isa = PBXGroup;
 			children = (
 				81C3B45029F669C900D79294 /* ColorDefine.h */,
+				9AD346212A08E828005CA070 /* ProjectConfig.h */,
 				8199001E2A0206F7006FE68C /* SizeDefine.h */,
 			);
 			path = Config;
@@ -400,6 +675,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				817244AD29F3B2EE005FA9C9 /* LaunchScreen.storyboard in Resources */,
+				9AD3460F2A08D60F005CA070 /* ZFPlayer.bundle in Resources */,
 				817244AA29F3B2EE005FA9C9 /* Assets.xcassets in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -516,20 +792,60 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				9AD345F82A08D60F005CA070 /* ZFPlayerGestureControl.m in Sources */,
+				9AD345FA2A08D60F005CA070 /* ZFLandscapeWindow.m in Sources */,
+				9AD346042A08D60F005CA070 /* ZFKVOController.m in Sources */,
+				9AD346132A08D60F005CA070 /* ZFLoadingView.m in Sources */,
 				8172449F29F3B2ED005FA9C9 /* AppDelegate.m in Sources */,
 				817244B029F3B2EE005FA9C9 /* main.m in Sources */,
+				9AD346102A08D60F005CA070 /* ZFSliderView.m in Sources */,
 				9A337E4E2A04F46600D058A5 /* AViewController.m in Sources */,
+				9AD346112A08D60F005CA070 /* ZFPlayerControlView.m in Sources */,
+				9AD345B12A08D5ED005CA070 /* GoodsBannerCollectionViewCell.m in Sources */,
+				9AD345B22A08D5ED005CA070 /* GoodsVideoCollectionViewCell.m in Sources */,
 				819900222A020A6F006FE68C /* LYTools.m in Sources */,
+				9AD346012A08D60F005CA070 /* ZFFloatView.m in Sources */,
+				9AD345F92A08D60F005CA070 /* ZFPlayerController.m in Sources */,
+				9AD345AC2A08D59A005CA070 /* WKM_goodsBanner.m in Sources */,
+				9AD346002A08D60F005CA070 /* ZFPresentTransition.m in Sources */,
 				9A337E3B2A04EE1A00D058A5 /* BViewController.m in Sources */,
+				9AD345A72A08D571005CA070 /* TYPageControl.m in Sources */,
 				9AD364D12A05EC7800452C7A /* AS_TabBarViewController.m in Sources */,
+				9AD345FB2A08D60F005CA070 /* ZFOrientationObserver.m in Sources */,
+				9AD346192A08D679005CA070 /* GoodsBannerModel.m in Sources */,
+				9AD346082A08D60F005CA070 /* ZFIJKPlayerManager.m in Sources */,
+				9AD3459E2A08D545005CA070 /* GoodsDetailSrcView.m in Sources */,
+				9AD346022A08D60F005CA070 /* ZFPlayerView.m in Sources */,
 				81C3B44429F6612800D79294 /* ASBaseViewController.m in Sources */,
 				81C3B44A29F6661500D79294 /* ASBaseNavController.m in Sources */,
 				81C3B44729F664A500D79294 /* ASTabBarController.m in Sources */,
+				9AD3460C2A08D60F005CA070 /* ZFVolumeBrightnessView.m in Sources */,
+				9AD346072A08D60F005CA070 /* UIViewController+ZFPlayerRotation.m in Sources */,
+				9AD346142A08D60F005CA070 /* ZFSpeedLoadingView.m in Sources */,
+				9AD346062A08D60F005CA070 /* ZFReachabilityManager.m in Sources */,
+				9AD345FE2A08D60F005CA070 /* UIScrollView+ZFPlayer.m in Sources */,
 				9A788C442A08A663003E0025 /* Target_Goods.m in Sources */,
+				9AD3461D2A08D6F0005CA070 /* GoodsInformationM.m in Sources */,
+				9AD345A82A08D571005CA070 /* TYCyclePagerView.m in Sources */,
+				9AD346202A08E30E005CA070 /* SelectVCollectionViewCell.m in Sources */,
+				9AD3460A2A08D60F005CA070 /* ZFUtilities.m in Sources */,
 				9A337E3A2A04EE1A00D058A5 /* Target_B.m in Sources */,
+				9AD345FF2A08D60F005CA070 /* ZFPlayerNotification.m in Sources */,
+				9AD346092A08D60F005CA070 /* ZFAVPlayerManager.m in Sources */,
+				9AD346122A08D60F005CA070 /* ZFSmallFloatControlView.m in Sources */,
+				9AD3460E2A08D60F005CA070 /* ZFNetworkSpeedMonitor.m in Sources */,
+				9AD346052A08D60F005CA070 /* ZFLandscapeViewController.m in Sources */,
+				9AD346032A08D60F005CA070 /* ZFPortraitViewController.m in Sources */,
+				9AD3460D2A08D60F005CA070 /* ZFLandScapeControlView.m in Sources */,
 				9AD364C62A05E73E00452C7A /* AS_GoodsDetailsC.m in Sources */,
+				9AD3460B2A08D60F005CA070 /* UIView+ZFFrame.m in Sources */,
 				81C3B45529F66C1700D79294 /* UIView+PublicInit.m in Sources */,
+				9AD345FD2A08D60F005CA070 /* ZFPersentInteractiveTransition.m in Sources */,
+				9AD345FC2A08D60F005CA070 /* ZFPlayerLogManager.m in Sources */,
+				9AD346162A08D60F005CA070 /* UIImageView+ZFCache.m in Sources */,
+				9AD345A92A08D571005CA070 /* TYCyclePagerTransformLayout.m in Sources */,
 				81932E2B29F7539B007C37AF /* UIColor+AS.m in Sources */,
+				9AD346152A08D60F005CA070 /* ZFPortraitControlView.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

+ 12 - 0
Asteria/Config/ProjectConfig.h

@@ -0,0 +1,12 @@
+//
+//  ProjectConfig.h
+//  Asteria
+//
+//  Created by 王猛 on 2023/5/8.
+//
+
+#ifndef ProjectConfig_h
+#define ProjectConfig_h
+#define UIImageDefaultImg_SD    [UIImage imageNamed:@"placeHolder_img"]
+
+#endif /* ProjectConfig_h */

+ 77 - 0
Asteria/Fuction/Goods/M/GoodsInformationM.h

@@ -0,0 +1,77 @@
+//
+//  GoodsInformationM.h
+//  westkissMob
+//
+//  Created by 王猛 on 2022/9/16.
+//
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+@class GoodsCoupon;
+@class reviewsModel;
+@interface GoodsInformationM : NSObject
+@property (nonatomic, copy) NSString *product_details;
+
+@property(nonatomic, copy) NSString *goodsId;
+@property (nonatomic, copy) NSArray *imgarr;
+@property (nonatomic, copy) NSArray *imgDicAry;
+@property (nonatomic, copy) NSString *mp4Str;
+
+@property(nonatomic, copy) NSString *title;
+@property(nonatomic, copy) NSString *sale_num;
+@property(nonatomic, copy) NSString *reviews_count;
+@property (nonatomic, copy) NSString *href;
+@property (nonatomic, copy) NSString *href_normal;
+@property(nonatomic, copy) NSString *price;
+@property(nonatomic, copy) NSString *price_normal;
+@property(nonatomic, copy) NSString *final_price;
+@property(nonatomic, copy) NSString *final_price_normal;
+@property(nonatomic, copy) NSString *save_price;
+@property(nonatomic, copy) NSString *save_price_normal;
+///货币单位,后台给定,个人切换
+@property(nonatomic, copy) NSString *price_unit;
+
+///折扣
+@property(nonatomic, copy) NSString *percent;
+///优惠码
+@property (nonatomic, strong) NSArray <GoodsCoupon *>*coupon;
+@property (nonatomic, copy) NSString *countdown_status;
+@property (nonatomic, copy) NSString *countdown_details;
+
+///分期
+@property(nonatomic, copy) NSString *stages;
+
+
+///short_description
+@property (nonatomic, copy) NSString *short_description;
+
+@property (nonatomic, strong)reviewsModel *reviews;
+
+///积分商品参数
+@property (nonatomic, copy) NSString *points;
+
++ (GoodsInformationM *)wm_demoData;
+@end
+
+
+@interface GoodsCoupon : NSObject
+@property(nonatomic, copy) NSString *coupon_title;
+///优惠码
+@property(nonatomic, copy) NSString *coupon_details;
+@property(nonatomic, copy) NSString *coupon_code;
+
+
+@end
+
+
+@interface reviewsModel : NSObject
+@property(nonatomic, copy) NSString *startsNum;
+@property(nonatomic, copy) NSString *reviewsNum;
+@property(nonatomic, strong) NSArray *showImgurls;
+@property(nonatomic, copy) NSString *picturesNum;
+
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 65 - 0
Asteria/Fuction/Goods/M/GoodsInformationM.m

@@ -0,0 +1,65 @@
+//
+//  GoodsInformationM.m
+//  westkissMob
+//
+//  Created by 王猛 on 2022/9/16.
+//
+
+#import "GoodsInformationM.h"
+
+@implementation GoodsInformationM
+
++ (GoodsInformationM *)wm_demoData {
+    GoodsInformationM *m = [[GoodsInformationM alloc] init];
+    m.title = @"Highlight Bob Wig Straight Middle Part Bob With Grey Highlights";
+    m.sale_num = @"15K";
+    m.reviews_count = @"231";
+    m.href = @"www.baidu.com";
+    m.price = @"146.10";
+    m.final_price = @"146.10";
+    m.price = @"171.88";
+    m.save_price = @"13.65";
+    NSMutableArray *couponAry = [[NSMutableArray alloc]init];
+    for (int i=0; i<4; i++) {
+        GoodsCoupon * coupon = [[GoodsCoupon alloc]init];
+        coupon.coupon_title = @"99";
+        coupon.coupon_details = @"5";
+        coupon.coupon_code = @"111111";
+        [couponAry addObject:coupon];
+    }
+    m.coupon = [couponAry copy];
+    
+    
+    reviewsModel *reviewM = [[reviewsModel alloc]init];
+    reviewM.startsNum = @"5";
+    reviewM.reviewsNum = @"621";
+    reviewM.showImgurls = @[@"https://media.glamour.com/photos/5f3e9ad26ed7249924aba0c7/1:1/w_1234,h_1234,c_limit/IMG_2772.jpg",
+                            @"https://media.glamour.com/photos/5f3e9ad26ed7249924aba0c7/1:1/w_1234,h_1234,c_limit/IMG_2772.jpg",
+                            @"https://media.glamour.com/photos/5f3e9ad26ed7249924aba0c7/1:1/w_1234,h_1234,c_limit/IMG_2772.jpg"];
+    reviewM.picturesNum = @"100";
+    m.reviews = reviewM;
+    return m;
+}
+
+
++ (NSDictionary *)mj_objectClassInArray
+{
+    return @{@"coupon": @"GoodsCoupon",
+    };
+}
+
++ (NSDictionary *)mj_replacedKeyFromPropertyName {
+    return @{
+        @"goodsId": @"id",
+    };
+}
+
+
+
+@end
+@implementation GoodsCoupon
+@end
+
+
+@implementation reviewsModel
+@end

+ 22 - 0
Asteria/Fuction/Goods/V/Banner/GoodsBannerCollectionViewCell.h

@@ -0,0 +1,22 @@
+//
+//  GoodsBannerCollectionViewCell.h
+//  westkissMob
+//
+//  Created by 王猛 on 2022/9/14.
+//
+
+#import <UIKit/UIKit.h>
+#import "GoodsBannerModel.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface GoodsBannerCollectionViewCell : UICollectionViewCell
+@property(nonatomic, strong) GoodsBannerModel *model;
+
+@property(nonatomic, strong)UIImageView *imgV;
+
+
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 45 - 0
Asteria/Fuction/Goods/V/Banner/GoodsBannerCollectionViewCell.m

@@ -0,0 +1,45 @@
+//
+//  GoodsBannerCollectionViewCell.m
+//  westkissMob
+//
+//  Created by 王猛 on 2022/9/14.
+//
+
+#import "GoodsBannerCollectionViewCell.h"
+
+@implementation GoodsBannerCollectionViewCell
+- (instancetype)initWithFrame:(CGRect)frame
+{
+    self = [super initWithFrame:frame];
+    if (self) {
+        [self tt_addSubViews];
+    }
+    return self;
+}
+-(void)tt_addSubViews{
+    [self addSubview:self.imgV];
+    [self.imgV mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.left.right.top.bottom.mas_equalTo(0);
+    }];
+}
+
+
+-(void)setModel:(GoodsBannerModel *)model{
+    _model = model;
+    if (model.cellType == CellContentTypeImg) {
+        self.imgV.hidden = NO;
+        [self.imgV sd_setImageWithURL:[NSURL URLWithString:model.url] placeholderImage:UIImageDefaultImg_SD];
+    }
+    
+}
+-(UIImageView *)imgV{
+    if (!_imgV) {
+        _imgV = [[UIImageView alloc]init];
+        _imgV.userInteractionEnabled = YES;
+    }
+    return _imgV;
+}
+
+
+
+@end

+ 29 - 0
Asteria/Fuction/Goods/V/Banner/GoodsVideoCollectionViewCell.h

@@ -0,0 +1,29 @@
+//
+//  GoodsVideoCollectionViewCell.h
+//  westkissMob
+//
+//  Created by 王猛 on 2022/9/15.
+//
+
+#import <UIKit/UIKit.h>
+#import "ZFPlayer.h"
+#import "ZFAVPlayerManager.h"
+#import "ZFPlayerControlView.h"
+#import "GoodsBannerModel.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface GoodsVideoCollectionViewCell : UICollectionViewCell
+@property (nonatomic, strong) GoodsBannerModel *model;
+@property(nonatomic, strong) UIView *forPlayView;
+@property(nonatomic, strong) ZFPlayerController *player;
+@property(nonatomic, strong) ZFAVPlayerManager *playerManager;
+@property(nonatomic, strong) ZFPlayerControlView *controlView;
+@property(nonatomic, strong) UIButton *closeBtn;
+
+- (void)playerDealloc;
+
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 132 - 0
Asteria/Fuction/Goods/V/Banner/GoodsVideoCollectionViewCell.m

@@ -0,0 +1,132 @@
+//
+//  GoodsVideoCollectionViewCell.m
+//  westkissMob
+//
+//  Created by 王猛 on 2022/9/15.
+//
+
+#import "GoodsVideoCollectionViewCell.h"
+
+@interface GoodsVideoCollectionViewCell ()
+
+@property (nonatomic, assign) BOOL isFirst;
+@end
+
+
+@implementation GoodsVideoCollectionViewCell
+
+- (instancetype)initWithFrame:(CGRect)frame{
+    self = [super initWithFrame:frame];
+    if (self) {
+        self.isFirst = YES;
+        [self xxx_loadIntView];
+        
+
+       
+    }
+    return self;
+}
+-(void)xxx_loadIntView{//@"http://www.w3school.com.cn/example/html5/mov_bbb.mp4"
+    [self.contentView addSubview:self.forPlayView];
+    self.forPlayView.frame = self.bounds;
+    
+}
+- (UIView *)forPlayView {
+    if(_forPlayView == nil) {
+        _forPlayView = [[UIView alloc]initWithFrame:self.bounds];
+        _forPlayView.hidden = YES;
+        UIButton *voiceBtn = [UIButton buttonWithType:UIButtonTypeCustom];
+        [voiceBtn setImage:[UIImage imageNamed:@"goods_voice_open"] forState:UIControlStateNormal];
+        [voiceBtn setImage:[UIImage imageNamed:@"goods_voice_close"] forState:UIControlStateSelected];
+        [voiceBtn addTarget:self action:@selector(handleVoiceBtnEvent:) forControlEvents:UIControlEventTouchUpInside];
+        [_forPlayView addSubview:voiceBtn];
+        voiceBtn.frame = CGRectMake(self.mj_h-60, self.mj_w-60, 44, 44);
+    }
+    return _forPlayView;
+}
+
+-(void)handleVoiceBtnEvent:(UIButton *)btn{
+    btn.selected = !btn.selected;
+    if (self.player.isMuted) {
+        self.player.muted = NO;
+    }else{
+        self.player.muted = YES;
+    }
+}
+
+
+
+#pragma mark - 网络视频模块
+- (ZFAVPlayerManager *)playerManager {
+    if(_playerManager == nil) {
+        _playerManager = [[ZFAVPlayerManager alloc] init];
+    }
+    return _playerManager;
+}
+
+
+- (ZFPlayerController *)player {
+    if(_player == nil) {
+        _player = [[ZFPlayerController alloc] initWithPlayerManager:self.playerManager containerView:self.forPlayView];
+        _player.controlView = self.controlView;
+        _player.playerDisapperaPercent = 1.0f;
+        
+        __weak typeof(self) weakSelf = self;
+        _player.playerDidToEnd = ^(id<ZFPlayerMediaPlayback> asset) { //结束播放
+//            [weakSelf.player stop];
+        };
+        [_player setPlayerPlayStateChanged:^(id<ZFPlayerMediaPlayback> asset, ZFPlayerPlaybackState playState) {
+            if(playState == ZFPlayerPlayStatePlayStopped) {
+//                NSLog(@"播放暂停");
+            }
+        }];
+        [_player setPlayerPlayTimeChanged:^(id<ZFPlayerMediaPlayback> asset, NSTimeInterval currentTime, NSTimeInterval duration) {
+//            NSLog(@"播放改变currentTime - %f duration - %f", currentTime, duration);
+        }];
+    }
+    return _player;
+}
+
+-(ZFPlayerControlView *)controlView {
+   if (_controlView == nil) {
+       _controlView = [[ZFPlayerControlView alloc]init];
+       _controlView.fastViewAnimated = YES;
+       _controlView.autoHiddenTimeInterval = 5;
+       _controlView.autoFadeTimeInterval = 0.5;
+       _controlView.prepareShowLoading = YES;
+       _controlView.prepareShowControlView = NO;
+       [_controlView.portraitControlView.fullScreenBtn setImage:[UIImage imageNamed:@"goods_voice_open"] forState:UIControlStateNormal];
+       [_controlView.portraitControlView.fullScreenBtn setImage:[UIImage imageNamed:@"goods_voice_close"] forState:UIControlStateSelected];
+       [_controlView.portraitControlView.fullScreenBtn addTarget:self action:@selector(handleVoiceBtnEvent:) forControlEvents:UIControlEventTouchUpInside];
+       
+   }
+   return _controlView;
+}
+- (void)playerDealloc {
+   //网络视频
+   if(_playerManager) {
+       _playerManager = nil;
+   }
+   if(_player) {
+       _player.viewControllerDisappear = YES;
+       [_player stop];
+       _player = nil;
+   }
+}
+-(void)setModel:(GoodsBannerModel *)model{
+    NSString *videoUrl = model.url;
+    self.forPlayView.hidden = NO;
+    if (self.isFirst) {
+        self.isFirst = NO;
+        [self.player.currentPlayerManager setAssetURL:[NSURL URLWithString:videoUrl]];
+        @weakify(self)
+        self.player.playerReadyToPlay = ^(id<ZFPlayerMediaPlayback>  _Nonnull asset, NSURL * _Nonnull assetURL) {
+            @strongify(self)
+            self.controlView.portraitControlView.fullScreenBtn.selected = YES;
+            self.player.muted = NO;
+        };
+    }
+
+}
+
+@end

+ 24 - 0
Asteria/Fuction/Goods/V/Banner/M/GoodsBannerModel.h

@@ -0,0 +1,24 @@
+//
+//  GoodsBannerModel.h
+//  westkissMob
+//
+//  Created by 王猛 on 2022/9/14.
+//
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+typedef NS_ENUM(NSUInteger,CellContentType){
+    CellContentTypeImg  ,
+    CellContentTypeVideo
+    
+} ;
+@interface GoodsBannerModel : NSObject
+@property(nonatomic, assign) CellContentType cellType;
+@property (nonatomic, copy) NSString *url;
+@property (nonatomic, copy) NSString *label;
+
++(GoodsBannerModel *)xxx_loadWithModel:(NSDictionary *)bannerDic;
+@end
+
+NS_ASSUME_NONNULL_END

+ 24 - 0
Asteria/Fuction/Goods/V/Banner/M/GoodsBannerModel.m

@@ -0,0 +1,24 @@
+//
+//  GoodsBannerModel.m
+//  westkissMob
+//
+//  Created by 王猛 on 2022/9/14.
+//
+
+#import "GoodsBannerModel.h"
+
+@implementation GoodsBannerModel
+
++ (GoodsBannerModel *)xxx_loadWithModel:(NSDictionary *)bannerDic{
+    GoodsBannerModel *model = [[GoodsBannerModel alloc]init];
+    model.url = bannerDic[@"url"];
+    model.label = bannerDic[@"label"];
+    if([bannerDic[@"type"] isEqualToString:@"mp4"]){
+        model.cellType = CellContentTypeVideo;
+    }else{
+        model.cellType = CellContentTypeImg;
+    }
+    return model;
+}
+
+@end

+ 17 - 0
Asteria/Fuction/Goods/V/Banner/SelectVCollectionViewCell.h

@@ -0,0 +1,17 @@
+//
+//  SelectVCollectionViewCell.h
+//  Asteria
+//
+//  Created by 王猛 on 2023/5/8.
+//
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface SelectVCollectionViewCell : UICollectionViewCell
+@property (nonatomic, strong) UIImageView *imgV;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 48 - 0
Asteria/Fuction/Goods/V/Banner/SelectVCollectionViewCell.m

@@ -0,0 +1,48 @@
+//
+//  SelectVCollectionViewCell.m
+//  Asteria
+//
+//  Created by 王猛 on 2023/5/8.
+//
+
+#import "SelectVCollectionViewCell.h"
+
+@interface SelectVCollectionViewCell ()
+
+@end
+
+@implementation SelectVCollectionViewCell
+- (instancetype)initWithFrame:(CGRect)frame
+{
+    self = [super initWithFrame:frame];
+    if (self) {
+        [self tt_addSubViews];
+    }
+    return self;
+}
+
+-(void)tt_addSubViews{
+    UIView *bgView= [[UIView alloc]initWithFrame:self.frame];
+    bgView.layer.cornerRadius = 8;
+    bgView.layer.borderColor = [UIColor qmui_colorWithHexString:@"#043632"].CGColor;
+    bgView.layer.borderWidth =2;
+    bgView.clipsToBounds = YES;
+    self.selectedBackgroundView = bgView;
+    
+    [self.contentView addSubview:self.imgV];
+    [self.imgV mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.edges.mas_equalTo(5);
+    }];
+}
+
+- (UIImageView *)imgV {
+    if (!_imgV) {
+        _imgV = [[UIImageView alloc] initWithImage:nil];
+        _imgV.contentMode = UIViewContentModeScaleAspectFill;
+        _imgV.layer.cornerRadius = 4;
+        _imgV.clipsToBounds = YES;
+    }
+    return _imgV;
+}
+
+@end

+ 74 - 0
Asteria/Fuction/Goods/V/Banner/TYCyclePagerView/TYCyclePagerTransformLayout.h

@@ -0,0 +1,74 @@
+//
+//  TYCyclePagerViewLayout.h
+//  TYCyclePagerViewDemo
+//
+//  Created by tany on 2017/6/19.
+//  Copyright © 2017年 tany. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+typedef NS_ENUM(NSUInteger, TYCyclePagerTransformLayoutType) {
+    TYCyclePagerTransformLayoutNormal,
+    TYCyclePagerTransformLayoutLinear,
+    TYCyclePagerTransformLayoutCoverflow,
+};
+
+@class TYCyclePagerTransformLayout;
+@protocol TYCyclePagerTransformLayoutDelegate <NSObject>
+
+// initialize layout attributes
+- (void)pagerViewTransformLayout:(TYCyclePagerTransformLayout *)pagerViewTransformLayout initializeTransformAttributes:(UICollectionViewLayoutAttributes *)attributes;
+
+// apply layout attributes
+- (void)pagerViewTransformLayout:(TYCyclePagerTransformLayout *)pagerViewTransformLayout applyTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes;
+
+@end
+
+
+@interface TYCyclePagerViewLayout : NSObject
+
+@property (nonatomic, assign) CGSize itemSize;
+@property (nonatomic, assign) CGFloat itemSpacing;
+@property (nonatomic, assign) UIEdgeInsets sectionInset;
+
+@property (nonatomic, assign) TYCyclePagerTransformLayoutType layoutType;
+
+@property (nonatomic, assign) CGFloat minimumScale; // sacle default 0.8
+@property (nonatomic, assign) CGFloat minimumAlpha; // alpha default 1.0
+@property (nonatomic, assign) CGFloat maximumAngle; // angle is % default 0.2
+
+@property (nonatomic, assign) BOOL isInfiniteLoop;  // infinte scroll
+@property (nonatomic, assign) CGFloat rateOfChange; // scale and angle change rate
+@property (nonatomic, assign) BOOL adjustSpacingWhenScroling; 
+
+/**
+ pageView cell item vertical centering
+ */
+@property (nonatomic, assign) BOOL itemVerticalCenter;
+
+/**
+ first and last item horizontalc enter, when isInfiniteLoop is NO
+ */
+@property (nonatomic, assign) BOOL itemHorizontalCenter;
+
+// sectionInset
+@property (nonatomic, assign, readonly) UIEdgeInsets onlyOneSectionInset;
+@property (nonatomic, assign, readonly) UIEdgeInsets firstSectionInset;
+@property (nonatomic, assign, readonly) UIEdgeInsets lastSectionInset;
+@property (nonatomic, assign, readonly) UIEdgeInsets middleSectionInset;
+
+@end
+
+
+@interface TYCyclePagerTransformLayout : UICollectionViewFlowLayout
+
+@property (nonatomic, strong) TYCyclePagerViewLayout *layout;
+
+@property (nonatomic, weak, nullable) id<TYCyclePagerTransformLayoutDelegate> delegate;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 300 - 0
Asteria/Fuction/Goods/V/Banner/TYCyclePagerView/TYCyclePagerTransformLayout.m

@@ -0,0 +1,300 @@
+//
+//  TYCyclePagerViewLayout.m
+//  TYCyclePagerViewDemo
+//
+//  Created by tany on 2017/6/19.
+//  Copyright © 2017年 tany. All rights reserved.
+//
+
+#import "TYCyclePagerTransformLayout.h"
+
+typedef NS_ENUM(NSUInteger, TYTransformLayoutItemDirection) {
+    TYTransformLayoutItemLeft,
+    TYTransformLayoutItemCenter,
+    TYTransformLayoutItemRight,
+};
+
+
+@interface TYCyclePagerTransformLayout () {
+    struct {
+        unsigned int applyTransformToAttributes   :1;
+        unsigned int initializeTransformAttributes   :1;
+    }_delegateFlags;
+}
+
+@property (nonatomic, assign) BOOL applyTransformToAttributesDelegate;
+
+@end
+
+
+@interface TYCyclePagerViewLayout ()
+
+@property (nonatomic, weak) UIView *pageView;
+
+@end
+
+
+@implementation TYCyclePagerTransformLayout
+
+- (instancetype)init {
+    if (self = [super init]) {
+        self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
+    }
+    return self;
+}
+
+- (instancetype)initWithCoder:(NSCoder *)aDecoder {
+    if (self = [super initWithCoder:aDecoder]) {
+        self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
+    }
+    return self;
+}
+
+#pragma mark - getter setter
+
+- (void)setDelegate:(id<TYCyclePagerTransformLayoutDelegate>)delegate {
+    _delegate = delegate;
+    _delegateFlags.initializeTransformAttributes = [delegate respondsToSelector:@selector(pagerViewTransformLayout:initializeTransformAttributes:)];
+    _delegateFlags.applyTransformToAttributes = [delegate respondsToSelector:@selector(pagerViewTransformLayout:applyTransformToAttributes:)];
+}
+
+- (void)setLayout:(TYCyclePagerViewLayout *)layout {
+    _layout = layout;
+    _layout.pageView = self.collectionView;
+    self.itemSize = _layout.itemSize;
+    self.minimumInteritemSpacing = _layout.itemSpacing;
+    self.minimumLineSpacing = _layout.itemSpacing;
+}
+
+- (CGSize)itemSize {
+    if (!_layout) {
+        return [super itemSize];
+    }
+    return _layout.itemSize;
+}
+
+- (CGFloat)minimumLineSpacing {
+    if (!_layout) {
+        return [super minimumLineSpacing];
+    }
+    return _layout.itemSpacing;
+}
+
+- (CGFloat)minimumInteritemSpacing {
+    if (!_layout) {
+        return [super minimumInteritemSpacing];
+    }
+    return _layout.itemSpacing;
+}
+
+- (TYTransformLayoutItemDirection)directionWithCenterX:(CGFloat)centerX {
+    TYTransformLayoutItemDirection direction= TYTransformLayoutItemRight;
+    CGFloat contentCenterX = self.collectionView.contentOffset.x + CGRectGetWidth(self.collectionView.frame)/2;
+    if (ABS(centerX - contentCenterX) < 0.5) {
+        direction = TYTransformLayoutItemCenter;
+    }else if (centerX - contentCenterX < 0) {
+        direction = TYTransformLayoutItemLeft;
+    }
+    return direction;
+}
+
+#pragma mark - layout
+
+-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
+{
+    return _layout.layoutType == TYCyclePagerTransformLayoutNormal ? [super shouldInvalidateLayoutForBoundsChange:newBounds] : YES;
+}
+
+- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
+    if (_delegateFlags.applyTransformToAttributes || _layout.layoutType != TYCyclePagerTransformLayoutNormal) {
+        NSArray *attributesArray = [[NSArray alloc] initWithArray:[super layoutAttributesForElementsInRect:rect] copyItems:YES];
+        CGRect visibleRect = {self.collectionView.contentOffset,self.collectionView.bounds.size};
+        for (UICollectionViewLayoutAttributes *attributes in attributesArray) {
+            if (!CGRectIntersectsRect(visibleRect, attributes.frame)) {
+                continue;
+            }
+            if (_delegateFlags.applyTransformToAttributes) {
+                [_delegate pagerViewTransformLayout:self applyTransformToAttributes:attributes];
+            }else {
+                [self applyTransformToAttributes:attributes layoutType:_layout.layoutType];
+            }
+        }
+        return attributesArray;
+    }
+    return [super layoutAttributesForElementsInRect:rect];
+}
+
+- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
+    UICollectionViewLayoutAttributes *attributes = [super layoutAttributesForItemAtIndexPath:indexPath];
+    if (_delegateFlags.initializeTransformAttributes) {
+        [_delegate pagerViewTransformLayout:self initializeTransformAttributes:attributes];
+    }else if(_layout.layoutType != TYCyclePagerTransformLayoutNormal){
+        [self initializeTransformAttributes:attributes layoutType:_layout.layoutType];
+    }
+    return attributes;
+}
+
+#pragma mark - transform
+
+- (void)initializeTransformAttributes:(UICollectionViewLayoutAttributes *)attributes layoutType:(TYCyclePagerTransformLayoutType)layoutType {
+    switch (layoutType) {
+        case TYCyclePagerTransformLayoutLinear:
+            [self applyLinearTransformToAttributes:attributes scale:_layout.minimumScale alpha:_layout.minimumAlpha];
+            break;
+        case TYCyclePagerTransformLayoutCoverflow:
+        {
+            [self applyCoverflowTransformToAttributes:attributes angle:_layout.maximumAngle alpha:_layout.minimumAlpha];
+            break;
+        }
+        default:
+            break;
+    }
+}
+
+- (void)applyTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes layoutType:(TYCyclePagerTransformLayoutType)layoutType {
+    switch (layoutType) {
+        case TYCyclePagerTransformLayoutLinear:
+            [self applyLinearTransformToAttributes:attributes];
+            break;
+        case TYCyclePagerTransformLayoutCoverflow:
+            [self applyCoverflowTransformToAttributes:attributes];
+            break;
+        default:
+            break;
+    }
+}
+
+#pragma mark - LinearTransform
+
+- (void)applyLinearTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes {
+    CGFloat collectionViewWidth = self.collectionView.frame.size.width;
+    if (collectionViewWidth <= 0) {
+        return;
+    }
+    CGFloat centetX = self.collectionView.contentOffset.x + collectionViewWidth/2;
+    CGFloat delta = ABS(attributes.center.x - centetX);
+    CGFloat scale = MAX(1 - delta/collectionViewWidth*_layout.rateOfChange, _layout.minimumScale);
+    CGFloat alpha = MAX(1 - delta/collectionViewWidth, _layout.minimumAlpha);
+    [self applyLinearTransformToAttributes:attributes scale:scale alpha:alpha];
+}
+
+- (void)applyLinearTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes scale:(CGFloat)scale alpha:(CGFloat)alpha {
+    CGAffineTransform transform = CGAffineTransformMakeScale(scale, scale);
+    if (_layout.adjustSpacingWhenScroling) {
+        TYTransformLayoutItemDirection direction = [self directionWithCenterX:attributes.center.x];
+        CGFloat translate = 0;
+        switch (direction) {
+            case TYTransformLayoutItemLeft:
+                translate = 1.15 * attributes.size.width*(1-scale)/2;
+                break;
+            case TYTransformLayoutItemRight:
+                translate = -1.15 * attributes.size.width*(1-scale)/2;
+                break;
+            default:
+                // center
+                scale = 1.0;
+                alpha = 1.0;
+                break;
+        }
+        transform = CGAffineTransformTranslate(transform,translate, 0);
+    }
+    attributes.transform = transform;
+    attributes.alpha = alpha;
+}
+
+#pragma mark - CoverflowTransform
+
+- (void)applyCoverflowTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes{
+    CGFloat collectionViewWidth = self.collectionView.frame.size.width;
+    if (collectionViewWidth <= 0) {
+        return;
+    }
+    CGFloat centetX = self.collectionView.contentOffset.x + collectionViewWidth/2;
+    CGFloat delta = ABS(attributes.center.x - centetX);
+    CGFloat angle = MIN(delta/collectionViewWidth*(1-_layout.rateOfChange), _layout.maximumAngle);
+    CGFloat alpha = MAX(1 - delta/collectionViewWidth, _layout.minimumAlpha);
+    [self applyCoverflowTransformToAttributes:attributes angle:angle alpha:alpha];
+}
+
+- (void)applyCoverflowTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes angle:(CGFloat)angle alpha:(CGFloat)alpha {
+    TYTransformLayoutItemDirection direction = [self directionWithCenterX:attributes.center.x];
+    CATransform3D transform3D = CATransform3DIdentity;
+    transform3D.m34 = -0.002;
+    CGFloat translate = 0;
+    switch (direction) {
+        case TYTransformLayoutItemLeft:
+            translate = (1-cos(angle*1.2*M_PI))*attributes.size.width;
+            break;
+        case TYTransformLayoutItemRight:
+            translate = -(1-cos(angle*1.2*M_PI))*attributes.size.width;
+            angle = -angle;
+            break;
+        default:
+            // center
+            angle = 0;
+            alpha = 1;
+            break;
+    }
+
+    transform3D = CATransform3DRotate(transform3D, M_PI*angle, 0, 1, 0);
+    if (_layout.adjustSpacingWhenScroling) {
+        transform3D = CATransform3DTranslate(transform3D, translate, 0, 0);
+    }
+    attributes.transform3D = transform3D;
+    attributes.alpha = alpha;
+
+}
+@end
+
+
+@implementation TYCyclePagerViewLayout
+
+- (instancetype)init {
+    if (self = [super init]) {
+        _itemVerticalCenter = YES;
+        _minimumScale = 0.8;
+        _minimumAlpha = 1.0;
+        _maximumAngle = 0.2;
+        _rateOfChange = 0.4;
+        _adjustSpacingWhenScroling = YES;
+    }
+    return self;
+}
+
+#pragma mark - getter
+
+- (UIEdgeInsets)onlyOneSectionInset {
+    CGFloat leftSpace = _pageView && !_isInfiniteLoop && _itemHorizontalCenter ? (CGRectGetWidth(_pageView.frame) - _itemSize.width)/2 : _sectionInset.left;
+    CGFloat rightSpace = _pageView && !_isInfiniteLoop && _itemHorizontalCenter ? (CGRectGetWidth(_pageView.frame) - _itemSize.width)/2 : _sectionInset.right;
+    if (_itemVerticalCenter) {
+        CGFloat verticalSpace = (CGRectGetHeight(_pageView.frame) - _itemSize.height)/2;
+        return UIEdgeInsetsMake(verticalSpace, leftSpace, verticalSpace, rightSpace);
+    }
+    return UIEdgeInsetsMake(_sectionInset.top, leftSpace, _sectionInset.bottom, rightSpace);
+}
+
+- (UIEdgeInsets)firstSectionInset {
+    if (_itemVerticalCenter) {
+        CGFloat verticalSpace = (CGRectGetHeight(_pageView.frame) - _itemSize.height)/2;
+        return UIEdgeInsetsMake(verticalSpace, _sectionInset.left, verticalSpace, _itemSpacing);
+    }
+    return UIEdgeInsetsMake(_sectionInset.top, _sectionInset.left, _sectionInset.bottom, _itemSpacing);
+}
+
+- (UIEdgeInsets)lastSectionInset {
+    if (_itemVerticalCenter) {
+        CGFloat verticalSpace = (CGRectGetHeight(_pageView.frame) - _itemSize.height)/2;
+        return UIEdgeInsetsMake(verticalSpace, 0, verticalSpace, _sectionInset.right);
+    }
+    return UIEdgeInsetsMake(_sectionInset.top, 0, _sectionInset.bottom, _sectionInset.right);
+}
+
+- (UIEdgeInsets)middleSectionInset {
+    if (_itemVerticalCenter) {
+        CGFloat verticalSpace = (CGRectGetHeight(_pageView.frame) - _itemSize.height)/2;
+        return UIEdgeInsetsMake(verticalSpace, 0, verticalSpace, _itemSpacing);
+    }
+    return _sectionInset;
+}
+
+@end

+ 184 - 0
Asteria/Fuction/Goods/V/Banner/TYCyclePagerView/TYCyclePagerView.h

@@ -0,0 +1,184 @@
+//
+//  TYCyclePagerView.h
+//  TYCyclePagerViewDemo
+//
+//  Created by tany on 2017/6/14.
+//  Copyright © 2017年 tany. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import "TYCyclePagerTransformLayout.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+typedef struct {
+    NSInteger index;
+    NSInteger section;
+}TYIndexSection;
+
+// pagerView scrolling direction
+typedef NS_ENUM(NSUInteger, TYPagerScrollDirection) {
+    TYPagerScrollDirectionLeft,
+    TYPagerScrollDirectionRight,
+};
+
+@class TYCyclePagerView;
+@protocol TYCyclePagerViewDataSource <NSObject>
+
+- (NSInteger)numberOfItemsInPagerView:(TYCyclePagerView *)pageView;
+
+- (__kindof UICollectionViewCell *)pagerView:(TYCyclePagerView *)pagerView cellForItemAtIndex:(NSInteger)index;
+
+/**
+ return pagerView layout,and cache layout
+ */
+- (TYCyclePagerViewLayout *)layoutForPagerView:(TYCyclePagerView *)pageView;
+
+@end
+
+@protocol TYCyclePagerViewDelegate <NSObject>
+
+@optional
+
+/**
+ pagerView did scroll to new index page
+ */
+- (void)pagerView:(TYCyclePagerView *)pageView didScrollFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex;
+
+/**
+ pagerView did selected item cell
+ */
+- (void)pagerView:(TYCyclePagerView *)pageView didSelectedItemCell:(__kindof UICollectionViewCell *)cell atIndex:(NSInteger)index;
+- (void)pagerView:(TYCyclePagerView *)pageView didSelectedItemCell:(__kindof UICollectionViewCell *)cell atIndexSection:(TYIndexSection)indexSection;
+
+// custom layout
+- (void)pagerView:(TYCyclePagerView *)pageView initializeTransformAttributes:(UICollectionViewLayoutAttributes *)attributes;
+
+- (void)pagerView:(TYCyclePagerView *)pageView applyTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes;
+
+
+// scrollViewDelegate
+
+- (void)pagerViewDidScroll:(TYCyclePagerView *)pageView;
+
+- (void)pagerViewWillBeginDragging:(TYCyclePagerView *)pageView;
+
+- (void)pagerViewDidEndDragging:(TYCyclePagerView *)pageView willDecelerate:(BOOL)decelerate;
+
+- (void)pagerViewWillBeginDecelerating:(TYCyclePagerView *)pageView;
+
+- (void)pagerViewDidEndDecelerating:(TYCyclePagerView *)pageView;
+
+- (void)pagerViewWillBeginScrollingAnimation:(TYCyclePagerView *)pageView;
+
+- (void)pagerViewDidEndScrollingAnimation:(TYCyclePagerView *)pageView;
+
+@end
+
+
+@interface TYCyclePagerView : UIView
+
+// will be automatically resized to track the size of the pagerView
+@property (nonatomic, strong, nullable) UIView *backgroundView; 
+
+@property (nonatomic, weak, nullable) id<TYCyclePagerViewDataSource> dataSource;
+@property (nonatomic, weak, nullable) id<TYCyclePagerViewDelegate> delegate;
+
+// pager view, don't set dataSource and delegate
+@property (nonatomic, weak, readonly) UICollectionView *collectionView;
+// pager view layout
+@property (nonatomic, strong, readonly) TYCyclePagerViewLayout *layout;
+
+/**
+ is infinite cycle pageview
+ */
+@property (nonatomic, assign) BOOL isInfiniteLoop;
+
+/**
+ pagerView automatic scroll time interval, default 0,disable automatic
+ */
+@property (nonatomic, assign) CGFloat autoScrollInterval;
+
+@property (nonatomic, assign) BOOL reloadDataNeedResetIndex;
+
+/**
+ current page index
+ */
+@property (nonatomic, assign, readonly) NSInteger curIndex;
+@property (nonatomic, assign, readonly) TYIndexSection indexSection;
+
+// scrollView property
+@property (nonatomic, assign, readonly) CGPoint contentOffset;
+@property (nonatomic, assign, readonly) BOOL tracking;
+@property (nonatomic, assign, readonly) BOOL dragging;
+@property (nonatomic, assign, readonly) BOOL decelerating;
+
+
+/**
+ reload data, !!important!!: will clear layout and call delegate layoutForPagerView
+ */
+- (void)reloadData;
+
+/**
+ update data is reload data, but not clear layuot
+ */
+- (void)updateData;
+
+/**
+ if you only want update layout
+ */
+- (void)setNeedUpdateLayout;
+
+- (void)addTimer;
+
+- (void)removeTimer;
+
+/**
+ will set layout nil and call delegate->layoutForPagerView
+ */
+- (void)setNeedClearLayout;
+
+/**
+ current index cell in pagerView
+ */
+- (__kindof UICollectionViewCell * _Nullable)curIndexCell;
+
+/**
+ visible cells in pageView
+ */
+- (NSArray<__kindof UICollectionViewCell *> *_Nullable)visibleCells;
+
+
+/**
+ visible pageView indexs, maybe repeat index
+ */
+- (NSArray *)visibleIndexs;
+
+/**
+ scroll to item at index
+ */
+- (void)scrollToItemAtIndex:(NSInteger)index animate:(BOOL)animate;
+- (void)scrollToItemAtIndexSection:(TYIndexSection)indexSection animate:(BOOL)animate;
+/**
+ scroll to next or pre item
+ */
+- (void)scrollToNearlyIndexAtDirection:(TYPagerScrollDirection)direction animate:(BOOL)animate;
+
+/**
+ register pager view cell with class
+ */
+- (void)registerClass:(Class)Class forCellWithReuseIdentifier:(NSString *)identifier;
+
+/**
+ register pager view cell with nib
+ */
+- (void)registerNib:(UINib *)nib forCellWithReuseIdentifier:(NSString *)identifier;
+
+/**
+ dequeue reusable cell for pagerView
+ */
+- (__kindof UICollectionViewCell *)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forIndex:(NSInteger)index;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 609 - 0
Asteria/Fuction/Goods/V/Banner/TYCyclePagerView/TYCyclePagerView.m

@@ -0,0 +1,609 @@
+//
+//  TYCyclePagerView.m
+//  TYCyclePagerViewDemo
+//
+//  Created by tany on 2017/6/14.
+//  Copyright © 2017年 tany. All rights reserved.
+//
+
+#import "TYCyclePagerView.h"
+
+NS_INLINE BOOL TYEqualIndexSection(TYIndexSection indexSection1,TYIndexSection indexSection2) {
+    return indexSection1.index == indexSection2.index && indexSection1.section == indexSection2.section;
+}
+
+NS_INLINE TYIndexSection TYMakeIndexSection(NSInteger index, NSInteger section) {
+    TYIndexSection indexSection;
+    indexSection.index = index;
+    indexSection.section = section;
+    return indexSection;
+}
+
+@interface TYCyclePagerView () <UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, TYCyclePagerTransformLayoutDelegate> {
+    struct {
+        unsigned int pagerViewDidScroll   :1;
+        unsigned int didScrollFromIndexToNewIndex   :1;
+        unsigned int initializeTransformAttributes   :1;
+        unsigned int applyTransformToAttributes   :1;
+    }_delegateFlags;
+    struct {
+        unsigned int cellForItemAtIndex   :1;
+        unsigned int layoutForPagerView   :1;
+    }_dataSourceFlags;
+}
+
+// UI
+@property (nonatomic, weak) UICollectionView *collectionView;
+@property (nonatomic, strong) TYCyclePagerViewLayout *layout;
+@property (nonatomic, strong) NSTimer *timer;
+
+// Data
+@property (nonatomic, assign) NSInteger numberOfItems;
+
+@property (nonatomic, assign) NSInteger dequeueSection;
+@property (nonatomic, assign) TYIndexSection beginDragIndexSection;
+@property (nonatomic, assign) NSInteger firstScrollIndex;
+
+@property (nonatomic, assign) BOOL needClearLayout;
+@property (nonatomic, assign) BOOL didReloadData;
+@property (nonatomic, assign) BOOL didLayout;
+@property (nonatomic, assign) BOOL needResetIndex;
+
+@end
+
+#define kPagerViewMaxSectionCount 200
+#define kPagerViewMinSectionCount 18
+
+@implementation TYCyclePagerView
+
+#pragma mark - life Cycle
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    if (self = [super initWithFrame:frame]) {
+        [self configureProperty];
+        
+        [self addCollectionView];
+    }
+    return self;
+}
+
+- (instancetype)initWithCoder:(NSCoder *)aDecoder {
+    if (self = [super initWithCoder:aDecoder]) {
+        [self configureProperty];
+        
+        [self addCollectionView];
+    }
+    return self;
+}
+
+- (void)configureProperty {
+    _needResetIndex = NO;
+    _didReloadData = NO;
+    _didLayout = NO;
+    _autoScrollInterval = 0;
+    _isInfiniteLoop = YES;
+    _beginDragIndexSection.index = 0;
+    _beginDragIndexSection.section = 0;
+    _indexSection.index = -1;
+    _indexSection.section = -1;
+    _firstScrollIndex = -1;
+}
+
+- (void)addCollectionView {
+    TYCyclePagerTransformLayout *layout = [[TYCyclePagerTransformLayout alloc]init];
+    UICollectionView *collectionView = [[UICollectionView alloc]initWithFrame:CGRectZero collectionViewLayout:layout];
+    layout.delegate = _delegateFlags.applyTransformToAttributes ? self : nil;;
+    collectionView.backgroundColor = [UIColor clearColor];
+    collectionView.dataSource = self;
+    collectionView.delegate = self;
+    collectionView.pagingEnabled = NO;
+    collectionView.decelerationRate = 1-0.0076;
+    if ([collectionView respondsToSelector:@selector(setPrefetchingEnabled:)]) {
+        collectionView.prefetchingEnabled = NO;
+    }
+    collectionView.showsHorizontalScrollIndicator = NO;
+    collectionView.showsVerticalScrollIndicator = NO;
+    [self addSubview:collectionView];
+    _collectionView = collectionView;
+}
+
+- (void)willMoveToSuperview:(UIView *)newSuperview {
+    if (!newSuperview) {
+        [self removeTimer];
+    }else {
+        [self removeTimer];
+        if (_autoScrollInterval > 0) {
+            [self addTimer];
+        }
+    }
+}
+
+
+#pragma mark - timer
+
+- (void)addTimer {
+    if (_timer || _autoScrollInterval <= 0) {
+        return;
+    }
+    _timer = [NSTimer timerWithTimeInterval:_autoScrollInterval target:self selector:@selector(timerFired:) userInfo:nil repeats:YES];
+    [[NSRunLoop mainRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
+}
+
+- (void)removeTimer {
+    if (!_timer) {
+        return;
+    }
+    [_timer invalidate];
+    _timer = nil;
+}
+
+- (void)timerFired:(NSTimer *)timer {
+    if (!self.superview || !self.window || _numberOfItems == 0 || self.tracking) {
+        return;
+    }
+    
+    [self scrollToNearlyIndexAtDirection:TYPagerScrollDirectionRight animate:YES];
+}
+
+#pragma mark - getter
+
+- (TYCyclePagerViewLayout *)layout {
+    if (!_layout) {
+        if (_dataSourceFlags.layoutForPagerView) {
+            _layout = [_dataSource layoutForPagerView:self];
+            _layout.isInfiniteLoop = _isInfiniteLoop;
+        }
+        if (_layout.itemSize.width <= 0 || _layout.itemSize.height <= 0) {
+            _layout = nil;
+        }
+    }
+    return _layout;
+}
+
+- (NSInteger)curIndex {
+    return _indexSection.index;
+}
+
+- (CGPoint)contentOffset {
+    return _collectionView.contentOffset;
+}
+
+- (BOOL)tracking {
+    return _collectionView.tracking;
+}
+
+- (BOOL)dragging {
+    return _collectionView.dragging;
+}
+
+- (BOOL)decelerating {
+    return _collectionView.decelerating;
+}
+
+- (UIView *)backgroundView {
+    return _collectionView.backgroundView;
+}
+
+- (__kindof UICollectionViewCell *)curIndexCell {
+    return [_collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:_indexSection.index inSection:_indexSection.section]];
+}
+
+- (NSArray<__kindof UICollectionViewCell *> *)visibleCells {
+    return _collectionView.visibleCells;
+}
+
+- (NSArray *)visibleIndexs {
+    NSMutableArray *indexs = [NSMutableArray array];
+    for (NSIndexPath *indexPath in _collectionView.indexPathsForVisibleItems) {
+        [indexs addObject:@(indexPath.item)];
+    }
+    return [indexs copy];
+}
+
+#pragma mark - setter
+
+- (void)setBackgroundView:(UIView *)backgroundView {
+    [_collectionView setBackgroundView:backgroundView];
+}
+
+- (void)setAutoScrollInterval:(CGFloat)autoScrollInterval {
+    _autoScrollInterval = autoScrollInterval;
+    [self removeTimer];
+    if (autoScrollInterval > 0 && self.superview) {
+        [self addTimer];
+    }
+}
+
+- (void)setDelegate:(id<TYCyclePagerViewDelegate>)delegate {
+    _delegate = delegate;
+    _delegateFlags.pagerViewDidScroll = [delegate respondsToSelector:@selector(pagerViewDidScroll:)];
+    _delegateFlags.didScrollFromIndexToNewIndex = [delegate respondsToSelector:@selector(pagerView:didScrollFromIndex:toIndex:)];
+    _delegateFlags.initializeTransformAttributes = [delegate respondsToSelector:@selector(pagerView:initializeTransformAttributes:)];
+    _delegateFlags.applyTransformToAttributes = [delegate respondsToSelector:@selector(pagerView:applyTransformToAttributes:)];
+    if (self.collectionView && self.collectionView.collectionViewLayout) {
+        ((TYCyclePagerTransformLayout *)self.collectionView.collectionViewLayout).delegate = _delegateFlags.applyTransformToAttributes ? self : nil;
+    }
+}
+
+- (void)setDataSource:(id<TYCyclePagerViewDataSource>)dataSource {
+    _dataSource = dataSource;
+    _dataSourceFlags.cellForItemAtIndex = [dataSource respondsToSelector:@selector(pagerView:cellForItemAtIndex:)];
+    _dataSourceFlags.layoutForPagerView = [dataSource respondsToSelector:@selector(layoutForPagerView:)];
+}
+
+#pragma mark - public
+
+- (void)reloadData {
+    _didReloadData = YES;
+    _needResetIndex = YES;
+    [self setNeedClearLayout];
+    [self clearLayout];
+    [self updateData];
+}
+
+// not clear layout
+- (void)updateData {
+    [self updateLayout];
+    _numberOfItems = [_dataSource numberOfItemsInPagerView:self];
+    [_collectionView reloadData];
+    if (!_didLayout && !CGRectIsEmpty(self.collectionView.frame) && _indexSection.index < 0) {
+        _didLayout = YES;
+    }
+    BOOL needResetIndex = _needResetIndex && _reloadDataNeedResetIndex;
+    _needResetIndex = NO;
+    if (needResetIndex) {
+        [self removeTimer];
+    }
+    [self resetPagerViewAtIndex:(_indexSection.index < 0 && !CGRectIsEmpty(self.collectionView.frame)) || needResetIndex ? 0 :_indexSection.index];
+    if (needResetIndex) {
+        [self addTimer];
+    }
+}
+
+- (void)scrollToNearlyIndexAtDirection:(TYPagerScrollDirection)direction animate:(BOOL)animate {
+    TYIndexSection indexSection = [self nearlyIndexPathAtDirection:direction];
+    [self scrollToItemAtIndexSection:indexSection animate:animate];
+}
+
+- (void)scrollToItemAtIndex:(NSInteger)index animate:(BOOL)animate {
+    if (!_didLayout && _didReloadData) {
+        _firstScrollIndex = index;
+    }else {
+        _firstScrollIndex = -1;
+    }
+    if (!_isInfiniteLoop) {
+        [self scrollToItemAtIndexSection:TYMakeIndexSection(index, 0) animate:animate];
+        return;
+    }
+
+    [self scrollToItemAtIndexSection:TYMakeIndexSection(index, index >= self.curIndex ? _indexSection.section : _indexSection.section+1) animate:animate];
+}
+
+- (void)scrollToItemAtIndexSection:(TYIndexSection)indexSection animate:(BOOL)animate {
+    if (_numberOfItems <= 0 || ![self isValidIndexSection:indexSection]) {
+        //NSLog(@"scrollToItemAtIndex: item indexSection is invalid!");
+        return;
+    }
+    
+    
+    
+    if (animate && [_delegate respondsToSelector:@selector(pagerViewWillBeginScrollingAnimation:)]) {
+        [_delegate pagerViewWillBeginScrollingAnimation:self];
+    }
+    CGFloat offset = [self caculateOffsetXAtIndexSection:indexSection];
+    [_collectionView setContentOffset:CGPointMake(offset, _collectionView.contentOffset.y) animated:animate];
+}
+
+- (void)registerClass:(Class)Class forCellWithReuseIdentifier:(NSString *)identifier {
+    [_collectionView registerClass:Class forCellWithReuseIdentifier:identifier];
+}
+
+- (void)registerNib:(UINib *)nib forCellWithReuseIdentifier:(NSString *)identifier {
+    [_collectionView registerNib:nib forCellWithReuseIdentifier:identifier];
+}
+
+- (__kindof UICollectionViewCell *)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forIndex:(NSInteger)index {
+    UICollectionViewCell *cell = [_collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:[NSIndexPath indexPathForItem:index inSection:_dequeueSection]];
+    return cell;
+}
+
+#pragma mark - configure layout
+
+- (void)updateLayout {
+    if (!self.layout) {
+        return;
+    }
+    self.layout.isInfiniteLoop = _isInfiniteLoop;
+    ((TYCyclePagerTransformLayout *)_collectionView.collectionViewLayout).layout = self.layout;
+}
+
+- (void)clearLayout {
+    if (_needClearLayout) {
+        _layout = nil;
+        _needClearLayout = NO;
+    }
+}
+
+- (void)setNeedClearLayout {
+    _needClearLayout = YES;
+}
+
+- (void)setNeedUpdateLayout {
+    if (!self.layout) {
+        return;
+    }
+    [self clearLayout];
+    [self updateLayout];
+    [_collectionView.collectionViewLayout invalidateLayout];
+    [self resetPagerViewAtIndex:_indexSection.index < 0 ? 0 :_indexSection.index];
+}
+
+#pragma mark - pager index
+
+- (BOOL)isValidIndexSection:(TYIndexSection)indexSection {
+    return indexSection.index >= 0 && indexSection.index < _numberOfItems && indexSection.section >= 0 && indexSection.section < kPagerViewMaxSectionCount;
+}
+
+- (TYIndexSection)nearlyIndexPathAtDirection:(TYPagerScrollDirection)direction{
+    return [self nearlyIndexPathForIndexSection:_indexSection direction:direction];
+}
+
+- (TYIndexSection)nearlyIndexPathForIndexSection:(TYIndexSection)indexSection direction:(TYPagerScrollDirection)direction {
+    if (indexSection.index < 0 || indexSection.index >= _numberOfItems) {
+        return indexSection;
+    }
+    
+    if (!_isInfiniteLoop) {
+        if (direction == TYPagerScrollDirectionRight && indexSection.index == _numberOfItems - 1) {
+            return _autoScrollInterval > 0 ? TYMakeIndexSection(0, 0) : indexSection;
+        } else if (direction == TYPagerScrollDirectionRight) {
+            return TYMakeIndexSection(indexSection.index+1, 0);
+        }
+        
+        if (indexSection.index == 0) {
+            return _autoScrollInterval > 0 ? TYMakeIndexSection(_numberOfItems - 1, 0) : indexSection;
+        }
+        return TYMakeIndexSection(indexSection.index-1, 0);
+    }
+    
+    if (direction == TYPagerScrollDirectionRight) {
+        if (indexSection.index < _numberOfItems-1) {
+            return TYMakeIndexSection(indexSection.index+1, indexSection.section);
+        }
+        if (indexSection.section >= kPagerViewMaxSectionCount-1) {
+            return TYMakeIndexSection(indexSection.index, kPagerViewMaxSectionCount-1);
+        }
+        return TYMakeIndexSection(0, indexSection.section+1);
+    }
+    
+    if (indexSection.index > 0) {
+        return TYMakeIndexSection(indexSection.index-1, indexSection.section);
+    }
+    if (indexSection.section <= 0) {
+        return TYMakeIndexSection(indexSection.index, 0);
+    }
+    return TYMakeIndexSection(_numberOfItems-1, indexSection.section-1);
+}
+
+- (TYIndexSection)caculateIndexSectionWithOffsetX:(CGFloat)offsetX {
+    if (_numberOfItems <= 0) {
+        return TYMakeIndexSection(0, 0);
+    }
+     UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)_collectionView.collectionViewLayout;
+    CGFloat leftEdge = _isInfiniteLoop ? _layout.sectionInset.left : _layout.onlyOneSectionInset.left;
+    CGFloat width = CGRectGetWidth(_collectionView.frame);
+    CGFloat middleOffset = offsetX + width/2;
+    CGFloat itemWidth = layout.itemSize.width + layout.minimumInteritemSpacing;
+    NSInteger curIndex = 0;
+    NSInteger curSection = 0;
+    if (middleOffset - leftEdge >= 0) {
+        NSInteger itemIndex = (middleOffset - leftEdge+layout.minimumInteritemSpacing/2)/itemWidth;
+        if (itemIndex < 0) {
+            itemIndex = 0;
+        }else if (itemIndex >= _numberOfItems*kPagerViewMaxSectionCount) {
+            itemIndex = _numberOfItems*kPagerViewMaxSectionCount-1;
+        }
+        curIndex = itemIndex%_numberOfItems;
+        curSection = itemIndex/_numberOfItems;
+    }
+    return TYMakeIndexSection(curIndex, curSection);
+}
+
+- (CGFloat)caculateOffsetXAtIndexSection:(TYIndexSection)indexSection{
+    if (_numberOfItems == 0) {
+        return 0;
+    }
+    UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)_collectionView.collectionViewLayout;
+    UIEdgeInsets edge = _isInfiniteLoop ? _layout.sectionInset : _layout.onlyOneSectionInset;
+    CGFloat leftEdge = edge.left;
+    CGFloat rightEdge = edge.right;
+    CGFloat width = CGRectGetWidth(_collectionView.frame);
+    CGFloat itemWidth = layout.itemSize.width + layout.minimumInteritemSpacing;
+    CGFloat offsetX = 0;
+    if (!_isInfiniteLoop && !_layout.itemHorizontalCenter && indexSection.index == _numberOfItems - 1) {
+        offsetX = leftEdge + itemWidth*(indexSection.index + indexSection.section*_numberOfItems) - (width - itemWidth) -  layout.minimumInteritemSpacing + rightEdge;
+    }else {
+        offsetX = leftEdge + itemWidth*(indexSection.index + indexSection.section*_numberOfItems) - layout.minimumInteritemSpacing/2 - (width - itemWidth)/2;
+    }
+    return MAX(offsetX, 0);
+}
+
+- (void)resetPagerViewAtIndex:(NSInteger)index {
+    if (_didLayout && _firstScrollIndex >= 0) {
+        index = _firstScrollIndex;
+        _firstScrollIndex = -1;
+    }
+    if (index < 0) {
+        return;
+    }
+    if (index >= _numberOfItems) {
+        index = 0;
+    }
+    [self scrollToItemAtIndexSection:TYMakeIndexSection(index, _isInfiniteLoop ? kPagerViewMaxSectionCount/3 : 0) animate:NO];
+    if (!_isInfiniteLoop && _indexSection.index < 0) {
+        [self scrollViewDidScroll:_collectionView];
+    }
+}
+
+- (void)recyclePagerViewIfNeed {
+    if (!_isInfiniteLoop) {
+        return;
+    }
+    if (_indexSection.section > kPagerViewMaxSectionCount - kPagerViewMinSectionCount || _indexSection.section < kPagerViewMinSectionCount) {
+        [self resetPagerViewAtIndex:_indexSection.index];
+    }
+}
+
+#pragma mark - UICollectionViewDataSource
+
+- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
+    return _isInfiniteLoop ? kPagerViewMaxSectionCount : 1;
+}
+
+- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
+    _numberOfItems = [_dataSource numberOfItemsInPagerView:self];
+    return _numberOfItems;
+}
+
+- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
+    _dequeueSection = indexPath.section;
+    if (_dataSourceFlags.cellForItemAtIndex) {
+       return [_dataSource pagerView:self cellForItemAtIndex:indexPath.row];
+    }
+    NSAssert(NO, @"pagerView cellForItemAtIndex: is nil!");
+    return nil;
+}
+
+#pragma mark - UICollectionViewDelegateFlowLayout
+
+- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
+    if (!_isInfiniteLoop) {
+        return _layout.onlyOneSectionInset;
+    }
+    if (section == 0 ) {
+        return _layout.firstSectionInset;
+    }else if (section == kPagerViewMaxSectionCount -1) {
+        return _layout.lastSectionInset;
+    }
+    return _layout.middleSectionInset;
+}
+
+- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
+    UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
+    if ([_delegate respondsToSelector:@selector(pagerView:didSelectedItemCell:atIndex:)]) {
+        [_delegate pagerView:self didSelectedItemCell:cell atIndex:indexPath.item];
+    }
+    if ([_delegate respondsToSelector:@selector(pagerView:didSelectedItemCell:atIndexSection:)]) {
+        [_delegate pagerView:self didSelectedItemCell:cell atIndexSection:TYMakeIndexSection(indexPath.item, indexPath.section)];
+    }
+}
+
+#pragma mark - UIScrollViewDelegate
+
+- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
+    if (!_didLayout) {
+        return;
+    }
+    TYIndexSection newIndexSection =  [self caculateIndexSectionWithOffsetX:scrollView.contentOffset.x];
+    if (_numberOfItems <= 0 || ![self isValidIndexSection:newIndexSection]) {
+        NSLog(@"inVlaidIndexSection:(%ld,%ld)!",(long)newIndexSection.index,(long)newIndexSection.section);
+        return;
+    }
+    TYIndexSection indexSection = _indexSection;
+    _indexSection = newIndexSection;
+    
+    if (_delegateFlags.pagerViewDidScroll) {
+        [_delegate pagerViewDidScroll:self];
+    }
+    
+    if (_delegateFlags.didScrollFromIndexToNewIndex && !TYEqualIndexSection(_indexSection, indexSection)) {
+        //NSLog(@"curIndex %ld",(long)_indexSection.index);
+        [_delegate pagerView:self didScrollFromIndex:MAX(indexSection.index, 0) toIndex:_indexSection.index];
+    }
+}
+
+- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
+    if (_autoScrollInterval > 0) {
+        [self removeTimer];
+    }
+    _beginDragIndexSection = [self caculateIndexSectionWithOffsetX:scrollView.contentOffset.x];
+    if ([_delegate respondsToSelector:@selector(pagerViewWillBeginDragging:)]) {
+        [_delegate pagerViewWillBeginDragging:self];
+    }
+}
+
+- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
+    if (fabs(velocity.x) < 0.35 || !TYEqualIndexSection(_beginDragIndexSection, _indexSection)) {
+        targetContentOffset->x = [self caculateOffsetXAtIndexSection:_indexSection];
+        return;
+    }
+    TYPagerScrollDirection direction = TYPagerScrollDirectionRight;
+    if ((scrollView.contentOffset.x < 0 && targetContentOffset->x <= 0) || (targetContentOffset->x < scrollView.contentOffset.x && scrollView.contentOffset.x < scrollView.contentSize.width - scrollView.frame.size.width)) {
+        direction = TYPagerScrollDirectionLeft;
+    }
+    TYIndexSection indexSection = [self nearlyIndexPathForIndexSection:_indexSection direction:direction];
+    targetContentOffset->x = [self caculateOffsetXAtIndexSection:indexSection];
+}
+
+- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
+    if (_autoScrollInterval > 0) {
+        [self addTimer];
+    }
+    if ([_delegate respondsToSelector:@selector(pagerViewDidEndDragging:willDecelerate:)]) {
+        [_delegate pagerViewDidEndDragging:self willDecelerate:decelerate];
+    }
+}
+
+- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView {
+    if ([_delegate respondsToSelector:@selector(pagerViewWillBeginDecelerating:)]) {
+        [_delegate pagerViewWillBeginDecelerating:self];
+    }
+}
+
+- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
+    [self recyclePagerViewIfNeed];
+    if ([_delegate respondsToSelector:@selector(pagerViewDidEndDecelerating:)]) {
+        [_delegate pagerViewDidEndDecelerating:self];
+    }
+}
+
+- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
+    [self recyclePagerViewIfNeed];
+    if ([_delegate respondsToSelector:@selector(pagerViewDidEndScrollingAnimation:)]) {
+        [_delegate pagerViewDidEndScrollingAnimation:self];
+    }
+}
+
+#pragma mark - TYCyclePagerTransformLayoutDelegate
+
+- (void)pagerViewTransformLayout:(TYCyclePagerTransformLayout *)pagerViewTransformLayout initializeTransformAttributes:(UICollectionViewLayoutAttributes *)attributes {
+    if (_delegateFlags.initializeTransformAttributes) {
+        [_delegate pagerView:self initializeTransformAttributes:attributes];
+    }
+}
+
+- (void)pagerViewTransformLayout:(TYCyclePagerTransformLayout *)pagerViewTransformLayout applyTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes {
+    if (_delegateFlags.applyTransformToAttributes) {
+        [_delegate pagerView:self applyTransformToAttributes:attributes];
+    }
+}
+
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    BOOL needUpdateLayout = !CGRectEqualToRect(_collectionView.frame, self.bounds);
+    _collectionView.frame = self.bounds;
+    if ((_indexSection.section < 0 || needUpdateLayout) && (_numberOfItems > 0 || _didReloadData)) {
+        _didLayout = YES;
+        [self setNeedUpdateLayout];
+    }
+}
+
+- (void)dealloc {
+    ((TYCyclePagerTransformLayout *)_collectionView.collectionViewLayout).delegate = nil;
+    _collectionView.delegate = nil;
+    _collectionView.dataSource = nil;
+}
+
+@end
+
+

+ 47 - 0
Asteria/Fuction/Goods/V/Banner/TYCyclePagerView/TYPageControl.h

@@ -0,0 +1,47 @@
+//
+//  TYPageControl.h
+//  TYCyclePagerViewDemo
+//
+//  Created by tany on 2017/6/20.
+//  Copyright © 2017年 tany. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface TYPageControl : UIControl
+
+@property (nonatomic, assign) NSInteger numberOfPages;          // default is 0
+@property (nonatomic, assign) NSInteger currentPage;            // default is 0. value pinned to 0..numberOfPages-1
+
+@property (nonatomic, assign) BOOL hidesForSinglePage;          // hide the the indicator if there is only one page. default is NO
+
+@property (nonatomic, assign) CGFloat pageIndicatorSpaing;
+@property (nonatomic, assign) UIEdgeInsets contentInset; // center will ignore this
+@property (nonatomic, assign ,readonly) CGSize contentSize; // real content size
+
+// override super 
+//@property (nonatomic, assign) UIControlContentVerticalAlignment contentVerticalAlignment;     // how to position content vertically inside control. default is center
+//@property (nonatomic, assign) UIControlContentHorizontalAlignment contentHorizontalAlignment; // how to position content hozontally inside control. default is center
+
+// indicatorTint color
+@property (nullable, nonatomic,strong) UIColor *pageIndicatorTintColor;
+@property (nullable, nonatomic,strong) UIColor *currentPageIndicatorTintColor;
+
+// indicator image
+@property (nullable, nonatomic,strong) UIImage *pageIndicatorImage;
+@property (nullable, nonatomic,strong) UIImage *currentPageIndicatorImage;
+
+@property (nonatomic, assign) UIViewContentMode indicatorImageContentMode; // default is UIViewContentModeCenter
+
+@property (nonatomic, assign) CGSize pageIndicatorSize; // indicator size
+@property (nonatomic, assign) CGSize currentPageIndicatorSize; // default pageIndicatorSize
+
+@property (nonatomic, assign) CGFloat animateDuring; // default 0.3
+
+- (void)setCurrentPage:(NSInteger)currentPage animate:(BOOL)animate;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 285 - 0
Asteria/Fuction/Goods/V/Banner/TYCyclePagerView/TYPageControl.m

@@ -0,0 +1,285 @@
+//
+//  TYPageControl.m
+//  TYCyclePagerViewDemo
+//
+//  Created by tany on 2017/6/20.
+//  Copyright © 2017年 tany. All rights reserved.
+//
+
+#import "TYPageControl.h"
+
+@interface TYPageControl ()
+// UI
+@property (nonatomic, strong) NSArray<UIImageView *> *indicatorViews;
+
+// Data
+@property (nonatomic, assign) BOOL forceUpdate;
+
+@end
+
+@implementation TYPageControl
+
+#pragma mark - life cycle
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    if (self = [super initWithFrame:frame]) {
+        [self configurePropertys];
+    }
+    return self;
+}
+
+- (instancetype)initWithCoder:(NSCoder *)aDecoder {
+    if (self = [super initWithCoder:aDecoder]) {
+        [self configurePropertys];
+    }
+    return self;
+}
+
+- (void)configurePropertys {
+    self.userInteractionEnabled = NO;
+    _forceUpdate = NO;
+    _animateDuring = 0.3;
+    _pageIndicatorSpaing = 10;
+    _indicatorImageContentMode = UIViewContentModeCenter;
+    _pageIndicatorSize = CGSizeMake(6,6);
+    _currentPageIndicatorSize = _pageIndicatorSize;
+    _pageIndicatorTintColor =  [TT_DarkmodeTool TT_NormalWhite];
+    _currentPageIndicatorTintColor = [UIColor colorWithRed:128/255. green:128/255. blue:128/255. alpha:1];
+}
+
+- (void)willMoveToSuperview:(UIView *)newSuperview {
+    [super willMoveToSuperview:newSuperview];
+    if (newSuperview) {
+        _forceUpdate = YES;
+        [self updateIndicatorViews];
+        _forceUpdate = NO;
+    }
+}
+
+#pragma mark - getter setter
+
+- (CGSize)contentSize {
+    CGFloat width = (_indicatorViews.count - 1) * (_pageIndicatorSize.width + _pageIndicatorSpaing) + _pageIndicatorSize.width + _contentInset.left +_contentInset.right;
+    CGFloat height = _currentPageIndicatorSize.height + _contentInset.top + _contentInset.bottom;
+    return CGSizeMake(width, height);
+}
+
+- (void)setNumberOfPages:(NSInteger)numberOfPages {
+    if (numberOfPages == _numberOfPages) {
+        return;
+    }
+    _numberOfPages = numberOfPages;
+    if (_currentPage >= numberOfPages) {
+        _currentPage = 0;
+    }
+    [self updateIndicatorViews];
+    if (_indicatorViews.count > 0) {
+        [self setNeedsLayout];
+    }
+}
+
+- (void)setCurrentPage:(NSInteger)currentPage {
+    if (_currentPage == currentPage || _indicatorViews.count <= currentPage) {
+        return;
+    }
+    _currentPage = currentPage;
+    if (!CGSizeEqualToSize(_currentPageIndicatorSize, _pageIndicatorSize)) {
+        [self setNeedsLayout];
+    }
+    [self updateIndicatorViewsBehavior];
+    if (self.userInteractionEnabled) {
+        [self sendActionsForControlEvents:UIControlEventValueChanged];
+    }
+}
+
+- (void)setCurrentPage:(NSInteger)currentPage animate:(BOOL)animate {
+    if (animate) {
+        [UIView animateWithDuration:_animateDuring animations:^{
+            [self setCurrentPage:currentPage];
+        }];
+    }else {
+        [self setCurrentPage:currentPage];
+    }
+}
+
+- (void)setPageIndicatorImage:(UIImage *)pageIndicatorImage {
+    _pageIndicatorImage = pageIndicatorImage;
+    [self updateIndicatorViewsBehavior];
+}
+
+- (void)setCurrentPageIndicatorImage:(UIImage *)currentPageIndicatorImage {
+    _currentPageIndicatorImage = currentPageIndicatorImage;
+    [self updateIndicatorViewsBehavior];
+}
+
+- (void)setPageIndicatorTintColor:(UIColor *)pageIndicatorTintColor {
+    _pageIndicatorTintColor = pageIndicatorTintColor;
+    [self updateIndicatorViewsBehavior];
+}
+
+- (void)setCurrentPageIndicatorTintColor:(UIColor *)currentPageIndicatorTintColor {
+    _currentPageIndicatorTintColor = currentPageIndicatorTintColor;
+    [self updateIndicatorViewsBehavior];
+}
+
+- (void)setPageIndicatorSize:(CGSize)pageIndicatorSize {
+    if (CGSizeEqualToSize(_pageIndicatorSize, pageIndicatorSize)) {
+        return;
+    }
+    _pageIndicatorSize = pageIndicatorSize;
+    if (CGSizeEqualToSize(_currentPageIndicatorSize, CGSizeZero) || (_currentPageIndicatorSize.width < pageIndicatorSize.width && _currentPageIndicatorSize.height < pageIndicatorSize.height)) {
+        _currentPageIndicatorSize = pageIndicatorSize;
+    }
+    if (_indicatorViews.count > 0) {
+        [self setNeedsLayout];
+    }
+}
+
+- (void)setPageIndicatorSpaing:(CGFloat)pageIndicatorSpaing {
+    _pageIndicatorSpaing = pageIndicatorSpaing;
+    if (_indicatorViews.count > 0) {
+        [self setNeedsLayout];
+    }
+}
+
+- (void)setCurrentPageIndicatorSize:(CGSize)currentPageIndicatorSize {
+    if (CGSizeEqualToSize(_currentPageIndicatorSize, currentPageIndicatorSize)) {
+        return;
+    }
+    _currentPageIndicatorSize = currentPageIndicatorSize;
+    if (_indicatorViews.count > 0) {
+        [self setNeedsLayout];
+    }
+}
+
+- (void)setContentHorizontalAlignment:(UIControlContentHorizontalAlignment)contentHorizontalAlignment {
+    [super setContentHorizontalAlignment:contentHorizontalAlignment];
+    if (_indicatorViews.count > 0) {
+        [self setNeedsLayout];
+    }
+}
+
+- (void)setContentVerticalAlignment:(UIControlContentVerticalAlignment)contentVerticalAlignment {
+    [super setContentVerticalAlignment:contentVerticalAlignment];
+    if (_indicatorViews.count > 0) {
+        [self setNeedsLayout];
+    }
+}
+
+#pragma mark - update indicator
+
+- (void)updateIndicatorViews {
+    if (!self.superview && !_forceUpdate) {
+        return;
+    }
+    if (_indicatorViews.count == _numberOfPages) {
+        [self updateIndicatorViewsBehavior];
+        return;
+    }
+    NSMutableArray *indicatorViews = _indicatorViews ? [_indicatorViews mutableCopy] :[NSMutableArray array];
+    if (indicatorViews.count < _numberOfPages) {
+        for (NSInteger idx = indicatorViews.count; idx < _numberOfPages; ++idx) {
+            UIImageView *indicatorView = [[UIImageView alloc]init];
+            indicatorView.contentMode = _indicatorImageContentMode;
+            [self addSubview:indicatorView];
+            [indicatorViews addObject:indicatorView];
+        }
+    }else if (indicatorViews.count > _numberOfPages) {
+        for (NSInteger idx = indicatorViews.count - 1; idx >= _numberOfPages; --idx) {
+            UIImageView *indicatorView = indicatorViews[idx];
+            [indicatorView removeFromSuperview];
+            [indicatorViews removeObjectAtIndex:idx];
+        }
+    }
+    _indicatorViews = [indicatorViews copy];
+    [self updateIndicatorViewsBehavior];
+}
+
+- (void)updateIndicatorViewsBehavior {
+    if (_indicatorViews.count == 0 || (!self.superview && !_forceUpdate)) {
+        return;
+    }
+    if (_hidesForSinglePage && _indicatorViews.count == 1) {
+        UIImageView *indicatorView = _indicatorViews.lastObject;
+        indicatorView.hidden = YES;
+        return;
+    }
+    NSInteger index = 0;
+    for (UIImageView *indicatorView in _indicatorViews) {
+        if (_pageIndicatorImage) {
+            indicatorView.contentMode = _indicatorImageContentMode;
+            indicatorView.image = _currentPage == index ? _currentPageIndicatorImage : _pageIndicatorImage;
+        }else {
+            indicatorView.image = nil;
+            indicatorView.backgroundColor = _currentPage == index ? _currentPageIndicatorTintColor : _pageIndicatorTintColor;
+        }
+        indicatorView.hidden = NO;
+        ++index;
+    }
+}
+
+#pragma mark - layout
+
+- (void)layoutIndicatorViews {
+    if (_indicatorViews.count == 0) {
+        return;
+    }
+    CGFloat orignX = 0;
+    CGFloat centerY = 0;
+    CGFloat pageIndicatorSpaing = _pageIndicatorSpaing;
+    switch (self.contentHorizontalAlignment) {
+        case UIControlContentHorizontalAlignmentCenter:
+            // ignore contentInset
+            orignX = (CGRectGetWidth(self.frame) - (_indicatorViews.count - 1) * (_pageIndicatorSize.width + _pageIndicatorSpaing) - _currentPageIndicatorSize.width)/2;
+            break;
+        case UIControlContentHorizontalAlignmentLeft:
+            orignX = _contentInset.left;
+            break;
+        case UIControlContentHorizontalAlignmentRight:
+            orignX = CGRectGetWidth(self.frame) - ((_indicatorViews.count - 1) * (_pageIndicatorSize.width + _pageIndicatorSpaing) + _currentPageIndicatorSize.width) - _contentInset.right;
+            break;
+        case UIControlContentHorizontalAlignmentFill:
+            orignX = _contentInset.left;
+            if (_indicatorViews.count > 1) {
+                pageIndicatorSpaing = (CGRectGetWidth(self.frame) - _contentInset.left - _contentInset.right - _pageIndicatorSize.width - (_indicatorViews.count - 1) * _pageIndicatorSize.width)/(_indicatorViews.count - 1);
+            }
+            break;
+        default:
+            break;
+    }
+    switch (self.contentVerticalAlignment) {
+        case UIControlContentVerticalAlignmentCenter:
+            centerY = CGRectGetHeight(self.frame)/2;
+            break;
+        case UIControlContentVerticalAlignmentTop:
+            centerY = _contentInset.top + _currentPageIndicatorSize.height/2;
+            break;
+        case UIControlContentVerticalAlignmentBottom:
+            centerY = CGRectGetHeight(self.frame) - _currentPageIndicatorSize.height/2 - _contentInset.bottom;
+            break;
+        case UIControlContentVerticalAlignmentFill:
+            centerY = (CGRectGetHeight(self.frame) - _contentInset.top - _contentInset.bottom)/2 + _contentInset.top;
+            break;
+        default:
+            break;
+    }
+    NSInteger index = 0;
+    for (UIImageView *indicatorView in _indicatorViews) {
+        if (_pageIndicatorImage) {
+            indicatorView.layer.cornerRadius = 0;
+        }else {
+            indicatorView.layer.cornerRadius = _currentPage == index ? _currentPageIndicatorSize.height/2 : _pageIndicatorSize.height/2;
+        }
+        CGSize size = index == _currentPage ? _currentPageIndicatorSize : _pageIndicatorSize;
+        indicatorView.frame = CGRectMake(orignX, centerY - size.height/2, size.width, size.height);
+        orignX += size.width + pageIndicatorSpaing;
+        ++index;
+    }
+}
+
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    [self layoutIndicatorViews];
+}
+
+@end

+ 24 - 0
Asteria/Fuction/Goods/V/Banner/WKM_goodsBanner.h

@@ -0,0 +1,24 @@
+//
+//  WKM_goodsBanner.h
+//  westkissMob
+//
+//  Created by 王猛 on 2022/9/14.
+//
+
+#import "TT_BaseV.h"
+#import "TYCyclePagerView.h"
+#import "GoodsBannerCollectionViewCell.h"
+#import "GoodsVideoCollectionViewCell.h"
+#import "GoodsInformationM.h"
+NS_ASSUME_NONNULL_BEGIN
+
+@interface WKM_goodsBanner : TT_BaseV
+///对Banner 的操作
+@property (nonatomic , strong) TYCyclePagerView *BannerV;
+@property (nonatomic, strong) GoodsVideoCollectionViewCell *viedeoCell;
+
+
+- (void)xxx_dealloc;
+@end
+
+NS_ASSUME_NONNULL_END

+ 173 - 0
Asteria/Fuction/Goods/V/Banner/WKM_goodsBanner.m

@@ -0,0 +1,173 @@
+//
+//  WKM_goodsBanner.m
+//  westkissMob
+//
+//  Created by 王猛 on 2022/9/14.
+//
+
+#import "WKM_goodsBanner.h"
+#import "SelectVCollectionViewCell.h"
+static NSString *const GoodsVideoCollectionViewCellID = @"GoodsVideoCollectionViewCellId";
+static NSString *const GoodsBannerCollectionViewCellID = @"GoodsBannerCollectionViewCellId";
+static NSString *const SelectVCollectionViewCellID = @"SelectVCollectionViewCellID";
+
+@interface WKM_goodsBanner()
+<TYCyclePagerViewDelegate,
+TYCyclePagerViewDataSource,
+UICollectionViewDataSource,
+UICollectionViewDelegate>
+@property (nonatomic, strong) NSMutableArray *dataAry;
+@property (nonatomic, strong) UICollectionView *collectV;
+@end
+
+@implementation WKM_goodsBanner
+
+- (void)tt_setupViews{
+    [self addSubview:self.BannerV];
+    [self addSubview:self.collectV];
+    
+    [self.BannerV mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.left.right.top.mas_equalTo(0);
+        make.width.height.mas_equalTo(KScreenWidth);
+    }];
+    [self.collectV mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.left.mas_equalTo(10);
+        make.right.mas_equalTo(0);
+        make.top.equalTo(self.BannerV.mas_bottom).offset(10);
+        make.height.mas_equalTo(112);
+    }];
+}
+
+-(void)tt_confignewdata:(id)data{
+    GoodsInformationM *model = (GoodsInformationM *)data;
+    NSMutableArray *imgArry =[NSMutableArray arrayWithArray:model.imgarr];
+    NSMutableArray *modelAry = [[NSMutableArray alloc]init];
+    for (int i = 0; i< imgArry.count; i++) {
+        GoodsBannerModel *model =  [GoodsBannerModel xxx_loadWithModel:imgArry[i]];
+        [modelAry addObject:model];
+    }
+    
+    self.dataAry = [NSMutableArray arrayWithArray:modelAry];
+    [self.BannerV reloadData];
+}
+
+
+- (NSInteger)numberOfItemsInPagerView:(TYCyclePagerView *)pageView {
+    return self.dataAry.count;
+}
+- (UICollectionViewCell *)pagerView:(TYCyclePagerView *)pagerView cellForItemAtIndex:(NSInteger)index{
+    GoodsBannerModel *model = self.dataAry[index];
+    if (model.cellType == CellContentTypeVideo) {
+        GoodsVideoCollectionViewCell *cell = [pagerView dequeueReusableCellWithReuseIdentifier:GoodsVideoCollectionViewCellID forIndex:index];
+        cell.model = model;
+        self.viedeoCell = cell;
+        
+        return cell;
+    }else{
+        GoodsBannerCollectionViewCell *cell = [pagerView dequeueReusableCellWithReuseIdentifier:GoodsBannerCollectionViewCellID forIndex:index];
+        cell.model = self.dataAry[index];
+        return cell;
+    }
+}
+
+- (TYCyclePagerViewLayout *)layoutForPagerView:(TYCyclePagerView *)pageView{
+    TYCyclePagerViewLayout *layout = [[TYCyclePagerViewLayout alloc]init];
+    layout.itemSize = CGSizeMake(KScreenWidth, KScreenWidth);
+    layout.itemSpacing = 0;
+    layout.layoutType = TYCyclePagerTransformLayoutNormal;
+    layout.itemHorizontalCenter = YES;
+    return layout;
+}
+#pragma mark - **************** TYCyclePagerViewDelegate ****************
+
+- (void)pagerView:(TYCyclePagerView *)pageView didSelectedItemCell:(__kindof UICollectionViewCell *)cell atIndex:(NSInteger)index {
+    GoodsBannerModel *model = self.dataAry[index];
+    NSMutableArray *imgAry = [[NSMutableArray alloc]init];
+    for (GoodsBannerModel *tmpModel in self.dataAry) {
+        if (tmpModel.cellType == CellContentTypeImg){
+            [imgAry addObject:tmpModel];
+        }
+    }
+    if (model.cellType == CellContentTypeImg) {
+        if (self.ViewtapClose) {
+            self.ViewtapClose(index-(self.dataAry.count-imgAry.count), imgAry);
+        }
+    }
+}
+
+- (void)pagerView:(TYCyclePagerView *)pageView didScrollFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex{
+    [self.collectV selectItemAtIndexPath:[NSIndexPath indexPathForRow:toIndex inSection:0] animated:YES scrollPosition:UICollectionViewScrollPositionNone];
+
+}
+
+- (TYCyclePagerView *)BannerV {
+    if (!_BannerV) {
+        _BannerV = [[TYCyclePagerView alloc]init];
+        _BannerV.isInfiniteLoop = YES;
+        _BannerV.dataSource = self;
+        _BannerV.delegate = self;
+        [_BannerV registerClass:[GoodsVideoCollectionViewCell class] forCellWithReuseIdentifier:GoodsVideoCollectionViewCellID];
+        [_BannerV registerClass:[GoodsBannerCollectionViewCell class] forCellWithReuseIdentifier:GoodsBannerCollectionViewCellID];
+
+    }
+    return _BannerV;
+}
+
+-(NSMutableArray *)dataAry{
+    if (!_dataAry) {
+        _dataAry = [[NSMutableArray alloc]init];
+    }
+    return _dataAry;
+}
+
+
+- (void)xxx_dealloc{
+    if(self.viedeoCell){
+        [self.viedeoCell playerDealloc];
+    }
+}
+
+- (UICollectionView *)collectV {
+    if (!_collectV) {
+        UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
+        layout.sectionInset = UIEdgeInsetsMake(10, 0, 10, 0);
+        layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
+        layout.itemSize = CGSizeMake(112, 112);
+        UICollectionView *collV = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
+        collV.alwaysBounceHorizontal = true;
+        collV.delegate = self;
+        collV.dataSource = self;
+        collV.showsHorizontalScrollIndicator = false;
+        [collV registerClass:[SelectVCollectionViewCell class] forCellWithReuseIdentifier:GoodsVideoCollectionViewCellID];
+        _collectV = collV;
+    }
+    return _collectV;
+}
+
+#pragma mark - **************** UICollectionViewDataSource ****************
+
+- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
+    return 1;
+}
+
+- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
+    return self.dataAry.count;
+}
+
+- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
+    GoodsBannerModel *model = self.dataAry[indexPath.row];
+    SelectVCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:SelectVCollectionViewCellID forIndexPath:indexPath];
+    [cell.imgV sd_setImageWithURL:[NSURL URLWithString:model.url] placeholderImage:UIImageDefaultImg_SD];
+    return cell;
+}
+
+- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
+    [self.BannerV scrollToItemAtIndex:indexPath.row animate:YES];
+    [collectionView selectItemAtIndexPath:indexPath animated:YES scrollPosition:UICollectionViewScrollPositionNone];
+    
+}
+
+
+
+
+@end

+ 44 - 0
Asteria/Fuction/Goods/V/Banner/ZFPlayer/AVPlayer/ZFAVPlayerManager.h

@@ -0,0 +1,44 @@
+//
+//  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;
+
+@property (nonatomic, strong, readonly) AVPlayerLayer *avPlayerLayer;
+
+@end

+ 527 - 0
Asteria/Fuction/Goods/V/Banner/ZFPlayer/AVPlayer/ZFAVPlayerManager.m

@@ -0,0 +1,527 @@
+//
+//  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/ZFKVOController.h>
+#import <ZFPlayer/ZFPlayerConst.h>
+#import <ZFPlayer/ZFReachabilityManager.h>
+#else
+#import "ZFKVOController.h"
+#import "ZFPlayerConst.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 : UIView
+
+@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;
+}
+
+- (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;
+@property (nonatomic, strong) AVAssetImageGenerator *imageGenerator;
+
+@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];
+    [_playerItem cancelPendingSeeks];
+    [_asset cancelLoading];
+    [self.player removeTimeObserver:_timeObserver];
+    [self.player replaceCurrentItemWithPlayerItem:nil];
+    self.presentationSize = CGSizeZero;
+    _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)
+        if (finished) {
+            [self play];
+        }
+    }];
+}
+
+- (void)seekToTime:(NSTimeInterval)time completionHandler:(void (^ __nullable)(BOOL finished))completionHandler {
+    if (self.totalTime > 0) {
+        [_player.currentItem cancelPendingSeeks];
+        int32_t timeScale = _player.currentItem.asset.duration.timescale;
+        CMTime seekTime = CMTimeMakeWithSeconds(time, timeScale);
+        [_player seekToTime:seekTime toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero completionHandler:completionHandler];
+    } else {
+        self.seekTime = time;
+    }
+}
+
+- (UIImage *)thumbnailImageAtCurrentTime {
+    CMTime expectedTime = self.playerItem.currentTime;
+    CGImageRef cgImage = NULL;
+    
+    self.imageGenerator.requestedTimeToleranceBefore = kCMTimeZero;
+    self.imageGenerator.requestedTimeToleranceAfter = kCMTimeZero;
+    cgImage = [self.imageGenerator copyCGImageAtTime:expectedTime actualTime:NULL error:NULL];
+
+    if (!cgImage) {
+        self.imageGenerator.requestedTimeToleranceBefore = kCMTimePositiveInfinity;
+        self.imageGenerator.requestedTimeToleranceAfter = kCMTimePositiveInfinity;
+        cgImage = [self.imageGenerator copyCGImageAtTime:expectedTime actualTime:NULL error:NULL];
+    }
+    
+    UIImage *image = [UIImage imageWithCGImage:cgImage];
+    return image;
+}
+
+- (void)thumbnailImageAtCurrentTime:(void(^)(UIImage *))handler {
+    CMTime expectedTime = self.playerItem.currentTime;
+    [self.imageGenerator generateCGImagesAsynchronouslyForTimes:@[[NSValue valueWithCMTime:expectedTime]] completionHandler:^(CMTime requestedTime, CGImageRef  _Nullable image, CMTime actualTime, AVAssetImageGeneratorResult result, NSError * _Nullable error) {
+        if (handler) {
+            UIImage *finalImage = [UIImage imageWithCGImage:image];
+            handler(finalImage);
+        }
+    }];
+}
+
+#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];
+    _imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:_asset];
+
+    [self enableAudioTracks:YES inPlayerItem:_playerItem];
+    
+    ZFPlayerPresentView *presentView = [[ZFPlayerPresentView alloc] init];
+    presentView.player = _player;
+    self.view.playerView = presentView;
+
+    self.scalingMode = _scalingMode;
+    if (@available(iOS 9.0, *)) {
+        _playerItem.canUseNetworkResourcesForLiveStreamingWhilePaused = NO;
+    }
+    if (@available(iOS 10.0, *)) {
+        _playerItem.preferredForwardBufferDuration = 5;
+        /// 关闭AVPlayer默认的缓冲延迟播放策略,提高首屏播放速度
+        _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 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) {
+                    if (self.shouldAutoPlay) [self pause];
+                    @weakify(self)
+                    [self seekToTime:self.seekTime completionHandler:^(BOOL finished) {
+                        @strongify(self)
+                        if (finished) {
+                            if (self.shouldAutoPlay) [self play];
+                        }
+                    }];
+                    self.seekTime = 0;
+                } else {
+                    if (self.shouldAutoPlay && self.isPlaying) [self play];
+                }
+                self.player.muted = self.muted;
+                NSArray *loadedRanges = self.playerItem.seekableTimeRanges;
+                if (loadedRanges.count > 0) {
+                    if (self.playerPlayTimeChanged) self.playerPlayTimeChanged(self, self.currentTime, self.totalTime);
+                }
+            } else if (self.player.currentItem.status == AVPlayerItemStatusFailed) {
+                self.playState = ZFPlayerPlayStatePlayFailed;
+                self->_isPlaying = NO;
+                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;
+        } else {
+            [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
+        }
+    });
+}
+
+#pragma mark - getter
+
+- (ZFPlayerView *)view {
+    if (!_view) {
+        ZFPlayerView *view = [[ZFPlayerView alloc] init];
+        _view = view;
+    }
+    return _view;
+}
+
+- (AVPlayerLayer *)avPlayerLayer {
+    ZFPlayerPresentView *view = (ZFPlayerPresentView *)self.view.playerView;
+    return [view avLayer];
+}
+
+- (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.playerView;
+    self.view.scalingMode = scalingMode;
+    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;
+}
+
+- (void)setPresentationSize:(CGSize)presentationSize {
+    _presentationSize = presentationSize;
+    self.view.presentationSize = presentationSize;
+    if (self.presentationSizeChanged) {
+        self.presentationSizeChanged(self, self.presentationSize);
+    }
+}
+
+@end
+
+#pragma clang diagnostic pop

+ 127 - 0
Asteria/Fuction/Goods/V/Banner/ZFPlayer/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

+ 411 - 0
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/UIImageView+ZFCache.m

@@ -0,0 +1,411 @@
+//
+//  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, ^{
+            [[NSFileManager defaultManager] removeItemAtPath:directoryPath error:nil];
+            [[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
Asteria/Fuction/Goods/V/Banner/ZFPlayer/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
Asteria/Fuction/Goods/V/Banner/ZFPlayer/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

+ 120 - 0
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFLandScapeControlView.h

@@ -0,0 +1,120 @@
+//
+//  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;
+
+/// 全屏模式
+@property (nonatomic, assign) ZFFullScreenMode fullScreenMode;
+
+/// 重置控制层
+- (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

+ 462 - 0
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFLandScapeControlView.m

@@ -0,0 +1,462 @@
+//
+//  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/ZFPlayerConst.h>
+#else
+#import "ZFPlayerConst.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;
+        self.lockBtn.zf_left = iPhoneX ? -82: -47;
+    } else {
+        self.lockBtn.zf_left = iPhoneX ? 50: 18;
+        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 - setter
+
+- (void)setFullScreenMode:(ZFFullScreenMode)fullScreenMode {
+    _fullScreenMode = fullScreenMode;
+    self.player.orientationObserver.fullScreenMode = fullScreenMode;
+    self.lockBtn.hidden = fullScreenMode == ZFFullScreenModePortrait;
+}
+
+#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
Asteria/Fuction/Goods/V/Banner/ZFPlayer/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
Asteria/Fuction/Goods/V/Banner/ZFPlayer/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
Asteria/Fuction/Goods/V/Banner/ZFPlayer/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

+ 167 - 0
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFNetworkSpeedMonitor.m

@@ -0,0 +1,167 @@
+//
+//  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"];
+        NSMutableDictionary *userInfo = @{}.mutableCopy;
+        userInfo[ZFNetworkSpeedNotificationKey] = _downloadNetworkSpeed;
+        
+        [[NSNotificationCenter defaultCenter] postNotificationName:ZFDownloadNetworkSpeedNotificationKey object:nil userInfo:userInfo];
+        ZFPlayerLog(@"downloadNetworkSpeed : %@",_downloadNetworkSpeed);
+    }
+    
+    _iBytes = iBytes;
+    
+    if (_oBytes != 0) {
+        _uploadNetworkSpeed = [[self stringWithbytes:oBytes - _oBytes] stringByAppendingString:@"/s"];
+        NSMutableDictionary *userInfo = @{}.mutableCopy;
+        userInfo[ZFNetworkSpeedNotificationKey] = _uploadNetworkSpeed;
+        
+        [[NSNotificationCenter defaultCenter] postNotificationName:ZFUploadNetworkSpeedNotificationKey object:nil userInfo:userInfo];
+        ZFPlayerLog(@"uploadNetworkSpeed :%@",_uploadNetworkSpeed);
+    }
+    
+    _oBytes = oBytes;
+}
+
+@end

二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_back_full@2x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_back_full@3x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_bottom_shadow.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_brightness_high@2x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_brightness_high@3x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_brightness_low@2x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_brightness_low@3x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_close@2x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_close@3x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_closeWatch@2x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_closeWatch@3x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_fast_backward@2x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_fast_backward@3x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_fast_forward@2x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_fast_forward@3x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_fullscreen@2x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_fullscreen@3x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_lock-nor@2x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_lock-nor@3x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_muted@2x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_muted@3x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_next@2x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_next@3x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_pause@2x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_pause@3x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_play@2x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_play@3x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_shrinkscreen@2x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_shrinkscreen@3x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_slider.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_slider@2x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_slider@3x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_top_shadow.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_unlock-nor@2x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_unlock-nor@3x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_volume_high@2x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_volume_high@3x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_volume_low@2x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/ZFPlayer_volume_low@3x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/new_allPause_44x44_@2x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/new_allPause_44x44_@3x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/new_allPlay_44x44_@2x.png


二进制
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayer.bundle/new_allPlay_44x44_@3x.png


+ 151 - 0
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayerControlView.h

@@ -0,0 +1,151 @@
+//
+//  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;
+
+/// 如果是暂停状态,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;
+
+/// 全屏模式
+@property (nonatomic, assign) ZFFullScreenMode fullScreenMode;
+
+/**
+ 设置标题、封面、全屏模式
+
+ @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)showFullScreen
+
+/**
+ 重置控制层
+ */
+- (void)resetControlView;
+
+@end

+ 836 - 0
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPlayerControlView.m

@@ -0,0 +1,836 @@
+//
+//  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/ZFPlayerConst.h>
+#else
+#import "ZFPlayerConst.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, 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];
+    /// 这里直接设置播放器视图里的coverImageView
+    [self.player.currentPlayerManager.view.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) {
+            if (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];
+    self.bgImgView.frame = player.currentPlayerManager.view.bounds;
+    self.bgImgView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+    self.effectView.frame = self.bgImgView.bounds;
+}
+
+- (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;
+    }
+}
+
+- (void)setFullScreenMode:(ZFFullScreenMode)fullScreenMode {
+    _fullScreenMode = fullScreenMode;
+    self.portraitControlView.fullScreenMode = fullScreenMode;
+    self.landScapeControlView.fullScreenMode = fullScreenMode;
+    self.player.orientationObserver.fullScreenMode = fullScreenMode;
+}
+
+#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:@"Loading Failed, Click Retry" 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;
+}
+
+- (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

+ 116 - 0
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPortraitControlView.h

@@ -0,0 +1,116 @@
+//
+//  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
+
+#define DCStatusBarH ([UIApplication sharedApplication].statusBarFrame.size.height)
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface ZFPortraitControlView : UIView
+
+/// 底部工具栏
+@property (nonatomic, strong, readonly) UIView *bottomToolView;
+
+/// 顶部工具栏
+@property (nonatomic, strong, readonly) UIView *topToolView;
+
+/// 播放或暂停按钮
+@property (nonatomic, strong, readonly) UIButton *backBtn;
+
+/// 标题
+@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) 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;
+
+/// 全屏模式
+@property (nonatomic, assign) ZFFullScreenMode fullScreenMode;
+
+/// 重置控制层
+- (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

+ 396 - 0
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFPortraitControlView.m

@@ -0,0 +1,396 @@
+//
+//  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/ZFPlayerConst.h>
+#else
+#import "ZFPlayerConst.h"
+#endif
+
+@interface ZFPortraitControlView () <ZFSliderViewDelegate>
+/// 底部工具栏
+@property (nonatomic, strong) UIView *bottomToolView;
+/// 顶部工具栏
+@property (nonatomic, strong) UIView *topToolView;
+/// 返回按钮
+@property (nonatomic, strong) UIButton *backBtn;
+/// 标题
+@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.backBtn];
+        [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 = DCStatusBarH + 40;
+    self.topToolView.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    
+//    min_x = 15;
+//    min_y = DCStatusBarH + 10;
+//    min_w = min_view_w - min_x - 15;
+//    min_h = 30;
+//    self.titleLabel.frame = CGRectMake(min_x, min_y, min_w, min_h);
+    
+    [_titleLabel mas_makeConstraints:^(MASConstraintMaker *make){
+        make.centerX.equalTo(self.topToolView);
+        make.top.equalTo(self.topToolView).offset(DCStatusBarH + 10);
+    }];
+
+    
+    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 - setter
+
+- (void)setFullScreenMode:(ZFFullScreenMode)fullScreenMode {
+    _fullScreenMode = fullScreenMode;
+    self.player.orientationObserver.fullScreenMode = fullScreenMode;
+}
+
+#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
Asteria/Fuction/Goods/V/Banner/ZFPlayer/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
Asteria/Fuction/Goods/V/Banner/ZFPlayer/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
Asteria/Fuction/Goods/V/Banner/ZFPlayer/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
Asteria/Fuction/Goods/V/Banner/ZFPlayer/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
Asteria/Fuction/Goods/V/Banner/ZFPlayer/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

+ 117 - 0
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFSpeedLoadingView.m

@@ -0,0 +1,117 @@
+//
+//  ZFSpeedLoadingView.m
+//  Pods-ZFPlayer_Example
+//
+//  Created by 紫枫 on 2018/6/27.
+//
+
+#import "ZFSpeedLoadingView.h"
+#import "ZFNetworkSpeedMonitor.h"
+#import "UIView+ZFFrame.h"
+
+@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
Asteria/Fuction/Goods/V/Banner/ZFPlayer/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
Asteria/Fuction/Goods/V/Banner/ZFPlayer/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
Asteria/Fuction/Goods/V/Banner/ZFPlayer/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

+ 162 - 0
Asteria/Fuction/Goods/V/Banner/ZFPlayer/ControlView/ZFVolumeBrightnessView.m

@@ -0,0 +1,162 @@
+//
+//  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"
+
+@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

+ 244 - 0
Asteria/Fuction/Goods/V/Banner/ZFPlayer/Core/UIScrollView+ZFPlayer.h

@@ -0,0 +1,244 @@
+//
+//  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
+};
+
+typedef NS_ENUM(NSInteger , ZFPlayerScrollViewScrollPosition) {
+    ZFPlayerScrollViewScrollPositionNone,
+    /// Apply to UITableView and UICollectionViewDirection is vertical scrolling.
+    ZFPlayerScrollViewScrollPositionTop,
+    ZFPlayerScrollViewScrollPositionCenteredVertically,
+    ZFPlayerScrollViewScrollPositionBottom,
+    
+    /// Only apply to UICollectionViewDirection is horizontal scrolling.
+    ZFPlayerScrollViewScrollPositionLeft,
+    ZFPlayerScrollViewScrollPositionCenteredHorizontally,
+    ZFPlayerScrollViewScrollPositionRight
+};
+
+@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 ZFPlayerScrollViewDirectionHorizontal,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 position.
+ 
+@param indexPath scroll the  indexPath.
+@param scrollPosition  scrollView scroll position.
+@param animated animate.
+@param completionHandler  Scroll completion callback.
+*/
+- (void)zf_scrollToRowAtIndexPath:(NSIndexPath *)indexPath
+                 atScrollPosition:(ZFPlayerScrollViewScrollPosition)scrollPosition
+                         animated:(BOOL)animated
+                completionHandler:(void (^ __nullable)(void))completionHandler;
+
+/**
+Scroll to indexPath with position.
+ 
+@param indexPath scroll the  indexPath.
+@param scrollPosition  scrollView scroll position.
+@param duration animate duration.
+@param completionHandler  Scroll completion callback.
+*/
+- (void)zf_scrollToRowAtIndexPath:(NSIndexPath *)indexPath
+                 atScrollPosition:(ZFPlayerScrollViewScrollPosition)scrollPosition
+                  animateDuration:(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.")));
+
+
+/// Scroll to indexPath position  `ZFPlayerScrollViewScrollPositionTop` with animations.
+- (void)zf_scrollToRowAtIndexPath:(NSIndexPath *)indexPath
+                completionHandler:(void (^ __nullable)(void))completionHandler __attribute__((deprecated("use `zf_scrollToRowAtIndexPath:atScrollPosition:animated:completionHandler:` instead.")));
+
+/// Scroll to indexPath position  `ZFPlayerScrollViewScrollPositionTop` with animations.
+- (void)zf_scrollToRowAtIndexPath:(NSIndexPath *)indexPath
+                         animated:(BOOL)animated
+                completionHandler:(void (^ __nullable)(void))completionHandler __attribute__((deprecated("use `zf_scrollToRowAtIndexPath:atScrollPosition:animated:completionHandler:` instead.")));
+
+/// Scroll to indexPath position  `ZFPlayerScrollViewScrollPositionTop` with animations.
+- (void)zf_scrollToRowAtIndexPath:(NSIndexPath *)indexPath
+              animateWithDuration:(NSTimeInterval)duration
+                completionHandler:(void (^ __nullable)(void))completionHandler __attribute__((deprecated("use `zf_scrollToRowAtIndexPath:atScrollPosition:animateDuration:completionHandler:` instead.")));
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 915 - 0
Asteria/Fuction/Goods/V/Banner/ZFPlayer/Core/UIScrollView+ZFPlayer.m

@@ -0,0 +1,915 @@
+//
+//  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 "ZFPlayerConst.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)
+
+#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;
+}
+
+/**
+Scroll to indexPath with position.
+ 
+@param indexPath scroll the  indexPath.
+@param scrollPosition  scrollView scroll position.
+@param animated animate.
+@param completionHandler  Scroll completion callback.
+*/
+- (void)zf_scrollToRowAtIndexPath:(NSIndexPath *)indexPath
+                 atScrollPosition:(ZFPlayerScrollViewScrollPosition)scrollPosition
+                         animated:(BOOL)animated
+                completionHandler:(void (^ __nullable)(void))completionHandler {
+    [self zf_scrollToRowAtIndexPath:indexPath atScrollPosition:scrollPosition animateDuration:animated ? 0.4 : 0.0 completionHandler:completionHandler];
+}
+
+- (void)zf_scrollToRowAtIndexPath:(NSIndexPath *)indexPath
+                 atScrollPosition:(ZFPlayerScrollViewScrollPosition)scrollPosition
+                  animateDuration:(NSTimeInterval)duration
+                completionHandler:(void (^ __nullable)(void))completionHandler {
+    BOOL animated = duration > 0.0;
+    if ([self _isTableView]) {
+        UITableView *tableView = (UITableView *)self;
+        UITableViewScrollPosition tableScrollPosition = UITableViewScrollPositionNone;
+        if (scrollPosition <= ZFPlayerScrollViewScrollPositionBottom) {
+            tableScrollPosition = (UITableViewScrollPosition)scrollPosition;
+        }
+        [tableView scrollToRowAtIndexPath:indexPath atScrollPosition:tableScrollPosition animated:animated];
+    } else if ([self _isCollectionView]) {
+        UICollectionView *collectionView = (UICollectionView *)self;
+        if (self.zf_scrollViewDirection == ZFPlayerScrollViewDirectionVertical) {
+            UICollectionViewScrollPosition collectionScrollPosition = UICollectionViewScrollPositionNone;
+            switch (scrollPosition) {
+                case ZFPlayerScrollViewScrollPositionNone:
+                    collectionScrollPosition = UICollectionViewScrollPositionNone;
+                    break;
+                case ZFPlayerScrollViewScrollPositionTop:
+                    collectionScrollPosition = UICollectionViewScrollPositionTop;
+                    break;
+                case ZFPlayerScrollViewScrollPositionCenteredVertically:
+                    collectionScrollPosition = UICollectionViewScrollPositionCenteredVertically;
+                    break;
+                case ZFPlayerScrollViewScrollPositionBottom:
+                    collectionScrollPosition = UICollectionViewScrollPositionBottom;
+                    break;
+                default:
+                    break;
+            }
+            [collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:collectionScrollPosition animated:animated];
+        } else if (self.zf_scrollViewDirection == ZFPlayerScrollViewDirectionHorizontal) {
+            UICollectionViewScrollPosition collectionScrollPosition = UICollectionViewScrollPositionNone;
+            switch (scrollPosition) {
+                case ZFPlayerScrollViewScrollPositionNone:
+                    collectionScrollPosition = UICollectionViewScrollPositionNone;
+                    break;
+                case ZFPlayerScrollViewScrollPositionLeft:
+                    collectionScrollPosition = UICollectionViewScrollPositionLeft;
+                    break;
+                case ZFPlayerScrollViewScrollPositionCenteredHorizontally:
+                    collectionScrollPosition = UICollectionViewScrollPositionCenteredHorizontally;
+                    break;
+                case ZFPlayerScrollViewScrollPositionRight:
+                    collectionScrollPosition = UICollectionViewScrollPositionRight;
+                    break;
+                default:
+                    break;
+            }
+            [collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:collectionScrollPosition 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 _findCorrectCellWhenScrollViewDirectionVertical:nil];
+        [self _scrollViewScrollingDirectionVertical];
+    } else {
+        [self _findCorrectCellWhenScrollViewDirectionHorizontal:nil];
+        [self _scrollViewScrollingDirectionHorizontal];
+    }
+}
+
+- (void)zf_scrollViewWillBeginDragging {
+    [self _scrollViewBeginDragging];
+}
+
+#pragma mark - private method
+
+- (void)_scrollViewDidStopScroll {
+    self.zf_scrollDirection = ZFPlayerScrollDirectionNone;
+    @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;
+
+    if (!self.zf_stopWhileNotVisible) {
+        /// If you have a cell that is playing, stop the traversal.
+        if (self.zf_playingIndexPath) {
+            NSIndexPath *finalIndexPath = self.zf_playingIndexPath;
+            if (self.zf_scrollViewDidScrollCallback) self.zf_scrollViewDidScrollCallback(finalIndexPath);
+            if (handler) handler(finalIndexPath);
+            self.zf_shouldPlayIndexPath = finalIndexPath;
+            return;
+        }
+    }
+    NSArray *visiableCells = nil;
+    NSIndexPath *indexPath = nil;
+    BOOL isLast = self.contentOffset.y + self.frame.size.height >= self.contentSize.height;
+    if ([self _isTableView]) {
+        UITableView *tableView = (UITableView *)self;
+        visiableCells = [tableView visibleCells];
+        // First visible cell indexPath
+        indexPath = tableView.indexPathsForVisibleRows.firstObject;
+        if ((self.contentOffset.y <= 0 || isLast) && (!self.zf_playingIndexPath || [indexPath compare:self.zf_playingIndexPath] == NSOrderedSame)) {
+            UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
+            UIView *playerView = [cell viewWithTag:self.zf_containerViewTag];
+            if (playerView && !playerView.hidden && playerView.alpha > 0.01) {
+                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 || isLast) && (!self.zf_playingIndexPath || [indexPath compare:self.zf_playingIndexPath] == NSOrderedSame)) {
+            UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
+            UIView *playerView = [cell viewWithTag:self.zf_containerViewTag];
+            if (playerView && !playerView.hidden && playerView.alpha > 0.01) {
+                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 || playerView.hidden || playerView.alpha <= 0.01) 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 (!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;
+    if (!self.zf_stopWhileNotVisible) {
+        /// If you have a cell that is playing, stop the traversal.
+        if (self.zf_playingIndexPath) {
+            NSIndexPath *finalIndexPath = self.zf_playingIndexPath;
+            if (self.zf_scrollViewDidScrollCallback) self.zf_scrollViewDidScrollCallback(finalIndexPath);
+            if (handler) handler(finalIndexPath);
+            self.zf_shouldPlayIndexPath = finalIndexPath;
+            return;
+        }
+    }
+    
+    NSArray *visiableCells = nil;
+    NSIndexPath *indexPath = nil;
+    BOOL isLast = self.contentOffset.x + self.frame.size.width >= self.contentSize.width;
+    if ([self _isTableView]) {
+        UITableView *tableView = (UITableView *)self;
+        visiableCells = [tableView visibleCells];
+        // First visible cell indexPath
+        indexPath = tableView.indexPathsForVisibleRows.firstObject;
+        if ((self.contentOffset.x <= 0 || isLast) && (!self.zf_playingIndexPath || [indexPath compare:self.zf_playingIndexPath] == NSOrderedSame)) {
+            UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
+            UIView *playerView = [cell viewWithTag:self.zf_containerViewTag];
+            if (playerView && !playerView.hidden && playerView.alpha > 0.01) {
+                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 || isLast) && (!self.zf_playingIndexPath || [indexPath compare:self.zf_playingIndexPath] == NSOrderedSame)) {
+            UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
+            UIView *playerView = [cell viewWithTag:self.zf_containerViewTag];
+            if (playerView && !playerView.hidden && playerView.alpha > 0.01) {
+                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 || playerView.hidden || playerView.alpha <= 0.01) 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 (!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 - 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 {
+    NSNumber *number = objc_getAssociatedObject(self, _cmd);
+    if (number) return number.boolValue;
+    self.zf_stopPlay = YES;
+    return YES;
+}
+
+- (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);
+}
+
+#pragma mark - method
+
+- (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 {
+    [self zf_scrollToRowAtIndexPath:indexPath atScrollPosition:ZFPlayerScrollViewScrollPositionTop animateDuration:duration completionHandler:completionHandler];
+}
+
+@end
+
+#pragma clang diagnostic pop

+ 120 - 0
Asteria/Fuction/Goods/V/Banner/ZFPlayer/Core/UIViewController+ZFPlayerRotation.m

@@ -0,0 +1,120 @@
+//
+//  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)initialize {
+    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 {
+    return [[self viewControllerRotation] shouldAutorotate];
+}
+
+// Which screen directions are supported.
+- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
+    return [[self viewControllerRotation] 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 viewControllerRotation] preferredInterfaceOrientationForPresentation];
+}
+
+//  Return ViewController which decide rotation,if selected in UITabBarController is UINavigationController,return topViewController
+- (UIViewController *)viewControllerRotation {
+    UIViewController *vc = self.viewControllers[self.selectedIndex];
+    if ([vc isKindOfClass:[UINavigationController class]]) {
+        UINavigationController *nav = (UINavigationController *)vc;
+        return nav.topViewController;
+    } else {
+        return vc;
+    }
+}
+
+
+@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
Asteria/Fuction/Goods/V/Banner/ZFPlayer/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
Asteria/Fuction/Goods/V/Banner/ZFPlayer/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
Asteria/Fuction/Goods/V/Banner/ZFPlayer/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

+ 130 - 0
Asteria/Fuction/Goods/V/Banner/ZFPlayer/Core/ZFKVOController.m

@@ -0,0 +1,130 @@
+//
+//  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, copy) NSString *keyPath;
+
+@end
+
+@implementation ZFKVOEntry
+
+@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 {
+    if (_target == nil) return;
+    
+    NSInteger indexEntry = [self indexEntryOfObserver:observer forKeyPath:keyPath];
+    if (indexEntry != NSNotFound) {
+        // duplicated register
+        NSLog(@"duplicated observer");
+    } else {
+        @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 {
+    if (_target == nil) return;
+    
+    NSInteger indexEntry = [self indexEntryOfObserver:observer forKeyPath:keyPath];
+    if (indexEntry == NSNotFound) {
+        // duplicated register
+        NSLog(@"duplicated observer");
+    } else {
+        [_observerArray removeObjectAtIndex:indexEntry];
+        @try {
+            [_target removeObserver:observer
+                            forKeyPath:keyPath];
+        } @catch (NSException *e) {
+            NSLog(@"ZFKVO: failed to remove observer for %@\n", keyPath);
+        }
+    }
+}
+
+- (void)safelyRemoveAllObservers {
+    if (_target == nil) return;
+    [_observerArray enumerateObjectsUsingBlock:^(ZFKVOEntry *entry, NSUInteger idx, BOOL *stop) {
+        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];
+}
+
+- (NSInteger)indexEntryOfObserver:(NSObject *)observer
+                   forKeyPath:(NSString *)keyPath {
+    __block NSInteger foundIndex = NSNotFound;
+    [_observerArray enumerateObjectsUsingBlock:^(ZFKVOEntry *entry, NSUInteger idx, BOOL *stop) {
+        if (entry.observer == observer &&
+            [entry.keyPath isEqualToString:keyPath]) {
+            foundIndex = idx;
+            *stop = YES;
+        }
+    }];
+    return foundIndex;
+}
+
+@end

+ 65 - 0
Asteria/Fuction/Goods/V/Banner/ZFPlayer/Core/ZFLandscapeViewController.h

@@ -0,0 +1,65 @@
+//
+//  ZFFullscreenViewController.h
+//  ZFPlayer
+//
+// Copyright (c) 2020年 任子丰 ( 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>
+@class ZFLandscapeViewController;
+
+NS_ASSUME_NONNULL_BEGIN
+
+@protocol ZFLandscapeViewControllerDelegate <NSObject>
+
+- (BOOL)ls_shouldAutorotate;
+- (void)ls_willRotateToOrientation:(UIInterfaceOrientation)orientation;
+- (void)ls_didRotateFromOrientation:(UIInterfaceOrientation)orientation;
+- (CGRect)ls_targetRect;
+
+@end
+
+@interface ZFLandscapeViewController : UIViewController
+
+@property (nonatomic, weak) UIView *contentView;
+
+@property (nonatomic, weak) UIView *containerView;
+
+@property (nonatomic, assign) CGRect targetRect;
+
+@property (nonatomic, weak, nullable) id<ZFLandscapeViewControllerDelegate> delegate;
+
+@property (nonatomic, readonly) BOOL isFullscreen;
+
+@property (nonatomic, getter=isRotating) BOOL rotating;
+
+@property (nonatomic, assign) BOOL disableAnimations;
+
+@property (nonatomic, assign) BOOL statusBarHidden;
+/// default is  UIStatusBarStyleLightContent.
+@property (nonatomic, assign) UIStatusBarStyle statusBarStyle;
+/// defalut is UIStatusBarAnimationSlide.
+@property (nonatomic, assign) UIStatusBarAnimation statusBarAnimation;
+
+@property (nonatomic, copy) void(^rotatingCompleted)(void);
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 136 - 0
Asteria/Fuction/Goods/V/Banner/ZFPlayer/Core/ZFLandscapeViewController.m

@@ -0,0 +1,136 @@
+//
+//  ZFFullScreenViewController.m
+//  ZFPlayer
+//
+// Copyright (c) 2020年 任子丰 ( 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 "ZFLandscapeViewController.h"
+
+@interface ZFLandscapeViewController ()
+
+@property (nonatomic, assign) UIInterfaceOrientation currentOrientation;
+
+@end
+
+@implementation ZFLandscapeViewController
+
+- (instancetype)init {
+    self = [super init];
+    if (self) {
+        _currentOrientation = UIInterfaceOrientationPortrait;
+        _statusBarStyle = UIStatusBarStyleLightContent;
+        _statusBarAnimation = UIStatusBarAnimationSlide;
+    }
+    return self;
+}
+
+- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
+    self.rotating = YES;
+    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
+    if (!UIDeviceOrientationIsValidInterfaceOrientation([UIDevice currentDevice].orientation)) {
+        return;
+    }
+    UIInterfaceOrientation newOrientation = (UIInterfaceOrientation)[UIDevice currentDevice].orientation;
+    UIInterfaceOrientation oldOrientation = _currentOrientation;
+    if (UIInterfaceOrientationIsLandscape(newOrientation)) {
+        if (self.contentView.superview != self.view) {
+            [self.view addSubview:self.contentView];
+        }
+    }
+    
+    if (oldOrientation == UIInterfaceOrientationPortrait) {
+        self.contentView.frame = [self.delegate ls_targetRect];
+        [self.contentView layoutIfNeeded];
+    }
+    self.currentOrientation = newOrientation;
+    
+    [self.delegate ls_willRotateToOrientation:self.currentOrientation];
+    BOOL isFullscreen = size.width > size.height;
+    [CATransaction begin];
+    [CATransaction setDisableActions:self.disableAnimations];
+    [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
+        if (isFullscreen) {
+            self.contentView.frame = CGRectMake(0, 0, size.width, size.height);
+        } else {
+            self.contentView.frame = [self.delegate ls_targetRect];
+        }
+        [self.contentView layoutIfNeeded];
+    } completion:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
+        [CATransaction commit];
+        [self.delegate ls_didRotateFromOrientation:self.currentOrientation];
+        if (!isFullscreen) {
+            self.contentView.frame = self.containerView.bounds;
+            [self.contentView layoutIfNeeded];
+        }
+        self.disableAnimations = NO;
+        self.rotating = NO;
+    }];
+}
+
+- (BOOL)isFullscreen {
+    return UIInterfaceOrientationIsLandscape(_currentOrientation);
+}
+
+- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
+    return UIInterfaceOrientationPortrait;
+}
+
+- (BOOL)shouldAutorotate {
+    return [self.delegate ls_shouldAutorotate];
+}
+
+- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
+    UIInterfaceOrientation currentOrientation = (UIInterfaceOrientation)[UIDevice currentDevice].orientation;
+    if (UIInterfaceOrientationIsLandscape(currentOrientation)) {
+        return UIInterfaceOrientationMaskLandscape;
+    }
+    return UIInterfaceOrientationMaskAll;
+}
+
+- (BOOL)prefersHomeIndicatorAutoHidden {
+    UIInterfaceOrientation currentOrientation = (UIInterfaceOrientation)[UIDevice currentDevice].orientation;
+    if (UIInterfaceOrientationIsLandscape(currentOrientation)) {
+        return YES;
+    }
+    return NO;
+}
+
+- (BOOL)prefersStatusBarHidden {
+    return self.statusBarHidden;
+}
+
+- (UIStatusBarStyle)preferredStatusBarStyle {
+    return self.statusBarStyle;
+}
+
+- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation {
+    return self.statusBarAnimation;
+}
+
+- (void)setRotating:(BOOL)rotating {
+    _rotating = rotating;
+    if (!rotating && self.rotatingCompleted) {
+        self.rotatingCompleted();
+    }
+}
+
+@end
+

+ 36 - 0
Asteria/Fuction/Goods/V/Banner/ZFPlayer/Core/ZFLandscapeWindow.h

@@ -0,0 +1,36 @@
+//
+//  ZFLandScaprWindow.h
+//  ZFPlayer
+//
+// Copyright (c) 2020年 任子丰 ( 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 "ZFLandscapeViewController.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface ZFLandscapeWindow : UIWindow
+
+@property (nonatomic, strong, readonly) ZFLandscapeViewController *landscapeViewController;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 0 - 0
Asteria/Fuction/Goods/V/Banner/ZFPlayer/Core/ZFLandscapeWindow.m


部分文件因为文件数量过多而无法显示