diff --git a/YuMi.xcodeproj/project.pbxproj b/YuMi.xcodeproj/project.pbxproj index c0e32a8c..1ab51be2 100644 --- a/YuMi.xcodeproj/project.pbxproj +++ b/YuMi.xcodeproj/project.pbxproj @@ -595,6 +595,8 @@ 4CD15D912D7E902800D9279F /* LoginViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CD15D902D7E902800D9279F /* LoginViewController.m */; }; 4CD15D922D7EC2AC00D9279F /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 23E56B3B2B03564B00C8DAC9 /* CoreTelephony.framework */; }; 4CD15D952D7FE9E400D9279F /* LoginTypesViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CD15D942D7FE9E400D9279F /* LoginTypesViewController.m */; }; + 4CD401472E7183A8003F5009 /* XPBlankCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CD401462E7183A8003F5009 /* XPBlankCollectionViewCell.m */; }; + 4CD4014A2E718E36003F5009 /* XPBlankRoomModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CD401492E718E36003F5009 /* XPBlankRoomModel.m */; }; 4CD47BB52E61514900BCDA46 /* StageViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CD47BB42E61514900BCDA46 /* StageViewManager.m */; }; 4CD47BBE2E619F1700BCDA46 /* XPRoomMoreMenuAction.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CD47BBB2E619F1700BCDA46 /* XPRoomMoreMenuAction.m */; }; 4CD47BBF2E619F1700BCDA46 /* XPRoomMoreMenuActionContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CD47BBD2E619F1700BCDA46 /* XPRoomMoreMenuActionContext.m */; }; @@ -2857,6 +2859,10 @@ 4CD15D902D7E902800D9279F /* LoginViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LoginViewController.m; sourceTree = ""; }; 4CD15D932D7FE9E400D9279F /* LoginTypesViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LoginTypesViewController.h; sourceTree = ""; }; 4CD15D942D7FE9E400D9279F /* LoginTypesViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LoginTypesViewController.m; sourceTree = ""; }; + 4CD401452E7183A8003F5009 /* XPBlankCollectionViewCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = XPBlankCollectionViewCell.h; sourceTree = ""; }; + 4CD401462E7183A8003F5009 /* XPBlankCollectionViewCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = XPBlankCollectionViewCell.m; sourceTree = ""; }; + 4CD401482E718E36003F5009 /* XPBlankRoomModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = XPBlankRoomModel.h; sourceTree = ""; }; + 4CD401492E718E36003F5009 /* XPBlankRoomModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = XPBlankRoomModel.m; sourceTree = ""; }; 4CD47BB32E61514900BCDA46 /* StageViewManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StageViewManager.h; sourceTree = ""; }; 4CD47BB42E61514900BCDA46 /* StageViewManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = StageViewManager.m; sourceTree = ""; }; 4CD47BB62E619F0B00BCDA46 /* XPTurboModeAction.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = XPTurboModeAction.h; sourceTree = ""; }; @@ -10221,6 +10227,8 @@ E87E62542A3F55BE002F68C9 /* Model */ = { isa = PBXGroup; children = ( + 4CD401482E718E36003F5009 /* XPBlankRoomModel.h */, + 4CD401492E718E36003F5009 /* XPBlankRoomModel.m */, 23FF42772AA6E19C0055733C /* HomeMenuSourceModel.h */, 23FF42782AA6E19C0055733C /* HomeMenuSourceModel.m */, E87DF4F32A42CC49009C1185 /* HomeMenuInfoModel.h */, @@ -10283,6 +10291,8 @@ E87E625F2A3F5669002F68C9 /* Cell */ = { isa = PBXGroup; children = ( + 4CD401452E7183A8003F5009 /* XPBlankCollectionViewCell.h */, + 4CD401462E7183A8003F5009 /* XPBlankCollectionViewCell.m */, 23FF25662ABC3BC00064E904 /* XPHomeGameCell.h */, 23FF25672ABC3BC00064E904 /* XPHomeGameCell.m */, E87E627D2A3F5D28002F68C9 /* XPNewHomePlayItemCollectionViewCell.h */, @@ -12448,6 +12458,7 @@ 189DD53426DE255300AB55B1 /* TabbarViewController.m in Sources */, 23C9DFC92B84917B00B51558 /* PIRoomActivityChoosePlayCell.m in Sources */, 9BA3B40B293DCDFD0071DF1C /* XPVersionUpdateModel.m in Sources */, + 4CD4014A2E718E36003F5009 /* XPBlankRoomModel.m in Sources */, 4C7989EC2D19392E006AE07B /* EmptyDataView.m in Sources */, 23C9DFCF2B85E21E00B51558 /* PIGuildSingleRoomIncomeCell.m in Sources */, 18EE401A2754BA9F00A452BF /* NIMMessageMaker.m in Sources */, @@ -13465,6 +13476,7 @@ E87E91522796A15500A7B3F2 /* MicroExtModel.m in Sources */, E8788948273A55D000BF1D57 /* XPGiftBarView.m in Sources */, 237700D32BC7CC7C00D661F1 /* NSObject+MJExtension.m in Sources */, + 4CD401472E7183A8003F5009 /* XPBlankCollectionViewCell.m in Sources */, 4C886BEE2E014B6C006F0BA7 /* Api+Medals.m in Sources */, E8D4DE442940462C00EC788D /* XPGiftTwelveStarBroadcastView.m in Sources */, 540EC1D02C89925F00F3BF0D /* GiftComboView.m in Sources */, diff --git a/YuMi/Modules/YMNewHome/Model/XPBlankRoomModel.h b/YuMi/Modules/YMNewHome/Model/XPBlankRoomModel.h new file mode 100644 index 00000000..746cb4f8 --- /dev/null +++ b/YuMi/Modules/YMNewHome/Model/XPBlankRoomModel.h @@ -0,0 +1,16 @@ +// +// XPBlankRoomModel.h +// YuMi +// +// Created by Linus on 2024/12/19. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface XPBlankRoomModel : NSObject + +@end + +NS_ASSUME_NONNULL_END diff --git a/YuMi/Modules/YMNewHome/Model/XPBlankRoomModel.m b/YuMi/Modules/YMNewHome/Model/XPBlankRoomModel.m new file mode 100644 index 00000000..0a81cd81 --- /dev/null +++ b/YuMi/Modules/YMNewHome/Model/XPBlankRoomModel.m @@ -0,0 +1,12 @@ +// +// XPBlankRoomModel.m +// YuMi +// +// Created by Linus on 2024/12/19. +// + +#import "XPBlankRoomModel.h" + +@implementation XPBlankRoomModel + +@end diff --git a/YuMi/Modules/YMNewHome/View/Cell/XPBlankCollectionViewCell.h b/YuMi/Modules/YMNewHome/View/Cell/XPBlankCollectionViewCell.h new file mode 100644 index 00000000..4a547c96 --- /dev/null +++ b/YuMi/Modules/YMNewHome/View/Cell/XPBlankCollectionViewCell.h @@ -0,0 +1,16 @@ +// +// XPBlankCollectionViewCell.h +// YuMi +// +// Created by Linus on 2024/12/19. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface XPBlankCollectionViewCell : UICollectionViewCell + +@end + +NS_ASSUME_NONNULL_END diff --git a/YuMi/Modules/YMNewHome/View/Cell/XPBlankCollectionViewCell.m b/YuMi/Modules/YMNewHome/View/Cell/XPBlankCollectionViewCell.m new file mode 100644 index 00000000..4958bbbd --- /dev/null +++ b/YuMi/Modules/YMNewHome/View/Cell/XPBlankCollectionViewCell.m @@ -0,0 +1,20 @@ +// +// XPBlankCollectionViewCell.m +// YuMi +// +// Created by Linus on 2024/12/19. +// + +#import "XPBlankCollectionViewCell.h" + +@implementation XPBlankCollectionViewCell + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + self.contentView.backgroundColor = [UIColor clearColor]; + } + return self; +} + +@end diff --git a/YuMi/Modules/YMNewHome/View/Cell/XPBlankRoomModel.h b/YuMi/Modules/YMNewHome/View/Cell/XPBlankRoomModel.h new file mode 100644 index 00000000..746cb4f8 --- /dev/null +++ b/YuMi/Modules/YMNewHome/View/Cell/XPBlankRoomModel.h @@ -0,0 +1,16 @@ +// +// XPBlankRoomModel.h +// YuMi +// +// Created by Linus on 2024/12/19. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface XPBlankRoomModel : NSObject + +@end + +NS_ASSUME_NONNULL_END diff --git a/YuMi/Modules/YMNewHome/View/Cell/XPBlankRoomModel.m b/YuMi/Modules/YMNewHome/View/Cell/XPBlankRoomModel.m new file mode 100644 index 00000000..0a81cd81 --- /dev/null +++ b/YuMi/Modules/YMNewHome/View/Cell/XPBlankRoomModel.m @@ -0,0 +1,12 @@ +// +// XPBlankRoomModel.m +// YuMi +// +// Created by Linus on 2024/12/19. +// + +#import "XPBlankRoomModel.h" + +@implementation XPBlankRoomModel + +@end diff --git a/YuMi/Modules/YMNewHome/View/Cell/XPNewHomePartyCollectionViewCell.m b/YuMi/Modules/YMNewHome/View/Cell/XPNewHomePartyCollectionViewCell.m index 04af0163..32e8c1d4 100644 --- a/YuMi/Modules/YMNewHome/View/Cell/XPNewHomePartyCollectionViewCell.m +++ b/YuMi/Modules/YMNewHome/View/Cell/XPNewHomePartyCollectionViewCell.m @@ -198,18 +198,7 @@ _avatarView.imageUrl = _roomInfo.avatar; self.levelImageView.imageUrl = roomInfo.roomLevelIcon; - for (int i = 0; i < self.membersCount; i++) { - NetImageView *iconView = _iconViews[i]; - if (i < _roomInfo.micUsers.count) { - iconView.hidden = NO; - // 更新约束和内容 - [iconView mas_remakeConstraints:^(MASConstraintMaker *make) { - make.width.height.mas_equalTo(kGetScaleWidth(20)); - }]; - } else { - iconView.hidden = YES; - } - } + [self updateMicUsersDisplay]; switch (roomInfo.homeRoomType) { case 1:{ @@ -296,19 +285,29 @@ _rankImageView.image = nil; } - for (int i = 0; i < self.membersCount; i++) { - NetImageView *iconView = [self.contentView viewWithTag:100 + i]; - if(i < _roomInfo.micUsers.count){ - iconView.hidden = NO; - HomePlayMicUserModel *playModel = _roomInfo.micUsers[i]; - iconView.imageUrl = playModel.avatar; - }else{ - iconView.hidden = YES; - } - } + [self updateMicUsersDisplay]; [self layoutIfNeeded]; } + +#pragma mark - Private Methods +- (void)updateMicUsersDisplay { + for (int i = 0; i < self.membersCount; i++) { + NetImageView *iconView = _iconViews[i]; + if (i < _roomInfo.micUsers.count) { + iconView.hidden = NO; + // 更新约束和内容 + [iconView mas_remakeConstraints:^(MASConstraintMaker *make) { + make.width.height.mas_equalTo(kGetScaleWidth(20)); + }]; + HomePlayMicUserModel *playModel = _roomInfo.micUsers[i]; + iconView.imageUrl = playModel.avatar; + } else { + iconView.hidden = YES; + } + } +} + #pragma mark - 懒加载 - (NetImageView *)avatarView{ if(!_avatarView){ diff --git a/YuMi/Modules/YMNewHome/View/XPHomePagingViewController.m b/YuMi/Modules/YMNewHome/View/XPHomePagingViewController.m index ca61e499..53f3adf8 100644 --- a/YuMi/Modules/YMNewHome/View/XPHomePagingViewController.m +++ b/YuMi/Modules/YMNewHome/View/XPHomePagingViewController.m @@ -217,6 +217,8 @@ - (void)didTapLayoutButton { self.layoutButton.selected = !self.layoutButton.isSelected; + // 发送布局切换通知 + [[NSNotificationCenter defaultCenter] postNotificationName:@"kHomeLayoutToggle" object:nil]; } #pragma mark - UIPageViewController Delegate & DataSource diff --git a/YuMi/Modules/YMNewHome/View/XPHomePartyViewController.m b/YuMi/Modules/YMNewHome/View/XPHomePartyViewController.m index 75d4e25d..0aa65f67 100644 --- a/YuMi/Modules/YMNewHome/View/XPHomePartyViewController.m +++ b/YuMi/Modules/YMNewHome/View/XPHomePartyViewController.m @@ -18,6 +18,8 @@ ///View #import "XPNewHomePartyCollectionViewCell.h" #import "XPGuildEmptyCollectionViewCell.h" +#import "XPBlankCollectionViewCell.h" +#import "XPBlankRoomModel.h" #import "XPWeakTimer.h" ///P #import "XPHomePresenter.h" @@ -107,12 +109,18 @@ @property (nonatomic,assign) int page; ///没有新的数据了 @property (nonatomic,assign) BOOL hasNoMoreData; +///布局模式:YES为两列,NO为一列 +@property (nonatomic,assign) BOOL isTwoColumnLayout; @end @implementation XPHomePartyViewController +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + - (BOOL)isHiddenNavBar { return YES; } @@ -125,6 +133,7 @@ [super viewDidLoad]; [self initSubViews]; [self initSubViewConstraints]; + [self setupLayoutNotification]; } - (void)starBeginHeaderRefresh { @@ -137,6 +146,93 @@ [self.view addSubview:self.collectionView]; } +- (void)setupLayoutNotification { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(handleLayoutToggle) + name:@"kHomeLayoutToggle" + object:nil]; +} + +- (void)handleLayoutToggle { + self.isTwoColumnLayout = !self.isTwoColumnLayout; + [self processCurrentDataSourceForLayout]; + [self.collectionView reloadData]; +} + +- (void)processCurrentDataSourceForLayout { + if (self.datasource.count == 0) return; + + if (self.isTwoColumnLayout) { + // 两列布局:为奇数个非banner元素添加占位model + NSInteger nonBannerCount = 0; + for (id item in self.datasource) { + if (![item isKindOfClass:[NSArray class]] && ![item isKindOfClass:[XPBlankRoomModel class]]) { + nonBannerCount++; + } + } + + // 如果非banner元素为奇数个,添加占位model + if (nonBannerCount % 2 != 0) { + // 找到最后一个非banner元素的位置,在其后插入占位model + NSInteger insertIndex = -1; + for (NSInteger i = self.datasource.count - 1; i >= 0; i--) { + id item = self.datasource[i]; + if (![item isKindOfClass:[NSArray class]] && ![item isKindOfClass:[XPBlankRoomModel class]]) { + insertIndex = i + 1; + break; + } + } + + if (insertIndex >= 0) { + [self.datasource insertObject:[[XPBlankRoomModel alloc] init] atIndex:insertIndex]; + } else { + [self.datasource addObject:[[XPBlankRoomModel alloc] init]]; + } + } + } else { + // 一列布局:移除所有占位model + NSMutableArray *processedDataSource = [NSMutableArray array]; + for (id item in self.datasource) { + if (![item isKindOfClass:[XPBlankRoomModel class]]) { + [processedDataSource addObject:item]; + } + } + self.datasource = processedDataSource; + } +} + +- (NSArray *)processDataSourceForLayout:(NSArray *)originalList { + if (originalList.count == 0) return originalList; + + if (self.isTwoColumnLayout) { + // 两列布局:为奇数个非banner元素添加占位model + NSMutableArray *processedDataSource = [NSMutableArray arrayWithArray:originalList]; + NSInteger nonBannerCount = 0; + + for (id item in originalList) { + if (![item isKindOfClass:[NSArray class]]) { + nonBannerCount++; + } + } + + // 如果非banner元素为奇数个,添加占位model + if (nonBannerCount % 2 != 0) { + [processedDataSource addObject:[[XPBlankRoomModel alloc] init]]; + } + + return processedDataSource; + } else { + // 一列布局:移除所有占位model + NSMutableArray *processedDataSource = [NSMutableArray array]; + for (id item in originalList) { + if (![item isKindOfClass:[XPBlankRoomModel class]]) { + [processedDataSource addObject:item]; + } + } + return processedDataSource; + } +} + - (void)initSubViewConstraints { [self.collectionView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.mas_equalTo(0); @@ -184,7 +280,15 @@ [cell setTitle:YMLocalizedString(@"XPGuildEmptyCollectionViewCell0")]; return cell; } + id item = [self.datasource xpSafeObjectAtIndex:indexPath.row]; + + // 检查是否为占位 model + if ([item isKindOfClass:[XPBlankRoomModel class]]) { + XPBlankCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass([XPBlankCollectionViewCell class]) forIndexPath:indexPath]; + return cell; + } + if ([item isKindOfClass:[NSArray class]]) { HomePartyBannerCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass([HomePartyBannerCell class]) forIndexPath:indexPath]; @@ -208,6 +312,7 @@ if(self.datasource.count == 0) { return 1; } + return self.datasource.count; } @@ -217,15 +322,32 @@ } id item = [self.datasource xpSafeObjectAtIndex:indexPath.row]; - if ([item isKindOfClass:[NSArray class]]) { - return CGSizeMake(kGetScaleWidth(345), kGetScaleWidth(105)); - } else { - return CGSizeMake(kGetScaleWidth(345), kGetScaleWidth(92)); + + // 占位 model:高度为0,宽度为半宽 + if ([item isKindOfClass:[XPBlankRoomModel class]]) { + return CGSizeMake(kGetScaleWidth(165), kGetScaleWidth(165)); } + + // 计算尺寸:两列模式非 banner 为正方形半宽;banner 始终全宽且固定高 + BOOL isBanner = [item isKindOfClass:[NSArray class]]; + if (isBanner) { + return CGSizeMake(kGetScaleWidth(345), kGetScaleWidth(105)); + } + if (self.isTwoColumnLayout) { + CGFloat side = kGetScaleWidth(165); + return CGSizeMake(side, side); + } + return CGSizeMake(kGetScaleWidth(345), kGetScaleWidth(92)); } -(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{ id item = [self.datasource xpSafeObjectAtIndex:indexPath.row]; + + // 跳过占位 model 的点击 + if ([item isKindOfClass:[XPBlankRoomModel class]]) { + return; + } + if ([item isKindOfClass:[HomePlayRoomModel class]]) { HomePlayRoomModel * roomInfo = (HomePlayRoomModel *)item; if (roomInfo.uid.length > 0) { @@ -241,8 +363,7 @@ model.width = [UILabel getWidthWithText:@(model.onlineNum).stringValue height:kGetScaleWidth(12) font:kFontBold(10)]+1; } - self.datasource = [NSMutableArray arrayWithArray:list]; - + self.datasource = [NSMutableArray arrayWithArray:[self processDataSourceForLayout:list]]; [self.collectionView reloadData]; } @@ -251,7 +372,9 @@ } - (NSMutableArray *)insertBannerData:(NSArray *)firstPageList { - NSMutableArray *mutableArrayA = [firstPageList mutableCopy]; + // 先处理数据布局(在插入banner之前) + NSArray *processedList = [self processDataSourceForLayout:firstPageList]; + NSMutableArray *mutableArrayA = [processedList mutableCopy]; if (self.bannerInfoList.count > 0) { NSInteger insertIndex = 5; @@ -274,9 +397,9 @@ if(self.page == 1){ self.datasource = [self insertBannerData:list]; }else{ - [self.datasource addObjectsFromArray:list]; + NSArray *processedList = [self processDataSourceForLayout:list]; + [self.datasource addObjectsFromArray:processedList]; } - [self.collectionView reloadData]; [[NSNotificationCenter defaultCenter]postNotificationName:@"khomeVCRefreshComplete" object:nil]; [self.collectionView.mj_footer endRefreshing]; @@ -311,9 +434,10 @@ font:kFontBold(10)] + 1; } if(self.page == 1){ - self.datasource = [NSMutableArray arrayWithArray:rooms]; + self.datasource = [NSMutableArray arrayWithArray:[self processDataSourceForLayout:rooms]]; }else{ - [self.datasource addObjectsFromArray:rooms]; + NSArray *processedList = [self processDataSourceForLayout:rooms]; + [self.datasource addObjectsFromArray:processedList]; } [self.collectionView reloadData]; } @@ -327,9 +451,10 @@ font:kFontBold(10)] + 1; } if(self.page == 1){ - self.datasource = [NSMutableArray arrayWithArray:rooms]; + self.datasource = [NSMutableArray arrayWithArray:[self processDataSourceForLayout:rooms]]; }else{ - [self.datasource addObjectsFromArray:rooms]; + NSArray *processedList = [self processDataSourceForLayout:rooms]; + [self.datasource addObjectsFromArray:processedList]; } [self.collectionView reloadData]; } @@ -385,6 +510,7 @@ [_collectionView registerClass:[XPNewHomePartyCollectionViewCell class] forCellWithReuseIdentifier:NSStringFromClass([XPNewHomePartyCollectionViewCell class])]; [_collectionView registerClass:[XPGuildEmptyCollectionViewCell class] forCellWithReuseIdentifier:NSStringFromClass([XPGuildEmptyCollectionViewCell class])]; [_collectionView registerClass:[HomePartyBannerCell class] forCellWithReuseIdentifier:NSStringFromClass([HomePartyBannerCell class])]; + [_collectionView registerClass:[XPBlankCollectionViewCell class] forCellWithReuseIdentifier:NSStringFromClass([XPBlankCollectionViewCell class])]; } return _collectionView; }