219 lines
8.5 KiB
Objective-C
219 lines
8.5 KiB
Objective-C
//
|
||
// KBSearchVC.m
|
||
// keyBoard
|
||
//
|
||
// Created by Mac on 2025/11/7.
|
||
//
|
||
|
||
#import "KBSearchVC.h"
|
||
#import "KBSearchBarView.h"
|
||
#import "KBSearchSectionHeader.h"
|
||
#import "KBTagCell.h"
|
||
#import "KBSkinCardCell.h"
|
||
|
||
static NSString * const kTagCellId = @"KBTagCell";
|
||
static NSString * const kSkinCellId = @"KBSkinCardCell";
|
||
static NSString * const kHeaderId = @"KBSearchSectionHeader";
|
||
|
||
typedef NS_ENUM(NSInteger, KBSearchSection) {
|
||
KBSearchSectionHistory = 0,
|
||
KBSearchSectionRecommend = 1,
|
||
};
|
||
|
||
@interface KBSearchVC ()<UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
|
||
// 顶部搜索栏(封装的 View)
|
||
@property (nonatomic, strong) KBSearchBarView *searchBarView;
|
||
// 列表
|
||
@property (nonatomic, strong) UICollectionView *collectionView;
|
||
@property (nonatomic, strong) UICollectionViewFlowLayout *flowLayout;
|
||
|
||
// 数据
|
||
@property (nonatomic, strong) NSMutableArray<NSString *> *historyWords; // 历史搜索
|
||
@property (nonatomic, strong) NSArray<NSDictionary *> *recommendItems; // 推荐数据(title/price)
|
||
@end
|
||
|
||
@implementation KBSearchVC
|
||
|
||
- (void)viewDidLoad {
|
||
[super viewDidLoad];
|
||
self.view.backgroundColor = [UIColor whiteColor];
|
||
|
||
// UI
|
||
[self.view addSubview:self.searchBarView];
|
||
[self.view addSubview:self.collectionView];
|
||
|
||
// 布局 - Masonry
|
||
[self.searchBarView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.top.equalTo(self.view.mas_top).offset(KB_NAV_TOTAL_HEIGHT + 8);
|
||
make.left.equalTo(self.view).offset(16);
|
||
make.right.equalTo(self.view).offset(-16);
|
||
make.height.mas_equalTo(40);
|
||
}];
|
||
|
||
[self.collectionView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.top.equalTo(self.searchBarView.mas_bottom).offset(12);
|
||
make.left.right.bottom.equalTo(self.view);
|
||
}];
|
||
|
||
// 初始化测试数据
|
||
self.historyWords = [@[@"果冻橙", @"芒果", @"有机水果卷心菜", @"水果萝卜", @"熟冻帝王蟹", @"赣南脐橙"] mutableCopy];
|
||
self.recommendItems = @[
|
||
@{@"title":@"Dopamine", @"price":@"20"},
|
||
@{@"title":@"Dopamine", @"price":@"20"},
|
||
@{@"title":@"Dopamine", @"price":@"20"},
|
||
@{@"title":@"Dopamine", @"price":@"20"},
|
||
@{@"title":@"Dopamine", @"price":@"20"},
|
||
@{@"title":@"Dopamine", @"price":@"20"},
|
||
];
|
||
|
||
[self.collectionView reloadData];
|
||
}
|
||
|
||
#pragma mark - Private
|
||
|
||
/// 执行搜索:简单将关键字加入历史
|
||
- (void)performSearch:(NSString *)kw {
|
||
NSString *trim = [kw stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||
if (trim.length == 0) { return; }
|
||
// 去重插入到最前
|
||
[self.historyWords removeObject:trim];
|
||
[self.historyWords insertObject:trim atIndex:0];
|
||
[self.collectionView reloadData];
|
||
}
|
||
|
||
/// 清空历史
|
||
- (void)clearHistory {
|
||
[self.historyWords removeAllObjects];
|
||
[self.collectionView reloadData];
|
||
}
|
||
|
||
#pragma mark - UICollectionViewDataSource
|
||
|
||
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
|
||
return 2; // 历史 + 推荐
|
||
}
|
||
|
||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||
if (section == KBSearchSectionHistory) {
|
||
return self.historyWords.count; // 无历史则为 0
|
||
}
|
||
return self.recommendItems.count;
|
||
}
|
||
|
||
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||
if (indexPath.section == KBSearchSectionHistory) {
|
||
KBTagCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kTagCellId forIndexPath:indexPath];
|
||
[cell config:self.historyWords[indexPath.item]];
|
||
return cell;
|
||
}
|
||
KBSkinCardCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kSkinCellId forIndexPath:indexPath];
|
||
NSDictionary *it = self.recommendItems[indexPath.item];
|
||
[cell configWithTitle:it[@"title"] imageURL:nil price:it[@"price"]];
|
||
return cell;
|
||
}
|
||
|
||
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
|
||
if (kind == UICollectionElementKindSectionHeader) {
|
||
KBSearchSectionHeader *header = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:kHeaderId forIndexPath:indexPath];
|
||
if (indexPath.section == KBSearchSectionHistory) {
|
||
// 当没有历史时,外部通过 sizeForHeader 返回 0,这里仍设置但不会显示
|
||
[header configWithTitle:@"Historical Search" showTrash:self.historyWords.count > 0];
|
||
__weak typeof(self) weakSelf = self;
|
||
header.onTapTrash = ^{ [weakSelf clearHistory]; };
|
||
} else {
|
||
[header configWithTitle:@"Recommended Skin" showTrash:NO];
|
||
}
|
||
return header;
|
||
}
|
||
return [UICollectionReusableView new];
|
||
}
|
||
|
||
#pragma mark - UICollectionViewDelegateFlowLayout
|
||
|
||
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||
CGFloat width = collectionView.bounds.size.width;
|
||
if (indexPath.section == KBSearchSectionHistory) {
|
||
NSString *t = self.historyWords[indexPath.item];
|
||
return [KBTagCell sizeForText:t];
|
||
}
|
||
// 两列卡片
|
||
CGFloat inset = 16; // 左右间距
|
||
CGFloat spacing = 12; // 列间距
|
||
CGFloat w = floor((width - inset*2 - spacing) / 2.0);
|
||
// 高度:封面 0.75w + 标题 + 价格 + 边距,近似定高
|
||
CGFloat h = w*0.75 + 8 + 20 + 10 + 6 + 8; // 估算
|
||
return CGSizeMake(w, h);
|
||
}
|
||
|
||
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
|
||
if (section == KBSearchSectionHistory) {
|
||
return UIEdgeInsetsMake(8, 16, 12, 16);
|
||
}
|
||
return UIEdgeInsetsMake(8, 16, 20, 16);
|
||
}
|
||
|
||
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
|
||
return section == KBSearchSectionHistory ? 8 : 12;
|
||
}
|
||
|
||
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
|
||
return section == KBSearchSectionHistory ? 8 : 16;
|
||
}
|
||
|
||
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section {
|
||
// 当历史记录为空时,header 高度为 0,从而不显示标题与垃圾桶
|
||
if (section == KBSearchSectionHistory) {
|
||
return self.historyWords.count == 0 ? CGSizeZero : CGSizeMake(collectionView.bounds.size.width, 40);
|
||
}
|
||
return CGSizeMake(collectionView.bounds.size.width, 40);
|
||
}
|
||
|
||
#pragma mark - UICollectionViewDelegate
|
||
|
||
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
|
||
if (indexPath.section == KBSearchSectionHistory) {
|
||
NSString *kw = self.historyWords[indexPath.item];
|
||
[self.searchBarView updateKeyword:kw];
|
||
[self performSearch:kw];
|
||
}
|
||
}
|
||
|
||
#pragma mark - Lazy
|
||
|
||
- (KBSearchBarView *)searchBarView {
|
||
if (!_searchBarView) {
|
||
_searchBarView = [[KBSearchBarView alloc] init];
|
||
_searchBarView.placeholder = @"Themes";
|
||
__weak typeof(self) weakSelf = self;
|
||
_searchBarView.onSearch = ^(NSString * _Nonnull keyword) {
|
||
[weakSelf performSearch:keyword];
|
||
};
|
||
}
|
||
return _searchBarView;
|
||
}
|
||
|
||
- (UICollectionViewFlowLayout *)flowLayout {
|
||
if (!_flowLayout) {
|
||
_flowLayout = [[UICollectionViewFlowLayout alloc] init];
|
||
_flowLayout.scrollDirection = UICollectionViewScrollDirectionVertical;
|
||
_flowLayout.sectionHeadersPinToVisibleBounds = NO;
|
||
}
|
||
return _flowLayout;
|
||
}
|
||
|
||
- (UICollectionView *)collectionView {
|
||
if (!_collectionView) {
|
||
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:self.flowLayout];
|
||
_collectionView.backgroundColor = [UIColor whiteColor];
|
||
_collectionView.dataSource = self;
|
||
_collectionView.delegate = self;
|
||
// 注册 cell & header
|
||
[_collectionView registerClass:KBTagCell.class forCellWithReuseIdentifier:kTagCellId];
|
||
[_collectionView registerClass:KBSkinCardCell.class forCellWithReuseIdentifier:kSkinCellId];
|
||
[_collectionView registerClass:KBSearchSectionHeader.class forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:kHeaderId];
|
||
}
|
||
return _collectionView;
|
||
}
|
||
|
||
@end
|