寫在前面寇损、感謝作者
使用AVPlayer自定義支持全屏的播放器http://www.reibang.com/p/11e05d684c05
說明:本文使用的是第一篇文章作者的框架狼纬,加入第二篇文章作者的思路呀邢,實現(xiàn)了 在tabbleViewCell上播放視頻缤苫、滑動自動播放暫停以及對播放器的定制等等。注意:此處并不包含播放完成cell自動滑動的功能坛怪,這一點也不難淤齐,相信你學(xué)會了滑動自動播放,這一功能也就水到渠成了袜匿。
項目效果圖
關(guān)于制作GIF圖的一種方法請?zhí)D(zhuǎn)
非常遺憾更啄,不滿足蘋果審核要求,項目遲遲未能上線居灯、不能被大家所下載
2017年7月11日 下午11:37
發(fā)件人 Apple
Guideline 3.2.2 - Business - Other Business Model Issues - Unacceptable
The feature in your app displays or promotes third-party apps, which is not appropriate for the App Store.
Please see attached screenshots for details.
Next Steps
To resolve this issue, please remove the feature from your app.
隱藏好像都已經(jīng)無可救藥了
2017年7月13日 下午8:37
發(fā)件人 Apple
- 2.2 Business: Other Business Model Issues - Unacceptable
Guideline 3.2.2 - Business - Other Business Model Issues - Unacceptable
Your app displays or promotes third-party apps, which is not appropriate for the App Store.
Next Steps
We encourage you to review your app concept and incorporate different content and features that are in compliance with the App Store Review Guidelines.
對比 作者與我修改后的界面(我只是單純的修改了一下界面)
作者的界面:
我修改后的界面:
修改地方:
將原來播放暫停的按鈕移動到屏幕正中央祭务,在左下角播放暫停按鈕處添加一個靜音按鈕,也就是要么靜音要么以某一音量播放(我添加的為0.3)
回到正題:AVPlayer的封裝怪嫌、tableviewcell上視頻播放以及滑動播放暫停
實現(xiàn)原理:關(guān)于tableviewcell上播放視頻的一些說明:首先义锥、我們并不是讓每一個cell都擁有一個播放器,而是讓tableview所在的控制器擁有一個播放器岩灭,然后根據(jù)計算來決定哪個cell此時應(yīng)該播放視頻拌倍,進而將控制器的播放器 添加 到cell的contentView上。在滑動過程中,我們會不斷的判斷正在播放的cell是否滑出屏幕或者正在播放的cell需要被另一個cell所替代柱恤,通過判斷來對播放器的銷毀以及重新初始化并添加到相應(yīng)的cell上数初。
讓控制器擁有一個播放器是我在項目實踐過程中想到的一個方案并付諸實踐,效果還可以梗顺,至少從內(nèi)存的角度可以看到變化泡孩。由原先的 130M左右降到現(xiàn)在的65M左右。
準備工作:下載作者或我的playerView代碼
作者GitHubhttps://github.com/JmoVxia/CLPlayer
說明:我會直接使用我項目中的截圖來給大家分享寺谤,沒有一個完整的demo仑鸥。但是我會教你怎么使用。
1.0關(guān)于cell中對于播放器view的布局 以及 cell需要添加一個videoFrame的屬性
播放器所在的視圖結(jié)構(gòu)大致就是這樣矗漾。將播放暫停按鈕的操作傳到tableview所在的控制器锈候,這里有一點需要注意:那就是 計算出 播放器所在的視圖也就是上面videoView的frame,傳遞給控制器以便初始化播放器的時候?qū)⑵涮砑拥絚ell上敞贡。所以泵琳,給每個需要播放視頻的cell 添加一個屬性,videoFrame誊役,來記錄videoView的frame
+ (instancetype)cellWithTableView:(UITableView *)tableView;
@property (nonatomic,strong)ConventionsModel *convention;
//用來記錄播放器在cell的frame
@property (nonatomic,assign)CGRect videoFrame;
@property (nonatomic,assign)id<DiscoverVideoCellDelegate> delegate;
@end
在給cell設(shè)置數(shù)據(jù)后并強制布局后再計算videoFrame
- (void)setConvention:(ConventionsModel *)convention
{
_convention = convention;
// 這里給cell上的控件賦值
//如果cell的高度需要自適應(yīng)获列,這里一定要強制布局,然后再計算videoFrame,否則蛔垢、播放器播放時可能不會在你想要的地方
[self layoutIfNeeded];
// convention.cellHeight = CGRectGetMaxY(self.gameIcon.frame) + CGRectGetMinY(self.titleLabel.frame);
// }
self.videoFrame = self.videoView.frame;
}
2.0在控制器中點擊播放暫停按鈕進行播放 或者 進入控制器后自動播放
理論說明:如果不需要自動播放击孩,那么通過代理將cell上的播放暫停按鈕點擊事件傳遞給控制器后,我們只需要 初始化 控制器擁有的那個播放器屬性鹏漆,并將其添加到點擊的cell上即可巩梢。
在需要自動播放時,我們就需要進行分類判斷艺玲,當進入該控制器括蝠,請求到數(shù)據(jù)后,播放當前tableview上的第一個(最上面的)視頻饭聚,當滑動tableview時忌警,播放cell中心(更準確的說:應(yīng)該是cell上videoView的中心)距離屏幕中心最近的cell上的視頻。
下面我直接分享自動播放的情況秒梳,在控制器中添加兩個屬性法绵、一個是播放器(view)一個是正在播放的cell。倘若你的tableview中只有一種cell酪碘,你可以直接使用該類型的cell朋譬,因為我的項目中并不是每個cell上都有視頻播放,所有我直接用UITableViewCell兴垦,模態(tài)屬性此熬,父類指向子類。
@property (nonatomic,strong)CLPlayerView *clPlayerView;
@property (nonatomic,strong)UITableViewCell *playingCell;
3.0請求到數(shù)據(jù)后播放第一個視頻
我們可以在請求到數(shù)據(jù)的回調(diào)里面刷新列表后播放第一個視頻
[self.tableView reloadData];
//進入界面播放
[self playVideoInVisiableCells];
3.1進入這個界面就自動播放
//進入這個界面就自動播放
-(void)playVideoInVisiableCells{
//下面是我實際項目中代碼。在這里你需要做的就是獲得第一個有視頻的cell犀忱,并進行播放和記錄。播放視頻可以抽到一個方法中扶关,需要的就是播放視頻所在的cell以及視頻播放所需要的地址URL等阴汇。可以仿照我的進行寫代碼节槐,當然搀庶,如果你的每個cell類型相同且都有視頻,你可以直接獲取可見的cell NSArray *visiableCells = [self.tableView visibleCells]; 判斷 visiableCells.count是否大于0铜异,正在播放的cell就是第一個了哥倔。接下來我們說一說播放視頻- (void)initPlayerView:(DiscoverVideoCell *)cell playClick:(ConventionsModel *)convention
// 找到下一個要播放的cell(最在屏幕中心的)
DiscoverVideoCell *firstCell = nil;
NSArray *visiableCells = [self.tableView visibleCells];
//存放大框播放視頻
for (int i = 0; i < visiableCells.count; i++) {
UITableViewCell *cell = visiableCells[i];
if ([cell isKindOfClass:[DiscoverVideoCell class]]) {
firstCell = (DiscoverVideoCell *)cell;
break;
}
}
//播放第一個視頻
[self initPlayerView:firstCell playClick:firstCell.convention];
}
4.0播放視頻
初始化視頻播放器,并將其添加到正在播放的cell上
- (void)initPlayerView:(DiscoverVideoCell *)cell playClick:(ConventionsModel *)convention
{
self.playingCell = cell;
// self.playingIndexPath = [self.tableView indexPathForCell:cell];
[_clPlayerView destroyPlayer];
_clPlayerView = nil;
CLPlayerView *playerView = [[CLPlayerView alloc] initWithFrame:cell.videoFrame];
_clPlayerView = playerView;
[cell.contentView addSubview:_clPlayerView];
//視頻地址
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
_clPlayerView.url = convention.url;
//播放
[_clPlayerView playVideo];
});
//返回按鈕點擊事件回調(diào)
[_clPlayerView backButton:^(UIButton *button) {
NSLog(@"返回按鈕被點擊");
}];
//播放完成回調(diào)
[_clPlayerView endPlay:^{
//銷毀播放器
[_clPlayerView destroyPlayer];
_clPlayerView = nil;
NSLog(@"播放完成");
}];
}
5.0滾動播放暫停
//滾動播放暫停說明:對于正在播放的視頻揍庄、我們需要時刻監(jiān)聽cell是否移除界面咆蒿;而對于正在播放的cell被替代時,我們可以在滾動停止時進行播放器的初始化并播放蚂子。
所以沃测、只需要在以下三個代理方法中實現(xiàn)即可。
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
//我發(fā)現(xiàn)作者對于內(nèi)存的釋放有一點問題食茎,播放器銷毀后內(nèi)存并沒有下降
// [_clPlayerView calculateScrollOffset:self.tableView cell:self.playingCell];
//我嘗試去修改作者的蒂破,似乎也沒有起作用,所有自己在改方法中進行銷毀
NSArray *cells = [self.tableView visibleCells];
if (![cells containsObject:self.playingCell]) {
if (_clPlayerView) {
//銷毀播放器
[_clPlayerView destroyPlayer];
_clPlayerView = nil;
}
}
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
//滑動播放
[self handleScrollPlaying:scrollView];
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
if (!decelerate){
//滑動播放
[self handleScrollPlaying:scrollView];
}
}
//這里參考第二篇文章的計算方式别渔,更準確的計算方式應(yīng)該是:cell中videoView的中心距屏幕的中心最近的cell為正在播放的cell附迷。
//滑動播放
- (void)handleScrollPlaying:(UIScrollView *)scrollView
{
// 找到下一個要播放的cell(最在屏幕中心的)
DiscoverVideoCell *finnalCell = nil;
NSArray *visiableCells = [self.tableView visibleCells];
//存放大框播放視頻
NSMutableArray *tempVideoCells = [NSMutableArray array];
for (int i = 0; i < visiableCells.count; i++) {
UITableViewCell *cell = visiableCells[i];
if ([cell isKindOfClass:[DiscoverVideoCell class]]) {
[tempVideoCells addObject:cell];
}
}
NSMutableArray *indexPaths = [NSMutableArray array];
CGFloat gap = MAXFLOAT;
for (DiscoverVideoCell *cell in tempVideoCells) {
[indexPaths addObject:[self.tableView indexPathForCell:cell]];
//計算距離屏幕中心最近的cell
CGPoint coorCentre = [cell.superview convertPoint:cell.center toView:nil];
CGFloat delta = fabs(coorCentre.y-[UIScreen mainScreen].bounds.size.height*0.5);
if (delta < gap) {
gap = delta;
finnalCell = cell;
}
}
// 注意, 如果正在播放的cell和finnalCell是同一個cell, 不應(yīng)該在播放
if (finnalCell != nil && self.playingCell != finnalCell) {
if (_clPlayerView) {
[_clPlayerView destroyPlayer];
_clPlayerView = nil;
}
[self initPlayerView:finnalCell playClick:finnalCell.convention];
self.playingCell = finnalCell;
return;
}
}
在tableviewcell上播放視頻,在這里基本上就結(jié)束了哎媚。目前在項目中使用良好喇伯。