缩放时间轴

项目需求:从云端获取视频片段,app中以时间轴展示视频片段列表,可以缩放时间轴,同时视频片段列表也需要跟随缩放,滑动时间轴,如果选中视频则选择该视频选中的时间点播放,如果没有选中视频,则找当前选中的时间最近的视频播放,视频每播放一秒,时间轴向下移动一秒,将视频长度对应的绘制在时间轴上,每个视频封面能否显示需要判断前后视频片段对应的时间轴高度等功能。需求还是比较难做。
代码中如有不明白的可以联系我,联系方式qq734651142,标明时间轴缩放。
运行效果如下:
GIF较长,选取了几张图片


IMG_5674.PNG
IMG_5673.PNG
IMG_5672.PNG

视频效果链接:http://www.iqiyi.com/v_1d07stutamw.html?social_platform=link&p1=2_22_221&_frd=J%2FH%2F%2Bxnuk92DZdUPTIw1L8wWEjd%2FupuwdxEwWJi24hLF1wovQ40WwyyJ7%2F5ho%2FvHbnxyQ8HXIZ5JqdMIGEG7UwnKfnQMSsrvjvN01wvoR%2B8%3D

目前使用起来还是非常流畅,数据特别多会有些许卡顿,小伙伴们有好的优化方式欢迎联系我。

比较重要的4个自定义控件
1、时间轴绘制控件 OU_CAMTimeAxisView
.h文件

#import <UIKit/UIKit.h>
#import "OU_CAMPlaybackModel.h"

NS_ASSUME_NONNULL_BEGIN

@interface OU_CAMTimeAxisView : UIView

@property (nonatomic, strong)NSArray <OU_CAMPlaybackModel *>* modelArray;

@property (nonatomic, strong)OU_CAMPlaybackModel* model;

@property (assign, nonatomic) CGFloat scale;

@end

NS_ASSUME_NONNULL_END

.m文件

#import "OU_CAMTimeAxisView.h"

#define SCALE1 0.5 //显示每分钟
#define SCALE2 0.1 //显示十分钟
#define SCALE3 0.05 //显示半小时
@implementation OU_CAMTimeAxisView

- (void)drawRect:(CGRect)rect{
    if (self.tag == 101) {///组头
         
         ///第一组组数组。只用绘画后2个刻度(当前视图内和当前视图下),即可保证所有的时间都能完整
         ///当前组头结束对应的时间点
         NSInteger cellStartTime = self.model.modelArray.firstObject.timeStamp;
     
                  
         NSMutableDictionary * dict = [[NSMutableDictionary alloc] init];
         dict[NSFontAttributeName] = [UIFont systemFontOfSize:14.0];
         dict[NSForegroundColorAttributeName] = [UIColor grayColor];

         ///小时
         NSInteger hour = (86400 - cellStartTime)/3600;
         ///分钟
         NSInteger mintues  = ((86400 - cellStartTime)%3600)/60 + 1;
       
        if (mintues >= 60) {
            mintues = mintues - 60;
            hour ++;
        }

         NSString * string = @"00:00";

         if (self.scale >= SCALE1) {
             ///相差的间隔(秒)
             NSInteger difference = hour*3600 + mintues * 60 - (86400 - cellStartTime);
         
             
             CGFloat y = self.frame.size.height - difference/3600.0 * CELLHEIGHT * self.scale;
             [self drawRuleWithY:y];
             
             ///刻度1
             if (hour < 10) {
                 if (mintues < 10) {
                     string = [NSString stringWithFormat:@"0%ld:0%ld",hour,mintues];
                 }else{
                     string = [NSString stringWithFormat:@"0%ld:%ld",hour,mintues];
                 }
                 
             }else{
                 if (mintues < 10) {
                     string = [NSString stringWithFormat:@"%ld:0%ld",hour,mintues];
                 }else{
                     string = [NSString stringWithFormat:@"%ld:%ld",hour,mintues];
                 }
             }
             
             [string drawInRect:CGRectMake(5, y - 10, 45, 20) withAttributes:dict];//在矩形上画字
             
             
             ///刻度2
             y = self.frame.size.height - (difference-60)/3600.0 * CELLHEIGHT * self.scale;
             [self drawRuleWithY:y];
             
             if (mintues == 0) {
                 mintues = 59;
                 hour --;
             }else{
                 mintues --;
             }
             if (hour <0) {
                 hour = 23;
             }
             
             if (hour < 10) {
                 if (mintues < 10) {
                     string = [NSString stringWithFormat:@"0%ld:0%ld",hour,mintues];
                 }else{
                     string = [NSString stringWithFormat:@"0%ld:%ld",hour,mintues];
                 }
                 
             }else{
                 if (mintues < 10) {
                     string = [NSString stringWithFormat:@"%ld:0%ld",hour,mintues];
                 }else{
                     string = [NSString stringWithFormat:@"%ld:%ld",hour,mintues];
                 }
             }
             [string drawInRect:CGRectMake(5, y - 10, 45, 20) withAttributes:dict];//在矩形上画字
             
         }else if(self.scale < SCALE1 && self.scale >= SCALE2){///显示10分钟,每分钟只显示刻度
             ///相差的间隔(秒)
             NSInteger difference = hour*3600 + mintues * 60 - (86400 - cellStartTime);
             
             CGFloat y = self.frame.size.height - difference/3600.0 * CELLHEIGHT * self.scale;
             
             if (mintues%10 == 0) {
                 [self drawLengthRuleWithY:y];
                 
                 if (hour < 10) {
                     if (mintues < 10) {
                         string = [NSString stringWithFormat:@"0%ld:0%ld",hour,mintues];
                     }else{
                         string = [NSString stringWithFormat:@"0%ld:%ld",hour,mintues];
                     }
                      
                 }else{
                     if (mintues < 10) {
                         string = [NSString stringWithFormat:@"%ld:0%ld",hour,mintues];
                     }else{
                         string = [NSString stringWithFormat:@"%ld:%ld",hour,mintues];
                     }
                 }
                 
                  
                 [string drawInRect:CGRectMake(5, y - 10, 45, 20) withAttributes:dict];//在矩形上画字
             }else{
                 [self drawRuleWithY:y];
             }
    

              ///刻度2
             y = self.frame.size.height - (difference - 60)/3600.0 * CELLHEIGHT * self.scale;
             
             
              
             if (mintues == 0) {
                 mintues = 59;
                 hour --;
             }else{
                  mintues --;
             }
             if (hour <0) {
                 hour = 23;
             }
             
             
             if (mintues%10 == 0) {
                 [self drawLengthRuleWithY:y];
                 
                 if (hour < 10) {
                     if (mintues < 10) {
                         string = [NSString stringWithFormat:@"0%ld:0%ld",hour,mintues];
                     }else{
                         string = [NSString stringWithFormat:@"0%ld:%ld",hour,mintues];
                     }
                     
                 }else{
                     if (mintues < 10) {
                         string = [NSString stringWithFormat:@"%ld:0%ld",hour,mintues];
                     }else{
                         string = [NSString stringWithFormat:@"%ld:%ld",hour,mintues];
                     }
                 }
                  
                 [string drawInRect:CGRectMake(5, y - 10, 45, 20) withAttributes:dict];//在矩形上画字
             }else{
                 [self drawRuleWithY:y];
             }
             
         }else if(self.scale <= SCALE2 && self.scale >= SCALE3){

             mintues = mintues/10*10+10;
             
             if (mintues >= 60) {
                 mintues = mintues - 30;
                 hour++;
             }
             
             
             NSInteger difference = hour*3600 + mintues * 60 - (86400 - cellStartTime);
             

             CGFloat y = self.frame.size.height - difference/3600.0 * CELLHEIGHT * self.scale;
             

             if (mintues%30 == 0) {
                 
                 [self drawLengthRuleWithY:y];

                 if (hour < 10) {
                     if (mintues < 10) {
                         string = [NSString stringWithFormat:@"0%ld:0%ld",hour,mintues];
                     }else{
                         string = [NSString stringWithFormat:@"0%ld:%ld",hour,mintues];
                     }

                 }else{
                     if (mintues < 10) {
                         string = [NSString stringWithFormat:@"%ld:0%ld",hour,mintues];
                     }else{
                         string = [NSString stringWithFormat:@"%ld:%ld",hour,mintues];
                     }
                 }
                 [string drawInRect:CGRectMake(5, y - 10, 45, 20) withAttributes:dict];//在矩形上画字
             }else{
                 [self drawRuleWithY:y];
             }

             ///刻度2
             y = self.frame.size.height + (600-difference)/3600.0 * CELLHEIGHT * self.scale;



             if (mintues < 10) {
                 mintues = mintues + 50;
                 hour --;
             }else{
                 mintues = mintues - 10;
             }
             
             if (hour <0) {
                 hour = 23;
             }

             if (mintues%30 == 0) {
                 [self drawLengthRuleWithY:y];

                 if (hour < 10) {
                     if (mintues < 10) {
                         string = [NSString stringWithFormat:@"0%ld:0%ld",hour,mintues];
                     }else{
                         string = [NSString stringWithFormat:@"0%ld:%ld",hour,mintues];
                     }

                 }else{
                     if (mintues < 10) {
                         string = [NSString stringWithFormat:@"%ld:0%ld",hour,mintues];
                     }else{
                         string = [NSString stringWithFormat:@"%ld:%ld",hour,mintues];
                         }
                     }

                     [string drawInRect:CGRectMake(5, y - 10, 45, 20) withAttributes:dict];//在矩形上画字
             }else{
                 [self drawRuleWithY:y];
             }
         }else{
             
             mintues = mintues/30*30+30;
             
             if (mintues >= 60) {
                 mintues = mintues - 60;
                 hour++;
             }

             NSInteger difference = hour*3600 + mintues * 60 - (86400 - cellStartTime);
                
             CGFloat y = self.frame.size.height - difference/3600.0 * CELLHEIGHT * self.scale;

             if (mintues%60 == 0) {
                 
                 [self drawLengthRuleWithY:y];

                 if (hour < 10) {
                     if (mintues < 10) {
                         string = [NSString stringWithFormat:@"0%ld:0%ld",hour,mintues];
                     }else{
                         string = [NSString stringWithFormat:@"0%ld:%ld",hour,mintues];
                     }

                 }else{
                     if (mintues < 10) {
                         string = [NSString stringWithFormat:@"%ld:0%ld",hour,mintues];
                     }else{
                         string = [NSString stringWithFormat:@"%ld:%ld",hour,mintues];
                     }
                 }

                 [string drawInRect:CGRectMake(5, y - 10, 45, 20) withAttributes:dict];//在矩形上画字
             }else{
                 [self drawRuleWithY:y];
             }

             ///刻度2
             y = self.frame.size.height + (1800 - difference)/3600.0 * CELLHEIGHT * self.scale;


             if (mintues == 30) {
                 mintues = 0;
             }else{
                 mintues = 30;
                 hour --;
             }
             if (hour <0) {
                 hour = 23;
             }

             if (mintues%60 == 0) {
                 [self drawLengthRuleWithY:y];

                 if (hour < 10) {
                     if (mintues < 10) {
                         string = [NSString stringWithFormat:@"0%ld:0%ld",hour,mintues];
                     }else{
                         string = [NSString stringWithFormat:@"0%ld:%ld",hour,mintues];
                     }

                 }else{
                     if (mintues < 10) {
                         string = [NSString stringWithFormat:@"%ld:0%ld",hour,mintues];
                     }else{
                         string = [NSString stringWithFormat:@"%ld:%ld",hour,mintues];
                         }
                     }

                 [string drawInRect:CGRectMake(5, y - 10, 45, 20) withAttributes:dict];//在矩形上画字
             }else{
                 [self drawRuleWithY:y];
             }
         }
         
     }else if (self.tag == 100) {///组尾
        
        ///最后一组数组。只用绘画前个刻度(当前视图内和当前视图上),即可保证所有的时间都能完整
        ///当前组尾开始对应的时间点
        NSInteger cellStartTime = self.model.modelArray.firstObject.timeStamp + self.model.spanTime;
    
     
        NSMutableDictionary * dict = [[NSMutableDictionary alloc] init];
        dict[NSFontAttributeName] = [UIFont systemFontOfSize:14.0];
        dict[NSForegroundColorAttributeName] = [UIColor grayColor];

        ///小时
        NSInteger hour = (86400 - cellStartTime)/3600;
        ///分钟
        NSInteger mintues  = ((86400 - cellStartTime)%3600)/60 + 1;

        NSString * string = @"00:00";

        if (self.scale >= SCALE1) {
            ///相差的间隔(秒)
            NSInteger difference = cellStartTime - cellStartTime/60*60;
        
            
            NSLog(@"相差的秒数:%ld",difference);
            
            
            CGFloat y = -difference/3600.0 * CELLHEIGHT * self.scale;
            [self drawRuleWithY:y];
            
            ///刻度1
            if (hour < 10) {
                if (mintues < 10) {
                    string = [NSString stringWithFormat:@"0%ld:0%ld",hour,mintues];
                }else{
                    string = [NSString stringWithFormat:@"0%ld:%ld",hour,mintues];
                }
                
            }else{
                if (mintues < 10) {
                    string = [NSString stringWithFormat:@"%ld:0%ld",hour,mintues];
                }else{
                    string = [NSString stringWithFormat:@"%ld:%ld",hour,mintues];
                }
            }
            
            [string drawInRect:CGRectMake(5, y - 10, 45, 20) withAttributes:dict];//在矩形上画字
            
            
            ///刻度2
            y = (60 - difference)/3600.0 * CELLHEIGHT * self.scale;
            [self drawRuleWithY:y];
            
            if (mintues == 0) {
                mintues = 59;
                hour --;
            }else{
                mintues --;
            }
            if (hour <0) {
                hour = 23;
            }
            
            if (hour < 10) {
                if (mintues < 10) {
                    string = [NSString stringWithFormat:@"0%ld:0%ld",hour,mintues];
                }else{
                    string = [NSString stringWithFormat:@"0%ld:%ld",hour,mintues];
                }
                
            }else{
                if (mintues < 10) {
                    string = [NSString stringWithFormat:@"%ld:0%ld",hour,mintues];
                }else{
                    string = [NSString stringWithFormat:@"%ld:%ld",hour,mintues];
                }
            }
            [string drawInRect:CGRectMake(5, y - 10, 45, 20) withAttributes:dict];//在矩形上画字
            
        }else if(self.scale < SCALE1 && self.scale >= SCALE2){///显示10分钟,每分钟只显示刻度
            ///相差的间隔(秒)
            NSInteger difference = cellStartTime - cellStartTime/60*60;
            
            CGFloat y = -difference/3600.0 * CELLHEIGHT * self.scale;
            
            if (mintues%10 == 0) {
                [self drawLengthRuleWithY:y];
                
                if (hour < 10) {
                    if (mintues < 10) {
                        string = [NSString stringWithFormat:@"0%ld:0%ld",hour,mintues];
                    }else{
                        string = [NSString stringWithFormat:@"0%ld:%ld",hour,mintues];
                    }
                     
                }else{
                    if (mintues < 10) {
                        string = [NSString stringWithFormat:@"%ld:0%ld",hour,mintues];
                    }else{
                        string = [NSString stringWithFormat:@"%ld:%ld",hour,mintues];
                    }
                }
                
                 
                [string drawInRect:CGRectMake(5, y - 10, 45, 20) withAttributes:dict];//在矩形上画字
            }else{
                [self drawRuleWithY:y];
            }
   

             ///刻度2
            y = (60 - difference)/3600.0 * CELLHEIGHT * self.scale;
            
            
             
            if (mintues == 0) {
                mintues = 59;
                hour --;
            }else{
                 mintues --;
            }
            if (hour <0) {
                hour = 23;
            }
            
            
            if (mintues%10 == 0) {
                [self drawLengthRuleWithY:y];
                
                if (hour < 10) {
                    if (mintues < 10) {
                        string = [NSString stringWithFormat:@"0%ld:0%ld",hour,mintues];
                    }else{
                        string = [NSString stringWithFormat:@"0%ld:%ld",hour,mintues];
                    }
                    
                }else{
                    if (mintues < 10) {
                        string = [NSString stringWithFormat:@"%ld:0%ld",hour,mintues];
                    }else{
                        string = [NSString stringWithFormat:@"%ld:%ld",hour,mintues];
                    }
                }
                 
                [string drawInRect:CGRectMake(5, y - 10, 45, 20) withAttributes:dict];//在矩形上画字
            }else{
                [self drawRuleWithY:y];
            }
            
        }else if(self.scale <= SCALE2 && self.scale >= SCALE3){

            NSInteger difference = cellStartTime - cellStartTime/600*600;
                     
            CGFloat y = -difference/3600.0 * CELLHEIGHT * self.scale;
            
            mintues = mintues/10*10+10;
            

            if (mintues%30 == 0) {
                
                [self drawLengthRuleWithY:y];

                if (hour < 10) {
                    if (mintues < 10) {
                        string = [NSString stringWithFormat:@"0%ld:0%ld",hour,mintues];
                    }else{
                        string = [NSString stringWithFormat:@"0%ld:%ld",hour,mintues];
                    }

                }else{
                    if (mintues < 10) {
                        string = [NSString stringWithFormat:@"%ld:0%ld",hour,mintues];
                    }else{
                        string = [NSString stringWithFormat:@"%ld:%ld",hour,mintues];
                    }
                }
                [string drawInRect:CGRectMake(5, y - 10, 45, 20) withAttributes:dict];//在矩形上画字
            }else{
                [self drawRuleWithY:y];
            }

            ///刻度2
            y = (600-difference)/3600.0 * CELLHEIGHT * self.scale;



            if (mintues < 10) {
                mintues = mintues + 50;
                hour --;
            }else{
                mintues = mintues - 10;
            }
            
            if (hour <0) {
                hour = 23;
            }

            if (mintues%30 == 0) {
                [self drawLengthRuleWithY:y];

                if (hour < 10) {
                    if (mintues < 10) {
                        string = [NSString stringWithFormat:@"0%ld:0%ld",hour,mintues];
                    }else{
                        string = [NSString stringWithFormat:@"0%ld:%ld",hour,mintues];
                    }

                }else{
                    if (mintues < 10) {
                        string = [NSString stringWithFormat:@"%ld:0%ld",hour,mintues];
                    }else{
                        string = [NSString stringWithFormat:@"%ld:%ld",hour,mintues];
                        }
                    }

                    [string drawInRect:CGRectMake(5, y - 10, 45, 20) withAttributes:dict];//在矩形上画字
            }else{
                [self drawRuleWithY:y];
            }
        }else{

            NSInteger difference = cellStartTime - cellStartTime/1800*1800;
                  
            mintues = mintues/30*30+30;

            CGFloat y = -difference/3600.0 * CELLHEIGHT * self.scale;

            if (mintues%60 == 0) {
                
                [self drawLengthRuleWithY:y];

                if (hour < 10) {
                    if (mintues < 10) {
                        string = [NSString stringWithFormat:@"0%ld:0%ld",hour,mintues];
                    }else{
                        string = [NSString stringWithFormat:@"0%ld:%ld",hour,mintues];
                    }

                }else{
                    if (mintues < 10) {
                        string = [NSString stringWithFormat:@"%ld:0%ld",hour,mintues];
                    }else{
                        string = [NSString stringWithFormat:@"%ld:%ld",hour,mintues];
                    }
                }

                [string drawInRect:CGRectMake(5, y - 10, 45, 20) withAttributes:dict];//在矩形上画字
            }else{
                [self drawRuleWithY:y];
            }

            ///刻度2
            y = (1800 - difference)/3600.0 * CELLHEIGHT * self.scale;


            if (mintues == 30) {
                mintues = 0;
            }else{
                mintues = 30;
                hour --;
            }
            if (hour <0) {
                hour = 23;
            }

            if (mintues%60 == 0) {
                [self drawLengthRuleWithY:y];

                if (hour < 10) {
                    if (mintues < 10) {
                        string = [NSString stringWithFormat:@"0%ld:0%ld",hour,mintues];
                    }else{
                        string = [NSString stringWithFormat:@"0%ld:%ld",hour,mintues];
                    }

                }else{
                    if (mintues < 10) {
                        string = [NSString stringWithFormat:@"%ld:0%ld",hour,mintues];
                    }else{
                        string = [NSString stringWithFormat:@"%ld:%ld",hour,mintues];
                        }
                    }

                    [string drawInRect:CGRectMake(5, y - 10, 45, 20) withAttributes:dict];//在矩形上画字
            }else{
                [self drawRuleWithY:y];
            }
        }
        
    }else{
        
        ///绘制时间轴,每1分钟绘制长度为CELLHEIGHT,根据数组内容绘制
        NSInteger cellStartTime = self.model.modelArray.firstObject.timeStamp;
        
        for (int i = 0; i < self.model.modelArray.count; i++) {

            OU_CAMPlaybackModel * model = self.model.modelArray[I];
            
            ///开始时间(秒)
            NSInteger startTime = model.timeStamp + model.timeLength - cellStartTime;
            ///结束时间(秒)
            NSInteger stopTime = model.timeStamp - cellStartTime;

            ///开始时间点位
            CGFloat startPoint = startTime/3600.0 * CELLHEIGHT * self.scale;
            
            ///结束时间点位
            CGFloat stopPoint = stopTime/3600.0 * CELLHEIGHT * self.scale;
            
            [self drawLineWithForm:startPoint To:stopPoint];
      
        }
        
        ///绘制时间,计算当前cell的刻度
        
        ///与0点的时间间隔,计算时间
        NSInteger zoneTime = (86400 - cellStartTime);
         
        ///当前cell最大对应的时间(单位:分)
        NSInteger maxTime = zoneTime/60;
        
        ///当前cell最大分钟刻度对应该cell顶部的时间差值,上下限各往外+1,防止字体空间不够造成的空缺(单位:秒)
        NSInteger difference = (86400 - (maxTime * 60)) - cellStartTime;
        
        ///当前cell所包含的时间跨度,上下限各往外+1,防止字体空间不够造成的空缺(单位:分)
        NSInteger span = (self.model.spanTime - difference)/60.0 + 1;
        
        
        NSMutableDictionary * dict = [[NSMutableDictionary alloc] init];
        dict[NSFontAttributeName] = [UIFont systemFontOfSize:14.0];
        dict[NSForegroundColorAttributeName] = [UIColor grayColor];
        
        ///小时
        NSInteger hour = (maxTime * 60)/3600;
        ///分钟
        NSInteger mintues  = ((maxTime * 60)%3600)/60;
        
        
        
        
        NSString * string = @"24:00";

        if (self.scale >= SCALE1) {
            for (int i = 0; i <= span; i++) {

                CGFloat y = (i*60.0+difference)/3600.0 * CELLHEIGHT * self.scale;
                [self drawRuleWithY:y];
                
                if (hour < 10) {
                    if (mintues < 10) {
                        string = [NSString stringWithFormat:@"0%ld:0%ld",hour,mintues];
                    }else{
                        string = [NSString stringWithFormat:@"0%ld:%ld",hour,mintues];
                    }
                    
                }else{
                    if (mintues < 10) {
                        string = [NSString stringWithFormat:@"%ld:0%ld",hour,mintues];
                    }else{
                        string = [NSString stringWithFormat:@"%ld:%ld",hour,mintues];
                    }
                }
                [string drawInRect:CGRectMake(5, y - 10, 45, 20) withAttributes:dict];//在矩形上画字
                
                if (mintues == 0) {
                    mintues = 59;
                    hour --;
                }else{
                    mintues --;
                }
                
            }
            
            ///计算第一个刻度与顶部的距离
       
        }else if(self.scale < SCALE1 && self.scale >= SCALE2){///显示10分钟,每分钟只显示刻度
            
            for (int i = 0; i <= span; i++) {

                CGFloat y = (i*60.0+difference)/3600.0 * CELLHEIGHT * self.scale;
                
                [self drawRuleWithY:y];
                
                
                if (mintues%10 == 0) {
                    [self drawLengthRuleWithY:y];
                    
                    
                    if (hour < 10) {
                        string = [NSString stringWithFormat:@"0%ld:%ld0",hour,mintues/10];
                    }else{
                        string = [NSString stringWithFormat:@"%ld:%ld0",hour,mintues/10];

                    }
                    [string drawInRect:CGRectMake(5, y - 10, 45, 20) withAttributes:dict];//在矩形上画字
                }

                if (mintues == 0) {
                    mintues = 59;
                    hour --;
                }else{
                    mintues --;
                }
                
            }

       
        }else if(self.scale <= SCALE2 && self.scale >= SCALE3){///显示半小时,每十分钟只显示刻度

            for (int i = 0; i <= span; i++) {

                if (mintues%10 == 0) {
                    
                    
                    CGFloat y = (i*60.0+difference)/3600.0 * CELLHEIGHT * self.scale;
                    
                    [self drawRuleWithY:y];
                    
                    
                    if (mintues%30 == 0) {
                        
                        [self drawLengthRuleWithY:y];
                        
                        if (hour < 10) {
                            string = [NSString stringWithFormat:@"0%ld:%ld0",hour,mintues/10];
                        }else{
                            string = [NSString stringWithFormat:@"%ld:%ld0",hour,mintues/10];

                        }
                        [string drawInRect:CGRectMake(5, y - 10, 45, 20) withAttributes:dict];//在矩形上画字
                    }
                }


                if (mintues == 0) {
                    mintues = 59;
                    hour --;
                }else{
                    mintues --;
                }
                
            }
            
        }else{///显示每小时,每半小时只显示刻度
            
            for (int i = 0; i <= span; i++) {

                if (mintues%30 == 0) {
                    CGFloat y = (i*60.0+difference)/3600.0 * CELLHEIGHT * self.scale;
                    
                    [self drawRuleWithY:y];
                    if (mintues%60 == 0) {
                        
                        [self drawLengthRuleWithY:y];
                        
                        
                        
                        if (hour < 10) {
                            string = [NSString stringWithFormat:@"0%ld:00",hour];
                        }else{
                            string = [NSString stringWithFormat:@"%ld:00",hour];

                        }
                        
                        [string drawInRect:CGRectMake(5, y - 10, 45, 20) withAttributes:dict];//在矩形上画字
                    }
                }


                if (mintues == 0) {
                    mintues = 59;
                    hour --;
                }else{
                    mintues --;
                }
                
            }

        }

    }
    

}

#pragma mark 使用默认context进行绘图
- (void)drawLineWithForm:(CGFloat)form To:(CGFloat)to{
    
    UIColor *color = MainColor;
    [color set]; //设置线条颜色

    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:CGPointMake(58, form)];
    [path addLineToPoint:CGPointMake(58, to)];

    path.lineWidth = 4.0;
    path.lineCapStyle = kCGLineCapButt; //线条拐角
    path.lineJoinStyle = kCGLineJoinBevel; //终点处理

    [path stroke];
}

#pragma mark ===============绘制长刻度===============
- (void)drawLengthRuleWithY:(CGFloat)y{

    UIColor *color = [UIColor grayColor];
    [color set]; //设置线条颜色

    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:CGPointMake(41, y)];
    [path addLineToPoint:CGPointMake(56, y)];

    path.lineWidth = 1.0;
    path.lineCapStyle = kCGLineCapButt; //线条拐角
    path.lineJoinStyle = kCGLineJoinBevel; //终点处理

    [path stroke];
}

#pragma mark ===============绘制刻度===============
- (void)drawRuleWithY:(CGFloat)y{
        
    UIColor *color = [UIColor grayColor];
    [color set]; //设置线条颜色

    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:CGPointMake(46, y)];
    [path addLineToPoint:CGPointMake(56, y)];

    path.lineWidth = 1.0;
    path.lineCapStyle = kCGLineCapButt; //线条拐角
    path.lineJoinStyle = kCGLineJoinBevel; //终点处理

    [path stroke];
}


@end

上面的代码涉及到视频片段的模型,模型属性如下:
///开始时间
@property (strong, nonatomic) NSString *startTime;
///结束时间
@property (strong, nonatomic) NSString *endTime;
///封面URL
@property (strong, nonatomic) NSString *coverURL;
///视频URL
@property (strong, nonatomic) NSString *videoURL;

///日期 2020-08-25
@property (strong, nonatomic) NSString *dateString;
///时间 12:35
@property (strong, nonatomic) NSString *timeString;

///结束时间相对于当天24时的时间戳 0~246060
@property (assign, nonatomic) NSInteger timeStamp;
///回放时长 单位为秒
@property (assign, nonatomic) NSInteger timeLength;
///动态刷新记录cell高度
@property (assign, nonatomic) CGFloat cellHeight;

///记录该cell的跨度时间长度
@property (assign, nonatomic) NSInteger spanTime;
///动态刷新,记录在同一个cell中的模型
@property (nonatomic, strong)NSMutableArray <OU_CAMPlaybackModel > modelArray;

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface OU_CAMPlaybackModel : NSObject

///开始时间
@property (strong, nonatomic) NSString *startTime;
///结束时间
@property (strong, nonatomic) NSString *endTime;
///封面URL
@property (strong, nonatomic) NSString *coverURL;
///视频URL
@property (strong, nonatomic) NSString *videoURL;

///日期 2020-08-25
@property (strong, nonatomic) NSString *dateString;
///时间 12:35
@property (strong, nonatomic) NSString *timeString;


///结束时间相对于当天24时的时间戳 0~24*60*60
@property (assign, nonatomic) NSInteger timeStamp;
///回放时长 单位为秒
@property (assign, nonatomic) NSInteger timeLength;
///动态刷新记录cell高度
@property (assign, nonatomic) CGFloat cellHeight;

///记录该cell的跨度时间长度
@property (assign, nonatomic) NSInteger spanTime;
///动态刷新,记录在同一个cell中的模型
@property (nonatomic, strong)NSMutableArray <OU_CAMPlaybackModel *>* modelArray;

+ (NSMutableArray * )setPlaybackModelWithArray:(NSArray *)array;


@end

NS_ASSUME_NONNULL_END

2、列表头部视图 OU_CAMPlaybackHeaderView
.h文件

#import <UIKit/UIKit.h>
#import "OU_CAMTimeAxisView.h"
NS_ASSUME_NONNULL_BEGIN

@interface OU_CAMPlaybackHeaderView : UITableViewHeaderFooterView

@property (weak, nonatomic) IBOutlet OU_CAMTimeAxisView *timeAxisView;

@end

NS_ASSUME_NONNULL_END

.m文件中无内容,xib中添加了时间轴绘制控件,做的时候怎么方便怎么来,没用代码布局。xib布局如下:


WechatIMG95.png

3、中间cell视图 OU_CAMPlayBackTableViewCell

#import <UIKit/UIKit.h>
#import "OU_CAMTimeAxisView.h"

NS_ASSUME_NONNULL_BEGIN


@interface OU_CAMPlayBackTableViewCell : UITableViewCell
@property (weak, nonatomic) IBOutlet UIImageView *contentImageView;

@property (weak, nonatomic) IBOutlet OU_CAMTimeAxisView *timeAxisView;

@end
NS_ASSUME_NONNULL_END

相对于头部多了一个封面预览图
xib布局如下:


WechatIMG96.png

.m文件中无内容

4、尾部视图 OU_CAMPlaybackFooterView

#import <UIKit/UIKit.h>
#import "OU_CAMTimeAxisView.h"

NS_ASSUME_NONNULL_BEGIN

@interface OU_CAMPlaybackFooterView : UITableViewHeaderFooterView

@property (weak, nonatomic) IBOutlet UIImageView *contentImageView;

@property (weak, nonatomic) IBOutlet OU_CAMTimeAxisView *timeAxisView;

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *contentImageViewLayout_Top;


@end

NS_ASSUME_NONNULL_END

xib布局如下:


image.png

.m文件中无内容

VC中调用

#import "OU_CAMPlayBackTableViewCell.h"
#import "OU_CAMPlaybackModel.h"
#import "OU_CAMTimeAxisView.h"
#import "OU_CAMPlaybackHeaderView.h"
#import "OU_CAMPlaybackFooterView.h"
#define MaxSCale 1.0  //最大缩放比例
#define MinScale 0.02  //最小缩放比例

- (void)viewDidLoad {
    [super viewDidLoad];
    self.OU_CAMPlaybackTableView.delegate = self;
    self.OU_CAMPlaybackTableView.dataSource = self;
    self.OU_CAMPlaybackTableView.separatorColor = [UIColor clearColor];
    
    self.OU_CAMPlaybackTableView.estimatedRowHeight = 0;
    self.OU_CAMPlaybackTableView.estimatedSectionHeaderHeight = 0;
    self.OU_CAMPlaybackTableView.estimatedSectionFooterHeight = 0;
    ///监听滑动手势
    [self.OU_CAMPlaybackTableView addObserver:self forKeyPath:@"panGestureRecognizer.state" options:NSKeyValueObservingOptionNew context:nil];
    ///计算滑动区域
    ///如果刘海屏,下盘的操作按钮留出安全区域
    CGFloat Height = 64;
    if (@available(iOS 11.0, *)) {
        CGFloat a = [[UIApplication sharedApplication] delegate].window.safeAreaInsets.bottom;
        if (a>0) {
            Height = 44+44+34;
        }
    } else {
        
    }
    
    CGFloat contentBottom = SCREEN_H - (SCREEN_W / 16.0 * 9.0 + 60 + 80) - Height - 80;

    self.OU_CAMPlaybackTableView.contentInset = UIEdgeInsetsMake(-20, 0, contentBottom - 100, 0);
}
#pragma mark ===============加载数据(视频回放)===============
- (void)OU_CAMLoadPlaybackData{
    /*
     ///开始时间
     @property (strong, nonatomic) NSString *startTime;
     ///结束时间
     @property (strong, nonatomic) NSString *endTime;
     ///封面URL
     @property (strong, nonatomic) NSString *coverURL;
     ///视频URL
     @property (strong, nonatomic) NSString *videoURL;
     ///结束时间相对于当天0时的时间戳 0~24*60*60
     @property (assign, nonatomic) NSInteger timeStamp;
     ///回放时长 单位为秒
     @property (assign, nonatomic) NSInteger timeLength;
     */
    NSArray * array = @[@{@"startTime":@"2020-08-14 15:29:29",@"endTime":@"2020-08-14 15:30:00",@"coverURL":@"1",@"videoURL":@"http://vfx.mtime.cn/Video/2019/02/04/mp4/190204084208765161.mp4"},@{@"startTime":@"2020-08-14 14:27:10",@"endTime":@"2020-08-14 14:28:49",@"coverURL":@"1",@"videoURL":@"http://vfx.mtime.cn/Video/2019/03/21/mp4/190321153853126488.mp4"},@{@"startTime":@"2020-08-14 14:24:06",@"endTime":@"2020-08-14 14:25:05",@"coverURL":@"1",@"videoURL":@"http://vfx.mtime.cn/Video/2019/03/19/mp4/190319222227698228.mp4"},@{@"startTime":@"2020-08-14 14:10:05",@"endTime":@"2020-08-14 14:12:32",@"coverURL":@"1",@"videoURL":@"http://vfx.mtime.cn/Video/2019/03/19/mp4/190319212559089721.mp4"},@{@"startTime":@"2020-08-14 13:59:22",@"endTime":@"2020-08-14 14:00:43",@"coverURL":@"1",@"videoURL":@"http://vfx.mtime.cn/Video/2019/03/14/mp4/190314102306987969.mp4"},@{@"startTime":@"2020-08-14 13:25:05",@"endTime":@"2020-08-14 13:26:26",@"coverURL":@"1",@"videoURL":@"http://vfx.mtime.cn/Video/2019/03/17/mp4/190317150237409904.mp4"},@{@"startTime":@"2020-08-14 13:11:05",@"endTime":@"2020-08-14 13:12:38",@"coverURL":@"1",@"videoURL":@"http://vfx.mtime.cn/Video/2019/03/19/mp4/190319125415785691.mp4"},@{@"startTime":@"2020-08-14 12:55:25",@"endTime":@"2020-08-14 12:56:34",@"coverURL":@"1",@"videoURL":@"http://vfx.mtime.cn/Video/2019/03/19/mp4/190319104618910544.mp4"},@{@"startTime":@"2020-08-14 11:31:05",@"endTime":@"2020-08-14 11:32:14",@"coverURL":@"1",@"videoURL":@"http://vfx.mtime.cn/Video/2019/03/18/mp4/190318214226685784.mp4"},@{@"startTime":@"2020-08-14 00:27:15",@"endTime":@"2020-08-14 00:28:15",@"coverURL":@"1",@"videoURL":@"http://vfx.mtime.cn/Video/2019/03/18/mp4/190318231014076505.mp4"}];
    
    self.OU_CAMDataArray = [OU_CAMPlaybackModel setPlaybackModelWithArray:array];
    
    ///计算
    CGFloat height = 0;
    
    int index = 0;

    
    for (int i = 0; i < self.OU_CAMDataArray.count; i++) {
    
        OU_CAMPlaybackModel * model = self.OU_CAMDataArray[i];

        [model.modelArray removeAllObjects];

        if (i == 0) {
            [self.OU_CAMDataArr addObject:model];
            [model.modelArray addObject:model];
         
        }else{///计算与前面cell的时间戳,判断是否可以显示该model
            OU_CAMPlaybackModel * model1 = self.OU_CAMDataArray[index];

            height = (model.timeStamp - model1.timeStamp)/3600.0*CELLHEIGHT;
          
            if (height > 80) {///展示该cell,同时height置0
                 
                  [self.OU_CAMDataArr addObject:model];
                  [model.modelArray addObject:model];
                 
                  model1.cellHeight = height;
                  model1.spanTime = model.timeStamp - model1.timeStamp;
                  height = 0;
                  index = i;
                 
                if (i == self.OU_CAMDataArray.count-1) {
                    model.cellHeight = model.timeLength/3600.0*CELLHEIGHT;
                    model.spanTime = model.timeLength;
                }
                 
                 
            }else{
                [model1.modelArray addObject:model];
                if (i == self.OU_CAMDataArray.count-1) {
                    model1.cellHeight = height;
                     
                    model.spanTime = model.timeStamp + model.timeLength - model1.timeStamp;
                }
            }
   
        }

    }



    [self.OU_CAMPlaybackTableView reloadData];

    [self OU_CAMComputingTimeWithY:0];

    ///添加缩放手势
    UIPinchGestureRecognizer * ges = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(OU_CAMPinch:)];

    [self.OU_CAMBgView addGestureRecognizer:ges];
    
}

#pragma mark ===============缩放手势===============
// 处理缩放手势
- (void)OU_CAMPinch:(UIPinchGestureRecognizer*)ges{
    
    if (self.OU_CAMDataArray.count == 0) {
        return;
    }
 
    CGFloat scale = ges.scale;
    //放大情况
    if(scale > 1.0){
        if(self.OU_CAMZoomScaling > MaxSCale) return;
    }
    //缩小情况
    if (scale < 1.0) {
        if (self.OU_CAMZoomScaling < MinScale) return;
    }
    
    if (ges.state == UIGestureRecognizerStateBegan) {
        ///刷新滚动位置
        self.currentTime = self.pointY/CELLHEIGHT/self.OU_CAMZoomScaling;

    }if (ges.state == UIGestureRecognizerStateChanged) {
        

        self.OU_CAMZoomScaling = scale * self.OU_CAMZoomScaling;
        
        if (self.OU_CAMZoomScaling > MaxSCale) {
            self.OU_CAMZoomScaling = MaxSCale;
        }else if(self.OU_CAMZoomScaling < MinScale){
            self.OU_CAMZoomScaling = MinScale;
        }
    
        ///计算
               
       CGFloat height = 0;
       
       int index = 0;
       
       [self.OU_CAMDataArr removeAllObjects];
       for (int i = 0; i < self.OU_CAMDataArray.count; i++) {
           OU_CAMPlaybackModel * model = self.OU_CAMDataArray[i];
           if (i == 0) {
               [self.OU_CAMDataArr addObject:model];
               [model.modelArray addObject:model];
           }else{///计算与前面cell的时间戳,判断是否可以显示该model
               OU_CAMPlaybackModel * model1 = self.OU_CAMDataArray[index];

               height = (model.timeStamp - model1.timeStamp)/3600.0*CELLHEIGHT*self.OU_CAMZoomScaling;
            
               if (height > 80) {///展示该cell,同时height置0
                   [self.OU_CAMDataArr addObject:model];
                   [model.modelArray addObject:model];
                   
                   model1.cellHeight = height;
                   model1.spanTime = model.timeStamp - model1.timeStamp;
                   height = 0;
                   index = i;
                   
                   if (i == self.OU_CAMDataArray.count-1) {
                       model.cellHeight = model.timeLength/3600.0*CELLHEIGHT*self.OU_CAMZoomScaling;
                       model.spanTime = model.timeLength;
                   }
               }else{
                   [model1.modelArray addObject:model];
                   if (i == self.OU_CAMDataArray.count-1) {
                       model1.cellHeight = height;
                       
                       model.spanTime = model.timeStamp + model.timeLength - model1.timeStamp;
                   }
               }
           }
       }
        
        OU_CAMPlaybackModel * model = self.OU_CAMDataArray.lastObject;
        NSLog(@"spanTime == %ld",(long)model.spanTime);

        
       [self.OU_CAMPlaybackTableView reloadData];
        
        //时间转换为距离
        [self.OU_CAMPlaybackTableView setContentOffset:CGPointMake(0, self.currentTime/3600.0*CELLHEIGHT*self.OU_CAMZoomScaling + 20) animated:NO];
        
        
        [self.OU_CAMPlaybackTableView reloadData];

    }else if(ges.state == UIGestureRecognizerStateEnded){

        [self OU_CAMCalculationFragment];
    }
}
    
#pragma mark ===============计算滑动&缩放后选中的时间===============
- (void)OU_CAMComputingTimeWithY:(CGFloat)y{
    
    if (self.OU_CAMDataArray.count == 0) {
        return;
    }
    
    NSInteger seconds = y/self.OU_CAMZoomScaling;
    ///距离当天0点对应的秒数
    OU_CAMPlaybackModel * model = self.OU_CAMDataArray.firstObject;
    self.OU_CAMTimeStamp = (model.timeStamp + seconds);
    NSInteger timeStamp = 86400 - self.OU_CAMTimeStamp;
    if (!self.isTiming) {///当计时器在计时时,不用滚动更改
        [self OU_CAMSelectTimeUI:timeStamp];
    }
}

#pragma mark ===============选中的时间展示===============
- (void)OU_CAMSelectTimeUI:(NSInteger)timeStamp{
    
    NSInteger hour = timeStamp/3600;
    NSInteger mintues = (timeStamp%3600)/60;
    NSInteger sec = timeStamp%3600%60;


    if (hour < 0) {
        hour = 0;
    }
    if (hour > 23) {
        hour = 23;
    }
    
    if (mintues < 0) {
        mintues = 0;
    }
    if (mintues > 59) {
        mintues = 59;
    }
    
    if (sec < 0) {
        sec = 0;
    }
    if (sec > 59) {
        sec = 59;
    }
    
    
    
    if (hour < 10) {
       if (mintues < 10) {
           if (sec < 10) {
               self.OU_CAMSelectTimeLabel.text = [NSString stringWithFormat:@"0%ld:0%ld:0%ld",(long)hour,(long)mintues,(long)sec];
           }else{
               self.OU_CAMSelectTimeLabel.text = [NSString stringWithFormat:@"0%ld:0%ld:%ld",(long)hour,(long)mintues,(long)sec];
           }
           
       }else{
           if (sec < 10) {
                self.OU_CAMSelectTimeLabel.text = [NSString stringWithFormat:@"0%ld:%ld:0%ld",(long)hour,(long)mintues,(long)sec];
            }else{
                self.OU_CAMSelectTimeLabel.text = [NSString stringWithFormat:@"0%ld:%ld:%ld",(long)hour,(long)mintues,(long)sec];
            }
       }
    }else{
       if (mintues < 10) {
           if (sec < 10) {
                self.OU_CAMSelectTimeLabel.text = [NSString stringWithFormat:@"%ld:0%ld:0%ld",(long)hour,(long)mintues,(long)sec];
            }else{
                self.OU_CAMSelectTimeLabel.text = [NSString stringWithFormat:@"%ld:0%ld:%ld",(long)hour,(long)mintues,(long)sec];
            }
       }else{
           if (sec < 10) {
                self.OU_CAMSelectTimeLabel.text = [NSString stringWithFormat:@"%ld:%ld:0%ld",(long)hour,(long)mintues,(long)sec];
            }else{
                self.OU_CAMSelectTimeLabel.text = [NSString stringWithFormat:@"%ld:%ld:%ld",(long)hour,(long)mintues,(long)sec];
            }
           
       }
    }
    
}

#pragma mark ===============添加回放计时器===============
- (void)OU_CAMAddBackplayTimer{
    
    [self OU_CAMRemoveBackplayTimer];
    
    if (!self.OU_CAMBackplayTimer) {
        
        self.isTiming = YES;
        
        self.OU_CAMBackplayTimer = [NSTimer timerWithTimeInterval:0.2 target:self selector:@selector(OU_CAMBackplayTimerClick) userInfo:nil repeats:YES];
        
        [[NSRunLoop mainRunLoop] addTimer:self.OU_CAMBackplayTimer forMode:NSDefaultRunLoopMode];
    }
    
    
}
#pragma mark ===============移除回放计时器===============
- (void)OU_CAMRemoveBackplayTimer{
    if (self.OU_CAMBackplayTimer) {
        
        self.isTiming = NO;
        
        [self.OU_CAMBackplayTimer invalidate];
        self.OU_CAMBackplayTimer = nil;
    }
    
}
#pragma mark ===============回放计时器事件===============
- (void)OU_CAMBackplayTimerClick{
    ///获取当前视频播放的进度(已经播放时间)
    self.OU_CAMBackPlayTimeLength = round(self.playerItem.currentTime.value/self.playerItem.currentTime.timescale);
    
//    self.OU_CAMBackPlayStartTime - currentTime
    ///选中时间展示
    [self OU_CAMSelectTimeUI:86400 - self.OU_CAMBackPlayStartTime + self.OU_CAMBackPlayTimeLength];
    ///滚动距离
    [self OU_CAMScrollDistanceWithTimeStamp:self.OU_CAMBackPlayStartTime - self.OU_CAMBackPlayTimeLength];

}


#pragma mark ===============缩放结束&滑动停止后需要计算指定位播放===============
- (void)OU_CAMCalculationFragment{
    if (self.OU_CAMDataArray.count == 0) {
        return;
    }
    ///优先判断选中的时间是否正好处于回放片段内,是则不用滚动到最近的回放片段
    BOOL res = NO;
    int index = 0;
    for (int i = 0; i < self.OU_CAMDataArray.count ; i++) {
        OU_CAMPlaybackModel * model = self.OU_CAMDataArray[i];
        
        if (self.OU_CAMTimeStamp >= model.timeStamp && self.OU_CAMTimeStamp <= model.timeStamp + model.timeLength) {
            
            [self OU_CAMAddBackplayTimer];

            res = YES;

            ///需要设置的播放点
            self.OU_CAMBackPlayTimeLength = model.timeStamp + model.timeLength - self.OU_CAMTimeStamp;
            
            index = i;
            ///判断是否是同一个播放源,是的话直接跳进度,如果不是,则需要先切换播放源,然后跳进度
            if (index == self.playIndex) {///相同播放源

            }else{///不同播放源
                self.playIndex = i;
                
                self.OU_CAMBackPlayStartTime = model.timeStamp + model.timeLength;
                
                [self OU_CAMStartBackplay];
            }
            
            //让视频从指定的CMTime对象处播放。
            CMTime startTime = CMTimeMakeWithSeconds(self.OU_CAMBackPlayTimeLength, self.playerItem.currentTime.timescale);
            //让视频从指定处播放
            [self.player seekToTime:startTime toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
            
            [self.player play];
            if (@available(iOS 10.0, *)) {
                [self.player playImmediatelyAtRate:self.OU_CAMBackplaySpeed];
            } else {
                [self.player setRate:self.OU_CAMBackplaySpeed];
            }
            
            return;
         }
    }
    
    

    NSInteger seconds = 86400;
    index = 0;
    for (int i = 0; i < self.OU_CAMDataArray.count; i++) {
        OU_CAMPlaybackModel * model = self.OU_CAMDataArray[i];
        
        
        if (abs(self.OU_CAMTimeStamp - model.timeStamp - model.timeLength) < seconds) {
            seconds = abs(self.OU_CAMTimeStamp - model.timeStamp - model.timeLength);
            index = i;
        }
    }
    
    OU_CAMPlaybackModel * model1 = self.OU_CAMDataArray[index];
    

    ///选中播放的模型
    self.playIndex = index;
    ///该模型开始时间
    self.OU_CAMBackPlayStartTime = model1.timeStamp + model1.timeLength;
    self.OU_CAMBackPlayTimeLength = 0;
    
    
    
    [self OU_CAMStartBackplay];
    
    [self OU_CAMScrollDistanceWithTimeStamp:self.OU_CAMBackPlayStartTime];

}
#pragma mark ===============根据当前时间戳计算滚动距离===============
- (void)OU_CAMScrollDistanceWithTimeStamp:(NSInteger)timeStamp{
    
    ///使用第一个模型的结束时间时间戳差值来计算需要滚动的距离
    OU_CAMPlaybackModel * model = self.OU_CAMDataArray.firstObject;
    
    timeStamp = timeStamp - model.timeStamp;
    
    
    [self.OU_CAMPlaybackTableView setContentOffset:CGPointMake(0, timeStamp * self.OU_CAMZoomScaling + 20) animated:YES];
    
}

#pragma mark ===============初始化播放器===============
- (void)OU_CAMStartBackplay{
    
    [self OU_CAMNotPlayBackStatus];
    
    self.OU_CAMPlayingback = NO;

    OU_CAMPlaybackModel * model1 = self.OU_CAMDataArray[self.playIndex];
    
    
    self.OU_CAMBackplayBgView.hidden = NO;
    ///移除监听
    [self.playerItem removeObserver:self forKeyPath:@"status"];
    

    NSURL*playUrl = [NSURL URLWithString:model1.videoURL];

    self.playerItem = [AVPlayerItem playerItemWithURL:playUrl];//如果要切换视频需要调AVPlayer的replaceCurrentItemWithPlayerItem:方法

    if (self.player) {
        [self.player replaceCurrentItemWithPlayerItem:self.playerItem];
    }else{
        self.player = [AVPlayer playerWithPlayerItem:self.playerItem];

        self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];

        self.playerLayer.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.width/16.0*9.0);//放置播放器的视图
        
        [self.OU_CAMPlayerBgView.layer addSublayer:self.playerLayer];
        
    }


    ///播放完成通知
    [[NSNotificationCenter defaultCenter]  addObserver:self selector:@selector(OU_CAMPlayerMovieFinish) name:AVPlayerItemDidPlayToEndTimeNotification object:[self.player currentItem]];

    ///状态通知
    [self.playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
    
    [self OU_CAMAddBackplayTimer];

}

#pragma mark ===============监听回调(手势与播放器)===============
- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void*)context{
    if([object isKindOfClass:[AVPlayerItem class]]) {
        if([keyPath isEqualToString:@"status"]) {
            switch(_playerItem.status) {
                case AVPlayerItemStatusReadyToPlay://推荐将视频播放放这里
                    [self OU_CAMStartPlayingBackStatus];
                break;
                case AVPlayerItemStatusUnknown:
                    NSLog(@"AVPlayerItemStatusUnknown");
                break;
                case AVPlayerItemStatusFailed:
                    NSLog(@"AVPlayerItemStatusFailed");
                break;
                default:
                break;
            }
        }
    }else{///监听滑动手势,当手势滑动时,关闭计时器
        [self OU_CAMRemoveBackplayTimer];
    }
}

  
#pragma mark ===============播放结束通知===============
- (void)OU_CAMPlayerMovieFinish{
    [self OU_CAMNotPlayBackStatus];
    
    if (self.playIndex <= 0) {///全部播放完
        [self OU_CAMRemoveBackplayTimer];
    }else {
        self.playIndex--;
        
        OU_CAMPlaybackModel * model1 = self.OU_CAMDataArray[self.playIndex];
        ///该模型开始时间
        self.OU_CAMBackPlayStartTime = model1.timeStamp + model1.timeLength;
        self.OU_CAMBackPlayTimeLength = 0;
        [self OU_CAMScrollDistanceWithTimeStamp:self.OU_CAMBackPlayStartTime];
        
        [self OU_CAMStartBackplay];
        
    }
    
}
#pragma mark ===============开始播放更改UI状态===============
- (void)OU_CAMStartPlayingBackStatus{
    
    [self.player play];
    
    self.OU_CAMPlayingback = YES;
    self.OU_CAMBackplaySpeedButton.alpha = 1.0;
    self.OU_CAMBackplayStartAndSuspendButton.alpha = 1.0;
    self.OU_CAMBackplaySpeedBgView.alpha = 1.0;
    
    self.OU_CAMBackplaySpeedButton.userInteractionEnabled = YES;
    self.OU_CAMBackplayStartAndSuspendButton.userInteractionEnabled = YES;
    
    [self.OU_CAMBackplayStartAndSuspendButton setImage:[UIImage imageNamed:@"播放_灰"] forState:UIControlStateNormal];
    
    if (@available(iOS 10.0, *)) {
        [self.player playImmediatelyAtRate:self.OU_CAMBackplaySpeed];
    } else {
        [self.player setRate:self.OU_CAMBackplaySpeed];
    }

}
#pragma mark ===============未开始播放状态===============
- (void)OU_CAMNotPlayBackStatus{
    
    self.OU_CAMPlayingback = NO;
    self.OU_CAMBackplaySpeedButton.alpha = 0.4;
    self.OU_CAMBackplayStartAndSuspendButton.alpha = 0.4;
    self.OU_CAMBackplaySpeedBgView.alpha = 0.4;
    
    self.OU_CAMBackplaySpeedButton.userInteractionEnabled = NO;
    self.OU_CAMBackplayStartAndSuspendButton.userInteractionEnabled = NO;
    
    [self.OU_CAMBackplayStartAndSuspendButton setImage:[UIImage imageNamed:@"播放_黑"] forState:UIControlStateNormal];
}

#pragma mark ===============回放暂停与播放===============
- (IBAction)OU_CAMBackplayStartAndSuspend:(id)sender {
    
    if (self.OU_CAMPlayingback) {
        [self.player pause];
        [self.OU_CAMBackplayStartAndSuspendButton setImage:[UIImage imageNamed:@"播放_黑"] forState:UIControlStateNormal];
    }else{
        [self.player play];
        if (@available(iOS 10.0, *)) {
            [self.player playImmediatelyAtRate:self.OU_CAMBackplaySpeed];
        } else {
            [self.player setRate:self.OU_CAMBackplaySpeed];
        }
        [self.OU_CAMBackplayStartAndSuspendButton setImage:[UIImage imageNamed:@"播放_灰"] forState:UIControlStateNormal];
    }
    self.OU_CAMPlayingback = !self.OU_CAMPlayingback;
}
#pragma mark ===============回放速率调整===============
- (IBAction)OU_CAMBackplaySpeed:(id)sender {
    if (self.OU_CAMBackplaySpeed == 1) {
        self.OU_CAMBackplaySpeed = 4;
    }else if (self.OU_CAMBackplaySpeed == 4) {
        self.OU_CAMBackplaySpeed = 8;
    }else if (self.OU_CAMBackplaySpeed == 8) {
        self.OU_CAMBackplaySpeed = 16;
    }else{
        self.OU_CAMBackplaySpeed = 1;
    }
    
    [self.OU_CAMBackplaySpeedButton setTitle:[NSString stringWithFormat:@"X%ld",(long)self.OU_CAMBackplaySpeed] forState:UIControlStateNormal];
    

    if (@available(iOS 10.0, *)) {
        [self.player playImmediatelyAtRate:self.OU_CAMBackplaySpeed];
    } else {
        [self.player setRate:self.OU_CAMBackplaySpeed];
    }
}

#pragma mark ===============UITableViewDelegate&UITableViewDataSource===============
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{

    return self.OU_CAMDataArr.count;
    
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

    OU_CAMPlayBackTableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"OU_CAMPlayBackTableViewCell"];
     
     if (!cell) {
         cell = [[[NSBundle mainBundle] loadNibNamed:@"OU_CAMPlayBackTableViewCell" owner:self options:0] objectAtIndex:0];
         cell.selectionStyle = UITableViewCellSelectionStyleNone;
         
         [cell setValue:@"OU_CAMPlayBackTableViewCell" forKey:@"reuseIdentifier"];
     }
    cell.timeAxisView.scale = self.OU_CAMZoomScaling;
    if (self.OU_CAMDataArr.count > indexPath.row) {
        OU_CAMPlaybackModel * model = self.OU_CAMDataArr[indexPath.row];
        cell.timeAxisView.model = model;
        [cell.contentImageView sd_setImageWithURL:[NSURL URLWithString:model.coverURL] placeholderImage:[UIImage imageNamed:@"logo"]];
    }
    
    [cell.timeAxisView setNeedsDisplay];

    return cell;
}


- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{

    OU_CAMPlaybackModel * model = self.OU_CAMDataArr[indexPath.row];
    
    return model.cellHeight;

}

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{
    
}


- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{
    if (self.OU_CAMDataArr.count) {
        return 100;
    }
    return 0.001;
}

- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section{
    OU_CAMPlaybackFooterView * view = (OU_CAMPlaybackFooterView *)[tableView dequeueReusableHeaderFooterViewWithIdentifier:@"OU_CAMPlaybackFooterView"];
    if (!view) {
        view = [[NSBundle mainBundle] loadNibNamed:@"OU_CAMPlaybackFooterView" owner:self options:0].firstObject;
        view.timeAxisView.tag = 100;
    }
    
    view.timeAxisView.scale = self.OU_CAMZoomScaling;
    
    if (self.OU_CAMDataArr.count) {
        OU_CAMPlaybackModel * model = self.OU_CAMDataArr.lastObject;

        view.timeAxisView.model = model;
        [view.timeAxisView setNeedsDisplay];
        
        if (view.timeAxisView.model.cellHeight < 64) {///需要补全图片
            view.contentImageView.hidden = NO;
            view.contentImageViewLayout_Top.constant = -view.timeAxisView.model.cellHeight;
        }else{
            view.contentImageView.hidden = YES;
        }
        
        [view.contentImageView sd_setImageWithURL:[NSURL URLWithString:model.coverURL] placeholderImage:[UIImage imageNamed:@"logo"]];
        
    }
    return view;
}


- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
    if (self.OU_CAMDataArr.count) {
        return 100;
    }
    return 0.001;
}

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
    OU_CAMPlaybackHeaderView * view = (OU_CAMPlaybackHeaderView *)[tableView dequeueReusableHeaderFooterViewWithIdentifier:@"OU_CAMPlaybackHeaderView"];
    if (!view) {
        view = [[NSBundle mainBundle] loadNibNamed:@"OU_CAMPlaybackHeaderView" owner:self options:0].firstObject;
        view.timeAxisView.tag = 101;
    }
    
    view.timeAxisView.scale = self.OU_CAMZoomScaling;
    
    if (self.OU_CAMDataArr.count) {
        view.timeAxisView.model = self.OU_CAMDataArr.firstObject;
        [view.timeAxisView setNeedsDisplay];

    }
    return view;
}
    -(void)scrollViewDidScroll:(UIScrollView *)scrollView {
    
    if (scrollView == self.OU_CAMPlaybackTableView) {
        [self OU_CAMComputingTimeWithY:scrollView.contentOffset.y - 20];
        
        self.pointY = self.OU_CAMPlaybackTableView.contentOffset.y - 20;

    }
}

- (void)scrollViewDidEndDecelerating:(nonnull UIScrollView *)scrollView{
    // 在这里面写scrollView停止时需要做的事情
    if (scrollView == self.OU_CAMPlaybackTableView) {
        self.OU_CAMPlayOnlineBgView.hidden = NO;
        [self OU_CAMCalculationFragment];
    }
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
    
    if (scrollView == self.OU_CAMPlaybackTableView) {
        if (!decelerate) {
            if (!scrollView.dragging && !scrollView.decelerating) {
                self.OU_CAMPlayOnlineBgView.hidden = NO;
                [self OU_CAMCalculationFragment];
            }
        }
    }

}

控制器中还有别的功能,我就没有复制过来,代码比较多,不知道是否有复制完全,如果按照代码来的无法编译,可以联系我。
最后,如果觉得有用,请给个Star,谢谢!!!
联系方式 qq734651142,备注时间轴缩放。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352

推荐阅读更多精彩内容