261 lines
9.4 KiB
Objective-C
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
|