項(xiàng)目需求:從云端獲取視頻片段箕速,app中以時(shí)間軸展示視頻片段列表端幼,可以縮放時(shí)間軸,同時(shí)視頻片段列表也需要跟隨縮放弧满,滑動(dòng)時(shí)間軸婆跑,如果選中視頻則選擇該視頻選中的時(shí)間點(diǎn)播放,如果沒有選中視頻庭呜,則找當(dāng)前選中的時(shí)間最近的視頻播放滑进,視頻每播放一秒,時(shí)間軸向下移動(dòng)一秒募谎,將視頻長度對(duì)應(yīng)的繪制在時(shí)間軸上扶关,每個(gè)視頻封面能否顯示需要判斷前后視頻片段對(duì)應(yīng)的時(shí)間軸高度等功能。需求還是比較難做数冬。
代碼中如有不明白的可以聯(lián)系我节槐,聯(lián)系方式qq734651142,標(biāo)明時(shí)間軸縮放拐纱。
運(yùn)行效果如下:
GIF較長铜异,選取了幾張圖片
目前使用起來還是非常流暢,數(shù)據(jù)特別多會(huì)有些許卡頓秸架,小伙伴們有好的優(yōu)化方式歡迎聯(lián)系我揍庄。
比較重要的4個(gè)自定義控件
1、時(shí)間軸繪制控件 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 //顯示半小時(shí)
@implementation OU_CAMTimeAxisView
- (void)drawRect:(CGRect)rect{
if (self.tag == 101) {///組頭
///第一組組數(shù)組东抹。只用繪畫后2個(gè)刻度(當(dāng)前視圖內(nèi)和當(dāng)前視圖下)蚂子,即可保證所有的時(shí)間都能完整
///當(dāng)前組頭結(jié)束對(duì)應(yīng)的時(shí)間點(diǎn)
NSInteger cellStartTime = self.model.modelArray.firstObject.timeStamp;
NSMutableDictionary * dict = [[NSMutableDictionary alloc] init];
dict[NSFontAttributeName] = [UIFont systemFontOfSize:14.0];
dict[NSForegroundColorAttributeName] = [UIColor grayColor];
///小時(shí)
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) {///組尾
///最后一組數(shù)組缭黔。只用繪畫前個(gè)刻度(當(dāng)前視圖內(nèi)和當(dāng)前視圖上)食茎,即可保證所有的時(shí)間都能完整
///當(dāng)前組尾開始對(duì)應(yīng)的時(shí)間點(diǎn)
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];
///小時(shí)
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(@"相差的秒數(shù):%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{
///繪制時(shí)間軸馏谨,每1分鐘繪制長度為CELLHEIGHT别渔,根據(jù)數(shù)組內(nèi)容繪制
NSInteger cellStartTime = self.model.modelArray.firstObject.timeStamp;
for (int i = 0; i < self.model.modelArray.count; i++) {
OU_CAMPlaybackModel * model = self.model.modelArray[I];
///開始時(shí)間(秒)
NSInteger startTime = model.timeStamp + model.timeLength - cellStartTime;
///結(jié)束時(shí)間(秒)
NSInteger stopTime = model.timeStamp - cellStartTime;
///開始時(shí)間點(diǎn)位
CGFloat startPoint = startTime/3600.0 * CELLHEIGHT * self.scale;
///結(jié)束時(shí)間點(diǎn)位
CGFloat stopPoint = stopTime/3600.0 * CELLHEIGHT * self.scale;
[self drawLineWithForm:startPoint To:stopPoint];
}
///繪制時(shí)間,計(jì)算當(dāng)前cell的刻度
///與0點(diǎn)的時(shí)間間隔,計(jì)算時(shí)間
NSInteger zoneTime = (86400 - cellStartTime);
///當(dāng)前cell最大對(duì)應(yīng)的時(shí)間(單位:分)
NSInteger maxTime = zoneTime/60;
///當(dāng)前cell最大分鐘刻度對(duì)應(yīng)該cell頂部的時(shí)間差值,上下限各往外+1钠糊,防止字體空間不夠造成的空缺(單位:秒)
NSInteger difference = (86400 - (maxTime * 60)) - cellStartTime;
///當(dāng)前cell所包含的時(shí)間跨度,上下限各往外+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];
///小時(shí)
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 --;
}
}
///計(jì)算第一個(gè)刻度與頂部的距離
}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){///顯示半小時(shí)抄伍,每十分鐘只顯示刻度
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{///顯示每小時(shí)艘刚,每半小時(shí)只顯示刻度
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 使用默認(rèn)context進(jìn)行繪圖
- (void)drawLineWithForm:(CGFloat)form To:(CGFloat)to{
UIColor *color = MainColor;
[color set]; //設(shè)置線條顏色
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(58, form)];
[path addLineToPoint:CGPointMake(58, to)];
path.lineWidth = 4.0;
path.lineCapStyle = kCGLineCapButt; //線條拐角
path.lineJoinStyle = kCGLineJoinBevel; //終點(diǎn)處理
[path stroke];
}
#pragma mark ===============繪制長刻度===============
- (void)drawLengthRuleWithY:(CGFloat)y{
UIColor *color = [UIColor grayColor];
[color set]; //設(shè)置線條顏色
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(41, y)];
[path addLineToPoint:CGPointMake(56, y)];
path.lineWidth = 1.0;
path.lineCapStyle = kCGLineCapButt; //線條拐角
path.lineJoinStyle = kCGLineJoinBevel; //終點(diǎn)處理
[path stroke];
}
#pragma mark ===============繪制刻度===============
- (void)drawRuleWithY:(CGFloat)y{
UIColor *color = [UIColor grayColor];
[color set]; //設(shè)置線條顏色
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(46, y)];
[path addLineToPoint:CGPointMake(56, y)];
path.lineWidth = 1.0;
path.lineCapStyle = kCGLineCapButt; //線條拐角
path.lineJoinStyle = kCGLineJoinBevel; //終點(diǎn)處理
[path stroke];
}
@end
上面的代碼涉及到視頻片段的模型,模型屬性如下:
///開始時(shí)間
@property (strong, nonatomic) NSString *startTime;
///結(jié)束時(shí)間
@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;
///時(shí)間 12:35
@property (strong, nonatomic) NSString *timeString;
///結(jié)束時(shí)間相對(duì)于當(dāng)天24時(shí)的時(shí)間戳 0~246060
@property (assign, nonatomic) NSInteger timeStamp;
///回放時(shí)長 單位為秒
@property (assign, nonatomic) NSInteger timeLength;
///動(dòng)態(tài)刷新記錄cell高度
@property (assign, nonatomic) CGFloat cellHeight;
///記錄該cell的跨度時(shí)間長度
@property (assign, nonatomic) NSInteger spanTime;
///動(dòng)態(tài)刷新截珍,記錄在同一個(gè)cell中的模型
@property (nonatomic, strong)NSMutableArray <OU_CAMPlaybackModel > modelArray;
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface OU_CAMPlaybackModel : NSObject
///開始時(shí)間
@property (strong, nonatomic) NSString *startTime;
///結(jié)束時(shí)間
@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;
///時(shí)間 12:35
@property (strong, nonatomic) NSString *timeString;
///結(jié)束時(shí)間相對(duì)于當(dāng)天24時(shí)的時(shí)間戳 0~24*60*60
@property (assign, nonatomic) NSInteger timeStamp;
///回放時(shí)長 單位為秒
@property (assign, nonatomic) NSInteger timeLength;
///動(dòng)態(tài)刷新記錄cell高度
@property (assign, nonatomic) CGFloat cellHeight;
///記錄該cell的跨度時(shí)間長度
@property (assign, nonatomic) NSInteger spanTime;
///動(dòng)態(tài)刷新攀甚,記錄在同一個(gè)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文件中無內(nèi)容岗喉,xib中添加了時(shí)間軸繪制控件秋度,做的時(shí)候怎么方便怎么來,沒用代碼布局钱床。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
相對(duì)于頭部多了一個(gè)封面預(yù)覽圖
xib布局如下:
.m文件中無內(nèi)容
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文件中無內(nèi)容
VC中調(diào)用
#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;
///監(jiān)聽滑動(dòng)手勢(shì)
[self.OU_CAMPlaybackTableView addObserver:self forKeyPath:@"panGestureRecognizer.state" options:NSKeyValueObservingOptionNew context:nil];
///計(jì)算滑動(dòng)區(qū)域
///如果劉海屏查牌,下盤的操作按鈕留出安全區(qū)域
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 ===============加載數(shù)據(jù)(視頻回放)===============
- (void)OU_CAMLoadPlaybackData{
/*
///開始時(shí)間
@property (strong, nonatomic) NSString *startTime;
///結(jié)束時(shí)間
@property (strong, nonatomic) NSString *endTime;
///封面URL
@property (strong, nonatomic) NSString *coverURL;
///視頻URL
@property (strong, nonatomic) NSString *videoURL;
///結(jié)束時(shí)間相對(duì)于當(dāng)天0時(shí)的時(shí)間戳 0~24*60*60
@property (assign, nonatomic) NSInteger timeStamp;
///回放時(shí)長 單位為秒
@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];
///計(jì)算
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{///計(jì)算與前面cell的時(shí)間戳事期,判斷是否可以顯示該model
OU_CAMPlaybackModel * model1 = self.OU_CAMDataArray[index];
height = (model.timeStamp - model1.timeStamp)/3600.0*CELLHEIGHT;
if (height > 80) {///展示該cell,同時(shí)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];
///添加縮放手勢(shì)
UIPinchGestureRecognizer * ges = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(OU_CAMPinch:)];
[self.OU_CAMBgView addGestureRecognizer:ges];
}
#pragma mark ===============縮放手勢(shì)===============
// 處理縮放手勢(shì)
- (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) {
///刷新滾動(dòng)位置
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;
}
///計(jì)算
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{///計(jì)算與前面cell的時(shí)間戳,判斷是否可以顯示該model
OU_CAMPlaybackModel * model1 = self.OU_CAMDataArray[index];
height = (model.timeStamp - model1.timeStamp)/3600.0*CELLHEIGHT*self.OU_CAMZoomScaling;
if (height > 80) {///展示該cell,同時(shí)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];
//時(shí)間轉(zhuǎn)換為距離
[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 ===============計(jì)算滑動(dòng)&縮放后選中的時(shí)間===============
- (void)OU_CAMComputingTimeWithY:(CGFloat)y{
if (self.OU_CAMDataArray.count == 0) {
return;
}
NSInteger seconds = y/self.OU_CAMZoomScaling;
///距離當(dāng)天0點(diǎn)對(duì)應(yīng)的秒數(shù)
OU_CAMPlaybackModel * model = self.OU_CAMDataArray.firstObject;
self.OU_CAMTimeStamp = (model.timeStamp + seconds);
NSInteger timeStamp = 86400 - self.OU_CAMTimeStamp;
if (!self.isTiming) {///當(dāng)計(jì)時(shí)器在計(jì)時(shí)時(shí)纸颜,不用滾動(dòng)更改
[self OU_CAMSelectTimeUI:timeStamp];
}
}
#pragma mark ===============選中的時(shí)間展示===============
- (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 ===============添加回放計(jì)時(shí)器===============
- (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 ===============移除回放計(jì)時(shí)器===============
- (void)OU_CAMRemoveBackplayTimer{
if (self.OU_CAMBackplayTimer) {
self.isTiming = NO;
[self.OU_CAMBackplayTimer invalidate];
self.OU_CAMBackplayTimer = nil;
}
}
#pragma mark ===============回放計(jì)時(shí)器事件===============
- (void)OU_CAMBackplayTimerClick{
///獲取當(dāng)前視頻播放的進(jìn)度(已經(jīng)播放時(shí)間)
self.OU_CAMBackPlayTimeLength = round(self.playerItem.currentTime.value/self.playerItem.currentTime.timescale);
// self.OU_CAMBackPlayStartTime - currentTime
///選中時(shí)間展示
[self OU_CAMSelectTimeUI:86400 - self.OU_CAMBackPlayStartTime + self.OU_CAMBackPlayTimeLength];
///滾動(dòng)距離
[self OU_CAMScrollDistanceWithTimeStamp:self.OU_CAMBackPlayStartTime - self.OU_CAMBackPlayTimeLength];
}
#pragma mark ===============縮放結(jié)束&滑動(dòng)停止后需要計(jì)算指定位播放===============
- (void)OU_CAMCalculationFragment{
if (self.OU_CAMDataArray.count == 0) {
return;
}
///優(yōu)先判斷選中的時(shí)間是否正好處于回放片段內(nèi)兽泣,是則不用滾動(dòng)到最近的回放片段
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;
///需要設(shè)置的播放點(diǎn)
self.OU_CAMBackPlayTimeLength = model.timeStamp + model.timeLength - self.OU_CAMTimeStamp;
index = i;
///判斷是否是同一個(gè)播放源,是的話直接跳進(jìn)度胁孙,如果不是唠倦,則需要先切換播放源,然后跳進(jìn)度
if (index == self.playIndex) {///相同播放源
}else{///不同播放源
self.playIndex = i;
self.OU_CAMBackPlayStartTime = model.timeStamp + model.timeLength;
[self OU_CAMStartBackplay];
}
//讓視頻從指定的CMTime對(duì)象處播放涮较。
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;
///該模型開始時(shí)間
self.OU_CAMBackPlayStartTime = model1.timeStamp + model1.timeLength;
self.OU_CAMBackPlayTimeLength = 0;
[self OU_CAMStartBackplay];
[self OU_CAMScrollDistanceWithTimeStamp:self.OU_CAMBackPlayStartTime];
}
#pragma mark ===============根據(jù)當(dāng)前時(shí)間戳計(jì)算滾動(dòng)距離===============
- (void)OU_CAMScrollDistanceWithTimeStamp:(NSInteger)timeStamp{
///使用第一個(gè)模型的結(jié)束時(shí)間時(shí)間戳差值來計(jì)算需要滾動(dòng)的距離
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;
///移除監(jiān)聽
[self.playerItem removeObserver:self forKeyPath:@"status"];
NSURL*playUrl = [NSURL URLWithString:model1.videoURL];
self.playerItem = [AVPlayerItem playerItemWithURL:playUrl];//如果要切換視頻需要調(diào)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]];
///狀態(tài)通知
[self.playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
[self OU_CAMAddBackplayTimer];
}
#pragma mark ===============監(jiān)聽回調(diào)(手勢(shì)與播放器)===============
- (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{///監(jiān)聽滑動(dòng)手勢(shì)稠鼻,當(dāng)手勢(shì)滑動(dòng)時(shí),關(guān)閉計(jì)時(shí)器
[self OU_CAMRemoveBackplayTimer];
}
}
#pragma mark ===============播放結(jié)束通知===============
- (void)OU_CAMPlayerMovieFinish{
[self OU_CAMNotPlayBackStatus];
if (self.playIndex <= 0) {///全部播放完
[self OU_CAMRemoveBackplayTimer];
}else {
self.playIndex--;
OU_CAMPlaybackModel * model1 = self.OU_CAMDataArray[self.playIndex];
///該模型開始時(shí)間
self.OU_CAMBackPlayStartTime = model1.timeStamp + model1.timeLength;
self.OU_CAMBackPlayTimeLength = 0;
[self OU_CAMScrollDistanceWithTimeStamp:self.OU_CAMBackPlayStartTime];
[self OU_CAMStartBackplay];
}
}
#pragma mark ===============開始播放更改UI狀態(tài)===============
- (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:@"播放_(tái)灰"] forState:UIControlStateNormal];
if (@available(iOS 10.0, *)) {
[self.player playImmediatelyAtRate:self.OU_CAMBackplaySpeed];
} else {
[self.player setRate:self.OU_CAMBackplaySpeed];
}
}
#pragma mark ===============未開始播放狀態(tài)===============
- (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:@"播放_(tái)黑"] forState:UIControlStateNormal];
}
#pragma mark ===============回放暫停與播放===============
- (IBAction)OU_CAMBackplayStartAndSuspend:(id)sender {
if (self.OU_CAMPlayingback) {
[self.player pause];
[self.OU_CAMBackplayStartAndSuspendButton setImage:[UIImage imageNamed:@"播放_(tái)黑"] 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:@"播放_(tái)灰"] forState:UIControlStateNormal];
}
self.OU_CAMPlayingback = !self.OU_CAMPlayingback;
}
#pragma mark ===============回放速率調(diào)整===============
- (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) {///需要補(bǔ)全圖片
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停止時(shí)需要做的事情
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];
}
}
}
}
控制器中還有別的功能法希,我就沒有復(fù)制過來枷餐,代碼比較多靶瘸,不知道是否有復(fù)制完全苫亦,如果按照代碼來的無法編譯,可以聯(lián)系我怨咪。
最后屋剑,如果覺得有用,請(qǐng)給個(gè)Star诗眨,謝謝0ω摇!!
聯(lián)系方式 qq734651142巍膘,備注時(shí)間軸縮放厂财。