Files
keyboard/keyBoard/Class/Shop/VC/KBShopVC.m
2025-12-11 15:19:23 +08:00

334 lines
13 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.

//
// KBShopVC.m
// keyBoard
//
// Created by Mac on 2025/11/6.
//
#import "KBShopVC.h"
#import "JXPagerView.h"
#import "KBShopHeadView.h"
#import <JXCategoryView/JXCategoryView.h>
#import "KBCategoryTitleView.h"
#import <JXPagingView/JXPagerView.h>
#import <MJRefresh/MJRefresh.h>
#import "KBShopItemVC.h"
#import "KBSearchVC.h"
#import "MySkinVC.h"
#import "KBWebViewViewController.h"
#import "KBShopVM.h"
#import "KBHUD.h"
static const CGFloat JXTableHeaderViewHeight = (323);
static const CGFloat JXheightForHeaderInSection = 50;
@interface KBShopVC ()<JXPagerViewDelegate, JXPagerMainTableViewGestureDelegate,JXCategoryViewDelegate>
@property (nonatomic, strong) UIView *naviBGView;
@property (nonatomic, strong) JXPagerView *pagerView;
@property (nonatomic, strong) KBShopHeadView *userHeaderView;
@property (nonatomic, assign) BOOL isNeedFooter;
@property (nonatomic, assign) BOOL isNeedHeader;
- (JXPagerView *)preferredPagingView;
@property (nonatomic, strong) JXCategoryTitleView *categoryView;
@property (nonatomic, strong) NSArray <NSString *> *titles;
@property (nonatomic, copy) NSArray<KBShopStyleModel *> *styles;
@property (nonatomic, strong) UIImageView *bgImageView; // 全屏背景图
@property (nonatomic, strong) UIButton *searchBtn;
@property (nonatomic, strong) UIButton *skinBtn;
// 记录当前分类条是否为白底,避免重复设置
@property (nonatomic, assign) BOOL categoryIsWhite;
@property (nonatomic, strong) KBShopVM *shopVM;
@end
@implementation KBShopVC
- (void)viewDidLoad {
[super viewDidLoad];
self.bgImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"my_bg_icon"]];
self.bgImageView.contentMode = UIViewContentModeScaleAspectFill;
[self.view addSubview:self.bgImageView];
[self.bgImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.view);
}];
[self setupUI];
[self.view addSubview:self.skinBtn];
[self.view addSubview:self.searchBtn];
[self.skinBtn mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(self.view).offset(-16);
make.top.mas_equalTo(KB_NAV_TOTAL_HEIGHT - 25);
make.width.height.mas_equalTo(25);
}];
[self.searchBtn mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(self.skinBtn.mas_left).offset(-16);
make.top.equalTo(self.skinBtn);
make.width.height.mas_equalTo(25);
}];
[self fetchShopStylesWithHUD:YES];
[self fetchWalletBalanceWithHUD:NO];
}
// 系统导航栏显隐由 Base 统一管理(全局隐藏),该 VC 不再手动切换,避免闪烁。
- (void)setupUI{
self.automaticallyAdjustsScrollViewInsets = NO;
self.view.backgroundColor = [UIColor whiteColor];
self.navigationController.navigationBar.translucent = false;
self.edgesForExtendedLayout = UIRectEdgeNone;
self.styles = @[];
_titles = @[];
_userHeaderView = [[KBShopHeadView alloc] init];
_categoryView = (JXCategoryTitleView *)[[KBCategoryTitleView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, JXheightForHeaderInSection)];
self.categoryView.titles = self.titles;
self.categoryView.backgroundColor = [UIColor clearColor];
self.categoryView.delegate = self;
self.categoryView.titleSelectedColor = [UIColor colorWithHex:0x1B1F1A];
self.categoryView.titleColor = [UIColor colorWithHex:0x9F9F9F];
// 左右滑动时不要文字渐变色
self.categoryView.titleColorGradientEnabled = NO;
// 不需要文字放大效果
self.categoryView.cellWidthZoomEnabled = NO;
self.categoryView.cellWidthZoomScale = 1.0;
self.categoryView.contentScrollViewClickTransitionAnimationEnabled = NO;
// Unselected items need a rounded gray background like the screenshot.
// JXCategoryTitleView supports cell background colors via JXCategoryIndicatorView.
self.categoryView.cellBackgroundColorGradientEnabled = YES;
self.categoryView.cellBackgroundUnselectedColor = [UIColor colorWithHex:0xEFEFEF];
self.categoryView.cellBackgroundSelectedColor = [UIColor whiteColor];
// Make the pills look compact
self.categoryView.cellWidthIncrement = 20; // horizontal padding for each item
self.categoryView.cellSpacing = 12; // spacing between items
self.categoryView.contentEdgeInsetLeft = 16;
self.categoryView.contentEdgeInsetRight = 16;
self.categoryView.averageCellSpacingEnabled = NO;
JXCategoryIndicatorBackgroundView *backgroundView = [[JXCategoryIndicatorBackgroundView alloc] init];
backgroundView.indicatorHeight = 30;
backgroundView.indicatorCornerRadius = JXCategoryViewAutomaticDimension;
backgroundView.indicatorColor = [UIColor whiteColor]; // keep selected fill white
backgroundView.layer.borderColor = [UIColor colorWithHex:KBColorValue].CGColor;
backgroundView.layer.borderWidth = 1;
backgroundView.indicatorWidthIncrement = 0; // 指示器宽度不额外加宽
// 点击切换时不需要左右滚动动画,直接跳转到目标位置
backgroundView.scrollEnabled = NO;
backgroundView.scrollAnimationDuration = 0;
self.categoryView.indicators = @[backgroundView];
_pagerView = [self preferredPagingView];
self.pagerView.mainTableView.gestureDelegate = self;
self.pagerView.mainTableView.backgroundColor = [UIColor clearColor];
[self.view addSubview:self.pagerView];
// self.pagerView.listContainerView.scrollView.scrollEnabled = false;
// self.pagerView.listContainerView.listCellBackgroundColor = [UIColor clearColor];
self.categoryView.listContainer = (id<JXCategoryViewListContainer>)self.pagerView.listContainerView;
//导航栏隐藏的情况,处理扣边返回,下面的代码要加上
// [self.pagerView.listContainerView.scrollView.panGestureRecognizer requireGestureRecognizerToFail:self.navigationController.interactivePopGestureRecognizer];
// [self.pagerView.mainTableView.panGestureRecognizer requireGestureRecognizerToFail:self.navigationController.interactivePopGestureRecognizer];
__weak typeof(self)weakSelf = self;
self.pagerView.mainTableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
[weakSelf fetchShopStylesWithHUD:NO];
[weakSelf fetchWalletBalanceWithHUD:NO];
}];
self.pagerView.pinSectionHeaderVerticalOffset = KB_NAV_TOTAL_HEIGHT;
self.naviBGView = [[UIView alloc] init];
self.naviBGView.alpha = 0;
self.naviBGView.backgroundColor = [UIColor clearColor];
self.naviBGView.frame = CGRectMake(0, 0, KB_SCREEN_WIDTH, KB_NAV_TOTAL_HEIGHT);
[self.view addSubview:self.naviBGView];
UILabel *naviTitleLabel = [[UILabel alloc] init];
naviTitleLabel.text = KBLocalized(@"Shop");
naviTitleLabel.textAlignment = NSTextAlignmentCenter;
naviTitleLabel.frame = CGRectMake(0, KB_STATUSBAR_HEIGHT, self.view.bounds.size.width, 44);
[self.naviBGView addSubview:naviTitleLabel];
}
- (JXPagerView *)preferredPagingView {
return [[JXPagerView alloc] initWithDelegate:self];
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
self.pagerView.frame = self.view.bounds;
}
#pragma mark - JXPagerViewDelegate
- (UIView *)tableHeaderViewInPagerView:(JXPagerView *)pagerView {
return self.userHeaderView;
}
- (NSUInteger)tableHeaderViewHeightInPagerView:(JXPagerView *)pagerView {
return KBFit(JXTableHeaderViewHeight);
}
- (NSUInteger)heightForPinSectionHeaderInPagerView:(JXPagerView *)pagerView {
return JXheightForHeaderInSection;
}
- (UIView *)viewForPinSectionHeaderInPagerView:(JXPagerView *)pagerView {
return self.categoryView;
}
- (NSInteger)numberOfListsInPagerView:(JXPagerView *)pagerView {
//和categoryView的item数量一致
return self.categoryView.titles.count;
}
- (id<JXPagerViewListViewDelegate>)pagerView:(JXPagerView *)pagerView initListAtIndex:(NSInteger)index {
KBShopItemVC *list = [[KBShopItemVC alloc] init];
list.title = self.titles[index];
list.isNeedHeader = self.isNeedHeader;
list.isNeedFooter = self.isNeedFooter;
list.shopViewModel = self.shopVM;
if (index < self.styles.count) {
list.style = self.styles[index];
}
return list;
}
#pragma mark - JXCategoryViewDelegate
- (void)categoryView:(JXCategoryBaseView *)categoryView didSelectedItemAtIndex:(NSInteger)index {
self.navigationController.interactivePopGestureRecognizer.enabled = (index == 0);
}
#pragma mark - JXPagerMainTableViewGestureDelegate
- (BOOL)mainTableViewGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
//禁止categoryView左右滑动的时候上下和左右都可以滚动
if (otherGestureRecognizer == self.categoryView.collectionView.panGestureRecognizer) {
return NO;
}
return [gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]] && [otherGestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]];
}
- (void)pagerView:(JXPagerView *)pagerView mainTableViewDidScroll:(UIScrollView *)scrollView {
// 计算吸顶阈值:头图高度 - 固定区偏移(即导航高度)
CGFloat headerH = (CGFloat)[self tableHeaderViewHeightInPagerView:self.pagerView];
CGFloat thresholdDistance = MAX(0.0, headerH - self.pagerView.pinSectionHeaderVerticalOffset);
// 不要渐变:小于阈值 alpha=0达到阈值(吸顶)后 alpha=1
BOOL shouldWhite = (thresholdDistance > 0.0 && scrollView.contentOffset.y >= (thresholdDistance - 0.5));
self.naviBGView.alpha = shouldWhite ? 1.0 : 0.0;
self.userHeaderView.alpha = shouldWhite ? 0 : 1.0;
// 分类条背景:未吸顶时透明,吸顶后白色
if (shouldWhite != self.categoryIsWhite) {
self.categoryIsWhite = shouldWhite;
UIColor *bg = shouldWhite ? [UIColor whiteColor] : [UIColor clearColor];
self.categoryView.backgroundColor = bg;
// 内部 collectionView 也同步,避免出现条纹底色
self.categoryView.collectionView.backgroundColor = bg;
self.naviBGView.backgroundColor = bg;
}
}
#pragma mark - action
- (void)searchBtnAction{
KBSearchVC *vc = [[KBSearchVC alloc] init];
[self.navigationController pushViewController:vc animated:true];
}
- (void)skinBtnAction{
MySkinVC *vc = [[MySkinVC alloc] init];
[self.navigationController pushViewController:vc animated:true];
}
#pragma mark - lazy
- (UIButton *)searchBtn{
if (!_searchBtn) {
_searchBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[_searchBtn setImage:[UIImage imageNamed:@"shop_search_icon"] forState:UIControlStateNormal];
[_searchBtn addTarget:self action:@selector(searchBtnAction) forControlEvents:UIControlEventTouchUpInside];
}
return _searchBtn;
}
- (UIButton *)skinBtn{
if (!_skinBtn) {
_skinBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[_skinBtn setImage:[UIImage imageNamed:@"shop_skin_icon"] forState:UIControlStateNormal];
[_skinBtn addTarget:self action:@selector(skinBtnAction) forControlEvents:UIControlEventTouchUpInside];
}
return _skinBtn;
}
- (KBShopVM *)shopVM {
if (!_shopVM) {
_shopVM = [[KBShopVM alloc] init];
}
return _shopVM;
}
- (void)fetchWalletBalanceWithHUD:(BOOL)showHUD {
if (showHUD) {
[KBHUD show];
}
__weak typeof(self) weakSelf = self;
[self.shopVM fetchWalletBalanceWithCompletion:^(NSNumber * _Nullable balance, NSError * _Nullable error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (showHUD) {
[KBHUD dismiss];
}
if (error) {
NSString *msg = error.localizedDescription ?: KBLocalized(@"Network error");
[KBHUD showInfo:msg];
return;
}
double amountValue = balance.doubleValue;
NSString *amountString = [NSString stringWithFormat:@"%.2f", amountValue];
[weakSelf.userHeaderView updatePoints:amountString];
});
}];
}
- (void)fetchShopStylesWithHUD:(BOOL)showHUD {
if (showHUD) {
[KBHUD show];
}
__weak typeof(self) weakSelf = self;
[self.shopVM fetchAllStylesWithCompletion:^(NSArray<KBShopStyleModel *> * _Nullable styles, NSError * _Nullable error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (showHUD) {
[KBHUD dismiss];
}
[weakSelf.pagerView.mainTableView.mj_header endRefreshing];
if (error) {
NSString *msg = error.localizedDescription ?: KBLocalized(@"Network error");
[KBHUD showInfo:msg];
return;
}
[weakSelf applyStyles:styles];
});
}];
}
- (void)applyStyles:(NSArray<KBShopStyleModel *> *)styles {
self.styles = styles ?: @[];
NSMutableArray *names = [NSMutableArray array];
for (KBShopStyleModel *style in self.styles) {
NSString *name = style.styleName.length ? style.styleName : KBLocalized(@"Themes");
[names addObject:name];
}
self.titles = names.copy;
self.categoryView.titles = self.titles;
self.categoryView.defaultSelectedIndex = 0;
[self.categoryView reloadData];
[self.pagerView reloadData];
}
@end