This commit is contained in:
2025-11-07 22:22:41 +08:00
parent b23c9a678b
commit 9a39c29e88
12 changed files with 731 additions and 1 deletions

View File

@@ -0,0 +1,218 @@
//
// 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