Files
SellyCloudSDK_demo/Example/SellyCloudSDK/Play/SCPlayerDebugView.m
2026-03-01 15:59:27 +08:00

261 lines
9.4 KiB
Objective-C

//
// SCPlayerDebugView.m
// SellyCloudSDK_Example
//
// Created by Caleb on 07/1/26.
// Copyright © 2026 Caleb. All rights reserved.
//
#import "SCPlayerDebugView.h"
#import <Masonry/Masonry.h>
@interface SCPlayerDebugView ()
@property (nonatomic, strong) UIVisualEffectView *blurView;
@property (nonatomic, strong) UIView *headerView;
@property (nonatomic, strong) UIView *contentView;
@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UILabel *logLabel;
@property (nonatomic, strong) UIButton *toggleButton;
@property (nonatomic, strong) UIButton *clearButton;
@property (nonatomic, strong) MASConstraint *contentViewHeightConstraint;
@property (nonatomic, strong) NSMutableArray<NSString *> *logs;
@property (nonatomic, strong) NSDateFormatter *dateFormatter;
@end
@implementation SCPlayerDebugView
- (instancetype)init {
self = [super init];
if (self) {
_isExpanded = YES; // 默认展开
_logs = [NSMutableArray array];
// 日期格式化器(用于时间戳)
_dateFormatter = [[NSDateFormatter alloc] init];
_dateFormatter.dateFormat = @"HH:mm:ss.SSS";
[self setupView];
}
return self;
}
- (void)setupView {
// 毛玻璃背景
UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialDark];
_blurView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
_blurView.layer.cornerRadius = 12;
_blurView.layer.masksToBounds = YES;
[self addSubview:_blurView];
[_blurView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self);
}];
// 边框
self.layer.cornerRadius = 12;
self.layer.borderWidth = 0.5;
self.layer.borderColor = [[UIColor whiteColor] colorWithAlphaComponent:0.3].CGColor;
// 标题栏(可点击)
_headerView = [[UIView alloc] init];
[_blurView.contentView addSubview:_headerView];
[_headerView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.left.right.equalTo(_blurView.contentView);
make.height.offset(44);
}];
// 添加点击手势
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(toggleButtonTapped)];
[_headerView addGestureRecognizer:tap];
// 标题
_titleLabel = [[UILabel alloc] init];
_titleLabel.text = @"🐛 调试日志";
_titleLabel.font = [UIFont systemFontOfSize:14 weight:UIFontWeightSemibold];
_titleLabel.textColor = [UIColor whiteColor];
[_headerView addSubview:_titleLabel];
[_titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(_headerView);
make.left.offset(12);
}];
// 清空按钮
_clearButton = [UIButton buttonWithType:UIButtonTypeSystem];
[_clearButton setImage:[UIImage systemImageNamed:@"trash.circle.fill"] forState:UIControlStateNormal];
_clearButton.tintColor = [[UIColor whiteColor] colorWithAlphaComponent:0.8];
[_clearButton addTarget:self action:@selector(clearButtonTapped) forControlEvents:UIControlEventTouchUpInside];
[_headerView addSubview:_clearButton];
[_clearButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(_headerView);
make.right.offset(-44);
make.width.height.offset(24);
}];
// 展开/收起按钮
_toggleButton = [UIButton buttonWithType:UIButtonTypeSystem];
// 默认展开状态,显示向上箭头(表示可以收起)
[_toggleButton setImage:[UIImage systemImageNamed:@"chevron.up.circle.fill"] forState:UIControlStateNormal];
_toggleButton.tintColor = [[UIColor whiteColor] colorWithAlphaComponent:0.8];
[_toggleButton addTarget:self action:@selector(toggleButtonTapped) forControlEvents:UIControlEventTouchUpInside];
[_headerView addSubview:_toggleButton];
[_toggleButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(_headerView);
make.right.offset(-12);
make.width.height.offset(24);
}];
// 分割线
UIView *separatorLine = [[UIView alloc] init];
separatorLine.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.2];
[_blurView.contentView addSubview:separatorLine];
[separatorLine mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(_headerView.mas_bottom);
make.left.offset(12);
make.right.offset(-12);
make.height.offset(0.5);
}];
// 内容容器
_contentView = [[UIView alloc] init];
_contentView.clipsToBounds = YES;
[_blurView.contentView addSubview:_contentView];
[_contentView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(separatorLine.mas_bottom);
make.left.right.bottom.equalTo(_blurView.contentView);
// 保存高度约束的引用,用于动态调整
self.contentViewHeightConstraint = make.height.offset(200); // 默认高度
}];
// ScrollView 用于滚动内容
_scrollView = [[UIScrollView alloc] init];
_scrollView.showsVerticalScrollIndicator = YES;
_scrollView.showsHorizontalScrollIndicator = NO;
_scrollView.alwaysBounceVertical = YES;
[_contentView addSubview:_scrollView];
[_scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(_contentView).insets(UIEdgeInsetsMake(8, 12, 8, 12));
}];
// 日志文本标签
_logLabel = [[UILabel alloc] init];
_logLabel.font = [UIFont monospacedSystemFontOfSize:10 weight:UIFontWeightRegular];
_logLabel.textColor = [UIColor whiteColor];
_logLabel.numberOfLines = 0; // 多行显示
_logLabel.lineBreakMode = NSLineBreakByCharWrapping;
_logLabel.text = @""; // 初始为空
[_scrollView addSubview:_logLabel];
[_logLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(_scrollView);
make.width.equalTo(_scrollView); // 限制宽度,允许文本换行
}];
}
- (void)toggleButtonTapped {
// 切换状态
[self setIsExpanded:!self.isExpanded];
}
- (void)clearButtonTapped {
[self clearLogs];
// 触觉反馈
UIImpactFeedbackGenerator *feedback = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleMedium];
[feedback impactOccurred];
}
#pragma mark - Public Methods
- (void)appendLog:(NSString *)message {
[self appendLog:message withPrefix:nil];
}
- (void)appendLog:(NSString *)message withPrefix:(nullable NSString *)prefix {
if (!message || message.length == 0) {
return;
}
// 生成时间戳
NSString *timestamp = [self.dateFormatter stringFromDate:[NSDate date]];
// 构建完整的日志条目
NSString *logEntry;
// if (prefix && prefix.length > 0) {
// logEntry = [NSString stringWithFormat:@"[%@] %@ %@", timestamp, prefix, message];
// } else {
logEntry = [NSString stringWithFormat:@"[%@] %@", timestamp, message];
// }
// 添加到日志数组
[self.logs addObject:logEntry];
// 限制日志数量(最多保留 200 条)
if (self.logs.count > 200) {
[self.logs removeObjectAtIndex:0];
}
// 更新 UI
[self updateLogDisplay];
}
- (void)clearLogs {
[self.logs removeAllObjects];
[self updateLogDisplay];
}
#pragma mark - Private Methods
- (void)updateLogDisplay {
// 将所有日志拼接成一个字符串
NSString *allLogs = [self.logs componentsJoinedByString:@"\n"];
self.logLabel.text = allLogs;
// 更新布局
[self.logLabel mas_updateConstraints:^(MASConstraintMaker *make) {
// 强制刷新高度
}];
[self.logLabel layoutIfNeeded];
// 滚动到底部(显示最新的日志)
dispatch_async(dispatch_get_main_queue(), ^{
CGFloat bottomOffset = MAX(0, self.scrollView.contentSize.height - self.scrollView.bounds.size.height);
[self.scrollView setContentOffset:CGPointMake(0, bottomOffset) animated:YES];
});
}
- (void)setIsExpanded:(BOOL)isExpanded {
if (_isExpanded == isExpanded) {
return; // 状态相同,不执行任何操作
}
_isExpanded = isExpanded;
// 执行动画更新 UI
CGFloat expandedHeight = 200; // 展开时的高度
CGFloat collapsedHeight = 0; // 收起时的高度
[UIView animateWithDuration:0.3 delay:0 usingSpringWithDamping:0.8 initialSpringVelocity:0.5 options:UIViewAnimationOptionCurveEaseInOut animations:^{
if (self.isExpanded) {
// 展开状态:显示向上箭头(表示可以收起)
[self.toggleButton setImage:[UIImage systemImageNamed:@"chevron.up.circle.fill"] forState:UIControlStateNormal];
[self.contentViewHeightConstraint setOffset:expandedHeight];
} else {
// 收起状态:显示向下箭头(表示可以展开)
[self.toggleButton setImage:[UIImage systemImageNamed:@"chevron.down.circle.fill"] forState:UIControlStateNormal];
[self.contentViewHeightConstraint setOffset:collapsedHeight];
}
// 显示/隐藏内容(用 alpha 做淡入淡出效果)
self.contentView.alpha = self.isExpanded ? 1.0 : 0.0;
// 更新约束触发布局更新
[self.superview layoutIfNeeded];
} completion:nil];
// 触觉反馈
UIImpactFeedbackGenerator *feedback = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleLight];
[feedback impactOccurred];
}
@end