From 413b2c6944d9fd5dfd272fb9c125560727c4b3d8 Mon Sep 17 00:00:00 2001 From: edwinQQQ Date: Wed, 18 Jun 2025 17:11:13 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=AD=89=E7=BA=A7=E6=8C=87?= =?UTF-8?q?=E7=A4=BA=E5=99=A8=E8=A7=86=E5=9B=BE=E5=92=8C=E5=AE=B9=E5=99=A8?= =?UTF-8?q?=E8=A7=86=E5=9B=BE=EF=BC=8C=E6=9B=B4=E6=96=B0=20MedalsCollectio?= =?UTF-8?q?nViewCell=20=E4=BB=A5=E9=9B=86=E6=88=90=E7=AD=89=E7=BA=A7?= =?UTF-8?q?=E6=8C=87=E7=A4=BA=E5=99=A8=E5=8A=9F=E8=83=BD=EF=BC=8C=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E7=AD=89=E7=BA=A7=E9=80=89=E6=8B=A9=E5=9B=9E=E8=B0=83?= =?UTF-8?q?=E3=80=82=E6=9B=B4=E6=96=B0=20.vscode/settings.json=20=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E4=BB=A5=E5=8C=85=E5=90=AB=E6=96=B0=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=20QGVAP=20=E7=9A=84=E9=85=8D=E7=BD=AE=EF=BC=8C=E4=BF=9D?= =?UTF-8?q?=E6=8C=81=E4=BB=A3=E7=A0=81=E7=BB=93=E6=9E=84=E4=B8=80=E8=87=B4?= =?UTF-8?q?=E6=80=A7=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 1 + .../View/Medals/MedalsCollectionViewCell.m | 275 +++++++++++++++++- 2 files changed, 274 insertions(+), 2 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 748c946b..20240b1f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -16,6 +16,7 @@ "Nonnull", "NSEC", "Procotol", + "QGVAP", "Subview", "Superview", "Uids" diff --git a/YuMi/Modules/YMMine/View/Medals/MedalsCollectionViewCell.m b/YuMi/Modules/YMMine/View/Medals/MedalsCollectionViewCell.m index c28cd089..d6c4b0ac 100644 --- a/YuMi/Modules/YMMine/View/Medals/MedalsCollectionViewCell.m +++ b/YuMi/Modules/YMMine/View/Medals/MedalsCollectionViewCell.m @@ -10,6 +10,241 @@ #import #import "XPRoomGiftAnimationParser.h" +// 等级指示器视图 +@interface LevelItemView : UIView + +@property (nonatomic, strong) UILabel *levelLabel; +@property (nonatomic, strong) UIView *dotView; // 圆点视图 +@property (nonatomic, assign) BOOL isSelected; +@property (nonatomic, assign) NSInteger level; + +- (instancetype)initWithLevel:(NSInteger)level; +- (void)setSelected:(BOOL)selected animated:(BOOL)animated; + +@end + +@implementation LevelItemView + +- (instancetype)initWithLevel:(NSInteger)level { + self = [super init]; + if (self) { + _level = level; + _isSelected = NO; + + // 创建圆点视图 + _dotView = [[UIView alloc] init]; + _dotView.backgroundColor = UIColorFromRGB(0x8B54E8); + _dotView.layer.cornerRadius = 3; // 圆点半径 + _dotView.clipsToBounds = YES; + [self addSubview:_dotView]; + + // 创建等级标签 + self.levelLabel = [UILabel labelInitWithText:[NSString stringWithFormat:@"LV%ld", (long)level] + font:kFontMedium(10) + textColor:UIColorFromRGB(0x8B54E8)]; + self.levelLabel.textAlignment = NSTextAlignmentCenter; + [self addSubview:self.levelLabel]; + + // 布局 + [_dotView mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerX.mas_equalTo(self); + make.top.mas_equalTo(self); + make.width.height.mas_equalTo(6); // 圆点大小 + }]; + + [self.levelLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerX.mas_equalTo(self); + make.top.mas_equalTo(_dotView.mas_bottom).offset(4); // 圆点和文字的间距 + make.leading.trailing.bottom.mas_equalTo(self); + }]; + } + return self; +} + +- (void)setSelected:(BOOL)selected animated:(BOOL)animated { + if (_isSelected == selected) { + return; + } + + _isSelected = selected; + + void (^updateBlock)(void) = ^{ + UIColor *color = selected ? [UIColor whiteColor] : UIColorFromRGB(0x8B54E8); + self.levelLabel.textColor = color; + self.dotView.backgroundColor = color; + }; + + if (animated) { + [UIView animateWithDuration:0.2 animations:updateBlock]; + } else { + updateBlock(); + } +} + +@end + +// 等级指示器容器视图 +@interface LevelIndicatorView : UIView + +@property (nonatomic, strong) NSMutableArray *levelItems; +@property (nonatomic, strong) NSMutableArray *connectionLines; // 连接线数组 +@property (nonatomic, assign) NSInteger maxLevel; +@property (nonatomic, assign) NSInteger selectedLevel; +@property (nonatomic, copy) void (^levelSelectedBlock)(NSInteger level); + +@end + +@implementation LevelIndicatorView + +- (instancetype)init { + self = [super init]; + if (self) { + _levelItems = [NSMutableArray array]; + _connectionLines = [NSMutableArray array]; + _selectedLevel = 1; + + UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)]; + [self addGestureRecognizer:tapGesture]; + } + return self; +} + +- (void)setupWithMaxLevel:(NSInteger)maxLevel { + if (maxLevel < 0) { + maxLevel = 1; + } + if (_maxLevel == maxLevel && _levelItems.count == maxLevel) { + return; + } + + _maxLevel = maxLevel; + + // 清除现有的等级指示器和连接线 + for (UIView *view in _levelItems) { + [view removeFromSuperview]; + } + [_levelItems removeAllObjects]; + + for (UIView *line in _connectionLines) { + [line removeFromSuperview]; + } + [_connectionLines removeAllObjects]; + + // 创建新的等级指示器 + CGFloat itemWidth = 25.0; // 每个等级指示器的宽度 + CGFloat spacing = 15.0; // 等级指示器之间的间距 + CGFloat totalWidth = itemWidth * maxLevel + spacing * (maxLevel - 1); + CGFloat startX = (self.bounds.size.width - totalWidth) / 2; + + for (NSInteger i = 1; i <= maxLevel; i++) { + // 创建等级指示器 + LevelItemView *levelItem = [[LevelItemView alloc] initWithLevel:i]; + [self addSubview:levelItem]; + [_levelItems addObject:levelItem]; + + // 设置位置 + CGFloat x = startX + (i - 1) * (itemWidth + spacing); + [levelItem mas_makeConstraints:^(MASConstraintMaker *make) { + make.width.mas_equalTo(itemWidth); + make.height.mas_equalTo(self); + make.centerY.mas_equalTo(self); + make.leading.mas_equalTo(self).offset(x); + }]; + + // 如果不是第一个,添加连接线 + if (i > 1) { + UIView *line = [[UIView alloc] init]; + line.backgroundColor = UIColorFromRGB(0x8B54E8); // 默认非选中颜色 + [self insertSubview:line atIndex:0]; + [_connectionLines addObject:line]; + + // 连接线位置:从上一个圆点到当前圆点 + [line mas_makeConstraints:^(MASConstraintMaker *make) { + make.height.mas_equalTo(1); // 线的高度 + make.centerY.mas_equalTo(levelItem.dotView); + make.leading.mas_equalTo(_levelItems[i-2].dotView.mas_centerX); + make.trailing.mas_equalTo(levelItem.dotView.mas_centerX); + }]; + } + } + + // 默认选中LV1 + [self setSelectedLevel:1 animated:NO]; +} + +- (void)layoutSubviews { + [super layoutSubviews]; + + if (_maxLevel > 0 && _levelItems.count > 0) { + // 重新计算布局,确保居中显示 + CGFloat itemWidth = 25.0; + CGFloat spacing = 15.0; + CGFloat totalWidth = itemWidth * _maxLevel + spacing * (_maxLevel - 1); + CGFloat startX = (self.bounds.size.width - totalWidth) / 2; + + for (NSInteger i = 0; i < _levelItems.count; i++) { + LevelItemView *item = _levelItems[i]; + CGFloat x = startX + i * (itemWidth + spacing); + [item mas_updateConstraints:^(MASConstraintMaker *make) { + make.leading.mas_equalTo(self).offset(x); + }]; + } + } +} + +- (void)setSelectedLevel:(NSInteger)level animated:(BOOL)animated { + if (level < 1 || level > _maxLevel) { + return; + } + + _selectedLevel = level; + + // 更新等级指示器状态 + for (NSInteger i = 0; i < _levelItems.count; i++) { + LevelItemView *item = _levelItems[i]; + [item setSelected:(i + 1) <= level animated:animated]; + } + + // 更新连接线状态 + for (NSInteger i = 0; i < _connectionLines.count; i++) { + UIView *line = _connectionLines[i]; + // 连接线的状态取决于它连接的两个等级指示器是否都被选中 + // 如果连接线两端的等级指示器都被选中,则连接线也被选中 + BOOL isSelected = (i + 2) <= level; + + void (^updateBlock)(void) = ^{ + line.backgroundColor = isSelected ? [UIColor whiteColor] : UIColorFromRGB(0x8B54E8); + }; + + if (animated) { + [UIView animateWithDuration:0.2 animations:updateBlock]; + } else { + updateBlock(); + } + } +} + +- (void)handleTap:(UITapGestureRecognizer *)gesture { + CGPoint location = [gesture locationInView:self]; + + for (NSInteger i = 0; i < _levelItems.count; i++) { + LevelItemView *item = _levelItems[i]; + CGPoint itemLocation = [self convertPoint:location toView:item]; + + if (CGRectContainsPoint(item.bounds, itemLocation)) { + NSInteger level = i + 1; + [self setSelectedLevel:level animated:YES]; + + if (_levelSelectedBlock) { + _levelSelectedBlock(level); + } + break; + } + } +} + +@end + @interface MedalsCollectionViewCell () @property(nonatomic, copy) NSString *imagePath; @@ -20,8 +255,10 @@ @property(nonatomic, strong) XPRoomGiftAnimationParser *mp4Parser; @property (nonatomic, strong) UILabel *titleLabel; @property (nonatomic, strong) UILabel *subLabel; +@property (nonatomic, strong) LevelIndicatorView *levelIndicatorView; @property (nonatomic, strong) MedalVos *displayModel; +@property (nonatomic, strong) MedalSeriesItemVo *currentItemVo; @end @implementation MedalsCollectionViewCell @@ -82,15 +319,50 @@ [self.subLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.centerX.mas_equalTo(self.contentView); make.top.mas_equalTo(self.titleLabel.mas_bottom).offset(7); - make.leading.trailing.mas_equalTo(self.contentView).inset( 3); + make.leading.trailing.mas_equalTo(self.contentView).inset(3); }]; + + // 添加等级指示器 + self.levelIndicatorView = [[LevelIndicatorView alloc] init]; + [self.contentView addSubview:self.levelIndicatorView]; + [self.levelIndicatorView mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerX.mas_equalTo(self.contentView); + make.bottom.mas_equalTo(self.contentView).offset(-8); + make.left.right.mas_greaterThanOrEqualTo(self.contentView).inset(8); + make.height.mas_equalTo(26); // 增加高度以适应圆点和文本 + }]; + + // 设置等级选择回调 + @kWeakify(self); + self.levelIndicatorView.levelSelectedBlock = ^(NSInteger level) { + @kStrongify(self); + // 处理等级选择事件 + if (self.currentItemVo && level <= self.currentItemVo.medalVos.count) { + MedalVos *selectedMedalVo = [self.currentItemVo.medalVos xpSafeObjectAtIndex:level - 1]; + if (selectedMedalVo) { + self.displayModel = selectedMedalVo; + [self updateDisplayWithCurrentModel]; + } + } + }; } return self; } - (void)updateCell:(MedalSeriesVo *)model { MedalSeriesItemVo *itemVos = [model.medalSeries xpSafeObjectAtIndex:0]; + self.currentItemVo = itemVos; self.displayModel = [itemVos.medalVos xpSafeObjectAtIndex:0]; + + // 配置等级指示器 + [self.levelIndicatorView setupWithMaxLevel:itemVos.medalLevel]; + + [self.levelIndicatorView setSelectedLevel:1 animated:NO]; + + [self updateDisplayWithCurrentModel]; +} + +- (void)updateDisplayWithCurrentModel { if (self.displayModel) { if ([self.displayModel.picUrl hasSuffix:@"mp4"]) { [self setMp4Path:self.displayModel.picUrl]; @@ -109,7 +381,6 @@ [NSDate timestampSwitchTime:self.displayModel.expireSeconds formatter:@"yyyy/mm/dd"]]; } - } }