// // 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 *contentView; @property (nonatomic, strong) UIImageView *leftImageView; @property (nonatomic, strong) UIImageView *rightImageView; /// 皇冠👑 @property (nonatomic, strong) UIImageView *hgImageView; @property (nonatomic, strong) UIButton *hotButton; @property (nonatomic, strong) UIButton *rankButton; @property (nonatomic, strong) UIView *underlineView; // 选中下划线 // 承载子控制器内容 @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]) { // self.backgroundColor = [UIColor redColor]; // HWBackgroundConfig *config = [HWBackgroundConfig configWithBehavior:HWBackgroundBehaviorDefault]; // config.backgroundAlpha = 0; // [self.hw_dimmedView reloadConfig:config]; // 添加容器 [self addSubview:self.contentView]; [self.contentView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.right.equalTo(self).inset(16); make.top.equalTo(self).offset(48); make.bottom.equalTo(self); }]; [self.contentView addSubview:self.leftImageView]; [self.contentView addSubview:self.rightImageView]; [self.leftImageView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.right.equalTo(self.contentView); make.top.equalTo(self.contentView); make.height.mas_equalTo(79); }]; [self.rightImageView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.right.equalTo(self.contentView); make.top.equalTo(self.contentView); make.height.equalTo(self.leftImageView); }]; // 顶部按钮 + 容器 [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.topBar = [[UIView alloc] init]; // self.topBar.backgroundColor = [UIColor colorWithWhite:1 alpha:0.9]; [self addSubview:self.topBar]; // 首次展示时先隐藏,待转场完成后再淡入,避免“自底向上滑入”的错觉 // self.topBar.alpha = 0.0; // 两个按钮 self.hotButton = [UIButton buttonWithType:UIButtonTypeCustom]; [self.hotButton setTitle:@"热门" 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:@"排行" 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.underlineView = [[UIView alloc] init]; self.underlineView.backgroundColor = [UIColor blackColor]; self.underlineView.layer.cornerRadius = 1.0; [self.topBar addSubview:self.underlineView]; // 容器视图 self.containerView = [[UIView alloc] init]; self.containerView.backgroundColor = [UIColor redColor]; self.containerView.clipsToBounds = YES; [self addSubview:self.containerView]; // Masonry 约束 CGFloat topPadding = 47; // 与顶部小指示器留点空间 [self.topBar mas_makeConstraints:^(MASConstraintMaker *make) { make.left.right.equalTo(self); make.top.equalTo(self).offset(topPadding); make.height.mas_equalTo(44); }]; [self.hotButton mas_makeConstraints:^(MASConstraintMaker *make) { make.top.bottom.equalTo(self.topBar); make.left.equalTo(self.topBar); }]; [self.rankButton mas_makeConstraints:^(MASConstraintMaker *make) { make.top.bottom.equalTo(self.topBar); make.right.equalTo(self.topBar); make.left.equalTo(self.hotButton.mas_right); make.width.equalTo(self.hotButton); }]; // 初始先放在“热门”下方,宽度稍小于按钮文字 [self.underlineView mas_makeConstraints:^(MASConstraintMaker *make) { make.height.mas_equalTo(2); make.bottom.equalTo(self.topBar.mas_bottom).offset(-2); make.centerX.equalTo(self.hotButton); make.width.mas_equalTo(24); }]; [self.containerView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(self.topBar.mas_bottom).offset(8); make.left.right.bottom.equalTo(self); }]; } #pragma mark - Action - (void)onTapTopButton:(UIButton *)sender { [self switchToIndex:sender.tag animated:YES]; // [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.backgroundColor = [UIColor colorWithWhite:0.98 alpha:1]; [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.underlineView mas_remakeConstraints:^(MASConstraintMaker *make) { make.height.mas_equalTo(2); make.bottom.equalTo(self.topBar.mas_bottom).offset(-2); make.centerX.equalTo(btn); make.width.mas_equalTo(24); }]; if (animated) { [UIView animateWithDuration:0.25 animations:^{ [self.topBar layoutIfNeeded]; }]; } else { [self.topBar layoutIfNeeded]; } } - (UIView *)contentView{ if (!_contentView) { _contentView = [[UIView alloc] init]; } return _contentView; } - (UIImageView *)leftImageView{ if (!_leftImageView) { _leftImageView = [[UIImageView alloc] init]; _leftImageView.image = [UIImage imageNamed:@"home_left_image"]; _leftImageView.contentMode = UIViewContentModeScaleToFill; } return _leftImageView; } - (UIImageView *)rightImageView{ if (!_rightImageView) { _rightImageView = [[UIImageView alloc] init]; _rightImageView.image = [UIImage imageNamed:@"home_right_image"]; _rightImageView.contentMode = UIViewContentModeScaleToFill; _rightImageView.hidden = true; } return _rightImageView; } - (UIImageView *)hgImageView{ if (!_hgImageView) { _hgImageView = [[UIImageView alloc] init]; _hgImageView.image = [UIImage imageNamed:@"home_hg_icon"]; _hgImageView.contentMode = UIViewContentModeScaleToFill; } return _hgImageView; } @end