美文网首页
仿封面视频详情视频播放大小跟随列表滑动变化

仿封面视频详情视频播放大小跟随列表滑动变化

作者: 小米咸鱼 | 来源:发表于2022-04-13 10:17 被阅读0次
    #import <UIKit/UIKit.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    /// 视图协议
    @protocol JYVideoNewsContentViewActionProtocol <NSObject>
    
    /// 头部滑动事件UIPanGestureRecognizer的SEL
    /// @param pan 滑动手势
    - (void)moveHeaderViewAction:(UIPanGestureRecognizer *)pan;
    @end
    
    
    
    /// 头部随底部ScrollView滚动变化的视图
    @interface JYVideoNewsContentView : UIView<JYVideoNewsContentViewActionProtocol>
    
    
    /// 头部容器视图
    @property(nonatomic,strong,readonly) UIView*         headerContainerView;
    
    /// 头部视图滑动手势是否可用(默认NO)
    @property(nonatomic,assign) BOOL                    headerContainViewPanEnable;
    /// 初始化
    /// @param headerMaxHeight 头部容器最大高度
    /// @param headerMinHeight 头部容器最小高度
    /// @param scrollView 底部可滚动视图(UIScrollview及子类)
    /// @param scrollDelegate 底部可滚动视图代理
    - (instancetype)initWithHeaderMaxHeight:(CGFloat)headerMaxHeight headerMinHeight:(CGFloat)headerMinHeight followScrollView:(UIScrollView *)scrollView scrollDelegate:(id<UIScrollViewDelegate>)scrollDelegate;
    @end
    
    #import "JYVideoNewsContentView.h"
    #import <Masonry.h>
    @interface JYVideoNewsContentView()<UIScrollViewDelegate>
    
    @property(nonatomic,strong,readwrite) UIView*         headerContainerView;
    @property(nonatomic,assign) CGFloat                  headerMaxHeight;
    @property(nonatomic,assign) CGFloat                  headerMinHeight;
    @property(nonatomic,strong) UIScrollView*            followScrollView;
    @property(nonatomic,assign) id<UIScrollViewDelegate>  scrollViewDelegate;
    @property(nonatomic,strong) UIPanGestureRecognizer*   headerPanGest;
    @end
    
    @implementation JYVideoNewsContentView
    
    
    - (instancetype)initWithHeaderMaxHeight:(CGFloat)headerMaxHeight headerMinHeight:(CGFloat)headerMinHeight followScrollView:(UIScrollView *)scrollView scrollDelegate:(id<UIScrollViewDelegate>)scrollDelegate{
        self = [self init];
        if (self) {
            self.headerMaxHeight = headerMaxHeight;
            self.headerMinHeight = headerMinHeight;
            self.followScrollView = scrollView;
            self.scrollViewDelegate = scrollDelegate;
            self.followScrollView.delegate = self;
            [self setupUI];
        }
        return self;
    }
    
    - (void)setupUI{
        [self addSubview:self.followScrollView];
        [self addSubview:self.headerContainerView];
        
        [self.headerContainerView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.left.top.width.mas_equalTo(self);
            make.height.mas_equalTo(self.headerMaxHeight);
        }];
        
        [self.followScrollView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.left.bottom.mas_equalTo(0);
            make.width.mas_equalTo(self);
            make.top.mas_equalTo(0);
        }];
        self.followScrollView.contentInset = UIEdgeInsetsMake(self.headerMaxHeight, 0, 0, 0);
        [self.followScrollView setContentOffset:CGPointMake(0, - self.headerMaxHeight) animated:NO];
    }
    
    #pragma mark - 添加头部滑动事件
    - (void)moveHeaderViewAction:(UIPanGestureRecognizer *)pan{
        static CGFloat beginOffsetY = 0;
        static BOOL canMove = NO;
        switch (pan.state) {
            case UIGestureRecognizerStateBegan:
                beginOffsetY = self.followScrollView.contentOffset.y;
                canMove = beginOffsetY == - CGRectGetHeight(self.headerContainerView.bounds);
                break;
            case UIGestureRecognizerStateEnded:
                canMove = NO;
            default:
                break;
        }
        
        CGPoint move = [pan translationInView:pan.view];
        CGFloat offsetY = beginOffsetY - move.y;
        if (offsetY >  - self.headerMinHeight) {
            offsetY = - self.headerMinHeight;
        }
        if (offsetY < - self.headerMaxHeight) {
            offsetY = - self.headerMaxHeight;
        }
        if (canMove){
            [self.followScrollView setContentOffset:CGPointMake(0, offsetY) animated:NO];
        }
    }
    
    #pragma mark - UIScrollViewDelegate
    - (void)scrollViewDidScroll:(UIScrollView *)scrollView{
        if ([scrollView isEqual:self.followScrollView]) {
            CGFloat height = - scrollView.contentOffset.y;
            if (height > self.headerMaxHeight){
                height = self.headerMaxHeight;
            }
            if (height < self.headerMinHeight && height != 0) {
                height = self.headerMinHeight;
            }
            self.followScrollView.bounces = height <= self.headerMinHeight;
            if (height < self.headerMinHeight || height > self.headerMaxHeight) return;
            [self.headerContainerView mas_updateConstraints:^(MASConstraintMaker *make) {
                make.height.mas_equalTo(height);
            }];
        }
        if ([self.scrollViewDelegate respondsToSelector:@selector(scrollViewDidScroll:)]){
            [self.scrollViewDelegate scrollViewDidScroll:scrollView];
        }
    }
    
    - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset{
        if ([scrollView isEqual:self.followScrollView]){
            //添加快速滑动定位到两端极限功能
            if (velocity.y >= 1 && (CGRectGetHeight(self.headerContainerView.bounds) != self.headerMinHeight)) {
                targetContentOffset->x = 0;
                targetContentOffset->y = -self.headerMinHeight;
            }else if (velocity.y <= -1 && (CGRectGetHeight(self.headerContainerView.bounds) != self.headerMaxHeight)){
                targetContentOffset->x = 0;
                targetContentOffset->y = -self.headerMaxHeight;
                self.followScrollView.bounces = NO;
            }
        }
        if ([self.scrollViewDelegate respondsToSelector:@selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:)]){
            [self.scrollViewDelegate scrollViewWillEndDragging:scrollView withVelocity:velocity targetContentOffset:targetContentOffset];
        }
    }
    
    #pragma mark - 处理滚动视图代理方法,该视图响应部分代理方法,代理响应所有可响应代理回调
    - (BOOL)respondsToSelector:(SEL)aSelector{
        return [super respondsToSelector:aSelector] || [self.scrollViewDelegate respondsToSelector:aSelector];
    }
    
    - (id)forwardingTargetForSelector:(SEL)aSelector{
        if ([super respondsToSelector:aSelector]) {
            return self;
        }else{
            return self.scrollViewDelegate;
        }
    }
    
    #pragma mark - setter
    - (void)setHeaderContainViewPanEnable:(BOOL)headerContainViewPanEnable{
        if (_headerContainViewPanEnable == headerContainViewPanEnable) return;
        if (_headerContainViewPanEnable && !headerContainViewPanEnable) [self.headerContainerView removeGestureRecognizer:self.headerPanGest];
        _headerContainViewPanEnable = headerContainViewPanEnable;
        if (_headerContainViewPanEnable) [self.headerContainerView addGestureRecognizer:self.headerPanGest];
    }
    
    #pragma mark - getter
    - (UIView *)headerContainerView{
        if (!_headerContainerView) {
            _headerContainerView = [UIView new];
            _headerContainerView.backgroundColor = [UIColor yellowColor];
            }
        return _headerContainerView;
    }
    
    - (UIPanGestureRecognizer *)headerPanGest{
        if (!_headerPanGest) {
            _headerPanGest = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(moveHeaderViewAction:)];
        }
        return _headerPanGest;
    }
    @end
    

    使用方式:

    #import "JYVideoNewsViewController.h"
    #import <Masonry.h>
    #import "JYVideoNewsContentView.h"
    #import <ZFPlayer/ZFPlayer.h>
    #import <ZFPlayer/ZFPlayerControlView.h>
    #import <ZFPlayer/ZFAVPlayerManager.h>
    
    
    @interface JYVideoNewsViewController ()<UIScrollViewDelegate,UITableViewDelegate,UITableViewDataSource>
    
    @property(nonatomic,strong) UITableView*              tableView;
    @property(nonatomic,strong) JYVideoNewsContentView*  contentView;
    @property(nonatomic,strong) ZFPlayerController*       player;
    @property(nonatomic,strong) ZFPlayerControlView*      controlView;
    @end
    
    @implementation JYVideoNewsViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        [self.view addSubview:self.contentView];
        [self.contentView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.edges.mas_equalTo(self.view);
        }];
        
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            self.player.assetURL = [NSURL URLWithString:@"http://jdyapp.obs.cn-north-1.myhuaweicloud.com/trans/2022/04/08/8a137058-47a1-4dfe-b485-bfe50c1638c5.mp4"];
        });
    }
    
    #pragma mark -
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
        return 20;
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
        UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"celll"];
        if (!cell) {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"celll"];
        }
        return cell;
    }
    
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
        
    }
    
    - (JYVideoNewsContentView *)contentView{
        if (!_contentView) {
            _contentView = [[JYVideoNewsContentView alloc] initWithHeaderMaxHeight:560 headerMinHeight:200 followScrollView:self.tableView scrollDelegate:self];
        }
        return _contentView;
    }
    
    - (UITableView *)tableView{
        if (!_tableView) {
            _tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
            if (@available(iOS 11.0, *)) {
                _tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
            }
            _tableView.dataSource = self;
        }
        return _tableView;
    }
    
    - (ZFPlayerController *)player{
        if (!_player) {
            ZFAVPlayerManager* manager = [[ZFAVPlayerManager alloc] init];
            _player = [[ZFPlayerController alloc] initWithPlayerManager:manager containerView:self.contentView.headerContainerView];
            _player.controlView = self.controlView;
        }
        return _player;
    }
    
    - (ZFPlayerControlView *)controlView{
        if (!_controlView) {
            _controlView = [ZFPlayerControlView new];
            UIPanGestureRecognizer* gest = [[UIPanGestureRecognizer alloc] initWithTarget:self.contentView action:@selector(moveHeaderViewAction:)];
            [_controlView addGestureRecognizer:gest];
        }
        return _controlView;
    }
    
    @end
    

    相关文章

      网友评论

          本文标题:仿封面视频详情视频播放大小跟随列表滑动变化

          本文链接:https://www.haomeiwen.com/subject/fioosrtx.html