Files
keyboard/keyBoard/Class/Home/V/KBPanModalView.m
2025-11-07 16:58:33 +08:00

463 lines
15 KiB
Objective-C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// 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 *leftImageView;
@property (nonatomic, strong) UIImageView *rightImageView;
@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]; // 柔和的绿色
// 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<HWPanModalIndicatorProtocol> *)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(47);
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];
// 调整层级:将人物与皇冠图添加到与 topBar 同一父视图,并放在 topBar 之下
[self.secWhiteContentView insertSubview:self.personImageView belowSubview:self.topBar];
[self.secWhiteContentView insertSubview:self.hgImageView belowSubview:self.topBar];
// [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 = 0; // 与顶部小指示器留点空间
[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.leftImageView mas_makeConstraints:^(MASConstraintMaker *make) {
// make.left.right.equalTo(self.topBar);
// make.top.equalTo(self.topBar);
// make.height.mas_equalTo(54);
// }];
// [self.rightImageView mas_makeConstraints:^(MASConstraintMaker *make) {
// make.left.right.equalTo(self.topBar);
// make.top.equalTo(self.topBar);
// make.height.equalTo(self.leftImageView);
//
// }];
[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(16);
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(22);
make.width.mas_equalTo(70);
make.height.mas_equalTo(107);
}];
[self.hgImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(self).offset(-38);
make.bottom.equalTo(self.topBar.mas_top).offset(12);
make.width.mas_equalTo(97);
make.height.mas_equalTo(78);
}];
}
#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.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.leftImageView.hidden = false;
self.rightImageView.hidden = true;
}else{
self.leftImageView.hidden = true;
self.rightImageView.hidden = false;
}
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 *)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 = UIViewContentModeScaleAspectFit;
_rightImageView.hidden = true;
}
return _rightImageView;
}
- (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