下面要说的就是短视频软件开发重中之重,仿抖音滑动播放视频的实现。

当我们首次进入播放短视频页面时,会优先判断当前的视频列表videoList是否有值,如果没有值或当前的视频的index大于videoList.count - 3 时,就会重新请求服务端,获取新的一组短视频。

下面时核心代码

if (!_videoList || _videoList.count == 0) {_isHome = YES;_currentIndex = 0;_pages = 1;self.videoList = [NSMutableArray array];[self requestMoreVideo];//请求数据并加载页面
}
if (_currentIndex>=_videoList.count-3) {_pages += 1;[self requestMoreVideo];//请求数据并加载页面}
- (void)requestMoreVideo { WeakSelf;[YBNetworking postWithUrl:url Dic:nil Suc:^(NSDictionary *data, NSString *code,  NSString *msg) {if ([code isEqual:@"0"]) {NSArray *info = [data valueForKey:@"info"];if (_pages==1) {[_videoList removeAllObjects];}[_videoList addObjectsFromArray:info];if (_isHome == YES) {_isHome = NO;_scrollViewOffsetYOnStartDrag = -100;[weakSelf scrollViewDidEndScrolling];//加载页面}}} Fail:^(id fail) {}];
}

结下来我们要介绍加载页面的三种情况,这里我们会用到三个UIImageView,为firstImageView、secondImageView,thirdImageView,对应三个展示UI的View,分别为firstFront、secondFront、thirdFront,对应三个数据源lastHostDic、hostdic、nextHostDic:

第一种是刚进来currentIndex == 0(currentIndex是指当前滚动到第几个视频),这时候我们要设置UIScrollView的ContentOffset为(0,0), currentPlayerIV(当前UIIMageView)为firstImageView,currentFront(当前呈现UI的View)为firstFront。并且要预加载secondImageView的数据,这里不用处理thirdImageView,因为只能向下滑,不需要预加载thirdImageView并且滚到第二个的时候自然给第三个赋值:

//第一个[self.backScrollView setContentOffset:CGPointMake(0, 0) animated:NO];_currentPlayerIV = _firstImageView;_currentFront = _firstFront;/***  _currentIndex=0时,重新处理下_secondImageView的封面、*  不用处理_thirdImageView,因为滚到第二个的时候上面的判断自然给第三个赋值*/[_firstImageView sd_setImageWithURL:[NSURL URLWithString:minstr([_hostdic valueForKey:@"thumb"])]];[self setUserData:_hostdic withFront:_firstFront];[self setVideoData:_hostdic withFront:_firstFront];[_secondImageView sd_setImageWithURL:[NSURL URLWithString:minstr([_nextHostDic valueForKey:@"thumb"])]];[self setUserData:_nextHostDic withFront:_secondFront];[self setVideoData:_nextHostDic withFront:_secondFront];

这里的setUerData和setVideoData是给页面加载数据的,详细实现为:

-(void)setUserData:(NSDictionary *)dataDic withFront:(FrontView*)front{NSDictionary *musicDic = [dataDic valueForKey:@"musicinfo"];id userinfo = [dataDic valueForKey:@"userinfo"];NSString *dataUid;NSString *dataIcon;NSString *dataUname;if ([userinfo isKindOfClass:[NSDictionary class]]) {dataUid = [NSString stringWithFormat:@"%@",[userinfo valueForKey:@"id"]];dataIcon = [NSString stringWithFormat:@"%@",[userinfo valueForKey:@"avatar"]];//右边最上面的带➕的头像图片dataUname = [NSString stringWithFormat:@"@%@",[userinfo valueForKey:@"user_nicename"]];//左下角第一行@的作者名}else{dataUid = @"0";dataIcon = @"";dataUname = @"";}NSString *musicID = [NSString stringWithFormat:@"%@",[musicDic valueForKey:@"id"]];NSString *musicCover = [NSString stringWithFormat:@"%@",[musicDic valueForKey:@"img_url"]];//musicIV右下角转动的唱片上覆盖的歌曲背景图片if ([musicID isEqual:@"0"]) {[front.musicIV sd_setImageWithURL:[NSURL URLWithString:_hosticon]];}else{[front.musicIV sd_setImageWithURL:[NSURL URLWithString:musicCover]];}[front setMusicName:[NSString stringWithFormat:@"%@",[musicDic valueForKey:@"music_format"]]];front.titleL.text = [NSString stringWithFormat:@"%@",[dataDic valueForKey:@"title"]];//左下角滚动的文字front.nameL.text = dataUname;[front.iconBtn sd_setBackgroundImageWithURL:[NSURL URLWithString:dataIcon] forState:UIControlStateNormal placeholderImage:[UIImage imageNamed:@"default_head.png"]];//广告NSString *is_ad_str = [NSString stringWithFormat:@"%@",[dataDic valueForKey:@"is_ad"]];NSString *ad_url_str = [NSString stringWithFormat:@"%@",[dataDic valueForKey:@"ad_url"]];CGFloat ad_img_w = 0;if (![PublicObj checkNull:ad_url_str]&&[is_ad_str isEqual:@"1"]&&![PublicObj checkNull:front.titleL.text]) {NSString *att_text = [NSString stringWithFormat:@"%@    ",front.titleL.text];UIImage *ad_link_img = [UIImage imageNamed:@"广告-详情"];NSMutableAttributedString *att_img = [NSMutableAttributedString yy_attachmentStringWithContent:ad_link_img contentMode:UIViewContentModeCenter attachmentSize:CGSizeMake(13, 13) alignToFont:SYS_Font(15) alignment:YYTextVerticalAlignmentCenter];NSMutableAttributedString *title_att = [[NSMutableAttributedString alloc]initWithString:att_text];//NSLog(@"-==-:%@==:%@==img:%@",att_text,title_att,att_img);[title_att appendAttributedString:att_img];NSRange click_range = [[title_att string] rangeOfString:[att_img string]];title_att.yy_font = SYS_Font(15);title_att.yy_color = [UIColor whiteColor];title_att.yy_lineBreakMode = NSLineBreakByTruncatingHead;title_att.yy_kern = [NSNumber numberWithFloat:0.2];[title_att addAttribute:NSBackgroundColorAttributeName value:[UIColor clearColor] range:click_range];[title_att yy_setTextHighlightRange:click_range color:[UIColor clearColor] backgroundColor:[UIColor clearColor] tapAction:^(UIView * _Nonnull containerView, NSAttributedString * _Nonnull text, NSRange range, CGRect rect) {//[YBMsgPop showPop:@"1111111"];[self adJump:ad_url_str];}];front.titleL.preferredMaxLayoutWidth =_window_width*0.75;front.titleL.attributedText = title_att;ad_img_w = 30;}//计算名称长度 最长3行高度最大60CGSize titleSize = [front.titleL.text boundingRectWithSize:CGSizeMake(_window_width*0.75, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:SYS_Font(15)} context:nil].size;CGFloat title_h = titleSize.height>60?60:titleSize.height;CGFloat title_w = _window_width*0.75;//titleSize.width>=(_window_width*0.75)?titleSize.width:titleSize.width+ad_img_w;front.titleL.frame = CGRectMake(0, front.musicL.top-title_h, title_w, title_h);front.nameL.frame = CGRectMake(0, front.titleL.top-25, front.botView.width, 25);front.followBtn.frame = CGRectMake(front.iconBtn.left+12, front.iconBtn.bottom-13, 26, 26);//广告if ([is_ad_str isEqual:@"1"]) {front.adLabel.hidden = NO;front.adLabel.frame = CGRectMake(0, front.nameL.top-25, 45, 20);}else{front.adLabel.hidden = YES;}}
-(void)setVideoData:(NSDictionary *)videoDic withFront:(FrontView*)front{_shares =[NSString stringWithFormat:@"%@",[videoDic valueForKey:@"shares"]];_likes = [NSString stringWithFormat:@"%@",[videoDic valueForKey:@"likes"]];_islike = [NSString stringWithFormat:@"%@",[videoDic valueForKey:@"islike"]];_comments = [NSString stringWithFormat:@"%@",[videoDic valueForKey:@"comments"]];NSString *isattent = [NSString stringWithFormat:@"%@",[NSString stringWithFormat:@"%@",[videoDic valueForKey:@"isattent"]]];//_steps = [NSString stringWithFormat:@"%@",[info valueForKey:@"steps"]];WeakSelf;//dispatch_async(dispatch_get_main_queue(), ^{//点赞数 评论数 分享数if ([weakSelf.islike isEqual:@"1"]) {[front.likebtn setImage:[UIImage imageNamed:@"home_zan_sel"] forState:0];//weakSelf.likebtn.userInteractionEnabled = NO;} else{[front.likebtn setImage:[UIImage imageNamed:@"home_zan"] forState:0];//weakSelf.likebtn.userInteractionEnabled = YES;}[front.likebtn setTitle:[NSString stringWithFormat:@"%@",_likes] forState:0];front.likebtn = [PublicObj setUpImgDownText:front.likebtn];[front.enjoyBtn setTitle:[NSString stringWithFormat:@"%@",_shares] forState:0];front.enjoyBtn = [PublicObj setUpImgDownText:front.enjoyBtn];[front.commentBtn setTitle:[NSString stringWithFormat:@"%@",_comments] forState:0];front.commentBtn = [PublicObj setUpImgDownText:front.commentBtn];if ([[Config getOwnID] isEqual:weakSelf.hostid] || [isattent isEqual:@"1"]) {front.followBtn.hidden = YES;}else{[front.followBtn setImage:[UIImage imageNamed:@"home_follow"] forState:0];front.followBtn.hidden = NO;[front.followBtn.layer addAnimation:[PublicObj followShowTransition] forKey:nil];}//});
}

第二种是当你用手滑动的时候,currentIndex > 0 并且小于videoList.count - 1(即既不是第一个也不是最后一个视频),这时候会优先触发代理方法:

#pragma mark - scrollView delegate
//开始拖拽
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{lastContenOffset = scrollView.contentOffset.y;//NSLog(@"111=====%f",scrollView.contentOffset.y);_currentPlayerIV.jp_progressView.hidden = YES;//当前播放进度隐藏self.scrollViewOffsetYOnStartDrag = scrollView.contentOffset.y;//记录开始拖拽的contentoffset
}
//结束拖拽
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollViewwillDecelerate:(BOOL)decelerate {endDraggingOffset = scrollView.contentOffset.y;//记录结束拖拽的位置//NSLog(@"222=====%f",scrollView.contentOffset.y);if (decelerate == NO) {[self scrollViewDidEndScrolling];}
}//开始减速
-(void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView {scrollView.scrollEnabled = NO;//NSLog(@"333=====%f",scrollView.contentOffset.y);}- (void)scrollViewDidScroll:(UIScrollView *)scrollView{//NSLog(@"currentIndex=====%.2f",scrollView.contentSize.height);
}//结束减速
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {scrollView.scrollEnabled = YES;//NSLog(@"444=====%f",scrollView.contentOffset.y);if (lastContenOffset < scrollView.contentOffset.y && (scrollView.contentOffset.y-lastContenOffset)>=_window_height) {NSLog(@"=====向上滚动=====");_currentIndex++;if (_currentIndex>_videoList.count-1) {_currentIndex =_videoList.count-1;}}else if(lastContenOffset > scrollView.contentOffset.y && (lastContenOffset-scrollView.contentOffset.y)>=_window_height){NSLog(@"=====向下滚动=====");_currentIndex--;if (_currentIndex<0) {_currentIndex=0;}}else{NSLog(@"=======本页拖动未改变数据=======");if (scrollView.contentOffset.y == 0 && _currentIndex==0) {[YBMsgPop showPop:@"已经到顶了哦^_^"];}else if (scrollView.contentOffset.y == _window_height*2 && _currentIndex==_videoList.count-1){[YBMsgPop showPop:@"没有更多了哦^_^"];}}_currentPlayerIV.jp_progressView.hidden = NO;[self scrollViewDidEndScrolling];if (_requestUrl) {if (_currentIndex>=_videoList.count-3) {_pages += 1;[self requestMoreVideo];}}}#pragma mark - Private- (void)scrollViewDidEndScrolling {if((self.scrollViewOffsetYOnStartDrag == self.backScrollView.contentOffset.y) && (endDraggingOffset!= _scrollViewOffsetYOnStartDrag)){return;}//NSLog(@"7-8==%f====%f",self.scrollViewOffsetYOnStartDrag,self.backScrollView.contentOffset.y);[self changeRoom];}

这时当scrollview 滑动自动触发翻页时,则让UIScrollView迅速复位,这时候我们要设置UIScrollView的ContentOffset为(0,_window_height), _window_height为当前屏幕大小,currentPlayerIV(当前UIIMageView)为secondImageView,currentFront(当前呈现UI的View)为secondFront。并且要预加载firstImageView,firstFront和thirdImageView,thirdFront数据的。代码如下:

[_secondImageView sd_setImageWithURL:[NSURL URLWithString:minstr([_hostdic valueForKey:@"thumb"])]];//这里设置视频的第一帧,用于在整个页面显示[self setUserData:_hostdic withFront:_secondFront];[self setVideoData:_hostdic withFront:_secondFront];
[self.backScrollView setContentOffset:CGPointMake(0, _window_height) animated:NO];_currentPlayerIV = _secondImageView;_currentFront = _secondFront;
 if (_curentIndex>0) {_lastHostDic = _videoList[_curentIndex-1];[_firstImageView sd_setImageWithURL:[NSURL URLWithString:minstr([_lastHostDic valueForKey:@"thumb"])]];[self setUserData:_lastHostDic withFront:_firstFront];[self setVideoData:_lastHostDic withFront:_firstFront];}if (_curentIndex < _videoList.count-1) {_nextHostDic = _videoList[_curentIndex+1];[_thirdImageView sd_setImageWithURL:[NSURL URLWithString:minstr([_nextHostDic valueForKey:@"thumb"])]];[self setUserData:_nextHostDic withFront:_thirdFront];[self setVideoData:_nextHostDic withFront:_thirdFront];}

第三种情况是滚动到最后一个,这时候我们要设置UIScrollView的ContentOffset为(0,_window_height*2), _window_height为当前屏幕大小,currentPlayerIV(当前UIIMageView)为thirdImageView,currentFront(当前呈现UI的View)为thirdFront。并且要预加载secondImageView,secondFront数据的。代码如下:

//最后一个[self.backScrollView setContentOffset:CGPointMake(0, _window_height*2) animated:NO];_currentPlayerIV = _thirdImageView;_currentFront = _thirdFront;/***  _currentIndex=_videoList.count-1时,重新处理下_secondImageView的封面、*  这个时候只能上滑 _secondImageView 给 _lastHostDic的值*/[_secondImageView sd_setImageWithURL:[NSURL URLWithString:minstr([_lastHostDic valueForKey:@"thumb"])]];[self setUserData:_lastHostDic withFront:_secondFront];[self setVideoData:_lastHostDic withFront:_secondFront];[_thirdImageView sd_setImageWithURL:[NSURL URLWithString:minstr([_hostdic valueForKey:@"thumb"])]];[self setUserData:_hostdic withFront:_thirdFront];[self setVideoData:_hostdic withFront:_thirdFront];

当三种情况都介绍完后就涉及到短视频软件开发最终的播放了,这里我使用的是JPVideoPlayer播放器(完全开源的,有兴趣的可以自行下载研究原理),播放的主要代码如下:

  //切记一定要先把当前播放的上一个关闭[_currentPlayerIV jp_stopPlay];//开始播放[_currentPlayerIV jp_playVideoMuteWithURL:[NSURL URLWithString:_playUrl]bufferingIndicator:[JPBufferView new]progressView:[JPLookProgressView new]configuration:^(UIView *view, JPVideoPlayerModel *playerModel) {view.jp_muted = NO;//播放器的音频输出是否静音_firstWatch = YES;if (_currentPlayerIV.image.size.width>0 && (_currentPlayerIV.image.size.width >= _currentPlayerIV.image.size.height)) {playerModel.playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;}else{playerModel.playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;}}];

下面有几个需要设置的重要代理

1)实现重复播放

//return返回NO以防止重播视频。 返回YES则重复播放视频。如果未实施,则默认为YES
- (BOOL)shouldAutoReplayForURL:(nonnull NSURL *)videoURL
{return YES;
}

2)播放状态改变时需要做的相应处理,主要是页面消失的时候停止播放

//播放状态改变的时候触发
-(void)playerStatusDidChanged:(JPVideoPlayerStatus)playerStatus {NSLog(@"=====7-8====%lu",(unsigned long)playerStatus);if (_stopPlay == YES) {NSLog(@"8-4:play-停止了");_stopPlay = NO;_firstWatch = NO;//页面已经消失了,就不要播放了[_currentPlayerIV jp_stopPlay];}if (playerStatus == JPVideoPlayerStatusPlaying) {if (_bufferIV) {dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{[_bufferIV removeFromSuperview];});}}if (playerStatus == JPVideoPlayerStatusReadyToPlay && _firstWatch==YES) {//addview}if (playerStatus == JPVideoPlayerStatusStop && _firstWatch == YES) {//finish_firstWatch = NO;}}

短视频软件开发,仿抖音滑动播放视频的实现相关推荐

  1. android抖音切换实现,【Android 进阶】仿抖音系列之视频预览和录制(五)

    前言 大家好,在前几篇中,我们通过2种方式实现了仿抖音的翻页切换视频,仿抖音列表播放视频功能:这一篇,我们来说说视频的录制. 主流的视频录制,一般都采用的是FFmpeg 例如 腾讯短视频,由于FFmp ...

  2. 如何开发仿抖音短视频APP源码?

    如何开发仿抖音短视频APP源码? 流程列表 开发一个短视频最主要的流程分为 3 个,下面我将分步教你实现这 3 个流程下的各个功能点,功能点 API 可按需调用: 视频拍摄 a.启动拍摄 b.给拍摄添 ...

  3. 仿抖音滑动小短剧影视微信小程序源码带支付收益等模式

    项目功能介绍:支持无限滑动 高性能滑动 预加载 视频预览 支持剧情介绍,集合壁纸另外仿抖音滑动效果 支持会员模式,支持用户单独购买等等多功能 丰富的后台设置,具体大家可以看小编的后台演示图 具体小编也 ...

  4. android抖音自动刷新,Android 使用SwipeRefreshLayout控件仿抖音做的视频下拉刷新效果...

    SwipeRefreshLayout(这个控件),我先跟大家介绍一下这个控件: 一.SwipeRefreshLayout简单介绍 •先看以下官方文档,已有了很详细的描述了. 官方文档说明 •这里我再大 ...

  5. php+api抖音随机播放视频源码

    简介: php+api抖音随机播放视频源码,前端纯静态html+css,数据采用php+API接口调用第三方数据,不需要配置环境,上传即用. 源码体积小,视频采集自网络,无视频资源,内置多条播放线路. ...

  6. 短视频源码仿抖音短视频APP源码短视频平台源码短视频源码

    [WoShop仿抖音短视频源码的主要功能] 1.短视频带货:关联商品的短视频封面会有商品标识,短视频内容中会弹出商品链接 2.直播带货:短视频源码支持直播功能,直播间内可开启带货功能 3.邀请赚钱:用 ...

  7. flutter开发仿抖音首页面上下滑动切换播放视频效果

    题记 -- 执剑天涯,从你的点滴积累开始,所及之处,必精益求精,即是折腾每一天. -----[视频教程 感兴趣的伙伴可以瞅瞅] 本小节讲述: 1 VideoPlayer 视频播放组件使用 2 Vide ...

  8. 微信小程序 短剧开发技术踩坑指南 仿抖音快手小视频

    1.Video组件 微信官方文档地址: https://developers.weixin.qq.com/miniprogram/dev/component/video.html uniapp官方文档 ...

  9. 怎么让抖音视频当做铃声android,抖音怎么提取视频里的音乐?怎么将抖音里的音乐用来做手机铃声?抖音视频提取音频的方法...

    虽然说抖音发展到现在,褒贬不一,但是架不住人家火啊,现在的人大都喜欢捧着个手机刷抖音,来打发一些碎片时光.抖音不仅带火了短视频,同样也带火了视频里面的背景音乐,许多我们平时并没有听过的歌曲在抖音上就慢 ...

最新文章

  1. 算力大战是BCH最坏的一种处理方式
  2. div地址跳转 vue_vue---导航栏点击跳转到对应位置
  3. 415. Add Strings
  4. 标线markLine的用法
  5. 钓鱼基础设施的应用分析(钓鱼邮件利用、Gophish)
  6. 评委输入的密码如果不正确,当错误的次数达到5次时,该评委的账号会被锁定.如何解锁呢?
  7. 清华大学829考研 初试436经验谈
  8. 显卡对决nbsp;NVIDIAnbsp;GTnbsp;555Mnbsp;VS…
  9. 老泪纵横!伴随数代人成长的中国经典动画
  10. php整数溢出 ctf,PWN INTEGER OVERFLOW 整数溢出
  11. errMsg: “getUserProfile:fail can only be invoked by user TAP gesture.
  12. MTI Further
  13. linux第一块ide硬盘命名为,linux下硬盘分区
  14. H5指北针JavaScript代码
  15. Linux 对整个系统备份和还原
  16. 【软件测试】——编写测试用例实例
  17. CANFiber是什么?
  18. https web service(转)
  19. H3C和华为配置端口聚合的问题
  20. 北京晚报:谷歌中国访问量陡增

热门文章

  1. 阿里大师推荐的这份Java开发必读书单,让我成功在寒冬中站稳脚步
  2. 皮尔逊相关系数矩阵热图 代码
  3. 遇到Parallels Desktop 开机windows黑屏的解决办法
  4. TouchDesigner常用python语句表达
  5. 华三交换机升级的ipe文件_LSU1WCME0 V5升级V7失败问题处理经验
  6. HBASE一些简单的查询语句
  7. 校园卡管理系统实验报告c语言,基于C++的校园一卡通管理系统
  8. 龙争虎斗,360数科金融科技输出的强者恒强定律
  9. Adobe全家桶功能
  10. 特征向量一定是正交的吗