ZFSliderView.m 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. //
  2. // ZFSliderView.m
  3. // ZFPlayer
  4. //
  5. // Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
  6. //
  7. // Permission is hereby granted, free of charge, to any person obtaining a copy
  8. // of this software and associated documentation files (the "Software"), to deal
  9. // in the Software without restriction, including without limitation the rights
  10. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. // copies of the Software, and to permit persons to whom the Software is
  12. // furnished to do so, subject to the following conditions:
  13. //
  14. // The above copyright notice and this permission notice shall be included in
  15. // all copies or substantial portions of the Software.
  16. //
  17. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. // THE SOFTWARE.
  24. #import "ZFSliderView.h"
  25. #import "UIView+ZFFrame.h"
  26. /** 滑块的大小 */
  27. static const CGFloat kSliderBtnWH = 19.0;
  28. /** 进度的高度 */
  29. static const CGFloat kProgressH = 1.0;
  30. /** 拖动slider动画的时间*/
  31. static const CGFloat kAnimate = 0.3;
  32. @implementation ZFSliderButton
  33. // 重写此方法将按钮的点击范围扩大
  34. - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
  35. CGRect bounds = self.bounds;
  36. // 扩大点击区域
  37. bounds = CGRectInset(bounds, -20, -20);
  38. // 若点击的点在新的bounds里面。就返回yes
  39. return CGRectContainsPoint(bounds, point);
  40. }
  41. @end
  42. @interface ZFSliderView ()
  43. /** 进度背景 */
  44. @property (nonatomic, strong) UIImageView *bgProgressView;
  45. /** 缓存进度 */
  46. @property (nonatomic, strong) UIImageView *bufferProgressView;
  47. /** 滑动进度 */
  48. @property (nonatomic, strong) UIImageView *sliderProgressView;
  49. /** 滑块 */
  50. @property (nonatomic, strong) ZFSliderButton *sliderBtn;
  51. @property (nonatomic, strong) UIView *loadingBarView;
  52. @property (nonatomic, assign) BOOL isLoading;
  53. @property (nonatomic, strong) UITapGestureRecognizer *tapGesture;
  54. @end
  55. @implementation ZFSliderView
  56. - (instancetype)initWithFrame:(CGRect)frame {
  57. if (self = [super initWithFrame:frame]) {
  58. self.allowTapped = YES;
  59. self.animate = YES;
  60. [self addSubViews];
  61. }
  62. return self;
  63. }
  64. - (void)awakeFromNib {
  65. [super awakeFromNib];
  66. self.allowTapped = YES;
  67. self.animate = YES;
  68. [self addSubViews];
  69. }
  70. - (void)layoutSubviews {
  71. [super layoutSubviews];
  72. if (isnan(self.value) || isnan(self.bufferValue)) return;
  73. CGFloat min_x = 0;
  74. CGFloat min_y = 0;
  75. CGFloat min_w = 0;
  76. CGFloat min_h = 0;
  77. CGFloat min_view_w = self.bounds.size.width;
  78. CGFloat min_view_h = self.bounds.size.height;
  79. min_x = 0;
  80. min_w = min_view_w;
  81. min_y = 0;
  82. min_h = self.sliderHeight;
  83. self.bgProgressView.frame = CGRectMake(min_x, min_y, min_w, min_h);
  84. min_x = 0;
  85. min_y = 0;
  86. min_w = self.thumbSize.width;
  87. min_h = self.thumbSize.height;
  88. self.sliderBtn.frame = CGRectMake(min_x, min_y, min_w, min_h);
  89. self.sliderBtn.zf_centerX = self.bgProgressView.zf_width * self.value;
  90. min_x = 0;
  91. min_y = 0;
  92. if (self.sliderBtn.hidden) {
  93. min_w = self.bgProgressView.zf_width * self.value;
  94. } else {
  95. min_w = self.sliderBtn.zf_centerX;
  96. }
  97. min_h = self.sliderHeight;
  98. self.sliderProgressView.frame = CGRectMake(min_x, min_y, min_w, min_h);
  99. min_x = 0;
  100. min_y = 0;
  101. min_w = self.bgProgressView.zf_width * self.bufferValue;
  102. min_h = self.sliderHeight;
  103. self.bufferProgressView.frame = CGRectMake(min_x, min_y, min_w, min_h);
  104. min_w = 0.1;
  105. min_h = self.sliderHeight;
  106. min_x = (min_view_w - min_w)/2;
  107. min_y = (min_view_h - min_h)/2;
  108. self.loadingBarView.frame = CGRectMake(min_x, min_y, min_w, min_h);
  109. self.bgProgressView.zf_centerY = min_view_h * 0.5;
  110. self.bufferProgressView.zf_centerY = min_view_h * 0.5;
  111. self.sliderProgressView.zf_centerY = min_view_h * 0.5;
  112. self.sliderBtn.zf_centerY = min_view_h * 0.5;
  113. }
  114. /**
  115. 添加子视图
  116. */
  117. - (void)addSubViews {
  118. self.thumbSize = CGSizeMake(kSliderBtnWH, kSliderBtnWH);
  119. self.sliderHeight = kProgressH;
  120. self.backgroundColor = [UIColor clearColor];
  121. [self addSubview:self.bgProgressView];
  122. [self addSubview:self.bufferProgressView];
  123. [self addSubview:self.sliderProgressView];
  124. [self addSubview:self.sliderBtn];
  125. [self addSubview:self.loadingBarView];
  126. // 添加点击手势
  127. self.tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped:)];
  128. [self addGestureRecognizer:self.tapGesture];
  129. // 添加滑动手势
  130. UIPanGestureRecognizer *sliderGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(sliderGesture:)];
  131. [self addGestureRecognizer:sliderGesture];
  132. }
  133. #pragma mark - Setter
  134. - (void)setMaximumTrackTintColor:(UIColor *)maximumTrackTintColor {
  135. _maximumTrackTintColor = maximumTrackTintColor;
  136. self.bgProgressView.backgroundColor = maximumTrackTintColor;
  137. }
  138. - (void)setMinimumTrackTintColor:(UIColor *)minimumTrackTintColor {
  139. _minimumTrackTintColor = minimumTrackTintColor;
  140. self.sliderProgressView.backgroundColor = minimumTrackTintColor;
  141. }
  142. - (void)setBufferTrackTintColor:(UIColor *)bufferTrackTintColor {
  143. _bufferTrackTintColor = bufferTrackTintColor;
  144. self.bufferProgressView.backgroundColor = bufferTrackTintColor;
  145. }
  146. - (void)setLoadingTintColor:(UIColor *)loadingTintColor {
  147. _loadingTintColor = loadingTintColor;
  148. self.loadingBarView.backgroundColor = loadingTintColor;
  149. }
  150. - (void)setMaximumTrackImage:(UIImage *)maximumTrackImage {
  151. _maximumTrackImage = maximumTrackImage;
  152. self.bgProgressView.image = maximumTrackImage;
  153. self.maximumTrackTintColor = [UIColor clearColor];
  154. }
  155. - (void)setMinimumTrackImage:(UIImage *)minimumTrackImage {
  156. _minimumTrackImage = minimumTrackImage;
  157. self.sliderProgressView.image = minimumTrackImage;
  158. self.minimumTrackTintColor = [UIColor clearColor];
  159. }
  160. - (void)setBufferTrackImage:(UIImage *)bufferTrackImage {
  161. _bufferTrackImage = bufferTrackImage;
  162. self.bufferProgressView.image = bufferTrackImage;
  163. self.bufferTrackTintColor = [UIColor clearColor];
  164. }
  165. - (void)setBackgroundImage:(UIImage *)image forState:(UIControlState)state {
  166. [self.sliderBtn setBackgroundImage:image forState:state];
  167. }
  168. - (void)setThumbImage:(UIImage *)image forState:(UIControlState)state {
  169. [self.sliderBtn setImage:image forState:state];
  170. }
  171. - (void)setValue:(float)value {
  172. if (isnan(value)) return;
  173. value = MIN(1.0, value);
  174. _value = value;
  175. if (self.sliderBtn.hidden) {
  176. self.sliderProgressView.zf_width = self.bgProgressView.zf_width * value;
  177. } else {
  178. self.sliderBtn.zf_centerX = self.bgProgressView.zf_width * value;
  179. self.sliderProgressView.zf_width = self.sliderBtn.zf_centerX;
  180. }
  181. }
  182. - (void)setBufferValue:(float)bufferValue {
  183. if (isnan(bufferValue)) return;
  184. bufferValue = MIN(1.0, bufferValue);
  185. _bufferValue = bufferValue;
  186. self.bufferProgressView.zf_width = self.bgProgressView.zf_width * bufferValue;
  187. }
  188. - (void)setAllowTapped:(BOOL)allowTapped {
  189. _allowTapped = allowTapped;
  190. if (!allowTapped) {
  191. [self removeGestureRecognizer:self.tapGesture];
  192. }
  193. }
  194. - (void)setSliderHeight:(CGFloat)sliderHeight {
  195. if (isnan(sliderHeight)) return;
  196. _sliderHeight = sliderHeight;
  197. self.bgProgressView.zf_height = sliderHeight;
  198. self.bufferProgressView.zf_height = sliderHeight;
  199. self.sliderProgressView.zf_height = sliderHeight;
  200. }
  201. - (void)setSliderRadius:(CGFloat)sliderRadius {
  202. if (isnan(sliderRadius)) return;
  203. _sliderRadius = sliderRadius;
  204. self.bgProgressView.layer.cornerRadius = sliderRadius;
  205. self.bufferProgressView.layer.cornerRadius = sliderRadius;
  206. self.sliderProgressView.layer.cornerRadius = sliderRadius;
  207. self.bgProgressView.layer.masksToBounds = YES;
  208. self.bufferProgressView.layer.masksToBounds = YES;
  209. self.sliderProgressView.layer.masksToBounds = YES;
  210. }
  211. - (void)setIsHideSliderBlock:(BOOL)isHideSliderBlock {
  212. _isHideSliderBlock = isHideSliderBlock;
  213. // 隐藏滑块,滑杆不可点击
  214. if (isHideSliderBlock) {
  215. self.sliderBtn.hidden = YES;
  216. self.bgProgressView.zf_left = 0;
  217. self.bufferProgressView.zf_left = 0;
  218. self.sliderProgressView.zf_left = 0;
  219. self.allowTapped = NO;
  220. }
  221. }
  222. /**
  223. * Starts animation of the spinner.
  224. */
  225. - (void)startAnimating {
  226. if (self.isLoading) return;
  227. self.isLoading = YES;
  228. self.bufferProgressView.hidden = YES;
  229. self.sliderProgressView.hidden = YES;
  230. self.sliderBtn.hidden = YES;
  231. self.loadingBarView.hidden = NO;
  232. [self.loadingBarView.layer removeAllAnimations];
  233. CAAnimationGroup *animationGroup = [[CAAnimationGroup alloc] init];
  234. animationGroup.duration = 0.4;
  235. animationGroup.beginTime = CACurrentMediaTime() + 0.4;
  236. animationGroup.repeatCount = MAXFLOAT;
  237. animationGroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
  238. CABasicAnimation *scaleAnimation = [CABasicAnimation animation];
  239. scaleAnimation.keyPath = @"transform.scale.x";
  240. scaleAnimation.fromValue = @(1000.0f);
  241. scaleAnimation.toValue = @(self.zf_width * 10);
  242. CABasicAnimation *alphaAnimation = [CABasicAnimation animation];
  243. alphaAnimation.keyPath = @"opacity";
  244. alphaAnimation.fromValue = @(1.0f);
  245. alphaAnimation.toValue = @(0.0f);
  246. [animationGroup setAnimations:@[scaleAnimation, alphaAnimation]];
  247. [self.loadingBarView.layer addAnimation:animationGroup forKey:@"loading"];
  248. }
  249. /**
  250. * Stops animation of the spinnner.
  251. */
  252. - (void)stopAnimating {
  253. self.isLoading = NO;
  254. self.bufferProgressView.hidden = NO;
  255. self.sliderProgressView.hidden = NO;
  256. self.sliderBtn.hidden = self.isHideSliderBlock;
  257. self.loadingBarView.hidden = YES;
  258. [self.loadingBarView.layer removeAllAnimations];
  259. }
  260. #pragma mark - User Action
  261. - (void)sliderGesture:(UIGestureRecognizer *)gesture {
  262. switch (gesture.state) {
  263. case UIGestureRecognizerStateBegan: {
  264. [self sliderBtnTouchBegin:self.sliderBtn];
  265. }
  266. break;
  267. case UIGestureRecognizerStateChanged: {
  268. [self sliderBtnDragMoving:self.sliderBtn point:[gesture locationInView:self.bgProgressView]];
  269. }
  270. break;
  271. case UIGestureRecognizerStateEnded: {
  272. [self sliderBtnTouchEnded:self.sliderBtn];
  273. }
  274. break;
  275. default:
  276. break;
  277. }
  278. }
  279. - (void)sliderBtnTouchBegin:(UIButton *)btn {
  280. if ([self.delegate respondsToSelector:@selector(sliderTouchBegan:)]) {
  281. [self.delegate sliderTouchBegan:self.value];
  282. }
  283. if (self.animate) {
  284. [UIView animateWithDuration:kAnimate animations:^{
  285. btn.transform = CGAffineTransformMakeScale(1.2, 1.2);
  286. }];
  287. }
  288. }
  289. - (void)sliderBtnTouchEnded:(UIButton *)btn {
  290. if ([self.delegate respondsToSelector:@selector(sliderTouchEnded:)]) {
  291. [self.delegate sliderTouchEnded:self.value];
  292. }
  293. if (self.animate) {
  294. [UIView animateWithDuration:kAnimate animations:^{
  295. btn.transform = CGAffineTransformIdentity;
  296. }];
  297. }
  298. }
  299. - (void)sliderBtnDragMoving:(UIButton *)btn point:(CGPoint)touchPoint {
  300. // 点击的位置
  301. CGPoint point = touchPoint;
  302. // 获取进度值 由于btn是从 0-(self.width - btn.width)
  303. CGFloat value = (point.x - btn.zf_width * 0.5) / self.bgProgressView.zf_width;
  304. // value的值需在0-1之间
  305. value = value >= 1.0 ? 1.0 : value <= 0.0 ? 0.0 : value;
  306. if (self.value == value) return;
  307. self.isForward = self.value < value;
  308. self.value = value;
  309. if ([self.delegate respondsToSelector:@selector(sliderValueChanged:)]) {
  310. [self.delegate sliderValueChanged:value];
  311. }
  312. }
  313. - (void)tapped:(UITapGestureRecognizer *)tap {
  314. CGPoint point = [tap locationInView:self.bgProgressView];
  315. // 获取进度
  316. CGFloat value = (point.x - self.sliderBtn.zf_width * 0.5) * 1.0 / self.bgProgressView.zf_width;
  317. value = value >= 1.0 ? 1.0 : value <= 0 ? 0 : value;
  318. self.value = value;
  319. if ([self.delegate respondsToSelector:@selector(sliderTapped:)]) {
  320. [self.delegate sliderTapped:value];
  321. }
  322. }
  323. #pragma mark - getter
  324. - (UIView *)bgProgressView {
  325. if (!_bgProgressView) {
  326. _bgProgressView = [UIImageView new];
  327. _bgProgressView.backgroundColor = [UIColor grayColor];
  328. _bgProgressView.contentMode = UIViewContentModeScaleAspectFill;
  329. _bgProgressView.clipsToBounds = YES;
  330. }
  331. return _bgProgressView;
  332. }
  333. - (UIView *)bufferProgressView {
  334. if (!_bufferProgressView) {
  335. _bufferProgressView = [UIImageView new];
  336. _bufferProgressView.backgroundColor = [UIColor whiteColor];
  337. _bufferProgressView.contentMode = UIViewContentModeScaleAspectFill;
  338. _bufferProgressView.clipsToBounds = YES;
  339. }
  340. return _bufferProgressView;
  341. }
  342. - (UIView *)sliderProgressView {
  343. if (!_sliderProgressView) {
  344. _sliderProgressView = [UIImageView new];
  345. _sliderProgressView.backgroundColor = [UIColor redColor];
  346. _sliderProgressView.contentMode = UIViewContentModeScaleAspectFill;
  347. _sliderProgressView.clipsToBounds = YES;
  348. }
  349. return _sliderProgressView;
  350. }
  351. - (ZFSliderButton *)sliderBtn {
  352. if (!_sliderBtn) {
  353. _sliderBtn = [ZFSliderButton buttonWithType:UIButtonTypeCustom];
  354. [_sliderBtn setAdjustsImageWhenHighlighted:NO];
  355. }
  356. return _sliderBtn;
  357. }
  358. - (UIView *)loadingBarView {
  359. if (!_loadingBarView) {
  360. _loadingBarView = [[UIView alloc] init];
  361. _loadingBarView.backgroundColor = [UIColor whiteColor];
  362. _loadingBarView.hidden = YES;
  363. }
  364. return _loadingBarView;
  365. }
  366. @end