3
This commit is contained in:
@@ -6,16 +6,20 @@
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "KBCharacter.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// 首页排行榜卡片 Cell(两列)
|
||||
@interface HomeRankCardCell : UICollectionViewCell
|
||||
|
||||
/// 当前展示的角色模型
|
||||
@property (nonatomic, strong, nullable) KBCharacter *character;
|
||||
|
||||
/// 点击加号/勾选按钮回调
|
||||
@property (nonatomic, copy, nullable) void (^onTapAction)(void);
|
||||
|
||||
/// 统一配置数据
|
||||
/// 旧的配置方法(兼容用,不推荐继续使用)
|
||||
- (void)configureWithTitle:(NSString *)title
|
||||
desc:(NSString *)desc
|
||||
people:(NSString *)people
|
||||
@@ -24,4 +28,3 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
#import "UIView+KBShadow.h"
|
||||
|
||||
@interface HomeRankCardCell ()
|
||||
@property (nonatomic, strong) UIView *shadowView; // 阴影容器(不裁剪)
|
||||
@property (nonatomic, strong) UIView *cardView; // 白色圆角卡片
|
||||
@property (nonatomic, strong) UIView *badgeCircle; // 顶部圆形描边
|
||||
@property (nonatomic, strong) UIView *shadowView; // 阴影容器(不裁剪)
|
||||
@property (nonatomic, strong) UIImageView *cardView; // 卡片背景图片
|
||||
@property (nonatomic, strong) UIView *badgeCircle; // 顶部圆形描边
|
||||
@property (nonatomic, strong) UILabel *titleLabel;
|
||||
@property (nonatomic, strong) UILabel *descLabel;
|
||||
@property (nonatomic, strong) UILabel *peopleLabel;
|
||||
@property (nonatomic, strong) UIButton *actionBtn; // 加号/勾选按钮
|
||||
@property (nonatomic, strong) UIButton *actionBtn; // 加号/勾选按钮
|
||||
@property (nonatomic, assign) BOOL added;
|
||||
@end
|
||||
|
||||
@@ -125,6 +125,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setCharacter:(KBCharacter *)character {
|
||||
_character = character;
|
||||
|
||||
NSString *title = character.characterName ?: @"";
|
||||
NSString *people = character.download ?: @"";
|
||||
NSString *desc = @"Be Neither Too Close\nNor Too Distant..."; // 目前暂无描述字段,先用示例文案
|
||||
BOOL added = character.added;
|
||||
|
||||
[self configureWithTitle:title desc:desc people:people added:added];
|
||||
}
|
||||
|
||||
#pragma mark - Lazy UI
|
||||
|
||||
- (UIView *)shadowView {
|
||||
@@ -135,12 +146,15 @@
|
||||
return _shadowView;
|
||||
}
|
||||
|
||||
- (UIView *)cardView {
|
||||
- (UIImageView *)cardView {
|
||||
if (!_cardView) {
|
||||
_cardView = [UIView new];
|
||||
_cardView = [[UIImageView alloc] init];
|
||||
_cardView.backgroundColor = UIColor.whiteColor;
|
||||
_cardView.layer.cornerRadius = 18.0;
|
||||
_cardView.layer.masksToBounds = YES;
|
||||
_cardView.contentMode = UIViewContentModeScaleAspectFill;
|
||||
// 默认卡片背景图(可按需要替换)
|
||||
_cardView.image = [UIImage imageNamed:@"home_rank_card_bg"];
|
||||
}
|
||||
return _cardView;
|
||||
}
|
||||
|
||||
@@ -7,12 +7,15 @@
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "JXCategoryListContainerView.h"
|
||||
#import "KBTag.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface HomeRankContentVC : UIViewController<JXCategoryListContentViewDelegate, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
|
||||
|
||||
@property (nonatomic, strong) UICollectionView *collectionView;
|
||||
@property (nonatomic, strong) KBTag *tagModel;
|
||||
|
||||
/// 指定标签 id 的构造方法;index 对应的 tagId 由 HomeRankVC 传入
|
||||
- (instancetype)initWithTagId:(nullable NSString *)tagId;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -12,35 +12,55 @@
|
||||
|
||||
// 自定义卡片 Cell
|
||||
#import "HomeRankCardCell.h"
|
||||
#import "KBHomeVM.h"
|
||||
#import "KBCharacter.h"
|
||||
|
||||
@interface HomeRankContentVC ()
|
||||
@property (nonatomic, strong) NSArray<NSDictionary *> *dataSource; // 简单模拟数据
|
||||
@property (nonatomic, copy, nullable) NSString *tagId; // 当前标签 id
|
||||
@property (nonatomic, strong) KBHomeVM *homeVM;
|
||||
@property (nonatomic, strong) NSArray<KBCharacter *> *characters; // 当前标签下的角色列表
|
||||
@end
|
||||
|
||||
@implementation HomeRankContentVC
|
||||
|
||||
- (instancetype)initWithTagId:(NSString *)tagId {
|
||||
if (self = [super init]) {
|
||||
_tagId = [tagId copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
return [self initWithTagId:nil];
|
||||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
self.view.backgroundColor = COLOR_WITH_RGB(246/255.0, 253/255.0, 249/255.0, 1.0); // 淡绿色背景
|
||||
|
||||
// 数据
|
||||
self.dataSource = @[
|
||||
@{@"title":@"High EQ", @"desc":@"Be Neither Too Close\nNor Too Distant...", @"people":@"Two Million People\nHave Used It", @"added":@(NO)},
|
||||
@{@"title":@"High EQ", @"desc":@"Be Neither Too Close\nNor Too Distant...", @"people":@"Two Million People\nHave Used It", @"added":@(YES)},
|
||||
@{@"title":@"High EQ", @"desc":@"Be Neither Too Close\nNor Too Distant...", @"people":@"Two Million People\nHave Used It", @"added":@(NO)},
|
||||
@{@"title":@"High EQ", @"desc":@"Be Neither Too Close\nNor Too Distant...", @"people":@"Two Million People\nHave Used It", @"added":@(YES)},
|
||||
@{@"title":@"High EQ", @"desc":@"Be Neither Too Close\nNor Too Distant...", @"people":@"Two Million People\nHave Used It", @"added":@(NO)},
|
||||
@{@"title":@"High EQ", @"desc":@"Be Neither Too Close\nNor Too Distant...", @"people":@"Two Million People\nHave Used It", @"added":@(YES)},
|
||||
@{@"title":@"High EQ", @"desc":@"Be Neither Too Close\nNor Too Distant...", @"people":@"Two Million People\nHave Used It", @"added":@(NO)},
|
||||
@{@"title":@"High EQ", @"desc":@"Be Neither Too Close\nNor Too Distant...", @"people":@"Two Million People\nHave Used It", @"added":@(YES)}
|
||||
];
|
||||
|
||||
self.characters = @[];
|
||||
self.homeVM = [KBHomeVM new];
|
||||
|
||||
[self.view addSubview:self.collectionView];
|
||||
[self.collectionView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.equalTo(self.view);
|
||||
}];
|
||||
|
||||
// 加载当前 tag 下的角色列表
|
||||
[self loadCharactersForCurrentTag];
|
||||
}
|
||||
|
||||
- (void)loadCharactersForCurrentTag {
|
||||
KBWeakSelf
|
||||
[self.homeVM fetchRankListByTagId:self.tagId
|
||||
needShow:YES
|
||||
completion:^(NSArray<KBCharacter *> * _Nullable list, NSError * _Nullable error) {
|
||||
if (error) {
|
||||
return;
|
||||
}
|
||||
weakSelf.characters = list ?: @[];
|
||||
[weakSelf.collectionView reloadData];
|
||||
}];
|
||||
}
|
||||
|
||||
- (UICollectionView *)collectionView{
|
||||
@@ -66,26 +86,21 @@
|
||||
#pragma mark - UICollectionViewDataSource
|
||||
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||
return self.dataSource.count;
|
||||
return self.characters.count;
|
||||
}
|
||||
|
||||
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
HomeRankCardCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"HomeRankCardCell" forIndexPath:indexPath];
|
||||
NSDictionary *d = self.dataSource[indexPath.item];
|
||||
BOOL added = [d[@"added"] boolValue];
|
||||
[cell configureWithTitle:d[@"title"]
|
||||
desc:d[@"desc"]
|
||||
people:d[@"people"]
|
||||
added:added];
|
||||
KBCharacter *c = self.characters[indexPath.item];
|
||||
// 直接把模型交给 cell,由 cell 自己负责展示
|
||||
cell.character = c;
|
||||
KBWeakSelf
|
||||
cell.onTapAction = ^{
|
||||
// 切换添加/已添加状态并刷新该项
|
||||
NSMutableArray *m = [weakSelf.dataSource mutableCopy];
|
||||
NSMutableDictionary *md = [m[indexPath.item] mutableCopy];
|
||||
BOOL cur = [md[@"added"] boolValue];
|
||||
md[@"added"] = @(!cur);
|
||||
m[indexPath.item] = md;
|
||||
weakSelf.dataSource = [m copy];
|
||||
// 切换添加/已添加状态并刷新该项(只是本地 UI 状态)
|
||||
NSMutableArray *m = [weakSelf.characters mutableCopy];
|
||||
KBCharacter *mc = m[indexPath.item];
|
||||
mc.added = !mc.added;
|
||||
weakSelf.characters = [m copy];
|
||||
[weakSelf.collectionView reloadItemsAtIndexPaths:@[indexPath]];
|
||||
};
|
||||
return cell;
|
||||
@@ -105,13 +120,13 @@
|
||||
|
||||
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
|
||||
// 点击卡片 -> 展示弹窗
|
||||
NSDictionary *d = self.dataSource[indexPath.item];
|
||||
KBCharacter *c = self.characters[indexPath.item];
|
||||
|
||||
// 自定义内容视图(尺寸可按需调节)
|
||||
CGFloat width = MIN(KB_SCREEN_WIDTH - 76, 420);
|
||||
HomeRankDetailPopView *content = [[HomeRankDetailPopView alloc] initWithFrame:CGRectMake(0, 0, width, 460)];
|
||||
NSString *title = d[@"title"] ?: @"High EQ";
|
||||
NSString *people = d[@"people"] ?: @"Download: 1 Million";
|
||||
NSString *title = c.characterName ?: @"High EQ";
|
||||
NSString *people = c.download ?: @"Download: 1 Million";
|
||||
NSString *desc = @"Be Neither Too Close\nNor Too Distant"; // 示例文案
|
||||
[content configWithAvatar:nil title:title download:people desc:desc];
|
||||
|
||||
|
||||
@@ -179,11 +179,13 @@
|
||||
|
||||
// 返回各个列表菜单下的实例,该实例需要遵守并实现 <JXCategoryListContentViewDelegate> 协议
|
||||
- (id<JXCategoryListContentViewDelegate>)listContainerView:(JXCategoryListContainerView *)listContainerView initListForIndex:(NSInteger)index {
|
||||
KBTag *tagModel = self.tags[index];
|
||||
HomeRankContentVC *list = [[HomeRankContentVC alloc] init];
|
||||
list.tagModel = tagModel;
|
||||
NSString *tagId = nil;
|
||||
if (index >= 0 && index < self.tags.count) {
|
||||
KBTag *tag = self.tags[index];
|
||||
tagId = tag.tagId;
|
||||
}
|
||||
HomeRankContentVC *list = [[HomeRankContentVC alloc] initWithTagId:tagId];
|
||||
self.collectionView = list.collectionView;
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,11 @@ typedef void(^KBHomeTagCompletion)(NSArray<KBTag *> * _Nullable list,
|
||||
needShow:(BOOL)needShow
|
||||
completion:(KBHomeRankCompletion)completion;
|
||||
|
||||
/// 根据 tagId 获取角色列表(GET /character/listByTag)
|
||||
- (void)fetchRankListByTagId:(nullable NSString *)tagId
|
||||
needShow:(BOOL)needShow
|
||||
completion:(KBHomeRankCompletion)completion;
|
||||
|
||||
/// 请求排行榜标签列表(GET /tag/list)
|
||||
/// - Parameters:
|
||||
/// - params: 额外查询参数(可为空);
|
||||
|
||||
@@ -67,6 +67,63 @@
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)fetchRankListByTagId:(nullable NSString *)tagId
|
||||
needShow:(BOOL)needShow
|
||||
completion:(KBHomeRankCompletion)completion {
|
||||
NSMutableDictionary *params = [NSMutableDictionary dictionary];
|
||||
if (tagId.length) {
|
||||
params[@"tagId"] = tagId;
|
||||
}
|
||||
[self fetchRankListByTagParams:params
|
||||
needShow:needShow
|
||||
completion:completion];
|
||||
}
|
||||
|
||||
// 内部辅助方法:调用 /character/listByTag
|
||||
- (void)fetchRankListByTagParams:(NSDictionary *)params
|
||||
needShow:(BOOL)needShow
|
||||
completion:(KBHomeRankCompletion)completion {
|
||||
if (needShow) {
|
||||
[KBHUD show];
|
||||
}
|
||||
|
||||
[[KBNetworkManager shared] GET:KB_API_CHARACTER_LIST_BY_TAG
|
||||
parameters:params
|
||||
headers:nil
|
||||
autoShowBusinessError:NO
|
||||
completion:^(NSDictionary * _Nullable json, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
if (needShow) {
|
||||
[KBHUD dismiss];
|
||||
}
|
||||
|
||||
if (error) {
|
||||
NSString *msg = KBBizMessageFromJSONObject(json) ?: error.localizedDescription ?: KBLocalized(@"Network error");
|
||||
[KBHUD showInfo:msg];
|
||||
if (completion) {
|
||||
completion(nil, error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
id dataObj = json[KBData] ?: json[@"data"];
|
||||
if (![dataObj isKindOfClass:[NSArray class]]) {
|
||||
NSError *e = [NSError errorWithDomain:KBNetworkErrorDomain
|
||||
code:KBNetworkErrorInvalidResponse
|
||||
userInfo:@{NSLocalizedDescriptionKey: KBLocalized(@"Invalid response")}];
|
||||
[KBHUD showInfo:e.localizedDescription];
|
||||
if (completion) {
|
||||
completion(nil, e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
NSArray<KBCharacter *> *list = [KBCharacter mj_objectArrayWithKeyValuesArray:(NSArray *)dataObj];
|
||||
if (completion) {
|
||||
completion(list, nil);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)fetchTagListWithParams:(nullable NSDictionary *)params
|
||||
needShow:(BOOL)needShow
|
||||
completion:(KBHomeTagCompletion)completion {
|
||||
|
||||
Reference in New Issue
Block a user