From 345583c197546a19e18a1889d238c015ff278328 Mon Sep 17 00:00:00 2001 From: edwinQQQ Date: Mon, 15 Sep 2025 19:09:48 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E9=BA=A6=E4=BD=8D=E7=9B=B8?= =?UTF-8?q?=E9=82=BB=E6=80=A7=E5=88=A4=E6=96=AD=E9=80=BB=E8=BE=91=EF=BC=8C?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=AD=90=E7=B1=BB=E5=8F=AF=E9=87=8D=E5=86=99?= =?UTF-8?q?=E7=9A=84=E6=96=B9=E6=B3=95=E4=BB=A5=E6=94=AF=E6=8C=81=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E5=B8=83=E5=B1=80=E9=85=8D=E7=BD=AE=E3=80=82?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=90=84=E4=B8=AA=E9=BA=A6=E4=BD=8D=E5=B8=83?= =?UTF-8?q?=E5=B1=80=E7=B1=BB=EF=BC=8C=E7=AE=80=E5=8C=96=E7=9B=B8=E9=82=BB?= =?UTF-8?q?=E6=80=A7=E5=88=A4=E6=96=AD=EF=BC=8C=E7=A1=AE=E4=BF=9D=E5=B8=83?= =?UTF-8?q?=E5=B1=80=E9=80=BB=E8=BE=91=E7=9A=84=E4=B8=80=E8=87=B4=E6=80=A7?= =?UTF-8?q?=E5=92=8C=E5=8F=AF=E7=BB=B4=E6=8A=A4=E6=80=A7=E3=80=82=E5=90=8C?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E4=BC=98=E5=8C=96=E4=B8=AD=E7=82=B9=E7=9F=A9?= =?UTF-8?q?=E5=BD=A2=E8=AE=A1=E7=AE=97=E6=96=B9=E6=B3=95=EF=BC=8C=E6=8F=90?= =?UTF-8?q?=E5=8D=87=E4=BB=A3=E7=A0=81=E7=9A=84=E5=8F=AF=E8=AF=BB=E6=80=A7?= =?UTF-8?q?=E5=92=8C=E6=80=A7=E8=83=BD=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../YMRoom/View/StageView/AnchorPKStageView.m | 21 +--- .../YMRoom/View/StageView/AnchorStageView.m | 25 +--- .../YMRoom/View/StageView/DatingStageView.m | 24 ++-- .../View/StageView/FifteenMicStageView.m | 33 +----- .../StageView/LittleGameScrollStageView.m | 27 ++--- .../View/StageView/LittleGameStageView.m | 26 ++--- .../View/StageView/NineteenMicStageView.m | 27 ++--- .../YMRoom/View/StageView/SocialStageView.m | 47 ++++---- .../Modules/YMRoom/View/StageView/StageView.h | 16 +++ .../Modules/YMRoom/View/StageView/StageView.m | 109 +++++++++++++----- .../YMRoom/View/StageView/TenMicStageView.m | 32 +---- .../View/StageView/TwentyMicStageView.m | 34 ++---- 12 files changed, 172 insertions(+), 249 deletions(-) diff --git a/YuMi/Modules/YMRoom/View/StageView/AnchorPKStageView.m b/YuMi/Modules/YMRoom/View/StageView/AnchorPKStageView.m index c85f5e25..608c288e 100644 --- a/YuMi/Modules/YMRoom/View/StageView/AnchorPKStageView.m +++ b/YuMi/Modules/YMRoom/View/StageView/AnchorPKStageView.m @@ -147,24 +147,15 @@ return point; } -// 主播PK:两个位置(0、1)互为相邻 -- (CGRect)rectForMidpointBetweenMicAtIndex:(NSInteger)firstIndex andIndex:(NSInteger)secondIndex { - if (firstIndex == secondIndex) return CGRectZero; +// 主播PK:自定义相邻性判断(仅支持0-1的相邻对) +- (BOOL)isAdjacentMicAtIndex:(NSInteger)firstIndex andIndex:(NSInteger)secondIndex { + if (firstIndex == secondIndex) return NO; + NSInteger left = MIN(firstIndex, secondIndex); NSInteger right = MAX(firstIndex, secondIndex); - if (!(left == 0 && right == 1)) return CGRectZero; - CGRect l = [self rectForViewAtIndex:left]; - CGRect r = [self rectForViewAtIndex:right]; - if (CGRectIsEmpty(l) || CGRectIsEmpty(r)) return CGRectZero; - CGFloat midX = (CGRectGetMidX(l) + CGRectGetMidX(r)) / 2.0; - // 🔧 修改:使用两个麦位矩形的顶部对齐,而不是中心对齐 - CGFloat leftTopY = CGRectGetMinY(l); - CGFloat rightTopY = CGRectGetMinY(r); - CGFloat midTopY = (leftTopY + rightTopY) / 2.0; - - CGFloat size = 75.0; - return CGRectMake(midX - size / 2.0, midTopY, size, size); + // 仅支持0-1的相邻对 + return (left == 0 && right == 1); } - (void)onRoomEntered { diff --git a/YuMi/Modules/YMRoom/View/StageView/AnchorStageView.m b/YuMi/Modules/YMRoom/View/StageView/AnchorStageView.m index fbdc8307..27171f80 100644 --- a/YuMi/Modules/YMRoom/View/StageView/AnchorStageView.m +++ b/YuMi/Modules/YMRoom/View/StageView/AnchorStageView.m @@ -105,30 +105,15 @@ return point; } -// 主播房布局:房主(0) + 3个麦位(1-3),仅相邻麦位(1-2, 2-3)返回中点75x75 -- (CGRect)rectForMidpointBetweenMicAtIndex:(NSInteger)firstIndex andIndex:(NSInteger)secondIndex { - if (firstIndex == secondIndex) return CGRectZero; +// 主播房布局:自定义相邻性判断(仅支持1-2, 2-3的相邻对) +- (BOOL)isAdjacentMicAtIndex:(NSInteger)firstIndex andIndex:(NSInteger)secondIndex { + if (firstIndex == secondIndex) return NO; + NSInteger left = MIN(firstIndex, secondIndex); NSInteger right = MAX(firstIndex, secondIndex); // 仅支持1-2, 2-3的相邻对 - if (!((left == 1 && right == 2) || (left == 2 && right == 3))) { - return CGRectZero; - } - - CGRect l = [self rectForViewAtIndex:left]; - CGRect r = [self rectForViewAtIndex:right]; - if (CGRectIsEmpty(l) || CGRectIsEmpty(r)) return CGRectZero; - - CGFloat midX = (CGRectGetMidX(l) + CGRectGetMidX(r)) / 2.0; - - // 🔧 修改:使用两个麦位矩形的顶部对齐,而不是中心对齐 - CGFloat leftTopY = CGRectGetMinY(l); - CGFloat rightTopY = CGRectGetMinY(r); - CGFloat midTopY = (leftTopY + rightTopY) / 2.0; - - CGFloat size = 75.0; - return CGRectMake(midX - size / 2.0, midTopY, size, size); + return ((left == 1 && right == 2) || (left == 2 && right == 3)); } - (void)onRoomEntered { diff --git a/YuMi/Modules/YMRoom/View/StageView/DatingStageView.m b/YuMi/Modules/YMRoom/View/StageView/DatingStageView.m index dda72122..0fc03c09 100644 --- a/YuMi/Modules/YMRoom/View/StageView/DatingStageView.m +++ b/YuMi/Modules/YMRoom/View/StageView/DatingStageView.m @@ -157,26 +157,16 @@ return point; } -// 相亲布局:每行两侧各 2 个麦位,中间留 dating 区,允许每侧相邻对返回中点(1-2、3-4;5-6、7-8) -- (CGRect)rectForMidpointBetweenMicAtIndex:(NSInteger)firstIndex andIndex:(NSInteger)secondIndex { - if (firstIndex == secondIndex) return CGRectZero; +// 相亲布局:自定义相邻性判断(仅支持1-2、3-4、5-6、7-8的相邻对) +- (BOOL)isAdjacentMicAtIndex:(NSInteger)firstIndex andIndex:(NSInteger)secondIndex { + if (firstIndex == secondIndex) return NO; + NSInteger left = MIN(firstIndex, secondIndex); NSInteger right = MAX(firstIndex, secondIndex); - BOOL valid = ((left == 1 && right == 2) || (left == 3 && right == 4) || - (left == 5 && right == 6) || (left == 7 && right == 8)); - if (!valid) return CGRectZero; - CGRect l = [self rectForViewAtIndex:left]; - CGRect r = [self rectForViewAtIndex:right]; - if (CGRectIsEmpty(l) || CGRectIsEmpty(r)) return CGRectZero; - CGFloat midX = (CGRectGetMidX(l) + CGRectGetMidX(r)) / 2.0; - // 🔧 修改:使用两个麦位矩形的顶部对齐,而不是中心对齐 - CGFloat leftTopY = CGRectGetMinY(l); - CGFloat rightTopY = CGRectGetMinY(r); - CGFloat midTopY = (leftTopY + rightTopY) / 2.0; - - CGFloat size = 75.0; - return CGRectMake(midX - size / 2.0, midTopY, size, size); + // 仅支持1-2、3-4、5-6、7-8的相邻对 + return ((left == 1 && right == 2) || (left == 3 && right == 4) || + (left == 5 && right == 6) || (left == 7 && right == 8)); } /** diff --git a/YuMi/Modules/YMRoom/View/StageView/FifteenMicStageView.m b/YuMi/Modules/YMRoom/View/StageView/FifteenMicStageView.m index 796068cc..ec2b7e5b 100644 --- a/YuMi/Modules/YMRoom/View/StageView/FifteenMicStageView.m +++ b/YuMi/Modules/YMRoom/View/StageView/FifteenMicStageView.m @@ -126,36 +126,9 @@ return point; } -// 15麦位布局:5x3网格,仅同一行且相邻列(列差1)返回中点75x75 -- (CGRect)rectForMidpointBetweenMicAtIndex:(NSInteger)firstIndex andIndex:(NSInteger)secondIndex { - if (firstIndex == secondIndex) return CGRectZero; - NSInteger left = MIN(firstIndex, secondIndex); - NSInteger right = MAX(firstIndex, secondIndex); - - // 检查是否在同一行且相邻 - BOOL sameRow = ((left >= 0 && left <= 4 && right >= 0 && right <= 4) || - (left >= 5 && left <= 9 && right >= 5 && right <= 9) || - (left >= 10 && left <= 14 && right >= 10 && right <= 14)); - if (!sameRow) return CGRectZero; - - // 检查是否相邻(列差为1) - NSInteger leftCol = (left <= 4) ? left : ((left <= 9) ? (left - 5) : (left - 10)); - NSInteger rightCol = (right <= 4) ? right : ((right <= 9) ? (right - 5) : (right - 10)); - if ((rightCol - leftCol) != 1) return CGRectZero; - - CGRect l = [self rectForViewAtIndex:left]; - CGRect r = [self rectForViewAtIndex:right]; - if (CGRectIsEmpty(l) || CGRectIsEmpty(r)) return CGRectZero; - - CGFloat midX = (CGRectGetMidX(l) + CGRectGetMidX(r)) / 2.0; - - // 🔧 修改:使用两个麦位矩形的顶部对齐,而不是中心对齐 - CGFloat leftTopY = CGRectGetMinY(l); - CGFloat rightTopY = CGRectGetMinY(r); - CGFloat midTopY = (leftTopY + rightTopY) / 2.0; - - CGFloat size = 75.0; - return CGRectMake(midX - size / 2.0, midTopY, size, size); +// 15麦位布局:5x3网格配置 +- (NSArray *> *)micRowRanges { + return @[@[@0, @4], @[@5, @9], @[@10, @14]]; // 三行,每行5个麦位 } @end diff --git a/YuMi/Modules/YMRoom/View/StageView/LittleGameScrollStageView.m b/YuMi/Modules/YMRoom/View/StageView/LittleGameScrollStageView.m index 67b7ed3f..f9ddaa9b 100644 --- a/YuMi/Modules/YMRoom/View/StageView/LittleGameScrollStageView.m +++ b/YuMi/Modules/YMRoom/View/StageView/LittleGameScrollStageView.m @@ -137,26 +137,13 @@ UIKIT_EXTERN NSString * const kRoomRoomLittleGameMiniStageNotificationKey; return point; } -// 线性可滚动布局,相邻 index(差 1)返回中点 75x75(坐标基于 scrollView) -- (CGRect)rectForMidpointBetweenMicAtIndex:(NSInteger)firstIndex andIndex:(NSInteger)secondIndex { - if (firstIndex == secondIndex) return CGRectZero; - NSInteger left = MIN(firstIndex, secondIndex); - NSInteger right = MAX(firstIndex, secondIndex); - if (left < 0 || right >= [self countOfMicroView]) return CGRectZero; - if ((right - left) != 1) return CGRectZero; // 仅相邻 - CGRect l = [self rectForViewAtIndex:left]; - CGRect r = [self rectForViewAtIndex:right]; - if (CGRectIsEmpty(l) || CGRectIsEmpty(r)) return CGRectZero; - CGFloat midX = (CGRectGetMidX(l) + CGRectGetMidX(r)) / 2.0; - - // 🔧 修改:使用两个麦位矩形的顶部对齐,而不是中心对齐 - CGFloat leftTopY = CGRectGetMinY(l); - CGFloat rightTopY = CGRectGetMinY(r); - CGFloat midTopY = (leftTopY + rightTopY) / 2.0; - - CGFloat size = 75.0; - // 坐标在自身(scrollView 内),返回给调用方在自身坐标使用 - return CGRectMake(midX - size / 2.0, midTopY, size, size); +// 线性可滚动布局:单行线性排布配置 +- (NSArray *> *)micRowRanges { + NSInteger count = [self countOfMicroView]; + if (count > 0) { + return @[@[@0, @(count - 1)]]; // 所有麦位在一行 + } + return @[]; } - (void)didSelectAtIndex:(NSInteger)index { diff --git a/YuMi/Modules/YMRoom/View/StageView/LittleGameStageView.m b/YuMi/Modules/YMRoom/View/StageView/LittleGameStageView.m index 9ae36f96..413f0316 100644 --- a/YuMi/Modules/YMRoom/View/StageView/LittleGameStageView.m +++ b/YuMi/Modules/YMRoom/View/StageView/LittleGameStageView.m @@ -81,25 +81,13 @@ UIKIT_EXTERN NSString * const kRoomRoomLittleGameMiniStageNotificationKey; return point; } -// 同一行线性排布,允许相邻 index(差 1)返回中点 75x75 -- (CGRect)rectForMidpointBetweenMicAtIndex:(NSInteger)firstIndex andIndex:(NSInteger)secondIndex { - if (firstIndex == secondIndex) return CGRectZero; - NSInteger left = MIN(firstIndex, secondIndex); - NSInteger right = MAX(firstIndex, secondIndex); - if (left < 0 || right >= [self countOfMicroView]) return CGRectZero; - if ((right - left) != 1) return CGRectZero; // 仅相邻 - CGRect l = [self rectForViewAtIndex:left]; - CGRect r = [self rectForViewAtIndex:right]; - if (CGRectIsEmpty(l) || CGRectIsEmpty(r)) return CGRectZero; - CGFloat midX = (CGRectGetMidX(l) + CGRectGetMidX(r)) / 2.0; - - // 🔧 修改:使用两个麦位矩形的顶部对齐,而不是中心对齐 - CGFloat leftTopY = CGRectGetMinY(l); - CGFloat rightTopY = CGRectGetMinY(r); - CGFloat midTopY = (leftTopY + rightTopY) / 2.0; - - CGFloat size = 75.0; - return CGRectMake(midX - size / 2.0, midTopY, size, size); +// 小游戏布局:单行线性排布配置 +- (NSArray *> *)micRowRanges { + NSInteger count = [self countOfMicroView]; + if (count > 0) { + return @[@[@0, @(count - 1)]]; // 所有麦位在一行 + } + return @[]; } - (void)didSelectAtIndex:(NSInteger)index { diff --git a/YuMi/Modules/YMRoom/View/StageView/NineteenMicStageView.m b/YuMi/Modules/YMRoom/View/StageView/NineteenMicStageView.m index 91219b86..d6366042 100644 --- a/YuMi/Modules/YMRoom/View/StageView/NineteenMicStageView.m +++ b/YuMi/Modules/YMRoom/View/StageView/NineteenMicStageView.m @@ -143,9 +143,10 @@ static const NSInteger kMicCountPerRow = 5; return [self convertPoint:center toView:nil]; } -// 19麦位布局:复杂布局,仅同一行且相邻列(列差1)返回中点75x75 -- (CGRect)rectForMidpointBetweenMicAtIndex:(NSInteger)firstIndex andIndex:(NSInteger)secondIndex { - if (firstIndex == secondIndex) return CGRectZero; +// 19麦位布局:复杂布局的自定义相邻性判断 +- (BOOL)isAdjacentMicAtIndex:(NSInteger)firstIndex andIndex:(NSInteger)secondIndex { + if (firstIndex == secondIndex) return NO; + NSInteger left = MIN(firstIndex, secondIndex); NSInteger right = MAX(firstIndex, secondIndex); @@ -170,7 +171,7 @@ static const NSInteger kMicCountPerRow = 5; else if (left >= 10 && left <= 13 && right >= 10 && right <= 13) { // 排除11-12的相邻对 if (left == 11 && right == 12) { - return CGRectZero; + return NO; } sameRow = YES; leftCol = left - 10; @@ -183,24 +184,10 @@ static const NSInteger kMicCountPerRow = 5; rightCol = right - 14; } - if (!sameRow) return CGRectZero; + if (!sameRow) return NO; // 检查是否相邻(列差为1) - if ((rightCol - leftCol) != 1) return CGRectZero; - - CGRect l = [self rectForViewAtIndex:left]; - CGRect r = [self rectForViewAtIndex:right]; - if (CGRectIsEmpty(l) || CGRectIsEmpty(r)) return CGRectZero; - - CGFloat midX = (CGRectGetMidX(l) + CGRectGetMidX(r)) / 2.0; - - // 🔧 修改:使用两个麦位矩形的顶部对齐,而不是中心对齐 - CGFloat leftTopY = CGRectGetMinY(l); - CGFloat rightTopY = CGRectGetMinY(r); - CGFloat midTopY = (leftTopY + rightTopY) / 2.0; - - CGFloat size = 75.0; - return CGRectMake(midX - size / 2.0, midTopY, size, size); + return (rightCol - leftCol) == 1; } @end diff --git a/YuMi/Modules/YMRoom/View/StageView/SocialStageView.m b/YuMi/Modules/YMRoom/View/StageView/SocialStageView.m index f0e803c6..86675f00 100644 --- a/YuMi/Modules/YMRoom/View/StageView/SocialStageView.m +++ b/YuMi/Modules/YMRoom/View/StageView/SocialStageView.m @@ -128,47 +128,42 @@ return point; } -// 计算两个横向相邻麦位之间的中点矩形(75x75)。 -- (CGRect)rectForMidpointBetweenMicAtIndex:(NSInteger)firstIndex andIndex:(NSInteger)secondIndex { - // 仅支持下排与上排的麦位区间 [1-4], [5-8] 且相邻 - if (firstIndex == secondIndex) { - return CGRectZero; - } +// 社交布局:自定义相邻性判断(仅支持[1-4]和[5-8]区间内相邻) +- (BOOL)isAdjacentMicAtIndex:(NSInteger)firstIndex andIndex:(NSInteger)secondIndex { + if (firstIndex == secondIndex) return NO; + NSInteger left = MIN(firstIndex, secondIndex); NSInteger right = MAX(firstIndex, secondIndex); + + // 仅支持下排与上排的麦位区间 [1-4], [5-8] 且相邻 BOOL sameRowFirst = (left >= 1 && left <= 4 && right >= 1 && right <= 4); BOOL sameRowSecond = (left >= 5 && left <= 8 && right >= 5 && right <= 8); + if (!(sameRowFirst || sameRowSecond)) { - return CGRectZero; - } - if (right - left != 1) { - return CGRectZero; + return NO; } + + return (right - left) == 1; +} - // 取两个麦位的 rect - CGRect leftRect = [self rectForViewAtIndex:left]; - CGRect rightRect = [self rectForViewAtIndex:right]; - if (CGRectIsEmpty(leftRect) || CGRectIsEmpty(rightRect)) { - return CGRectZero; - } - - // 取头像区域(上方圆形区域)的中心点作为基准。头像宽为 mcWidth 的圆区域,居于麦位 rect 顶部。 - // 在已有实现中,动画点位使用了 (rect.origin.y + mcWidth/2 - 10)。这里复用相同的纵向基准,保证视觉一致。 +// 社交布局:自定义中点计算(使用头像区域中心点) +- (CGRect)calculateMidpointRectBetweenLeft:(CGRect)leftRect andRight:(CGRect)rightRect { + // 取头像区域(上方圆形区域)的中心点作为基准 CGFloat f_top = iPhoneXSeries ? firstRowTop : ownerHeight + marginV1 + ownerTopMargin_little_screen; CGFloat s_top = iPhoneXSeries ? secondRowTop : mcHeight + marginV2 + f_top; - - BOOL inFirstRow = sameRowFirst; - CGFloat circleCenterY = (inFirstRow ? (f_top + mcWidth / 2 - 10) : (s_top + mcWidth / 2 - 10)); - + + // 判断是否在第一行(根据Y坐标判断) + BOOL inFirstRow = (CGRectGetMinY(leftRect) < s_top); + CGFloat circleCenterY = (inFirstRow ? (f_top + mcWidth / 2 - 10) : (s_top + mcWidth / 2 - 10)) - 10.0; + // 两个头像中心的 X 坐标 CGFloat leftCenterX = CGRectGetMinX(leftRect) + mcWidth / 2; CGFloat rightCenterX = CGRectGetMinX(rightRect) + mcWidth / 2; CGFloat midX = (leftCenterX + rightCenterX) / 2.0; - + // 以中点为中心,返回 75x75 的矩形 CGFloat size = 75.0; - CGRect midRect = CGRectMake(midX - size / 2.0, circleCenterY - size / 2.0, size, size); - return midRect; + return CGRectMake(midX - size / 2.0, circleCenterY - size / 2.0, size, size); } @end diff --git a/YuMi/Modules/YMRoom/View/StageView/StageView.h b/YuMi/Modules/YMRoom/View/StageView/StageView.h index 68421661..e02ed267 100644 --- a/YuMi/Modules/YMRoom/View/StageView/StageView.h +++ b/YuMi/Modules/YMRoom/View/StageView/StageView.h @@ -77,6 +77,22 @@ NS_ASSUME_NONNULL_BEGIN /// 计算两个横向相邻麦位中点的矩形(默认返回基于两个坑位中心点的 75x75,非同一行或非相邻返回 CGRectZero)。 - (CGRect)rectForMidpointBetweenMicAtIndex:(NSInteger)firstIndex andIndex:(NSInteger)secondIndex; + +#pragma mark - 子类可重写的布局配置方法 + +/// 子类重写:返回麦位行配置,每行包含该行的索引范围数组 +/// 例如:@[@[@0, @4], @[@5, @9]] 表示两行,第一行0-4,第二行5-9 +- (NSArray *> *)micRowRanges; + +/// 子类重写:是否允许同行相邻麦位显示中点矩形 +- (BOOL)allowsAdjacentInSameRow; + +/// 子类重写:自定义相邻性判断逻辑(默认使用行配置) +- (BOOL)isAdjacentMicAtIndex:(NSInteger)firstIndex andIndex:(NSInteger)secondIndex; + +/// 子类重写:自定义中点矩形计算(默认使用顶部对齐的75x75) +- (CGRect)calculateMidpointRectBetweenLeft:(CGRect)leftRect andRight:(CGRect)rightRect; + @end NS_ASSUME_NONNULL_END diff --git a/YuMi/Modules/YMRoom/View/StageView/StageView.m b/YuMi/Modules/YMRoom/View/StageView/StageView.m index df225b5f..ea50d0a7 100644 --- a/YuMi/Modules/YMRoom/View/StageView/StageView.m +++ b/YuMi/Modules/YMRoom/View/StageView/StageView.m @@ -1215,37 +1215,86 @@ return CGRectZero; } -/// 默认实现:基于两个坑位的 rect 中点,返回 75x75 的矩形。 -/// 子类如有明确排布规则(如相同行的相邻判定),可重写以增强约束。 +/// 统一实现:使用子类提供的策略判断相邻性并计算中点矩形 - (CGRect)rectForMidpointBetweenMicAtIndex:(NSInteger)firstIndex andIndex:(NSInteger)secondIndex { - if (firstIndex == secondIndex) { - return CGRectZero; - } - NSInteger left = MIN(firstIndex, secondIndex); - NSInteger right = MAX(firstIndex, secondIndex); - CGRect leftRect = [self rectForViewAtIndex:left]; - CGRect rightRect = [self rectForViewAtIndex:right]; - if (CGRectIsEmpty(leftRect) || CGRectIsEmpty(rightRect)) { - return CGRectZero; - } - // 判断是否同一"行":中心 y 差值小于高度的三分之一 - CGFloat leftCenterY = CGRectGetMidY(leftRect); - CGFloat rightCenterY = CGRectGetMidY(rightRect); - if (fabs(leftCenterY - rightCenterY) > (CGRectGetHeight(leftRect) / 3.0)) { - return CGRectZero; - } - // 计算中点 - CGFloat leftCenterX = CGRectGetMidX(leftRect); - CGFloat rightCenterX = CGRectGetMidX(rightRect); - CGFloat midX = (leftCenterX + rightCenterX) / 2.0; - - // 🔧 修改:使用两个麦位矩形的顶部对齐,而不是中心对齐 - CGFloat leftTopY = CGRectGetMinY(leftRect); - CGFloat rightTopY = CGRectGetMinY(rightRect); - CGFloat midTopY = (leftTopY + rightTopY) / 2.0; - - CGFloat size = 75.0; - return CGRectMake(midX - size / 2.0, midTopY, size, size); + // 1. 基础验证 + if (firstIndex == secondIndex) { + return CGRectZero; + } + + // 2. 使用子类提供的策略判断相邻性 + if (![self isAdjacentMicAtIndex:firstIndex andIndex:secondIndex]) { + return CGRectZero; + } + + // 3. 获取矩形并验证 + NSInteger left = MIN(firstIndex, secondIndex); + NSInteger right = MAX(firstIndex, secondIndex); + CGRect leftRect = [self rectForViewAtIndex:left]; + CGRect rightRect = [self rectForViewAtIndex:right]; + + if (CGRectIsEmpty(leftRect) || CGRectIsEmpty(rightRect)) { + return CGRectZero; + } + + // 4. 使用子类提供的中点计算逻辑 + return [self calculateMidpointRectBetweenLeft:leftRect andRight:rightRect]; +} + +#pragma mark - 子类可重写的布局配置方法 + +- (NSArray *> *)micRowRanges { + // 默认实现:所有麦位在一行 + NSInteger count = [self countOfMicroView]; + if (count > 0) { + return @[@[@0, @(count - 1)]]; + } + return @[]; +} + +- (BOOL)allowsAdjacentInSameRow { + return YES; +} + +- (BOOL)isAdjacentMicAtIndex:(NSInteger)firstIndex andIndex:(NSInteger)secondIndex { + if (firstIndex == secondIndex) return NO; + + NSInteger left = MIN(firstIndex, secondIndex); + NSInteger right = MAX(firstIndex, secondIndex); + + // 使用行配置判断 + NSArray *> *rowRanges = [self micRowRanges]; + + for (NSArray *rowRange in rowRanges) { + if (rowRange.count >= 2) { + NSInteger rowStart = rowRange[0].integerValue; + NSInteger rowEnd = rowRange[1].integerValue; + + // 检查两个索引是否都在同一行 + if (left >= rowStart && left <= rowEnd && right >= rowStart && right <= rowEnd) { + // 检查是否相邻(索引差为1) + return (right - left) == 1; + } + } + } + + return NO; +} + +- (CGRect)calculateMidpointRectBetweenLeft:(CGRect)leftRect andRight:(CGRect)rightRect { + // 计算中点X坐标 + CGFloat leftCenterX = CGRectGetMidX(leftRect); + CGFloat rightCenterX = CGRectGetMidX(rightRect); + CGFloat midX = (leftCenterX + rightCenterX) / 2.0; + + // 使用两个麦位矩形的顶部对齐,并向上移动10px + CGFloat leftTopY = CGRectGetMinY(leftRect); + CGFloat rightTopY = CGRectGetMinY(rightRect); + CGFloat midTopY = (leftTopY + rightTopY) / 2.0 - 10.0; + + // 返回75x75的矩形 + CGFloat size = 75.0; + return CGRectMake(midX - size / 2.0, midTopY, size, size); } #pragma mark - StageViewProtocol - 基本上都是工具方法 diff --git a/YuMi/Modules/YMRoom/View/StageView/TenMicStageView.m b/YuMi/Modules/YMRoom/View/StageView/TenMicStageView.m index dd9ffe56..91fa1a9e 100644 --- a/YuMi/Modules/YMRoom/View/StageView/TenMicStageView.m +++ b/YuMi/Modules/YMRoom/View/StageView/TenMicStageView.m @@ -94,35 +94,9 @@ return point; } -// 10麦位布局:5x2网格,仅同一行且相邻列(列差1)返回中点75x75 -- (CGRect)rectForMidpointBetweenMicAtIndex:(NSInteger)firstIndex andIndex:(NSInteger)secondIndex { - if (firstIndex == secondIndex) return CGRectZero; - NSInteger left = MIN(firstIndex, secondIndex); - NSInteger right = MAX(firstIndex, secondIndex); - - // 检查是否在同一行且相邻 - BOOL sameRow = ((left >= 0 && left <= 4 && right >= 0 && right <= 4) || - (left >= 5 && left <= 9 && right >= 5 && right <= 9)); - if (!sameRow) return CGRectZero; - - // 检查是否相邻(列差为1) - NSInteger leftCol = (left <= 4) ? left : (left - 5); - NSInteger rightCol = (right <= 4) ? right : (right - 5); - if ((rightCol - leftCol) != 1) return CGRectZero; - - CGRect l = [self rectForViewAtIndex:left]; - CGRect r = [self rectForViewAtIndex:right]; - if (CGRectIsEmpty(l) || CGRectIsEmpty(r)) return CGRectZero; - - CGFloat midX = (CGRectGetMidX(l) + CGRectGetMidX(r)) / 2.0; - - // 🔧 修改:使用两个麦位矩形的顶部对齐,而不是中心对齐 - CGFloat leftTopY = CGRectGetMinY(l); - CGFloat rightTopY = CGRectGetMinY(r); - CGFloat midTopY = (leftTopY + rightTopY) / 2.0; - - CGFloat size = 75.0; - return CGRectMake(midX - size / 2.0, midTopY, size, size); +// 10麦位布局:5x2网格配置 +- (NSArray *> *)micRowRanges { + return @[@[@0, @4], @[@5, @9]]; // 第一行0-4,第二行5-9 } @end diff --git a/YuMi/Modules/YMRoom/View/StageView/TwentyMicStageView.m b/YuMi/Modules/YMRoom/View/StageView/TwentyMicStageView.m index feaa81a3..ddc5acd6 100644 --- a/YuMi/Modules/YMRoom/View/StageView/TwentyMicStageView.m +++ b/YuMi/Modules/YMRoom/View/StageView/TwentyMicStageView.m @@ -94,31 +94,19 @@ static const NSInteger kMicCountPerRow = 5; return CGPointMake(x, y); } -// 覆盖:仅当同一行且相邻列(列差 1)时,返回两麦位中点 75x75 矩形 -- (CGRect)rectForMidpointBetweenMicAtIndex:(NSInteger)firstIndex andIndex:(NSInteger)secondIndex { - if (firstIndex == secondIndex) return CGRectZero; - NSInteger left = MIN(firstIndex, secondIndex); - NSInteger right = MAX(firstIndex, secondIndex); - // 同一行且列差为 1 - NSInteger leftRow = left / kMicCountPerRow; - NSInteger rightRow = right / kMicCountPerRow; - NSInteger leftCol = left % kMicCountPerRow; - NSInteger rightCol = right % kMicCountPerRow; - if (!(leftRow == rightRow && (rightCol - leftCol) == 1)) { - return CGRectZero; +// 20麦位布局:5x4网格配置 +- (NSArray *> *)micRowRanges { + NSMutableArray *ranges = [NSMutableArray array]; + NSInteger totalMics = [self countOfMicroView]; + NSInteger rows = ceil((CGFloat)totalMics / kMicCountPerRow); + + for (NSInteger i = 0; i < rows; i++) { + NSInteger start = i * kMicCountPerRow; + NSInteger end = MIN(start + kMicCountPerRow - 1, totalMics - 1); + [ranges addObject:@[@(start), @(end)]]; } - CGRect l = [self rectForViewAtIndex:left]; - CGRect r = [self rectForViewAtIndex:right]; - if (CGRectIsEmpty(l) || CGRectIsEmpty(r)) return CGRectZero; - CGFloat midX = (CGRectGetMidX(l) + CGRectGetMidX(r)) / 2.0; - // 🔧 修改:使用两个麦位矩形的顶部对齐,而不是中心对齐 - CGFloat leftTopY = CGRectGetMinY(l); - CGFloat rightTopY = CGRectGetMinY(r); - CGFloat midTopY = (leftTopY + rightTopY) / 2.0; - - CGFloat size = 75.0; - return CGRectMake(midX - size / 2.0, midTopY, size, size); + return ranges; }