// // AVLiveStreamCell.m // AVDemo // #import "AVLiveStreamCell.h" #import "AVLiveStreamModel.h" #import #import @interface AVLiveStreamCell () @property (nonatomic, strong) UIImageView *thumbnailView; @property (nonatomic, strong) UIView *overlayView; @property (nonatomic, strong) UIImageView *playIcon; @property (nonatomic, strong) UILabel *durationLabel; @property (nonatomic, strong) UILabel *nameLabel; @property (nonatomic, strong) UILabel *liveLabel; @property (nonatomic, strong) UILabel *protocolLabel; @property (nonatomic, strong) UIImageView *encryptIcon; @end @implementation AVLiveStreamCell - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { [self setupUI]; } return self; } - (void)setupUI { // 配置 Cell 背景 self.contentView.backgroundColor = [UIColor secondarySystemBackgroundColor]; self.contentView.layer.cornerRadius = 8; self.contentView.clipsToBounds = YES; // 创建缩略图 _thumbnailView = [[UIImageView alloc] init]; _thumbnailView.backgroundColor = [UIColor systemGrayColor]; _thumbnailView.contentMode = UIViewContentModeScaleAspectFill; _thumbnailView.clipsToBounds = YES; [self.contentView addSubview:_thumbnailView]; // 半透明遮罩层 _overlayView = [[UIView alloc] init]; _overlayView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.2]; [_thumbnailView addSubview:_overlayView]; // 播放图标 _playIcon = [[UIImageView alloc] initWithImage:[UIImage systemImageNamed:@"play.circle.fill"]]; _playIcon.tintColor = [UIColor whiteColor]; _playIcon.contentMode = UIViewContentModeScaleAspectFit; _playIcon.layer.shadowColor = [UIColor blackColor].CGColor; _playIcon.layer.shadowOffset = CGSizeMake(0, 2); _playIcon.layer.shadowOpacity = 0.3; _playIcon.layer.shadowRadius = 4; [_thumbnailView addSubview:_playIcon]; // 直播时长标签 _durationLabel = [[UILabel alloc] init]; _durationLabel.font = [UIFont systemFontOfSize:12 weight:UIFontWeightMedium]; _durationLabel.textColor = [UIColor whiteColor]; _durationLabel.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.6]; _durationLabel.textAlignment = NSTextAlignmentCenter; _durationLabel.layer.cornerRadius = 4; _durationLabel.clipsToBounds = YES; [_thumbnailView addSubview:_durationLabel]; // 流名称标签 _nameLabel = [[UILabel alloc] init]; _nameLabel.font = [UIFont systemFontOfSize:14 weight:UIFontWeightSemibold]; _nameLabel.textColor = [UIColor labelColor]; _nameLabel.numberOfLines = 1; [self.contentView addSubview:_nameLabel]; // 底部信息容器 UIView *infoContainerView = [[UIView alloc] init]; [self.contentView addSubview:infoContainerView]; // 直播状态标签 _liveLabel = [[UILabel alloc] init]; _liveLabel.text = @"🔴 直播中"; _liveLabel.font = [UIFont systemFontOfSize:11 weight:UIFontWeightMedium]; _liveLabel.textColor = [UIColor systemRedColor]; [infoContainerView addSubview:_liveLabel]; // 协议标签 _protocolLabel = [[UILabel alloc] init]; _protocolLabel.font = [UIFont systemFontOfSize:10 weight:UIFontWeightMedium]; _protocolLabel.textColor = [UIColor whiteColor]; _protocolLabel.backgroundColor = [UIColor systemBlueColor]; _protocolLabel.textAlignment = NSTextAlignmentCenter; _protocolLabel.layer.cornerRadius = 3; _protocolLabel.clipsToBounds = YES; [infoContainerView addSubview:_protocolLabel]; // 布局 [_thumbnailView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.left.right.equalTo(self.contentView); // 使用较低优先级的宽高比约束 3:4,允许它在必要时被压缩 make.height.equalTo(_thumbnailView.mas_width).multipliedBy(4.0 / 3.0).priority(750); }]; [_overlayView mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(_thumbnailView); }]; [_playIcon mas_makeConstraints:^(MASConstraintMaker *make) { make.center.equalTo(_thumbnailView); make.width.height.equalTo(@50); }]; [_durationLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.bottom.equalTo(_thumbnailView).offset(-8); make.right.equalTo(_thumbnailView).offset(-8); make.height.equalTo(@20); make.width.greaterThanOrEqualTo(@50); }]; [_nameLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(_thumbnailView.mas_bottom).offset(8); make.left.equalTo(self.contentView).offset(8); make.right.equalTo(self.contentView).offset(-8); }]; [infoContainerView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(_nameLabel.mas_bottom).offset(4); make.left.equalTo(self.contentView).offset(8); make.right.lessThanOrEqualTo(self.contentView).offset(-8); make.bottom.lessThanOrEqualTo(self.contentView).offset(-8).priority(750); // 移除 height 的硬性约束,让它根据内容自适应 }]; [_liveLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.left.top.bottom.equalTo(infoContainerView); }]; [_protocolLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.left.equalTo(_liveLabel.mas_right).offset(8); make.centerY.equalTo(_liveLabel); make.height.equalTo(@16); make.width.greaterThanOrEqualTo(@40); }]; // 加密图标 _encryptIcon = [[UIImageView alloc] initWithImage:[UIImage systemImageNamed:@"lock.shield.fill"]]; _encryptIcon.tintColor = [UIColor systemOrangeColor]; _encryptIcon.contentMode = UIViewContentModeScaleAspectFit; _encryptIcon.hidden = YES; [infoContainerView addSubview:_encryptIcon]; [_encryptIcon mas_makeConstraints:^(MASConstraintMaker *make) { make.left.equalTo(_protocolLabel.mas_right).offset(6); make.centerY.equalTo(_liveLabel); make.width.height.equalTo(@20); make.right.lessThanOrEqualTo(infoContainerView); }]; } - (void)configureWithModel:(AVLiveStreamModel *)model { // 设置流名称 _nameLabel.text = model.displayName; // 设置时长 _durationLabel.text = model.durationString; // 设置协议标签 _protocolLabel.text = model.play_protocol.uppercaseString; // 加密图标 _encryptIcon.hidden = (model.xorKey.length == 0); // 使用 SDWebImage 加载预览图 if (model.preview_image.length > 0) { NSURL *imageURL = [NSURL URLWithString:model.preview_image]; [_thumbnailView sd_setImageWithURL:imageURL]; } else { // 没有预览图,清空图片 _thumbnailView.image = nil; } } - (void)prepareForReuse { [super prepareForReuse]; // 取消之前的图片加载任务 [_thumbnailView sd_cancelCurrentImageLoad]; // 清空数据,防止复用时显示错误内容 _thumbnailView.image = nil; _nameLabel.text = @""; _durationLabel.text = @""; _protocolLabel.text = @""; _encryptIcon.hidden = YES; } @end