diff --git a/keyBoard/Assets.xcassets/My/my_keyboard_bg.imageset/Contents.json b/keyBoard/Assets.xcassets/My/my_keyboard_bg.imageset/Contents.json new file mode 100644 index 0000000..5654fb6 --- /dev/null +++ b/keyBoard/Assets.xcassets/My/my_keyboard_bg.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "my_keyboard_bg@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "my_keyboard_bg@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/keyBoard/Assets.xcassets/My/my_keyboard_bg.imageset/my_keyboard_bg@2x.png b/keyBoard/Assets.xcassets/My/my_keyboard_bg.imageset/my_keyboard_bg@2x.png new file mode 100644 index 0000000..90acca4 Binary files /dev/null and b/keyBoard/Assets.xcassets/My/my_keyboard_bg.imageset/my_keyboard_bg@2x.png differ diff --git a/keyBoard/Assets.xcassets/My/my_keyboard_bg.imageset/my_keyboard_bg@3x.png b/keyBoard/Assets.xcassets/My/my_keyboard_bg.imageset/my_keyboard_bg@3x.png new file mode 100644 index 0000000..bc1ec54 Binary files /dev/null and b/keyBoard/Assets.xcassets/My/my_keyboard_bg.imageset/my_keyboard_bg@3x.png differ diff --git a/keyBoard/Class/Base/VC/BaseViewController.h b/keyBoard/Class/Base/VC/BaseViewController.h index 3b32969..f206efb 100644 --- a/keyBoard/Class/Base/VC/BaseViewController.h +++ b/keyBoard/Class/Base/VC/BaseViewController.h @@ -11,6 +11,17 @@ NS_ASSUME_NONNULL_BEGIN @interface BaseViewController : UIViewController +/// 是否启用自定义导航栏(默认 yes)。 +/// 开启后:隐藏系统导航栏,显示顶部自定义 navView(含返回按钮和中间标题)。 +@property (nonatomic, assign) BOOL kb_enableCustomNavBar; + +/// 顶部自定义导航栏视图(懒加载)。 +@property (nonatomic, strong, readonly) UIView *kb_navView; +/// 自定义导航栏中间标题(懒加载)。 +@property (nonatomic, strong, readonly) UILabel *kb_titleLabel; +/// 自定义导航栏左侧返回按钮(懒加载)。 +@property (nonatomic, strong, readonly) UIButton *kb_backButton; + @end NS_ASSUME_NONNULL_END diff --git a/keyBoard/Class/Base/VC/BaseViewController.m b/keyBoard/Class/Base/VC/BaseViewController.m index e736182..7fc6fc3 100644 --- a/keyBoard/Class/Base/VC/BaseViewController.m +++ b/keyBoard/Class/Base/VC/BaseViewController.m @@ -11,12 +11,159 @@ @end -@implementation BaseViewController +@interface BaseViewController () +@property (nonatomic, strong) UIView *kb_navViewInternal; // 自定义导航栏容器 +@property (nonatomic, strong) UIView *kb_navContentView; // 44 高度内容区(便于居中) +@property (nonatomic, strong) UILabel *kb_titleLabelInternal; // 中间标题 +@property (nonatomic, strong) UIButton *kb_backButtonInternal; // 返回 +@property (nonatomic, strong) MASConstraint *kb_navHeightConstraint; // 高度约束,适配刘海 +@end + +@implementation BaseViewController { + BOOL _kb_enableCustomNavBar; +} - (void)viewDidLoad { [super viewDidLoad]; - // Do any additional setup after loading the view. self.view.backgroundColor = [UIColor whiteColor]; + self.kb_enableCustomNavBar = true; +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + [self kb_updateCustomNavBarVisibility]; + [self kb_updateBackButtonVisibility]; +} + + +#pragma mark - Custom NavBar + +- (void)setKb_enableCustomNavBar:(BOOL)kb_enableCustomNavBar { + _kb_enableCustomNavBar = kb_enableCustomNavBar; + if (kb_enableCustomNavBar) { [self kb_buildNavIfNeeded]; } + [self kb_updateCustomNavBarVisibility]; +} + +- (BOOL)kb_enableCustomNavBar { return _kb_enableCustomNavBar; } + +/// 懒创建自定义导航栏及子视图 +- (void)kb_buildNavIfNeeded { + if (self.kb_navViewInternal.superview) { return; } + + // 容器 + [self.view addSubview:self.kb_navViewInternal]; + CGFloat status = KB_StatusBarHeight(); + [self.kb_navViewInternal mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.right.equalTo(self.view); + make.top.equalTo(self.view); + self.kb_navHeightConstraint = make.height.mas_equalTo(status + KB_NAVBAR_BASE_HEIGHT); + }]; + + // 内容区(44 高度) + [self.kb_navViewInternal addSubview:self.kb_navContentView]; + [self.kb_navContentView mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.right.bottom.equalTo(self.kb_navViewInternal); + make.height.mas_equalTo(KB_NAVBAR_BASE_HEIGHT); + }]; + + // 返回按钮 + [self.kb_navContentView addSubview:self.kb_backButtonInternal]; + [self.kb_backButtonInternal mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(self.kb_navContentView).offset(12); + make.centerY.equalTo(self.kb_navContentView); + make.width.height.mas_equalTo(32); + }]; + + // 标题 + [self.kb_navContentView addSubview:self.kb_titleLabelInternal]; + [self.kb_titleLabelInternal mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerX.equalTo(self.kb_navContentView); + make.centerY.equalTo(self.kb_navContentView); + make.left.greaterThanOrEqualTo(self.kb_backButtonInternal.mas_right).offset(8); + }]; + + // 初始标题显示为 VC 的 title + self.kb_titleLabelInternal.text = self.title ?: self.navigationItem.title; + // 背景色同步 + self.kb_navViewInternal.backgroundColor = [UIColor whiteColor]; +} + +- (void)kb_updateCustomNavBarVisibility { + // 控制系统导航栏显隐 + [self.navigationController setNavigationBarHidden:self.kb_enableCustomNavBar animated:NO]; + self.kb_navViewInternal.hidden = !self.kb_enableCustomNavBar; + + // 适配状态栏高度变化(横竖屏切换) + if (self.kb_navHeightConstraint) { + CGFloat status = KB_StatusBarHeight(); + [self.kb_navHeightConstraint uninstall]; + [self.kb_navViewInternal mas_updateConstraints:^(MASConstraintMaker *make) { + self.kb_navHeightConstraint = make.height.mas_equalTo(status + KB_NAVBAR_BASE_HEIGHT); + }]; + } +} + +- (void)kb_updateBackButtonVisibility { + BOOL canGoBack = (self.navigationController.viewControllers.count > 1) || self.presentingViewController != nil; + self.kb_backButtonInternal.hidden = !canGoBack; +} + +- (void)setTitle:(NSString *)title { + [super setTitle:title]; + self.kb_titleLabelInternal.text = title; +} + +- (UIView *)kb_navView { return self.kb_navViewInternal; } +- (UILabel *)kb_titleLabel { return self.kb_titleLabelInternal; } +- (UIButton *)kb_backButton { return self.kb_backButtonInternal; } + +#pragma mark - Lazy + +- (UIView *)kb_navViewInternal { + if (!_kb_navViewInternal) { + _kb_navViewInternal = [UIView new]; + _kb_navViewInternal.backgroundColor = [UIColor whiteColor]; + } + return _kb_navViewInternal; +} + +- (UIView *)kb_navContentView { + if (!_kb_navContentView) { + _kb_navContentView = [UIView new]; + } + return _kb_navContentView; +} + +- (UILabel *)kb_titleLabelInternal { + if (!_kb_titleLabelInternal) { + _kb_titleLabelInternal = [UILabel new]; + _kb_titleLabelInternal.font = [UIFont systemFontOfSize:18 weight:UIFontWeightSemibold]; + _kb_titleLabelInternal.textColor = [UIColor colorWithHex:0x1B1F1A]; // 深色标题 + _kb_titleLabelInternal.textAlignment = NSTextAlignmentCenter; + } + return _kb_titleLabelInternal; +} + +- (UIButton *)kb_backButtonInternal { + if (!_kb_backButtonInternal) { + _kb_backButtonInternal = [UIButton buttonWithType:UIButtonTypeCustom]; + UIImage *img = [UIImage imageNamed:@"back"]; // 资源名 back_black_icon 内含 back@2x/back@3x + if (!img) { img = [UIImage imageNamed:@"back_black_icon"]; } + if (img) { [_kb_backButtonInternal setImage:img forState:UIControlStateNormal]; } + [_kb_backButtonInternal addTarget:self action:@selector(kb_onBack) forControlEvents:UIControlEventTouchUpInside]; + _kb_backButtonInternal.adjustsImageWhenHighlighted = YES; + _kb_backButtonInternal.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft; + _kb_backButtonInternal.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0); + } + return _kb_backButtonInternal; +} + +- (void)kb_onBack { + if (self.navigationController && self.navigationController.viewControllers.count > 1) { + [self.navigationController popViewControllerAnimated:YES]; + } else if (self.presentingViewController) { + [self dismissViewControllerAnimated:YES completion:nil]; + } } /* diff --git a/keyBoard/Class/Me/V/KBMyKeyboardCell.h b/keyBoard/Class/Me/V/KBMyKeyboardCell.h index 27e1ba1..1523986 100644 --- a/keyBoard/Class/Me/V/KBMyKeyboardCell.h +++ b/keyBoard/Class/Me/V/KBMyKeyboardCell.h @@ -18,7 +18,10 @@ NS_ASSUME_NONNULL_BEGIN /// 根据文案计算自适应尺寸(高度固定,宽度随文本变化) + (CGSize)sizeForEmoji:(NSString *)emoji title:(NSString *)title; +/// 点击右上角减号回调(由外部设置)。 +/// 回传当前 cell,方便外部从列表中定位并处理删除。 +@property (nonatomic, copy, nullable) void (^onMinusTapped)(KBMyKeyboardCell *cell); + @end NS_ASSUME_NONNULL_END - diff --git a/keyBoard/Class/Me/V/KBMyKeyboardCell.m b/keyBoard/Class/Me/V/KBMyKeyboardCell.m index af886f4..855aa63 100644 --- a/keyBoard/Class/Me/V/KBMyKeyboardCell.m +++ b/keyBoard/Class/Me/V/KBMyKeyboardCell.m @@ -64,6 +64,11 @@ [self.minusLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.center.equalTo(self.minusBadge); }]; + + // 点击右上角减号 + self.minusBadge.userInteractionEnabled = YES; + UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTapMinus)]; + [self.minusBadge addGestureRecognizer:tap]; } return self; } @@ -157,5 +162,13 @@ return _coverView; } -@end +#pragma mark - Actions +// 触发减号点击回调,由外部(VC)决定是否弹框与删除数据 +- (void)didTapMinus { + if (self.onMinusTapped) { + self.onMinusTapped(self); + } +} + +@end diff --git a/keyBoard/Class/Me/VC/KBMyKeyBoardVC.h b/keyBoard/Class/Me/VC/KBMyKeyBoardVC.h index 2a13cec..2701bca 100644 --- a/keyBoard/Class/Me/VC/KBMyKeyBoardVC.h +++ b/keyBoard/Class/Me/VC/KBMyKeyBoardVC.h @@ -9,7 +9,7 @@ NS_ASSUME_NONNULL_BEGIN -@interface KBMyKeyBoardVC : UIViewController +@interface KBMyKeyBoardVC : BaseViewController @end diff --git a/keyBoard/Class/Me/VC/KBMyKeyBoardVC.m b/keyBoard/Class/Me/VC/KBMyKeyBoardVC.m index 7b8b04c..2a9c24e 100644 --- a/keyBoard/Class/Me/VC/KBMyKeyBoardVC.m +++ b/keyBoard/Class/Me/VC/KBMyKeyBoardVC.m @@ -9,6 +9,7 @@ #import "BMLongPressDragCellCollectionView.h" #import "UICollectionViewLeftAlignedLayout.h" #import "KBMyKeyboardCell.h" +#import "KBAlert.h" /// 复用标识 static NSString * const kKBMyKeyboardCellId = @"kKBMyKeyboardCellId"; @@ -24,6 +25,7 @@ static NSString * const kKBMyKeyboardCellId = @"kKBMyKeyboardCellId"; @property (nonatomic, strong) UIView *sheetView; // 底部白色容器(圆角) @property (nonatomic, strong) BMLongPressDragCellCollectionView *collectionView; // 可拖拽的列表 @property (nonatomic, strong) UIButton *saveButton; // 保存按钮 +@property (nonatomic, strong) UIImageView *bgImageView; // 背景 // 数据源(必须是二维数组,库内部会在拖动时直接调整顺序) @property (nonatomic, strong) NSMutableArray *> *dataSourceArray; // {emoji,title} @@ -39,13 +41,18 @@ static NSString * const kKBMyKeyboardCellId = @"kKBMyKeyboardCellId"; - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor colorWithHex:0xF6F8F9]; - self.navigationController.title = @"My KeyBoard"; + self.kb_navView.backgroundColor = [UIColor clearColor]; + self.kb_titleLabel.text = @"My KeyBoard"; // 布局视图 + [self.view insertSubview:self.bgImageView belowSubview:self.kb_navView]; [self.view addSubview:self.sheetView]; [self.sheetView addSubview:self.collectionView]; [self.view addSubview:self.saveButton]; - + [self.bgImageView mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.left.right.equalTo(self.view); + make.height.mas_equalTo(323); + }]; [self.sheetView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.right.equalTo(self.view); make.top.equalTo(self.view).offset(KB_NAV_TOTAL_HEIGHT + 60); @@ -149,6 +156,46 @@ static NSString * const kKBMyKeyboardCellId = @"kKBMyKeyboardCellId"; KBMyKeyboardCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kKBMyKeyboardCellId forIndexPath:indexPath]; NSDictionary *d = self.dataSourceArray[indexPath.section][indexPath.item]; [cell configEmoji:d[@"emoji"] title:d[@"title"]]; + __weak typeof(self) weakSelf = self; + __weak typeof(collectionView) weakCV = collectionView; + cell.onMinusTapped = ^(KBMyKeyboardCell * _Nonnull tappedCell) { + __strong typeof(weakSelf) self = weakSelf; + if (!self) { return; } + NSIndexPath *tapIndexPath = [weakCV indexPathForCell:tappedCell]; + if (!tapIndexPath) { return; } +// [KBAlert confirmTitle:@"删除该标签?" message:@"删除后不可恢复" completion:^(BOOL ok) { +// if (!ok) { return; } +// // 更新数据源并删除 item +// if (tapIndexPath.section < self.dataSourceArray.count) { +// NSMutableArray *section = self.dataSourceArray[tapIndexPath.section]; +// if (tapIndexPath.item < section.count) { +// [section removeObjectAtIndex:tapIndexPath.item]; +// [self.collectionView performBatchUpdates:^{ +// [self.collectionView deleteItemsAtIndexPaths:@[tapIndexPath]]; +// } completion:nil]; +// } +// } +// }]; + [KBAlert confirmTitle:@"删除该标签?" + message:@"删除后不可恢复" + ok:@"确定" + cancel:@"取消" + okColor:[UIColor redColor] + cancelColor:[UIColor blackColor] + completion:^(BOOL ok) { + if (!ok) { return; } + // 更新数据源并删除 item + if (tapIndexPath.section < self.dataSourceArray.count) { + NSMutableArray *section = self.dataSourceArray[tapIndexPath.section]; + if (tapIndexPath.item < section.count) { + [section removeObjectAtIndex:tapIndexPath.item]; + [self.collectionView performBatchUpdates:^{ + [self.collectionView deleteItemsAtIndexPaths:@[tapIndexPath]]; + } completion:nil]; + } + } + }]; + }; return cell; } @@ -237,4 +284,12 @@ static NSString * const kKBMyKeyboardCellId = @"kKBMyKeyboardCellId"; return _saveButton; } +- (UIImageView *)bgImageView{ + if (!_bgImageView) { + _bgImageView = [[UIImageView alloc] init]; + _bgImageView.image = [UIImage imageNamed:@"my_keyboard_bg"]; + } + return _bgImageView; +} + @end