项目需求:从云端获取视频片段,app中以时间轴展示视频片段列表,可以缩放时间轴,同时视频片段列表也需要跟随缩放,滑动时间轴,如果选中视频则选择该视频选中的时间点播放,如果没有选中视频,则找当前选中的时间最近的视频播放,视频每播放一秒,时间轴向下移动一秒,将视频长度对应的绘制在时间轴上,每个视频封面能否显示需要判断前后视频片段对应的时间轴高度等功能。需求还是比较难做。
代码中如有不明白的可以联系我,联系方式qq734651142,标明时间轴缩放。
运行效果如下:
GIF较长,选取了几张图片
目前使用起来还是非常流畅,数据特别多会有些许卡顿,小伙伴们有好的优化方式欢迎联系我。
比较重要的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布局如下:
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布局如下:
.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布局如下:
.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,备注时间轴缩放。