ios开发高仿抖音,上下切换横竖屏播放!(代码片段)

iOS大鑫 iOS大鑫     2022-12-13     664

关键词:

好久没写文章了,最近有点时间,模仿了一个抖音视频上下滑动切换播放功能,顾记录下实现方案,共勉。

一、先说下大致思路:
1.UITableView : Cell上展示视频第一帧图片,点赞,评论,头像等参数
2.封装一个视频播放View
3.定义一个属性currentIndex,并添加他的观察属性,当currentIndex属性值改变时,处理视频播放功能
4.UITableView滑动代理,处理视频上下滑动动画操作
5.注意,整个UITableView中,只存在一个视频播放实例方法,这样性能提升
直播功能的界面展示,也同样处理逻辑

开始之前,info.plist 需要增加麦克风,相册权限

因为是demo,所有代码怎么简单怎么来,谅解!!!

下面是具体代码,供参考,自己直接copy到项目中就可以用,如有需要再讲代码上传都codding

涉及图片资源,自己随便找个图顶下就行

欢迎关注公众号:编程大鑫,进群大家一起交流进步!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bi9YqM5B-1627022506398)(//upload-images.jianshu.io/upload_images/2151291-109c6326a56f2eaa.png?imageMogr2/auto-orient/strip|imageView2/2/w/722/format/webp)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DH4vadJr-1627022506399)(//upload-images.jianshu.io/upload_images/2151291-699b477a4032ba83.png?imageMogr2/auto-orient/strip|imageView2/2/w/722/format/webp)]

二、代码实现
1,HomeController.h类中

#import "HomeController.h"
#import "VideoTableCell.h" //自定义Cell
#import "VideoView.h" 

//位置:松开后切换视频
#define offsetY 100  

@interface HomeController ()<UITableViewDataSource,UITableViewDelegate>

    UITableView * table;
    NSArray * dataArray; //存放视频url
    NSMutableArray * videoPicArray;//视频第一帧图片,真实情况下后台会返回图片第一帧url


@property(nonatomic,strong)VideoView * videoView;//视频播放器
@property(nonatomic,assign)NSInteger currentIndex;//当前tableview indexPath

@end

@implementation HomeController

- (void)viewDidLoad 

    [super viewDidLoad];

    [self initData];

    [self setupView];

//获取视频第一帧
    dispatch_async(dispatch_get_global_queue(0,0), ^

        for (int i = 0; i < self->dataArray.count;i++) 

            UIImage * image = [self getVideoPreViewImage:[NSURL URLWithString:self->dataArray[i]]];

            [self->videoPicArray replaceObjectAtIndex:i withObject:image];

            dispatch_async(dispatch_get_main_queue(), ^
                [self->table reloadData];
            );
        
    );


-(void)viewWillAppear:(BOOL)animated
    [super viewWillAppear:animated];

//进入界面时,播放
    if(self.videoView)

        [self.videoView play];
    


-(void)viewWillDisappear:(BOOL)animated
    [super viewWillDisappear:animated];

//离开时暂停播放
    if(self.videoView)

        [self.videoView pause];
    


-(void)initData

    dataArray=@[
        @"https://aweme.snssdk.com/aweme/v1/play/?video_id=ba8f4ff0c1fe445dbfdc1cc9565222fa&line=0&ratio=720p&media_type=4&vr_type=0&test_cdn=None&improve_bitrate=0",
        @"http://ctgdev.oss-cn-shanghai.aliyuncs.com/zys/04795f79-697b-4647-958b-fed0261b2730.mp4",
        @"https://aweme.snssdk.com/aweme/v1/play/?video_id=ba8f4ff0c1fe445dbfdc1cc9565222fa&line=0&ratio=720p&media_type=4&vr_type=0&test_cdn=None&improve_bitrate=0",
        @"http://ctgdev.oss-cn-shanghai.aliyuncs.com/zys/04795f79-697b-4647-958b-fed0261b2730.mp4",
        @"https://aweme.snssdk.com/aweme/v1/play/?video_id=ba8f4ff0c1fe445dbfdc1cc9565222fa&line=0&ratio=720p&media_type=4&vr_type=0&test_cdn=None&improve_bitrate=0"];

    videoPicArray=[NSMutableArray array];

    for(int i=0;i<dataArray.count;i++)

        [videoPicArray addObject:[UIImage imageNamed:@"img_video_loading"]];
    


-(void)setupView

    navView.backgroundColor=MS_RGBA(0, 0, 0, 0);

    UILabel * liveLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, StatusHeight+10, 60, 20)];
    liveLabel.text=@"直播";
    liveLabel.font=[UIFont boldSystemFontOfSize:16];
    liveLabel.textAlignment=NSTextAlignmentCenter;
    liveLabel.textColor=[UIColor whiteColor];
    [navView addSubview:liveLabel];

    CGFloat leftX = (SCREEN_WIDTH-150)/3;

    UILabel * locationLabel = [[UILabel alloc] initWithFrame:CGRectMake(leftX+50, StatusHeight+10, 50, 20)];
    locationLabel.text=@"本地";
    locationLabel.font=[UIFont systemFontOfSize:17];
    locationLabel.textAlignment=NSTextAlignmentCenter;
    locationLabel.textColor=[UIColor whiteColor];
    [navView addSubview:locationLabel];

    UILabel * likeTitle = [[UILabel alloc] initWithFrame:CGRectMake(CGRectGetMaxX(locationLabel.frame), StatusHeight+10, 50, 20)];
    likeTitle.text=@"关注";
    likeTitle.font=[UIFont systemFontOfSize:16];
    likeTitle.textAlignment=NSTextAlignmentCenter;
    likeTitle.textColor=[UIColor whiteColor];
    [navView addSubview:likeTitle];

    UILabel * hotTitle = [[UILabel alloc] initWithFrame:CGRectMake(CGRectGetMaxX(likeTitle.frame), StatusHeight+10, 50, 20)];
    hotTitle.text=@"推荐";
    hotTitle.font=[UIFont boldSystemFontOfSize:16];
    hotTitle.textAlignment=NSTextAlignmentCenter;
    hotTitle.textColor=[UIColor whiteColor];
    [navView addSubview:hotTitle];

    UILabel * searchLabel = [[UILabel alloc] initWithFrame:CGRectMake(SCREEN_WIDTH-60, StatusHeight+10, 60, 20)];
    searchLabel.text=@"搜索";
    searchLabel.font=[UIFont boldSystemFontOfSize:16];
    searchLabel.textAlignment=NSTextAlignmentCenter;
    searchLabel.textColor=[UIColor whiteColor];
    [navView addSubview:searchLabel];

    table = [[UITableView alloc] initWithFrame:CGRectMake(0,0,SCREEN_WIDTH,SCREEN_HEIGHT)];
    table.dataSource = self;
    table.showsVerticalScrollIndicator = NO;
    table.delegate=self;
    table.separatorStyle = UITableViewCellSeparatorStyleNone;
    table.rowHeight=table.frame.size.height;
    table.backgroundColor=[UIColor blackColor];
    table.scrollsToTop=NO;
    table.contentInset=UIEdgeInsetsMake(0, 0, TabbarStautsHeight, 0);

    if (@available(ios 11.0,*)) 

        [table setContentInsetAdjustmentBehavior:UIScrollViewContentInsetAdjustmentNever];
    

    [self.view addSubview:table];
    [self.view addSubview:navView];

    [table registerClass:[VideoTableCell class] forCellReuseIdentifier:@"VideoTableCell"];

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^

        [self addObserver:self forKeyPath:@"currentIndex" options:NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionNew context:nil];//添加观察者,重点

    );


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 

    return dataArray.count;


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

    VideoTableCell *cell = [tableView dequeueReusableCellWithIdentifier:@"VideoTableCell" forIndexPath:indexPath];

//显示视频第一帧图片
    cell.bgImageView.image=videoPicArray[indexPath.row];
    return cell;


- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate

    dispatch_async(dispatch_get_main_queue(), ^

        CGPoint translatedPoint = [scrollView.panGestureRecognizer translationInView:scrollView];

        scrollView.panGestureRecognizer.enabled = NO;
        NSLog(@"UITableView禁止响应其他滑动手势");

        if(translatedPoint.y < -offsetY && self.currentIndex < (self->dataArray.count - 1)) 

            self.currentIndex ++;
            NSLog(@"向下滑动索引递增");
        

        if(translatedPoint.y > offsetY && self.currentIndex > 0) 

            self.currentIndex --;
            NSLog(@"向上滑动索引递减");
        

        [UIView animateWithDuration:0.15
                              delay:0.0
                            options:UIViewAnimationOptionCurveEaseOut animations:^

            [self->table scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:self.currentIndex inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];

         completion:^(BOOL finished) 

            scrollView.panGestureRecognizer.enabled = YES;
            NSLog(@"UITableView可以响应其他滑动手势");
        ];
    );


//观察currentIndex变化
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context 

    if ([keyPath isEqualToString:@"currentIndex"]) 

        NSLog(@"indexPath发生改变");

/*
整个列表视频播放,只会存在一个播放器
*/

        VideoTableCell *cell = [table cellForRowAtIndexPath:[NSIndexPath indexPathForRow:self.currentIndex inSection:0]];

        [self.videoView removePlayer];
        [self.videoView removeFromSuperview];
        self.videoView=[[VideoView alloc] initWithFrame:CGRectMake(0, 0,SCREEN_WIDTH, table.rowHeight) url:dataArray[self.currentIndex] image:videoPicArray[self.currentIndex]];
        [cell.contentView addSubview:self.videoView];
        [cell insertSubview:cell.middleView belowSubview:self.videoView];

        WEAKBLOCK(self);

        self.videoView.changeScreen = ^(BOOL isFull) 

            STRONGBLOCK(self);

            cell.bgImageView.hidden=YES;

            if(isFull)

                self.tabBarController.tabBar.hidden = YES;
                self->navView.hidden=YES;
                self->table.scrollEnabled=NO;
                cell.middleView.hidden=YES;

            else
                self.tabBarController.tabBar.hidden = NO;
                self->navView.hidden=NO;
                self->table.scrollEnabled=YES;
                cell.middleView.hidden=NO;
                cell.bgImageView.hidden=NO;
            

        ;
    


//mark:一般真实项目,后台会返回视频第一帧图片url给端
// 获取网络视频第一帧
- (UIImage*)getVideoPreViewImage:(NSURL *)path

    AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:path options:nil];
    AVAssetImageGenerator *assetGen = [[AVAssetImageGenerator alloc] initWithAsset:asset];

    assetGen.appliesPreferredTrackTransform = YES;
    CMTime time = CMTimeMakeWithSeconds(0, 1);
    NSError *error = nil;
    CMTime actualTime;
    CGImageRef image = [assetGen copyCGImageAtTime:time actualTime:&actualTime error:&error];
    UIImage *videoImage = [[UIImage alloc] initWithCGImage:image];
    CGImageRelease(image);
    return videoImage;


@end

2,VideoTableCell.h

@property(nonatomic,strong)UIImageView * bgImageView;
@property(nonatomic,strong)UIView * middleView;

VideoTableCell.m

#import "VideoTableCell.h"
#import "Config.h"

@implementation VideoTableCell

-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier

    if(self=[super initWithStyle:style reuseIdentifier:reuseIdentifier])

        self.contentView.backgroundColor=[UIColor blackColor];

        CGFloat height = SCREEN_HEIGHT;

        self.bgImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, height)];
        self.bgImageView.tag=100;
        self.bgImageView.image=[UIImage imageNamed:@"img_video_loading"];
        [self.contentView addSubview:self.bgImageView];

        self.middleView=[[UIView alloc] initWithFrame:CGRectMake(SCREEN_WIDTH-80, (height-150-StatusHeight)/2, 80, 50)];
        self.middleView.tag=200;
        [self.contentView addSubview:self.middleView];

        UILabel * titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 80, 50)];
        titleLabel.text=@"头像";
        titleLabel.font=[UIFont boldSystemFontOfSize:16];
        titleLabel.textColor=[UIColor whiteColor];
        titleLabel.textAlignment = 1;
        [self.middleView addSubview:titleLabel];

        UILabel * titleLabel2 = [[UILabel alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(titleLabel.frame), 80, 50)];
        titleLabel2.text=@"点赞";
        titleLabel2.font=[UIFont boldSystemFontOfSize:16];
        titleLabel2.textColor=[UIColor whiteColor];
        titleLabel2.textAlignment = 1;
        [self.middleView addSubview:titleLabel2];

        UILabel * titleLabel3 = [[UILabel alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(titleLabel2.frame), 80, 50)];
        titleLabel3.text=@"评论";
        titleLabel3.font=[UIFont boldSystemFontOfSize:16];
        titleLabel3.textColor=[UIColor whiteColor];
        titleLabel3.textAlignment = 1;
        [self.middleView addSubview:titleLabel3];
    

    return self;


@end

3,重点来啦,VideoView.h

@interface VideoView : UIView

    UIView * sliderView;
    UIView * bottomView;

    UILabel *countTimeLabel;

    UIButton * startVideoBtn;
    UIButton * changeFullScreenBtn;


///真实项目中,直接用dict包裹入参
-(instancetype)initWithFrame:(CGRect)frame url:(NSString*)url image:(UIImage*)image;

@property (nonatomic,strong)AVPlayer *player;//播放器对象
@property(nonatomic,strong) AVPlayerLayer *avLayer; //展示播放View
@property(nonatomic,strong)UILabel * currentTimeLabel;//当前倒计时
@property (nonatomic,strong)UISlider *slider;//滑竿
@property(nonatomic,assign)BOOL isFullScreen; //是否全屏状态 默认NO
@property (nonatomic, assign) CGRect smallFrame; //小屏幕frame
@property (nonatomic, assign) CGRect bigFrame; //全屏frame

///点击全屏,取消全屏回调
@property(nonatomic,copy)void(^changeScreen)(BOOL isFull);

///开始播放
-(void)play;

///暂停
-(void)pause;

///移除观察者
-(void)removePlayer;

VideoView.m

#import "VideoView.h"
#import "Config.h"

@implementation VideoView

-(instancetype)initWithFrame:(CGRect)frame url:(NSString*)url image:(UIImage *)image

    if(self=[super initWithFrame:frame])

        self.isFullScreen = NO;
        self.smallFrame = frame;
        self.bigFrame = CGRectMake(0, 0,SCREEN_WIDTH, SCREEN_HEIGHT);

        CGFloat height = frame.size.height;
        CGFloat width = frame.size.width;

        //占位,视频第一帧图片
        UIImageView* bgImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, width, height)];
        bgImageView.image=image;
        bgImageView.userInteractionEnabled=YES;
        [self addSubview:bgImageView];

        //网络视频路径
        NSURL *webVideoUrl = [NSURL URLWithString:url];
        AVPlayerItem *playerItem = [[AVPlayerItem alloc] initWithURL:webVideoUrl];
        self.player = [[AVPlayer alloc] initWithPlayerItem:playerItem];

        self.avLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
        self.avLayer.backgroundColor=[UIColor blackColor].CGColor;
        self.avLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
        self.avLayer.frame = CGRectMake(0, 0, bgImageView.frame.size.width, bgImageView.frame.size.height);
        [bgImageView.layer addSublayer:self.avLayer];

        sliderView =[[UIView alloc] initWithFrame:frame];
        sliderView.hidden=YES;
        [self addSubview:sliderView];

        bottomView=[[UIView alloc] initWithFrame:CGRectMake(0, sliderView.frame.size.height-50-TabbarStautsHeight, frame.size.width, 50)];
        bottomView.backgroundColor=MS_RGBA(0, 0, 0, 0.5);
        [sliderView addSubview:bottomView];

        startVideoBtn =[UIButton buttonWithType:UIButtonTypeCustom];
        startVideoBtn.frame=CGRectMake(0,0, 50, 50);
        [startVideoBtn setImage:[UIImage imageNamed:@"videoPauseBtn"] forState:normal];
        [startVideoBtn addTarget:self action:@selector(actStartVideo:) forControlEvents:UIControlEventTouchUpInside];
        [bottomView addSubview:startVideoBtn];

        self.currentTimeLabel = [[UILabel alloc] initWithFrame:CGRectMake(50, 0, 50, 50)];
        self.currentTimeLabel.textColor=[UIColor whiteColor];
        self.currentTimeLabel.text=@"00:00";
        self.currentTimeLabel.font=[UIFont systemFontOfSize:14];
        self.currentTimeLabel.textAlignment=1;
        [bottomView addSubview:self.currentTimeLabel];

        self.slider=[[UISlider alloc] initWithFrame:CGRectMake(100, 0, SCREEN_WIDTH-200, 50)];
        self.slider.minimumValue=0;
        self.slider.minimumTrackTintColor=[UIColor whiteColor];
        self.slider.maximumTrackTintColor =[UIColor colorWithRed:1 green:1 blue:1 alpha:0.5];
        [self.slider addTarget:self action:@selector(avSliderAction) forControlEvents:
        UIControlEventTouchUpInside|UIControlEventTouchCancel|UIControlEventTouchUpOutside];
        [self.slider setThumbImage:[UIImage imageNamed:@"slider"] forState:normal];
        [bottomView addSubview:self.slider];

        countTimeLabel = [[UILabel alloc] initWithFrame:CGRectMake(CGRectGetMaxX(self.slider.frame), 0, 50, 50)];
        countTimeLabel.textColor=[UIColor whiteColor];
        countTimeLabel.text=@"00:00";
        countTimeLabel.font=[UIFont systemFontOfSize:14];
        countTimeLabel.textAlignment=1;
        [bottomView addSubview:countTimeLabel];

        changeFullScreenBtn =[UIButton buttonWithType:UIButtonTypeCustom];
        changeFullScreenBtn.frame=CGRectMake(CGRectGetMaxX(countTimeLabel.frame),0, 50, 50);
        [changeFullScreenBtn setImage:[UIImage imageNamed:@"exitFullScreen"] forState:normal];
        [changeFullScreenBtn addTarget:self action:@selector(actChange:) forControlEvents:UIControlEventTouchUpInside];
        [bottomView addSubview:changeFullScreenBtn];
        changeFullScreenBtn.selected=NO;

        WEAKBLOCK(self);

        [self.player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(1, NSEC_PER_SEC) queue:NULL usingBlock:^(CMTime time) 

            STRONGBLOCK(self);

            NSInteger currentTime = CMTimeGetSeconds(self.player.currentItem.currentTime);
            NSInteger countTime = CMTimeGetSeconds(self.player.currentItem.duration);

            self.currentTimeLabel.text=[self getMMSSFromSS:[NSString stringWithFormat:@"%zi",currentTime]];

            self.slider.value=currentTime;

            if(currentTime>=countTime)

                self.slider.value=0;
                [self.player seekToTime:CMTimeMake(0, 1)];

            
        ];

        [self.player.currentItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];

        UITapGestureRecognizer *hidenTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(hiddenBottonView:)];
        [self addGestureRecognizer:hidenTap];
    

    return self;


- (void)hiddenBottonView: (UITapGestureRecognizer *)tap 

    if (sliderView.hidden) 

        sliderView.hidden = NO;

    else 

        sliderView.hidden = YES;
    


- (void)avSliderAction

    CGFloat seconds = self.slider.value;
    [self startPlayer:seconds];


-(void)startPlayer:(CGFloat)seconds

    CMTime startTime = CMTimeMakeWithSeconds(seconds, self.player.currentTime.timescale);
    [self.player seekToTime:startTime];


-(void)layoutSubviews

    [super layoutSubviews];

    self.avLayer.frame=self.bounds;
    sliderView.frame=self.bounds;

    CGFloat topY = !self.isFullScreen?TabbarStautsHeight:0;

    CGFloat leftX = !self.isFullScreen?0:NavigationHeight;

    CGFloat spaceWidth = !self.isFullScreen?0:TabbarStautsHeight;

    bottomView.frame=CGRectMake(0, sliderView.frame.size.height-topY-50, sliderView.frame.size.width, 50);

    startVideoBtn.frame=CGRectMake(leftX, 0, 50, 50);

    self.currentTimeLabel.frame = CGRectMake(leftX+50, 0, 50, 50);

    self.slider.frame=CGRectMake(CGRectGetMaxX(self.currentTimeLabel.frame), 0, sliderView.frame.size.width-100-spaceWidth-CGRectGetMaxX(self.currentTimeLabel.frame), 50);

    countTimeLabel.frame = CGRectMake(sliderView.frame.size.width-100-spaceWidth, 0, 50, 50);

    changeFullScreenBtn.frame=CGRectMake(sliderView.frame.size.width-50-spaceWidth, 0, 50, 50);


//观察currentIndex变化
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context 

    if ([keyPath isEqualToString:@"status"])

        //获取playerItem的status属性最新的状态
        AVPlayerStatus status = [[change objectForKey:@"new"] intValue];
        switch (status) 
            case AVPlayerStatusReadyToPlay:

                NSInteger countTime = CMTimeGetSeconds(self.player.currentItem.duration);
                self.slider.maximumValue =countTime;
                countTimeLabel.text=[self getMMSSFromSS:[NSString stringWithFormat:@"%zi",countTime]];
                [self.player play];

                break;
            
            case AVPlayerStatusFailed://视频加载失败,点击重新加载

                NSLog(@"视频播放失败");

                break;
            
            case AVPlayerStatusUnknown:

                NSLog(@"视频播放失败");
                break;
            
            default:
                break;
        
    


-(void)play

    [self.player play];


-(void)pause

    [self.player pause];


-(void)actStartVideo:(UIButton*)btn

    if(!startVideoBtn.selected)

        startVideoBtn.selected=YES;
        [startVideoBtn setImage:[UIImage imageNamed:@"videoPlayBtn"] forState:normal];
        [self pause];

    else

        startVideoBtn.selected=NO;
        [startVideoBtn setImage:[UIImage imageNamed:@"videoPauseBtn"] forState:normal];
        [self play];
    


-(void)actChange:(UIButton*)btn

    if(!changeFullScreenBtn.selected)

        self.isFullScreen=YES;
        changeFullScreenBtn.selected=YES;
        [changeFullScreenBtn setImage:[UIImage imageNamed:@"exitFullScreen"] forState:normal];

        [UIView animateWithDuration:0.3 animations:^
            self.transform = CGAffineTransformMakeRotation(M_PI / 2);
         completion:nil];

        self.frame=self.bigFrame;

        if(self.changeScreen)

            self.changeScreen(self.isFullScreen);
        

    else

        changeFullScreenBtn.selected=NO;
        self.isFullScreen=NO;
        [changeFullScreenBtn setImage:[UIImage imageNamed:@"kr-video-player-fullscreen"] forState:normal];

        [UIView animateWithDuration:0.3 animations:^
            self.transform = CGAffineTransformMakeRotation(M_PI * 2);
         completion:^(BOOL finished) 

            if(self.changeScreen)

                self.changeScreen(self.isFullScreen);
            
        ];

        self.frame=self.smallFrame;
    


-(void)removePlayer

    [self.player.currentItem removeObserver:self forKeyPath:@"status"];
    [self.player pause];


-(NSString *)getMMSSFromSS:(NSString *)totalTime

    NSInteger seconds = [totalTime integerValue];
    NSString *str_minute = [NSString stringWithFormat:@"%02ld",seconds/60];
    NSString *str_second = [NSString stringWithFormat:@"%02ld",seconds%60];
    NSString *format_time = [NSString stringWithFormat:@"%@:%@",str_minute,str_second];
    return format_time;


@end

4,config.h文件里常用方法

#ifndef Config_h
#define Config_h

///判断是否为iPhone X 系列
#define iPhoneX \\
(BOOL isPhoneX = NO;\\
if (@available(iOS 11.0, *)) \\
isPhoneX = [[UIApplication sharedApplication] delegate].window.safeAreaInsets.bottom > 0.0;\\
\\
(isPhoneX);)

#define SCREEN_WIDTH ([UIScreen mainScreen].bounds.size.width)
#define SCREEN_HEIGHT ([UIScreen mainScreen].bounds.size.height)

#define GL_isPad ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)

#define GL_isIPhone_Xr ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(828, 1792), [[UIScreen mainScreen] currentMode].size) && !GL_isPad : NO)

#define GL_isIPhone_Xs ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1125, 2436), [[UIScreen mainScreen] currentMode].size) && !GL_isPad : NO)

#define GL_isIPhone_Xs_Max ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1242, 2688), [[UIScreen mainScreen] currentMode].size) && !GL_isPad : NO)

#define GL_isIPhone_iPhone12_Mini ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1080, 2340), [[UIScreen mainScreen] currentMode].size) && !GL_isPad : NO)

#define GL_isIPhone_X ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1125, 2436), [[UIScreen mainScreen] currentMode].size) && !GL_isPad : NO)

#define GL_isIPhone_iPhone12 ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1170, 2532), [[UIScreen mainScreen] currentMode].size) && !GL_isPad : NO)

#define GL_isIPhone_iPhone12_ProMax ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1284, 2778), [[UIScreen mainScreen] currentMode].size) && !GL_isPad : NO)

///导航栏高度
#define NavigationHeight ((GL_isIPhone_Xr == YES || GL_isIPhone_Xs == YES || GL_isIPhone_Xs_Max == YES || GL_isIPhone_iPhone12_Mini == YES) ? 88.0 : (GL_isIPhone_X == YES) ? 92 : (GL_isIPhone_iPhone12 == YES || GL_isIPhone_iPhone12_ProMax == YES) ? 91 : 64.0)

///若果是iPhoneX 则底部减去一个半圆弧度高
#define TabbarHeight (iPhoneX?34:0)

///状态栏
#define StatusHeight [[UIApplication sharedApplication] statusBarFrame].size.height

#define TabbarStautsHeight (iPhoneX?83:49)

#define MS_RGBA(r,g,b,a) [UIColor colorWithRed:(r)/255.0f green:(g)/255.0f blue:(b)/255.0f \\
alpha:(a)]

///WEAKBLOCK
#define WEAKBLOCK(type) __weak __typeof(type) weak##type = type

///STRONGBLOCK
#define STRONGBLOCK(type) __strong __typeof(type) type = weak##type

#endif /* Config_h */

至此,仿抖音视频上下滑动切换功能已完成。

flutter开发仿抖音首页面上下滑动切换播放视频效果(代码片段)

题记——执剑天涯,从你的点滴积累开始,所及之处,必精益求精,即是折腾每一天。-----【视频教程感兴趣的伙伴可以瞅瞅】本小节讲述:1VideoPlayer视频播放组件使用2VideoPlayerController的使用分析3FutureBuilder的... 查看详情

基于uni-app多端「h5+小程序+app」高仿抖音小视频|直播|聊天实例(代码片段)

uni-ttLive基于uni-app+uView-ui跨端开发短视频+直播聊天实例。全新研发的一款多端仿制抖音短视频+直播+聊天项目,基于uniApp+Vue.js+Vuex+Nvue+uViewUI+uaPopup等技术开发而成。支持播放/暂停/上下滑动切换、全... 查看详情

仿抖音上下滑动播放视频(兼容安卓,ios,小程序,h5)

参考技术A运行条件HBuilderX2.2.2安装后,从插件市场导入,即可真机运行vue项目地址githubuniapp插件市场说明插件分别用swiper实现(多端兼容)和css3动画实现(暂时只支持app),可自行切换。插件在uni-app编译模式下编写(已切换)。默认为w... 查看详情

仿抖音上下滑动播放视频(代码片段)

不少朋友对短视频,上下滑动播放视频效果比较比较感兴趣,今天看看这个案例。1、效果图:讲下大概思路,使用Recycleview配合自定义LinearLayoutManager来实现这个功能,这里着重说下自定义LinearLayoutManager的实现可以看到每当下一... 查看详情

微信小程序视频列表滑动无限循环(仿抖音)(代码片段)

...播放页面地址进行解析就可以了)先上效果图 二、开发背景说明微信小程序中,同一个页面最多支持添加三个video组件,所以就通过数据处理的方式更新显示播放,有人说只写一个也行,如果只有一个那么上... 查看详情

text横竖屏切换(代码片段)

查看详情

javafragment横竖屏切换问题(代码片段)

查看详情

text横竖屏切换,生命周期(代码片段)

查看详情

javaandroid的横竖屏切换(参考)(代码片段)

查看详情

textandroid横竖屏切换判断活动是横屏还是竖屏(代码片段)

查看详情

unity之代码切换横竖屏(代码片段)

Unity之代码切换横竖屏及设置部分简介在Inspector面板上设置,一般在第一次打包时都会在这个面板上进行横竖屏锁定或者切换设置,解释如下图:使用代码进行横竖屏切换: publicvoidChangeScreenCh()if("切换到`在... 查看详情

java的android智能手机自动,手动切换横竖屏(代码片段)

查看详情

h5+jquery仿抖音视屏切换

参考技术A整体思路:jQuery--touch事件之滑动判断,当上划超过30px切换下一个视屏,调换<video>中的src。错误思路:原本想用swiper循坏<video>显示,视觉效果可以达到,但是会把所有的视屏都加载出来,虽然界面只显示一个... 查看详情

【ios】swift4.0横竖屏监测、动态切换

...屏!在部分页面如果打开横竖屏开关,则支持横竖屏动态切换;如果关闭,则需要点击才能跳转横屏页面。设备在控制页面打开横竖屏开关,即设备支持横竖屏动态切换。下图做了个简单的gif展现,下图的操作是操作手机横竖屏... 查看详情

flutter如何监听应用事件:前后台切换横竖屏切换键盘显隐等(代码片段)

实现在Flutter中可以通过WidgetsBinding的addObserver函数来监听应用事件,如下:WidgetsBinding.instance.addObserver(observer);//WidgetsBinding.instance.removeObserver(observer);这里的observer就是WidgetsBindingObserver 查看详情

flutter如何监听应用事件:前后台切换横竖屏切换键盘显隐等(代码片段)

实现在Flutter中可以通过WidgetsBinding的addObserver函数来监听应用事件,如下:WidgetsBinding.instance.addObserver(observer);//WidgetsBinding.instance.removeObserver(observer);这里的observer就是WidgetsBindingObserver 查看详情

compose横竖屏切换时状态如何保存?remembersaveable实现原理分析(代码片段)

...无法避免在ConfigurationChanged时的数据丢失。想要在横竖屏切换等场景下依然保存状态,就需要使用remembe 查看详情

避免切换横竖屏fragment的重复加载导致ui混乱(代码片段)

    当我们切换横竖屏时Activity的生命周期就会重走一遍,自然其中的Fragment的生命周期也就重新走了一遍,实践证明当熄屏再开屏时Fragment的生命周期也会重走一遍 解决方案:android:configChanges="orientation|keyboardHi... 查看详情