// // KBMyKeyBoardVC.m // keyBoard // // Created by Mac on 2025/11/10. // #import "KBMyKeyBoardVC.h" #import "BMLongPressDragCellCollectionView.h" #import "UICollectionViewLeftAlignedLayout.h" #import "KBMyKeyboardCell.h" /// 复用标识 static NSString * const kKBMyKeyboardCellId = @"kKBMyKeyboardCellId"; /// 截图页 - 自定义键盘管理 /// 要点: /// 1)使用 BMLongPressDragCellCollectionView 支持长按拖拽排序; /// 2)cell 宽度根据文案自适应; /// 3)全部使用 Masonry 进行布局,并采用懒加载创建控件; @interface KBMyKeyBoardVC () // UI @property (nonatomic, strong) UIView *sheetView; // 底部白色容器(圆角) @property (nonatomic, strong) BMLongPressDragCellCollectionView *collectionView; // 可拖拽的列表 @property (nonatomic, strong) UIButton *saveButton; // 保存按钮 // 数据源(必须是二维数组,库内部会在拖动时直接调整顺序) @property (nonatomic, strong) NSMutableArray *> *dataSourceArray; // {emoji,title} @end @interface KBMyKeyBoardVC () @end @implementation KBMyKeyBoardVC - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor colorWithHex:0xF6F8F9]; self.navigationController.title = @"My KeyBoard"; // 布局视图 [self.view addSubview:self.sheetView]; [self.sheetView addSubview:self.collectionView]; [self.view addSubview:self.saveButton]; [self.sheetView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.right.equalTo(self.view); make.top.equalTo(self.view).offset(KB_NAV_TOTAL_HEIGHT + 60); make.bottom.equalTo(self.view).offset(16); }]; [self.collectionView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.right.top.equalTo(self.sheetView); make.bottom.equalTo(self.saveButton.mas_top).offset(-15); }]; [self.saveButton mas_makeConstraints:^(MASConstraintMaker *make) { make.left.right.equalTo(self.view).insets(UIEdgeInsetsMake(0, 24, 0, 24)); make.bottom.equalTo(self.view.mas_safeAreaLayoutGuideBottom).offset(-12); make.height.mas_equalTo(50); }]; // 初始数据 [self buildDefaultData]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; // 隐藏系统导航栏 // [self.navigationController setNavigationBarHidden:YES animated:animated]; } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; // if (self.isMovingFromParentViewController || self.isBeingDismissed) { // [self.navigationController setNavigationBarHidden:NO animated:animated]; // } } #pragma mark - Data /// 构造示例数据(二维数组,仅 1 个 section) - (void)buildDefaultData { NSArray *arr = @[ @{@"emoji":@"😊", @"title":@"Humor"}, @{@"emoji":@"😄", @"title":@"Jokes"}, @{@"emoji":@"🥰", @"title":@"Love"}, @{@"emoji":@"🤔", @"title":@"Thinking"}, @{@"emoji":@"🔥", @"title":@"Hot"}, @{@"emoji":@"🎉", @"title":@"Celebrate"}, @{@"emoji":@"🧠", @"title":@"Brainstorm"}, @{@"emoji":@"🐱", @"title":@"Cats"}, @{@"emoji":@"😂", @"title":@"LOL"}, @{@"emoji":@"📸", @"title":@"Photography"}, @{@"emoji":@"🌟", @"title":@"Star"}, @{@"emoji":@"🍀", @"title":@"Lucky"}, @{@"emoji":@"📚", @"title":@"Knowledge"}, @{@"emoji":@"🎵", @"title":@"Music"}, @{@"emoji":@"🚀", @"title":@"Launch"}, @{@"emoji":@"😊", @"title":@"Humor"}, @{@"emoji":@"😄", @"title":@"Jokes"}, @{@"emoji":@"🥰", @"title":@"Love"}, @{@"emoji":@"🤔", @"title":@"Thinking"}, @{@"emoji":@"🔥", @"title":@"Hot"}, @{@"emoji":@"🎉", @"title":@"Celebrate"}, @{@"emoji":@"🧠", @"title":@"Brainstorm"}, @{@"emoji":@"🐱", @"title":@"Cats"}, @{@"emoji":@"😂", @"title":@"LOL"}, @{@"emoji":@"📸", @"title":@"Photography"}, @{@"emoji":@"🌟", @"title":@"Star"}, @{@"emoji":@"🍀", @"title":@"Lucky"}, @{@"emoji":@"📚", @"title":@"Knowledge"}, @{@"emoji":@"🎵", @"title":@"Music"}, @{@"emoji":@"🚀", @"title":@"Launch"}, @{@"emoji":@"😊", @"title":@"Humor"}, @{@"emoji":@"😄", @"title":@"Jokes"}, @{@"emoji":@"🥰", @"title":@"Love"}, @{@"emoji":@"🤔", @"title":@"Thinking"}, @{@"emoji":@"🔥", @"title":@"Hot"}, @{@"emoji":@"🎉", @"title":@"Celebrate"}, @{@"emoji":@"🧠", @"title":@"Brainstorm"}, @{@"emoji":@"🐱", @"title":@"Cats"}, @{@"emoji":@"😂", @"title":@"LOL"}, @{@"emoji":@"📸", @"title":@"Photography"}, @{@"emoji":@"🌟", @"title":@"Star"}, @{@"emoji":@"🍀", @"title":@"Lucky"}, @{@"emoji":@"📚", @"title":@"Knowledge"}, @{@"emoji":@"🎵", @"title":@"Music"}, @{@"emoji":@"🚀", @"title":@"Launch"}, ]; self.dataSourceArray = [@[[arr mutableCopy]] mutableCopy]; [self.collectionView reloadData]; } #pragma mark - BMLongPressDragCellCollectionViewDataSource - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { return self.dataSourceArray.count; } - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return self.dataSourceArray[section].count; } - (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { KBMyKeyboardCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kKBMyKeyboardCellId forIndexPath:indexPath]; NSDictionary *d = self.dataSourceArray[indexPath.section][indexPath.item]; [cell configEmoji:d[@"emoji"] title:d[@"title"]]; return cell; } // 拖拽库要求实现:返回当前“二维数组”数据源 - (NSArray *> *)dataSourceWithDragCellCollectionView:(__kindof BMLongPressDragCellCollectionView *)dragCellCollectionView { return self.dataSourceArray; } // 拖拽后回调:保存最新数据 - (void)dragCellCollectionView:(BMLongPressDragCellCollectionView *)dragCellCollectionView newDataArrayAfterMove:(nullable NSArray *> *)newDataArray { self.dataSourceArray = [newDataArray mutableCopy]; } #pragma mark - BMLongPressDragCellCollectionViewDelegate (布局) // 根据文案长度动态返回 item 尺寸 - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { NSDictionary *d = self.dataSourceArray[indexPath.section][indexPath.item]; return [KBMyKeyboardCell sizeForEmoji:d[@"emoji"] title:d[@"title"]]; } - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { return UIEdgeInsetsMake(12, 12, 12, 12); } - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section { return 10; } - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section { return 10; } #pragma mark - Actions - (void)onSave { // 这里只做示意:保存当前顺序 NSLog(@"保存顺序: %@", self.dataSourceArray); [KBHUD showInfo:@"已保存"]; } #pragma mark - Lazy UI //- (UILabel *)titleLabel { // if (!_titleLabel) { // _titleLabel = [UILabel new]; // _titleLabel.text = @"My Keyboard"; // 顶部标题 // _titleLabel.font = [UIFont systemFontOfSize:18 weight:UIFontWeightSemibold]; // _titleLabel.textColor = [UIColor colorWithHex:0x1B1F1A]; // } // return _titleLabel; //} - (UIView *)sheetView { if (!_sheetView) { _sheetView = [UIView new]; _sheetView.backgroundColor = [UIColor whiteColor]; _sheetView.layer.cornerRadius = 32.0; _sheetView.layer.masksToBounds = YES; } return _sheetView; } - (BMLongPressDragCellCollectionView *)collectionView { if (!_collectionView) { UICollectionViewLeftAlignedLayout *layout = [UICollectionViewLeftAlignedLayout new]; layout.scrollDirection = UICollectionViewScrollDirectionVertical; // layout.sectionInset = UIEdgeInsetsMake(16, 16, 16, 16); _collectionView = [[BMLongPressDragCellCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; _collectionView.backgroundColor = [UIColor clearColor]; _collectionView.delegate = self; // 注意:代理为 BMLongPressDragCellCollectionViewDelegate _collectionView.dataSource = self; // 注意:数据源为 BMLongPressDragCellCollectionViewDataSource _collectionView.alwaysBounceVertical = YES; _collectionView.showsVerticalScrollIndicator = NO; [_collectionView registerClass:KBMyKeyboardCell.class forCellWithReuseIdentifier:kKBMyKeyboardCellId]; } return _collectionView; } - (UIButton *)saveButton { if (!_saveButton) { _saveButton = [UIButton buttonWithType:UIButtonTypeSystem]; [_saveButton setTitle:@"Save" forState:UIControlStateNormal]; _saveButton.titleLabel.font = [UIFont systemFontOfSize:18 weight:UIFontWeightSemibold]; [_saveButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; _saveButton.backgroundColor = [UIColor colorWithHex:KBColorValue]; _saveButton.layer.cornerRadius = 25; _saveButton.layer.masksToBounds = YES; [_saveButton addTarget:self action:@selector(onSave) forControlEvents:UIControlEventTouchUpInside]; } return _saveButton; } @end