// // KBPanModalView.m // keyBoard // // Created by Mac on 2025/11/6. // #import "KBPanModalView.h" #import "KBDirectionIndicatorView.h" // 子控制器 #import "HomeHotVC.h" #import "HomeRankVC.h" @interface KBPanModalView() @property (nonatomic, strong) KBDirectionIndicatorView *indicator; // 顶部切换按钮与指示条 @property (nonatomic, strong) UIView *topBar; @property (nonatomic, strong) UIView *bigWhiteContentView; @property (nonatomic, strong) UIView *secWhiteContentView; /// 皇冠👑 @property (nonatomic, strong) UIImageView *hgImageView; /// 人 @property (nonatomic, strong) UIImageView *personImageView; @property (nonatomic, strong) UIImageView *leftBgImageView; @property (nonatomic, strong) UIImageView *rightBgImageView; @property (nonatomic, strong) UIButton *hotButton; @property (nonatomic, strong) UIButton *rankButton; @property (nonatomic, strong) UIImageView *underlineImageView; // 选中下划线 // 承载子控制器内容 @property (nonatomic, strong) UIView *containerView; @property (nonatomic, strong) UIViewController *currentChild; @property (nonatomic, strong) HomeHotVC *hotVC; @property (nonatomic, strong) HomeRankVC *rankVC; @property (nonatomic, assign) NSInteger currentIndex; @end @implementation KBPanModalView - (instancetype)initWithFrame:(CGRect)frame{ if (self = [super initWithFrame:frame]) { // 该背景色会被 HWPanModal 用来设置容器的 _contentView 背景色 // 参考 Pods/HWPanModal/Sources/View/PanModal/HWPanModalContainerView.m: adjustPanContainerBackgroundColor // 想要改变外层白色底(截图中 _contentView)的颜色,只需改这里即可 // self.backgroundColor = [UIColor colorWithHex:0xE8FFF4]; // 柔和的绿色 self.backgroundColor = [UIColor clearColor]; // HWBackgroundConfig *config = [HWBackgroundConfig configWithBehavior:HWBackgroundBehaviorDefault]; // config.backgroundAlpha = 0; // [self.hw_dimmedView reloadConfig:config]; // 顶部按钮 + 容器 [self setupTopButtonsAndContainer]; // 默认展示“热门” [self switchToIndex:0 animated:NO]; } return self; } - (HWBackgroundConfig *)backgroundConfig { HWBackgroundConfig *config = [HWBackgroundConfig configWithBehavior:HWBackgroundBehaviorDefault]; config.backgroundAlpha = 0; config.blurTintColor = [UIColor clearColor]; return config; } - (UIView *)customIndicatorView { if (!_indicator) _indicator = [KBDirectionIndicatorView new]; return _indicator; } //- (void)panModalTransitionDidFinish { // // 初次展示后按当前状态设定一次朝向 // [self.indicator applyPresentationState:self.hw_presentationState]; // // 避免出现内容随弹窗上移的“位移动画”观感: // // 顶部栏在展示动画期间先隐藏,待完成后淡入 // if (self.topBar && self.topBar.alpha < 1.0) { // [UIView animateWithDuration:0.18 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{ // self.topBar.alpha = 1.0; // } completion:nil]; // } //} - (void)didChangeTransitionToState:(PresentationState)state { // // 每次状态切换完成后刷新朝向 // [self.indicator applyPresentationState:state]; } - (PanModalHeight)shortFormHeight { return PanModalHeightMake(PanModalHeightTypeMaxTopInset, self.minHeight); } - (PanModalHeight)longFormHeight { return PanModalHeightMake(PanModalHeightTypeMaxTopInset, self.topInset ?: 100); } - (PresentationState)originPresentationState { return PresentationStateShort; // 初始就以最小高度展示 } - (BOOL)anchorModalToLongForm { return YES; // 到 long 后不再继续往上拖 } - (BOOL)allowsPullDownWhenShortState { return NO; // 在 short 状态禁止继续往下拉(锁住最小高度) } - (CGFloat)topOffset{ return 0.001; } /// 允许时间穿透 - (BOOL)allowsTouchEventsPassingThroughTransitionView { return YES; } -(BOOL)shouldAutoSetPanScrollContentInset{ return NO; } - (UIScrollView *)panScrollable { if (self.currentIndex == 0) { return self.hotVC.tableView; } return self.rankVC.collectionView; } // 可选:完全不允许拖拽关闭(避免被拉到底消失) - (BOOL)allowsDragToDismiss { return NO; } // //- (BOOL)showDragIndicator{ // return NO; //} // // 点背景不关闭 - (BOOL)allowsTapBackgroundToDismiss { return NO; } // 出现时不做上推动画(瞬时到位)开了下拉动画有问题 //- (NSTimeInterval)transitionDuration { // return 0; //} //// 可选:关闭触觉反馈,避免出现时的轻微震动 //- (BOOL)isHapticFeedbackEnabled { // return NO; //} #pragma mark - UI - (void)setupTopButtonsAndContainer { // 添加最大的白色容器 [self addSubview:self.bigWhiteContentView]; [self.bigWhiteContentView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.right.equalTo(self).inset(0); make.top.equalTo(self).offset(40); make.bottom.equalTo(self); }]; [self.bigWhiteContentView addSubview:self.secWhiteContentView]; [self.secWhiteContentView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.right.equalTo(self).inset(0); make.top.equalTo(self.bigWhiteContentView).offset(40); make.bottom.equalTo(self.bigWhiteContentView); }]; [self.secWhiteContentView addSubview:self.leftBgImageView]; [self.secWhiteContentView addSubview:self.rightBgImageView]; [self.leftBgImageView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.right.top.equalTo(self.secWhiteContentView); // make.bottom.equalTo(self.secWhiteContentView); }]; [self.rightBgImageView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.right.top.equalTo(self.secWhiteContentView); // make.bottom.equalTo(self.secWhiteContentView); }]; // 顶部栏 [self.secWhiteContentView addSubview:self.topBar]; [self.secWhiteContentView addSubview:self.containerView]; // 调整层级:将人物与皇冠图放到左右背景图的后面(z 轴更低) [self.secWhiteContentView insertSubview:self.personImageView belowSubview:self.leftBgImageView]; [self.secWhiteContentView insertSubview:self.hgImageView belowSubview:self.rightBgImageView]; // 固定各层 zPosition,避免插入顺序导致的偶发层级问题(背景 < 人/皇冠 < 磨砂 < 顶部栏) self.leftBgImageView.layer.zPosition = 0; self.rightBgImageView.layer.zPosition = 0; self.personImageView.layer.zPosition = 1; self.hgImageView.layer.zPosition = 1; self.topBar.layer.zPosition = 3; // [self.topBar addSubview:self.leftImageView]; // [self.topBar addSubview:self.rightImageView]; // 两个按钮 self.hotButton = [UIButton buttonWithType:UIButtonTypeCustom]; [self.hotButton setTitle:@"Ranking List" forState:UIControlStateNormal]; [self.hotButton setTitleColor:[UIColor darkTextColor] forState:UIControlStateNormal]; [self.hotButton setTitleColor:[UIColor blackColor] forState:UIControlStateSelected]; self.hotButton.titleLabel.font = [UIFont boldSystemFontOfSize:16]; self.hotButton.tag = 0; [self.hotButton addTarget:self action:@selector(onTapTopButton:) forControlEvents:UIControlEventTouchUpInside]; [self.topBar addSubview:self.hotButton]; self.rankButton = [UIButton buttonWithType:UIButtonTypeCustom]; [self.rankButton setTitle:@"Persona circle" forState:UIControlStateNormal]; [self.rankButton setTitleColor:[UIColor darkTextColor] forState:UIControlStateNormal]; [self.rankButton setTitleColor:[UIColor blackColor] forState:UIControlStateSelected]; self.rankButton.titleLabel.font = [UIFont boldSystemFontOfSize:16]; self.rankButton.tag = 1; [self.rankButton addTarget:self action:@selector(onTapTopButton:) forControlEvents:UIControlEventTouchUpInside]; [self.topBar addSubview:self.rankButton]; // 下划线(跟随选中按钮) [self.topBar addSubview:self.underlineImageView]; // Masonry 约束 CGFloat topPadding = 12; // 与顶部小指示器留点空间 [self.topBar mas_makeConstraints:^(MASConstraintMaker *make) { make.left.right.equalTo(self.secWhiteContentView); make.top.equalTo(self.secWhiteContentView).offset(topPadding); make.height.mas_equalTo(54); }]; [self.hotButton mas_makeConstraints:^(MASConstraintMaker *make) { make.centerY.equalTo(self.topBar).offset(3); make.left.equalTo(self.topBar); }]; [self.rankButton mas_makeConstraints:^(MASConstraintMaker *make) { make.centerY.equalTo(self.hotButton); make.right.equalTo(self.topBar); make.left.equalTo(self.hotButton.mas_right); make.width.equalTo(self.hotButton); }]; // 初始先放在“热门”下方,宽度稍小于按钮文字 [self.underlineImageView mas_makeConstraints:^(MASConstraintMaker *make) { make.height.mas_equalTo(5); make.bottom.equalTo(self.topBar.mas_bottom).offset(-14); make.centerX.equalTo(self.hotButton).offset(-0); make.width.mas_equalTo(78); }]; [self.containerView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(self.topBar.mas_bottom).offset(8); make.left.right.equalTo(self.secWhiteContentView).inset(20); make.bottom.equalTo(self.secWhiteContentView); }]; [self.personImageView mas_makeConstraints:^(MASConstraintMaker *make) { // 仍按页面整体的左右边距定位,保持与改层级前的视觉一致 make.left.equalTo(self).offset(46); make.bottom.equalTo(self.topBar.mas_top).offset(11); make.width.mas_equalTo(53); make.height.mas_equalTo(81); }]; [self.hgImageView mas_makeConstraints:^(MASConstraintMaker *make) { make.right.equalTo(self).offset(-38); make.bottom.equalTo(self.topBar.mas_top).offset(16); make.width.mas_equalTo(82); make.height.mas_equalTo(66); }]; } #pragma mark - Action - (void)onTapTopButton:(UIButton *)sender { [self switchToIndex:sender.tag animated:false]; // [self hw_panModalSetNeedsLayoutUpdate]; } #pragma mark - Switch Child - (void)switchToIndex:(NSInteger)index animated:(BOOL)animated { self.currentIndex = index; UIViewController *target = (index == 0) ? self.hotVC : self.rankVC; if (!target) { if (index == 0) { self.hotVC = [HomeHotVC new]; target = self.hotVC; } else { self.rankVC = [HomeRankVC new]; target = self.rankVC; } } if (self.currentChild == target) { // 已经是目标 [self updateButtonStateForIndex:index animated:animated]; return; } // 移除当前 if (self.currentChild) { [self.currentChild willMoveToParentViewController:nil]; [self.currentChild.view removeFromSuperview]; [self.currentChild removeFromParentViewController]; } // 添加目标 // [self addChildViewController:target]; [self.containerView addSubview:target.view]; [target.view mas_makeConstraints:^(MASConstraintMaker *make) { make.left.top.right.equalTo(self.containerView); make.bottom.equalTo(self.containerView).offset(-KB_TABBAR_HEIGHT); }]; // [target didMoveToParentViewController:self]; self.currentChild = target; [self updateButtonStateForIndex:index animated:animated]; } - (void)updateButtonStateForIndex:(NSInteger)index animated:(BOOL)animated { self.hotButton.selected = (index == 0); self.rankButton.selected = (index == 1); UIButton *btn = (index == 0) ? self.hotButton : self.rankButton; // 更新下划线位置 [self.underlineImageView mas_remakeConstraints:^(MASConstraintMaker *make) { make.height.mas_equalTo(5); make.bottom.equalTo(self.topBar.mas_bottom).offset(-15); make.centerX.equalTo(btn).offset(index == 0 ? -6 : -11); make.width.mas_equalTo(78); }]; if (index == 0) { self.leftBgImageView.hidden = NO; self.rightBgImageView.hidden = YES; self.personImageView.hidden = YES; self.hgImageView.hidden = NO; } else { self.leftBgImageView.hidden = YES; self.rightBgImageView.hidden = NO; self.personImageView.hidden = NO; self.hgImageView.hidden = YES; } // 确认层级:把可见的装饰图放到当前背景图后面 UIView *visibleBg = self.rightBgImageView.hidden ? self.leftBgImageView : self.rightBgImageView; if (!self.hgImageView.hidden) { [self.secWhiteContentView insertSubview:self.hgImageView belowSubview:visibleBg]; } if (!self.personImageView.hidden) { [self.secWhiteContentView insertSubview:self.personImageView belowSubview:visibleBg]; } if (animated) { [UIView animateWithDuration:0.25 animations:^{ [self.topBar layoutIfNeeded]; }]; } else { [self.topBar layoutIfNeeded]; } } - (UIView *)bigWhiteContentView{ if (!_bigWhiteContentView) { _bigWhiteContentView = [[UIView alloc] init]; _bigWhiteContentView.backgroundColor = [UIColor whiteColor]; _bigWhiteContentView.layer.cornerRadius = 40; // 不裁剪子视图,避免顶部装饰图越界部分被截断 _bigWhiteContentView.layer.masksToBounds = NO; // 等同于 clipsToBounds = NO } return _bigWhiteContentView; } - (UIView *)secWhiteContentView{ if (!_secWhiteContentView) { _secWhiteContentView = [[UIView alloc] init]; } return _secWhiteContentView; } - (UIImageView *)hgImageView{ if (!_hgImageView) { _hgImageView = [[UIImageView alloc] init]; _hgImageView.image = [UIImage imageNamed:@"home_hg_icon"]; _hgImageView.contentMode = UIViewContentModeScaleAspectFit; } return _hgImageView; } - (UIImageView *)personImageView{ if (!_personImageView) { _personImageView = [[UIImageView alloc] init]; _personImageView.image = [UIImage imageNamed:@"home_person_icon"]; _personImageView.contentMode = UIViewContentModeScaleAspectFit; } return _personImageView; } - (UIView *)topBar{ if (!_topBar) { _topBar = [[UIView alloc] init]; } return _topBar; } - (UIView *)containerView{ if (!_containerView) { _containerView = [[UIView alloc] init]; } return _containerView; } - (UIImageView *)underlineImageView{ if (!_underlineImageView) { _underlineImageView = [[UIImageView alloc] init]; _underlineImageView.image = [UIImage imageNamed:@"home_bar_underline"]; } return _underlineImageView; } - (UIImageView *)leftBgImageView{ if (!_leftBgImageView) { _leftBgImageView = [[UIImageView alloc] init]; _leftBgImageView.image = [UIImage imageNamed:@"home_left_bg"]; } return _leftBgImageView; } - (UIImageView *)rightBgImageView{ if (!_rightBgImageView) { _rightBgImageView = [[UIImageView alloc] init]; _rightBgImageView.image = [UIImage imageNamed:@"home_right_bg"]; } return _rightBgImageView; } @end