181 lines
4.6 KiB
Objective-C
181 lines
4.6 KiB
Objective-C
//
|
||
// SLSVideoGridView.m
|
||
// SellyCloudSDK_Example
|
||
//
|
||
// Created by Caleb on 13/11/25.
|
||
// Copyright © 2025 Caleb. All rights reserved.
|
||
//
|
||
|
||
#import "SLSVideoGridView.h"
|
||
|
||
@interface SLSVideoGridView ()
|
||
@property (nonatomic, strong) NSMutableDictionary<NSString*, SLSParticipant*> *participants;
|
||
@property (nonatomic, strong) NSMutableDictionary<NSString*, SLSVideoTileView*> *tiles;
|
||
@end
|
||
|
||
@implementation SLSVideoGridView
|
||
|
||
// 代码创建时走这里
|
||
- (instancetype)initWithFrame:(CGRect)frame {
|
||
if (self = [super initWithFrame:frame]) {
|
||
[self commonInit];
|
||
}
|
||
return self;
|
||
}
|
||
|
||
// xib / storyboard 反序列化时走这里
|
||
- (instancetype)initWithCoder:(NSCoder *)coder {
|
||
if (self = [super initWithCoder:coder]) {
|
||
[self commonInit];
|
||
}
|
||
return self;
|
||
}
|
||
|
||
// 公共初始化逻辑
|
||
- (void)commonInit {
|
||
_participants = [NSMutableDictionary dictionary];
|
||
_tiles = [NSMutableDictionary dictionary];
|
||
_spacing = 8.f;
|
||
_padding = UIEdgeInsetsMake(8, 8, 8, 8);
|
||
_keepAspect169 = YES;
|
||
|
||
self.backgroundColor = [UIColor blackColor];
|
||
}
|
||
|
||
#pragma mark - Public
|
||
|
||
- (SLSVideoTileView *)ensureRenderContainerForUID:(NSString *)uid
|
||
displayName:(nullable NSString *)name {
|
||
if (!uid) return nil;
|
||
|
||
SLSParticipant *p = self.participants[uid];
|
||
if (!p) {
|
||
p = [SLSParticipant new];
|
||
p.uid = uid;
|
||
p.displayName = name ?: uid;
|
||
p.lastActiveAt = [NSDate date];
|
||
self.participants[uid] = p;
|
||
}
|
||
|
||
SLSVideoTileView *tile = self.tiles[uid];
|
||
if (!tile) {
|
||
tile = [[SLSVideoTileView alloc] initWithFrame:CGRectZero];
|
||
self.tiles[uid] = tile;
|
||
[self addSubview:tile];
|
||
}
|
||
|
||
[tile updateWithParticipant:p];
|
||
[self _layout];
|
||
|
||
return tile;
|
||
}
|
||
|
||
- (void)detachUID:(NSString *)uid {
|
||
if (!uid) return;
|
||
SLSVideoTileView *tile = self.tiles[uid];
|
||
if (tile) {
|
||
[tile removeFromSuperview];
|
||
[self.tiles removeObjectForKey:uid];
|
||
}
|
||
[self.participants removeObjectForKey:uid];
|
||
[self _layout];
|
||
}
|
||
|
||
- (void)setLevel:(CGFloat)level forUID:(NSString *)uid {
|
||
SLSParticipant *p = self.participants[uid];
|
||
if (!p) return;
|
||
p.level = MAX(0.f, MIN(level, 1.f));
|
||
if (p.level > 0.1) {
|
||
p.lastActiveAt = [NSDate date];
|
||
}
|
||
SLSVideoTileView *tile = self.tiles[uid];
|
||
[tile updateWithParticipant:p];
|
||
}
|
||
|
||
- (void)setAudioMuted:(BOOL)muted forUID:(NSString *)uid {
|
||
SLSParticipant *p = self.participants[uid];
|
||
if (!p) return;
|
||
p.audioMuted = muted;
|
||
SLSVideoTileView *tile = self.tiles[uid];
|
||
[tile updateWithParticipant:p];
|
||
}
|
||
|
||
- (void)setVideoMuted:(BOOL)muted forUID:(NSString *)uid {
|
||
SLSParticipant *p = self.participants[uid];
|
||
if (!p) return;
|
||
p.videoMuted = muted;
|
||
SLSVideoTileView *tile = self.tiles[uid];
|
||
[tile updateWithParticipant:p];
|
||
}
|
||
|
||
#pragma mark - Layout
|
||
|
||
- (void)_layout {
|
||
NSArray<NSString *> *uids = self.participants.allKeys;
|
||
NSInteger n = uids.count;
|
||
if (n == 0) return;
|
||
|
||
UIEdgeInsets p = self.padding;
|
||
CGFloat W = self.bounds.size.width - p.left - p.right;
|
||
CGFloat H = self.bounds.size.height - p.top - p.bottom;
|
||
CGFloat s = self.spacing;
|
||
|
||
// ===== 按人数选择固定的行列数 =====
|
||
NSInteger cols = 1;
|
||
NSInteger rows = 1;
|
||
|
||
if (n <= 4) {
|
||
cols = 2;
|
||
rows = 2;
|
||
} else if (n <= 9) {
|
||
cols = 3;
|
||
rows = 3;
|
||
} else if (n <= 16) {
|
||
cols = 4;
|
||
rows = 4;
|
||
} else {
|
||
// >16 的情况先简单处理:依旧按 4x4 布局,多出来的不显示
|
||
cols = 4;
|
||
rows = 4;
|
||
}
|
||
|
||
// 每个 cell 的宽 / 高(都按“可用区域的 1/2、1/3、1/4”来,扣掉间距)
|
||
CGFloat cellW = 0;
|
||
CGFloat cellH = 0;
|
||
if (cols > 0) {
|
||
cellW = floor((W - s * (cols - 1)) / cols);
|
||
}
|
||
if (rows > 0) {
|
||
cellH = floor((H - s * (rows - 1)) / rows);
|
||
}
|
||
|
||
NSInteger maxCells = cols * rows;
|
||
NSInteger countToLayout = MIN(n, maxCells);
|
||
|
||
[uids enumerateObjectsUsingBlock:^(NSString *uid, NSUInteger idx, BOOL *stop) {
|
||
if (idx >= countToLayout) {
|
||
*stop = YES;
|
||
return;
|
||
}
|
||
|
||
NSInteger r = idx / cols; // 第几行
|
||
NSInteger c = idx % cols; // 第几列
|
||
|
||
CGFloat x = p.left + c * (cellW + s);
|
||
CGFloat y = p.top + r * (cellH + s);
|
||
|
||
SLSVideoTileView *tile = self.tiles[uid];
|
||
tile.frame = CGRectMake(x, y, cellW, cellH);
|
||
|
||
SLSParticipant *part = self.participants[uid];
|
||
[tile updateWithParticipant:part];
|
||
}];
|
||
}
|
||
|
||
- (void)layoutSubviews {
|
||
[super layoutSubviews];
|
||
[self _layout];
|
||
}
|
||
|
||
@end
|