1
This commit is contained in:
@@ -28,27 +28,12 @@ static CGFloat KEYBOARDHEIGHT = 256;
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
//
|
||||
// // Perform custom UI setup here
|
||||
// self.nextKeyboardButton = [UIButton buttonWithType:UIButtonTypeSystem];
|
||||
//
|
||||
// [self.nextKeyboardButton setTitle:NSLocalizedString(@"Next Keyboard", @"Title for 'Next Keyboard' button") forState:UIControlStateNormal];
|
||||
// [self.nextKeyboardButton sizeToFit];
|
||||
// self.nextKeyboardButton.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
//
|
||||
// [self.nextKeyboardButton addTarget:self action:@selector(handleInputModeListFromView:withEvent:) forControlEvents:UIControlEventAllTouchEvents];
|
||||
//
|
||||
// [self.view addSubview:self.nextKeyboardButton];
|
||||
//
|
||||
// [self.nextKeyboardButton.leftAnchor constraintEqualToAnchor:self.view.leftAnchor].active = YES;
|
||||
// [self.nextKeyboardButton.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor].active = YES;
|
||||
|
||||
[self setupUI];
|
||||
}
|
||||
|
||||
|
||||
- (void)setupUI {
|
||||
// self.view.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
// 固定键盘整体高度
|
||||
[self.view.heightAnchor constraintEqualToConstant:KEYBOARDHEIGHT].active = YES;
|
||||
|
||||
@@ -74,38 +59,15 @@ static CGFloat KEYBOARDHEIGHT = 256;
|
||||
}
|
||||
|
||||
|
||||
- (void)viewWillLayoutSubviews
|
||||
{
|
||||
self.nextKeyboardButton.hidden = !self.needsInputModeSwitchKey;
|
||||
[super viewWillLayoutSubviews];
|
||||
}
|
||||
|
||||
- (void)textWillChange:(id<UITextInput>)textInput {
|
||||
// 文档内容即将变化,可在此做准备
|
||||
}
|
||||
|
||||
- (void)textDidChange:(id<UITextInput>)textInput {
|
||||
// 文档内容刚发生变化,环境已更新
|
||||
|
||||
UIColor *textColor = nil;
|
||||
if (self.textDocumentProxy.keyboardAppearance == UIKeyboardAppearanceDark) {
|
||||
textColor = [UIColor whiteColor];
|
||||
} else {
|
||||
textColor = [UIColor blackColor];
|
||||
}
|
||||
[self.nextKeyboardButton setTitleColor:textColor forState:UIControlStateNormal];
|
||||
}
|
||||
|
||||
#pragma mark - KBToolBarDelegate
|
||||
|
||||
- (void)toolBar:(KBToolBar *)toolBar didTapActionAtIndex:(NSInteger)index {
|
||||
// 可根据业务透传或处理。示例:插入占位标记 [A1]..[A4]
|
||||
NSString *placeholder = [NSString stringWithFormat:@"[A%ld]", (long)index+1];
|
||||
[self.textDocumentProxy insertText:placeholder];
|
||||
// NSString *placeholder = [NSString stringWithFormat:@"[A%ld]", (long)index+1];
|
||||
|
||||
}
|
||||
|
||||
- (void)toolBarDidTapSettings:(KBToolBar *)toolBar {
|
||||
// 通常可通过 openURL 或宿主处理打开设置页。
|
||||
// 这里示例仅插入一个标记。
|
||||
[self.textDocumentProxy insertText:@"[settings]"];
|
||||
}
|
||||
|
||||
27
CustomKeyboard/View/KBFunctionBarView.h
Normal file
27
CustomKeyboard/View/KBFunctionBarView.h
Normal file
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// KBFunctionBarView.h
|
||||
// CustomKeyboard
|
||||
//
|
||||
// Created by Mac on 2025/10/28.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// 功能区顶部的Bar:左侧4个按钮,右侧3个按钮
|
||||
@interface KBFunctionBarView : UIView
|
||||
|
||||
/// 左侧4个按钮(懒加载创建,等宽水平排布)
|
||||
@property (nonatomic, strong, readonly) NSArray<UIButton *> *leftButtons;
|
||||
|
||||
/// 右侧3个按钮(懒加载创建,等宽水平排布,靠右)
|
||||
@property (nonatomic, strong, readonly) NSArray<UIButton *> *rightButtons;
|
||||
|
||||
/// 配置按钮标题(可选)
|
||||
@property (nonatomic, copy) NSArray<NSString *> *leftTitles; // 默认 @[@"帮回", @"会说", @"话术", @"更多"]
|
||||
@property (nonatomic, copy) NSArray<NSString *> *rightTitles; // 默认 @[@"❤", @"收藏", @"宫格"]
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
142
CustomKeyboard/View/KBFunctionBarView.m
Normal file
142
CustomKeyboard/View/KBFunctionBarView.m
Normal file
@@ -0,0 +1,142 @@
|
||||
//
|
||||
// KBFunctionBarView.m
|
||||
// CustomKeyboard
|
||||
//
|
||||
// Created by Mac on 2025/10/28.
|
||||
// 功能 - barview
|
||||
|
||||
#import "KBFunctionBarView.h"
|
||||
#import "Masonry.h"
|
||||
|
||||
@interface KBFunctionBarView ()
|
||||
@property (nonatomic, strong) UIView *leftContainer; // 左侧按钮容器
|
||||
@property (nonatomic, strong) UIView *rightContainer; // 右侧按钮容器
|
||||
@property (nonatomic, strong) NSArray<UIButton *> *leftButtonsInternal;
|
||||
@property (nonatomic, strong) NSArray<UIButton *> *rightButtonsInternal;
|
||||
@end
|
||||
|
||||
@implementation KBFunctionBarView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame{
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
_leftTitles = @[@"帮回", @"会说", @"话术", @"更多"];
|
||||
_rightTitles = @[@"❤", @"收藏", @"宫格"];
|
||||
[self buildUI];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Public
|
||||
|
||||
- (NSArray<UIButton *> *)leftButtons { return self.leftButtonsInternal; }
|
||||
- (NSArray<UIButton *> *)rightButtons { return self.rightButtonsInternal; }
|
||||
|
||||
|
||||
#pragma mark - UI
|
||||
|
||||
- (void)buildUI {
|
||||
// 左右两个容器,方便分别布局
|
||||
[self addSubview:self.leftContainer];
|
||||
[self addSubview:self.rightContainer];
|
||||
|
||||
[self.rightContainer mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.equalTo(self.mas_right).offset(-12);
|
||||
make.centerY.equalTo(self.mas_centerY);
|
||||
make.height.mas_equalTo(36);
|
||||
}];
|
||||
|
||||
[self.leftContainer mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.mas_left).offset(12);
|
||||
make.right.equalTo(self.rightContainer.mas_left).offset(-12);
|
||||
make.centerY.equalTo(self.mas_centerY);
|
||||
make.height.mas_equalTo(36);
|
||||
}];
|
||||
|
||||
// 左侧4个等宽按钮
|
||||
NSMutableArray<UIButton *> *leftBtns = [NSMutableArray arrayWithCapacity:4];
|
||||
UIView *prev = nil;
|
||||
for (NSInteger i = 0; i < 4; i++) {
|
||||
UIButton *btn = [self buildButtonWithTitle:(i < self.leftTitles.count ? self.leftTitles[i] : [NSString stringWithFormat:@"L%ld", (long)i])];
|
||||
btn.tag = 100 + i;
|
||||
[self.leftContainer addSubview:btn];
|
||||
[btn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
if (prev) {
|
||||
make.left.equalTo(prev.mas_right).offset(8);
|
||||
make.width.equalTo(prev);
|
||||
} else {
|
||||
make.left.equalTo(self.leftContainer.mas_left);
|
||||
}
|
||||
make.top.bottom.equalTo(self.leftContainer);
|
||||
}];
|
||||
prev = btn;
|
||||
[leftBtns addObject:btn];
|
||||
}
|
||||
[prev mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.equalTo(self.leftContainer.mas_right);
|
||||
}];
|
||||
self.leftButtonsInternal = leftBtns.copy;
|
||||
|
||||
// 右侧3个等宽按钮(靠右)
|
||||
NSMutableArray<UIButton *> *rightBtns = [NSMutableArray arrayWithCapacity:3];
|
||||
UIView *next = nil;
|
||||
for (NSInteger i = 0; i < 3; i++) {
|
||||
UIButton *btn = [self buildButtonWithTitle:(i < self.rightTitles.count ? self.rightTitles[i] : [NSString stringWithFormat:@"R%ld", (long)i])];
|
||||
btn.tag = 200 + i;
|
||||
[self.rightContainer addSubview:btn];
|
||||
[rightBtns addObject:btn];
|
||||
}
|
||||
|
||||
// 从右往左排,保证整体靠右
|
||||
UIButton *r0 = rightBtns.count > 0 ? rightBtns[0] : nil;
|
||||
UIButton *r1 = rightBtns.count > 1 ? rightBtns[1] : nil;
|
||||
UIButton *r2 = rightBtns.count > 2 ? rightBtns[2] : nil;
|
||||
if (r0 && r1 && r2) {
|
||||
[r2 mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.equalTo(self.rightContainer.mas_right);
|
||||
make.top.bottom.equalTo(self.rightContainer);
|
||||
}];
|
||||
[r1 mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.equalTo(r2.mas_left).offset(-8);
|
||||
make.top.bottom.equalTo(self.rightContainer);
|
||||
make.width.equalTo(r2);
|
||||
}];
|
||||
[r0 mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.equalTo(r1.mas_left).offset(-8);
|
||||
make.top.bottom.equalTo(self.rightContainer);
|
||||
make.width.equalTo(r1);
|
||||
make.left.greaterThanOrEqualTo(self.rightContainer.mas_left); // 内容撑开
|
||||
}];
|
||||
}
|
||||
|
||||
self.rightButtonsInternal = rightBtns.copy;
|
||||
}
|
||||
|
||||
- (UIButton *)buildButtonWithTitle:(NSString *)title {
|
||||
UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem];
|
||||
btn.layer.cornerRadius = 18;
|
||||
btn.layer.masksToBounds = YES;
|
||||
btn.backgroundColor = [UIColor colorWithWhite:1 alpha:0.9];
|
||||
btn.titleLabel.font = [UIFont systemFontOfSize:14 weight:UIFontWeightMedium];
|
||||
[btn setTitle:title forState:UIControlStateNormal];
|
||||
[btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
|
||||
return btn;
|
||||
}
|
||||
|
||||
#pragma mark - Lazy
|
||||
|
||||
- (UIView *)leftContainer {
|
||||
if (!_leftContainer) {
|
||||
_leftContainer = [[UIView alloc] init];
|
||||
}
|
||||
return _leftContainer;
|
||||
}
|
||||
|
||||
- (UIView *)rightContainer {
|
||||
if (!_rightContainer) {
|
||||
_rightContainer = [[UIView alloc] init];
|
||||
}
|
||||
return _rightContainer;
|
||||
}
|
||||
|
||||
@end
|
||||
23
CustomKeyboard/View/KBFunctionPasteView.h
Normal file
23
CustomKeyboard/View/KBFunctionPasteView.h
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// KBFunctionPasteView.h
|
||||
// CustomKeyboard
|
||||
//
|
||||
// Created by Mac on 2025/10/28.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// 粘贴提示输入框区域(左侧图标+占位文案,圆角白底)
|
||||
@interface KBFunctionPasteView : UIView
|
||||
|
||||
/// 左侧图标
|
||||
@property (nonatomic, strong, readonly) UIImageView *iconView;
|
||||
|
||||
/// 提示文案,例如:点击粘贴TA的话
|
||||
@property (nonatomic, strong, readonly) UILabel *placeholderLabel;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
75
CustomKeyboard/View/KBFunctionPasteView.m
Normal file
75
CustomKeyboard/View/KBFunctionPasteView.m
Normal file
@@ -0,0 +1,75 @@
|
||||
//
|
||||
// KBFunctionPasteView.m
|
||||
// CustomKeyboard
|
||||
//
|
||||
// Created by Mac on 2025/10/28.
|
||||
// 粘贴View
|
||||
|
||||
#import "KBFunctionPasteView.h"
|
||||
#import "Masonry.h"
|
||||
|
||||
@interface KBFunctionPasteView ()
|
||||
@property (nonatomic, strong) UIImageView *iconViewInternal;
|
||||
@property (nonatomic, strong) UILabel *placeholderLabelInternal;
|
||||
@end
|
||||
|
||||
@implementation KBFunctionPasteView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
// 白底圆角容器
|
||||
self.backgroundColor = [UIColor colorWithWhite:1 alpha:0.95];
|
||||
self.layer.cornerRadius = 12.0;
|
||||
self.layer.masksToBounds = YES;
|
||||
|
||||
[self addSubview:self.iconViewInternal];
|
||||
[self addSubview:self.placeholderLabelInternal];
|
||||
|
||||
[self.iconViewInternal mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.mas_left).offset(12);
|
||||
make.centerY.equalTo(self.mas_centerY);
|
||||
make.width.height.mas_equalTo(20);
|
||||
}];
|
||||
[self.placeholderLabelInternal mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.iconViewInternal.mas_right).offset(8);
|
||||
make.right.equalTo(self.mas_right).offset(-12);
|
||||
make.centerY.equalTo(self.mas_centerY);
|
||||
}];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Lazy
|
||||
|
||||
- (UIImageView *)iconViewInternal {
|
||||
if (!_iconViewInternal) {
|
||||
_iconViewInternal = [[UIImageView alloc] init];
|
||||
// 用简单的系统表情代替资源图(项目可替换成实际图片)
|
||||
UILabel *emoji = [[UILabel alloc] init];
|
||||
emoji.text = @"📋"; // 粘贴/剪贴板含义
|
||||
emoji.font = [UIFont systemFontOfSize:18];
|
||||
emoji.textAlignment = NSTextAlignmentCenter;
|
||||
[_iconViewInternal addSubview:emoji];
|
||||
[emoji mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.equalTo(_iconViewInternal);
|
||||
}];
|
||||
}
|
||||
return _iconViewInternal;
|
||||
}
|
||||
|
||||
- (UILabel *)placeholderLabelInternal {
|
||||
if (!_placeholderLabelInternal) {
|
||||
_placeholderLabelInternal = [[UILabel alloc] init];
|
||||
_placeholderLabelInternal.text = @"点击粘贴TA的话";
|
||||
_placeholderLabelInternal.textColor = [UIColor colorWithRed:0.20 green:0.64 blue:0.54 alpha:1.0];
|
||||
_placeholderLabelInternal.font = [UIFont systemFontOfSize:16 weight:UIFontWeightMedium];
|
||||
}
|
||||
return _placeholderLabelInternal;
|
||||
}
|
||||
|
||||
#pragma mark - Expose
|
||||
|
||||
- (UIImageView *)iconView { return self.iconViewInternal; }
|
||||
- (UILabel *)placeholderLabel { return self.placeholderLabelInternal; }
|
||||
|
||||
@end
|
||||
23
CustomKeyboard/View/KBFunctionTagCell.h
Normal file
23
CustomKeyboard/View/KBFunctionTagCell.h
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// KBFunctionTagCell.h
|
||||
// CustomKeyboard
|
||||
//
|
||||
// Created by Codex on 2025/10/28.
|
||||
// 话术标签Cell:左图标+右标题,圆角灰白底
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface KBFunctionTagCell : UICollectionViewCell
|
||||
|
||||
/// 标题
|
||||
@property (nonatomic, strong, readonly) UILabel *titleLabel;
|
||||
|
||||
/// 头像/图标
|
||||
@property (nonatomic, strong, readonly) UIImageView *iconView;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
73
CustomKeyboard/View/KBFunctionTagCell.m
Normal file
73
CustomKeyboard/View/KBFunctionTagCell.m
Normal file
@@ -0,0 +1,73 @@
|
||||
//
|
||||
// KBFunctionTagCell.m
|
||||
// CustomKeyboard
|
||||
//
|
||||
// Created by Codex on 2025/10/28.
|
||||
//
|
||||
|
||||
#import "KBFunctionTagCell.h"
|
||||
#import "Masonry.h"
|
||||
|
||||
@interface KBFunctionTagCell ()
|
||||
@property (nonatomic, strong) UILabel *titleLabelInternal;
|
||||
@property (nonatomic, strong) UIImageView *iconViewInternal;
|
||||
@end
|
||||
|
||||
@implementation KBFunctionTagCell
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
self.contentView.backgroundColor = [UIColor colorWithWhite:1 alpha:0.9];
|
||||
self.contentView.layer.cornerRadius = 12;
|
||||
self.contentView.layer.masksToBounds = YES;
|
||||
|
||||
[self.contentView addSubview:self.iconViewInternal];
|
||||
[self.contentView addSubview:self.titleLabelInternal];
|
||||
|
||||
[self.iconViewInternal mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.contentView.mas_left).offset(10);
|
||||
make.centerY.equalTo(self.contentView.mas_centerY);
|
||||
make.width.height.mas_equalTo(24);
|
||||
}];
|
||||
[self.titleLabelInternal mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.iconViewInternal.mas_right).offset(6);
|
||||
make.right.equalTo(self.contentView.mas_right).offset(-10);
|
||||
make.centerY.equalTo(self.contentView.mas_centerY);
|
||||
}];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Lazy
|
||||
|
||||
- (UIImageView *)iconViewInternal {
|
||||
if (!_iconViewInternal) {
|
||||
_iconViewInternal = [[UIImageView alloc] init];
|
||||
UILabel *emoji = [[UILabel alloc] init];
|
||||
emoji.text = @"🙂"; // 占位图标
|
||||
emoji.textAlignment = NSTextAlignmentCenter;
|
||||
emoji.font = [UIFont systemFontOfSize:20];
|
||||
[_iconViewInternal addSubview:emoji];
|
||||
[emoji mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.equalTo(_iconViewInternal);
|
||||
}];
|
||||
}
|
||||
return _iconViewInternal;
|
||||
}
|
||||
|
||||
- (UILabel *)titleLabelInternal {
|
||||
if (!_titleLabelInternal) {
|
||||
_titleLabelInternal = [[UILabel alloc] init];
|
||||
_titleLabelInternal.font = [UIFont systemFontOfSize:15 weight:UIFontWeightSemibold];
|
||||
_titleLabelInternal.textColor = [UIColor blackColor];
|
||||
}
|
||||
return _titleLabelInternal;
|
||||
}
|
||||
|
||||
#pragma mark - Expose
|
||||
|
||||
- (UILabel *)titleLabel { return self.titleLabelInternal; }
|
||||
- (UIImageView *)iconView { return self.iconViewInternal; }
|
||||
|
||||
@end
|
||||
|
||||
30
CustomKeyboard/View/KBFunctionView.h
Normal file
30
CustomKeyboard/View/KBFunctionView.h
Normal file
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// KBFunctionView.h
|
||||
// CustomKeyboard
|
||||
//
|
||||
// Created by Mac on 2025/10/28.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
@class KBFunctionBarView, KBFunctionPasteView;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// 整个功能面板视图:顶部Bar + 粘贴区 + 标签列表 + 右侧操作按钮
|
||||
@interface KBFunctionView : UIView
|
||||
|
||||
@property (nonatomic, strong, readonly) UICollectionView *collectionView; // 话术分类/标签列表
|
||||
@property (nonatomic, strong, readonly) NSArray<NSString *> *items; // 简单数据源(演示用)
|
||||
|
||||
// 子视图暴露,便于外部接入事件
|
||||
@property (nonatomic, strong, readonly) KBFunctionBarView *barView;
|
||||
@property (nonatomic, strong, readonly) KBFunctionPasteView *pasteView;
|
||||
|
||||
@property (nonatomic, strong, readonly) UIButton *pasteButton; // 右侧-粘贴
|
||||
@property (nonatomic, strong, readonly) UIButton *deleteButton; // 右侧-删除
|
||||
@property (nonatomic, strong, readonly) UIButton *clearButton; // 右侧-清空
|
||||
@property (nonatomic, strong, readonly) UIButton *sendButton; // 右侧-发送
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
263
CustomKeyboard/View/KBFunctionView.m
Normal file
263
CustomKeyboard/View/KBFunctionView.m
Normal file
@@ -0,0 +1,263 @@
|
||||
//
|
||||
// KBFunctionView.m
|
||||
// CustomKeyboard
|
||||
//
|
||||
// Created by Mac on 2025/10/28.
|
||||
//
|
||||
|
||||
#import "KBFunctionView.h"
|
||||
#import "KBFunctionBarView.h"
|
||||
#import "KBFunctionPasteView.h"
|
||||
#import "KBFunctionTagCell.h"
|
||||
#import "Masonry.h"
|
||||
|
||||
static NSString * const kKBFunctionTagCellId = @"KBFunctionTagCellId";
|
||||
|
||||
@interface KBFunctionView () <UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
|
||||
// UI
|
||||
@property (nonatomic, strong) KBFunctionBarView *barViewInternal;
|
||||
@property (nonatomic, strong) KBFunctionPasteView *pasteViewInternal;
|
||||
@property (nonatomic, strong) UICollectionView *collectionViewInternal;
|
||||
@property (nonatomic, strong) UIView *rightButtonContainer; // 右侧竖排按钮容器
|
||||
@property (nonatomic, strong) UIButton *pasteButtonInternal;
|
||||
@property (nonatomic, strong) UIButton *deleteButtonInternal;
|
||||
@property (nonatomic, strong) UIButton *clearButtonInternal;
|
||||
@property (nonatomic, strong) UIButton *sendButtonInternal;
|
||||
|
||||
// Data
|
||||
@property (nonatomic, strong) NSArray<NSString *> *itemsInternal;
|
||||
@end
|
||||
|
||||
@implementation KBFunctionView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
// 整体绿色背景(接近截图效果,项目可自行替换素材)
|
||||
self.backgroundColor = [UIColor colorWithRed:0.77 green:0.93 blue:0.82 alpha:1.0];
|
||||
|
||||
[self setupUI];
|
||||
[self reloadDemoData];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - UI
|
||||
|
||||
- (void)setupUI {
|
||||
// 1. 顶部 Bar
|
||||
[self addSubview:self.barViewInternal];
|
||||
[self.barViewInternal mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.right.equalTo(self);
|
||||
make.top.equalTo(self.mas_top).offset(6);
|
||||
make.height.mas_equalTo(48);
|
||||
}];
|
||||
|
||||
// 右侧竖排按钮容器
|
||||
[self addSubview:self.rightButtonContainer];
|
||||
[self.rightButtonContainer mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.equalTo(self.mas_right).offset(-12);
|
||||
make.top.equalTo(self.barViewInternal.mas_bottom).offset(8);
|
||||
make.bottom.equalTo(self.mas_bottom).offset(-10);
|
||||
make.width.mas_equalTo(72);
|
||||
}];
|
||||
|
||||
// 右侧四个按钮
|
||||
[self.rightButtonContainer addSubview:self.pasteButtonInternal];
|
||||
[self.rightButtonContainer addSubview:self.deleteButtonInternal];
|
||||
[self.rightButtonContainer addSubview:self.clearButtonInternal];
|
||||
[self.rightButtonContainer addSubview:self.sendButtonInternal];
|
||||
|
||||
// 竖向排布:粘贴、删除、清空为等高,发送略高
|
||||
CGFloat smallH = 44;
|
||||
CGFloat bigH = 56;
|
||||
CGFloat vSpace = 10;
|
||||
[self.pasteButtonInternal mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(self.rightButtonContainer.mas_top);
|
||||
make.left.right.equalTo(self.rightButtonContainer);
|
||||
make.height.mas_equalTo(smallH);
|
||||
}];
|
||||
[self.deleteButtonInternal mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(self.pasteButtonInternal.mas_bottom).offset(vSpace);
|
||||
make.left.right.equalTo(self.rightButtonContainer);
|
||||
make.height.equalTo(self.pasteButtonInternal);
|
||||
}];
|
||||
[self.clearButtonInternal mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(self.deleteButtonInternal.mas_bottom).offset(vSpace);
|
||||
make.left.right.equalTo(self.rightButtonContainer);
|
||||
make.height.equalTo(self.pasteButtonInternal);
|
||||
}];
|
||||
[self.sendButtonInternal mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(self.clearButtonInternal.mas_bottom).offset(vSpace);
|
||||
make.left.right.equalTo(self.rightButtonContainer);
|
||||
make.height.mas_equalTo(bigH);
|
||||
make.bottom.lessThanOrEqualTo(self.rightButtonContainer.mas_bottom); // 底部可伸缩
|
||||
}];
|
||||
|
||||
// 2. 粘贴区(位于右侧按钮左侧)
|
||||
[self addSubview:self.pasteViewInternal];
|
||||
[self.pasteViewInternal mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.mas_left).offset(12);
|
||||
make.right.equalTo(self.rightButtonContainer.mas_left).offset(-12);
|
||||
make.top.equalTo(self.barViewInternal.mas_bottom).offset(8);
|
||||
make.height.mas_equalTo(48);
|
||||
}];
|
||||
|
||||
// 3. CollectionView
|
||||
[self addSubview:self.collectionViewInternal];
|
||||
[self.collectionViewInternal mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.mas_left).offset(12);
|
||||
make.right.equalTo(self.rightButtonContainer.mas_left).offset(-12);
|
||||
make.top.equalTo(self.pasteViewInternal.mas_bottom).offset(10);
|
||||
make.bottom.equalTo(self.mas_bottom).offset(-10);
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Data
|
||||
|
||||
- (void)reloadDemoData {
|
||||
// 演示数据(可由外部替换)
|
||||
self.itemsInternal = @[@"高情商", @"暖味拉扯", @"风趣幽默", @"撩女生", @"社交惬匿", @"情场高手", @"一枚暖男", @"聊天搭子", @"表达爱意", @"更多话术"];
|
||||
[self.collectionViewInternal reloadData];
|
||||
}
|
||||
|
||||
#pragma mark - UICollectionView
|
||||
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||
return self.itemsInternal.count;
|
||||
}
|
||||
|
||||
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
KBFunctionTagCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kKBFunctionTagCellId forIndexPath:indexPath];
|
||||
cell.titleLabel.text = self.itemsInternal[indexPath.item];
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
// 三列等宽
|
||||
CGFloat totalW = collectionView.bounds.size.width;
|
||||
CGFloat space = 10.0;
|
||||
NSInteger columns = 3;
|
||||
CGFloat width = floor((totalW - space * (columns - 1)) / columns);
|
||||
return CGSizeMake(width, 48);
|
||||
}
|
||||
|
||||
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
|
||||
return 10.0;
|
||||
}
|
||||
|
||||
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
|
||||
return 12.0;
|
||||
}
|
||||
|
||||
#pragma mark - Button Actions
|
||||
|
||||
- (void)onTapPaste { NSLog(@"点击:粘贴"); }
|
||||
- (void)onTapDelete { NSLog(@"点击:删除"); }
|
||||
- (void)onTapClear { NSLog(@"点击:清空"); }
|
||||
- (void)onTapSend { NSLog(@"点击:发送"); }
|
||||
|
||||
#pragma mark - Lazy
|
||||
|
||||
- (KBFunctionBarView *)barViewInternal {
|
||||
if (!_barViewInternal) {
|
||||
_barViewInternal = [[KBFunctionBarView alloc] init];
|
||||
}
|
||||
return _barViewInternal;
|
||||
}
|
||||
|
||||
- (KBFunctionPasteView *)pasteViewInternal {
|
||||
if (!_pasteViewInternal) {
|
||||
_pasteViewInternal = [[KBFunctionPasteView alloc] init];
|
||||
}
|
||||
return _pasteViewInternal;
|
||||
}
|
||||
|
||||
- (UICollectionView *)collectionViewInternal {
|
||||
if (!_collectionViewInternal) {
|
||||
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
||||
layout.sectionInset = UIEdgeInsetsZero; // 外边距交由约束控制
|
||||
_collectionViewInternal = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
|
||||
_collectionViewInternal.backgroundColor = [UIColor clearColor];
|
||||
_collectionViewInternal.dataSource = self;
|
||||
_collectionViewInternal.delegate = self;
|
||||
[_collectionViewInternal registerClass:[KBFunctionTagCell class] forCellWithReuseIdentifier:kKBFunctionTagCellId];
|
||||
}
|
||||
return _collectionViewInternal;
|
||||
}
|
||||
|
||||
- (UIView *)rightButtonContainer {
|
||||
if (!_rightButtonContainer) {
|
||||
_rightButtonContainer = [[UIView alloc] init];
|
||||
_rightButtonContainer.backgroundColor = [UIColor clearColor];
|
||||
}
|
||||
return _rightButtonContainer;
|
||||
}
|
||||
|
||||
- (UIButton *)buildRightButtonWithTitle:(NSString *)title color:(UIColor *)color {
|
||||
UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem];
|
||||
btn.backgroundColor = color;
|
||||
btn.layer.cornerRadius = 12.0;
|
||||
btn.layer.masksToBounds = YES;
|
||||
btn.titleLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightSemibold];
|
||||
[btn setTitle:title forState:UIControlStateNormal];
|
||||
[btn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
|
||||
return btn;
|
||||
}
|
||||
|
||||
- (UIButton *)pasteButtonInternal {
|
||||
if (!_pasteButtonInternal) {
|
||||
_pasteButtonInternal = [self buildRightButtonWithTitle:@"粘贴" color:[UIColor colorWithRed:0.13 green:0.73 blue:0.60 alpha:1.0]];
|
||||
[_pasteButtonInternal addTarget:self action:@selector(onTapPaste) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _pasteButtonInternal;
|
||||
}
|
||||
|
||||
- (UIButton *)deleteButtonInternal {
|
||||
if (!_deleteButtonInternal) {
|
||||
// 浅灰底深色文字,更接近截图里“删除”样式
|
||||
_deleteButtonInternal = [UIButton buttonWithType:UIButtonTypeSystem];
|
||||
_deleteButtonInternal.backgroundColor = [UIColor colorWithWhite:0.92 alpha:1.0];
|
||||
_deleteButtonInternal.layer.cornerRadius = 12.0;
|
||||
_deleteButtonInternal.layer.masksToBounds = YES;
|
||||
_deleteButtonInternal.titleLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightSemibold];
|
||||
[_deleteButtonInternal setTitle:@"删除" forState:UIControlStateNormal];
|
||||
[_deleteButtonInternal setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
|
||||
[_deleteButtonInternal addTarget:self action:@selector(onTapDelete) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _deleteButtonInternal;
|
||||
}
|
||||
|
||||
- (UIButton *)clearButtonInternal {
|
||||
if (!_clearButtonInternal) {
|
||||
_clearButtonInternal = [UIButton buttonWithType:UIButtonTypeSystem];
|
||||
_clearButtonInternal.backgroundColor = [UIColor colorWithWhite:0.92 alpha:1.0];
|
||||
_clearButtonInternal.layer.cornerRadius = 12.0;
|
||||
_clearButtonInternal.layer.masksToBounds = YES;
|
||||
_clearButtonInternal.titleLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightSemibold];
|
||||
[_clearButtonInternal setTitle:@"清空" forState:UIControlStateNormal];
|
||||
[_clearButtonInternal setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
|
||||
[_clearButtonInternal addTarget:self action:@selector(onTapClear) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _clearButtonInternal;
|
||||
}
|
||||
|
||||
- (UIButton *)sendButtonInternal {
|
||||
if (!_sendButtonInternal) {
|
||||
_sendButtonInternal = [self buildRightButtonWithTitle:@"发送" color:[UIColor colorWithRed:0.13 green:0.73 blue:0.60 alpha:1.0]];
|
||||
[_sendButtonInternal addTarget:self action:@selector(onTapSend) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _sendButtonInternal;
|
||||
}
|
||||
|
||||
#pragma mark - Expose
|
||||
|
||||
- (UICollectionView *)collectionView { return self.collectionViewInternal; }
|
||||
- (NSArray<NSString *> *)items { return self.itemsInternal; }
|
||||
- (KBFunctionBarView *)barView { return self.barViewInternal; }
|
||||
- (KBFunctionPasteView *)pasteView { return self.pasteViewInternal; }
|
||||
- (UIButton *)pasteButton { return self.pasteButtonInternal; }
|
||||
- (UIButton *)deleteButton { return self.deleteButtonInternal; }
|
||||
- (UIButton *)clearButton { return self.clearButtonInternal; }
|
||||
- (UIButton *)sendButton { return self.sendButtonInternal; }
|
||||
|
||||
@end
|
||||
@@ -2,7 +2,7 @@
|
||||
// KBToolBar.h
|
||||
// CustomKeyboard
|
||||
//
|
||||
// Created by Mac on 2025/10/27.
|
||||
// Created by Mac on 2025/10/28.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// KBToolBar.m
|
||||
// CustomKeyboard
|
||||
//
|
||||
// Created by Mac on 2025/10/27.
|
||||
// Created by Mac on 2025/10/28.
|
||||
//
|
||||
|
||||
#import "KBToolBar.h"
|
||||
|
||||
@@ -32,6 +32,10 @@
|
||||
04FC95672EB0546C007BD342 /* KBKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC95652EB0546C007BD342 /* KBKey.m */; };
|
||||
04FC956A2EB05497007BD342 /* KBKeyButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC95692EB05497007BD342 /* KBKeyButton.m */; };
|
||||
04FC956D2EB054B7007BD342 /* KBKeyboardView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC956C2EB054B7007BD342 /* KBKeyboardView.m */; };
|
||||
04FC95702EB09516007BD342 /* KBFunctionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC956F2EB09516007BD342 /* KBFunctionView.m */; };
|
||||
04FC95732EB09570007BD342 /* KBFunctionBarView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC95722EB09570007BD342 /* KBFunctionBarView.m */; };
|
||||
04FC95762EB095DE007BD342 /* KBFunctionPasteView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC95752EB095DE007BD342 /* KBFunctionPasteView.m */; };
|
||||
A1B2C3D42EB0A0A100000001 /* KBFunctionTagCell.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3D32EB0A0A100000001 /* KBFunctionTagCell.m */; };
|
||||
7A36414DFDA5BEC9B7D2E318 /* Pods_CustomKeyboard.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2C1092FB2B452F95B15D4263 /* Pods_CustomKeyboard.framework */; };
|
||||
ECC9EE02174D86E8D792472F /* Pods_keyBoard.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 967065BB5230E43F293B3AF9 /* Pods_keyBoard.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
@@ -113,6 +117,14 @@
|
||||
04FC95692EB05497007BD342 /* KBKeyButton.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBKeyButton.m; sourceTree = "<group>"; };
|
||||
04FC956B2EB054B7007BD342 /* KBKeyboardView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBKeyboardView.h; sourceTree = "<group>"; };
|
||||
04FC956C2EB054B7007BD342 /* KBKeyboardView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBKeyboardView.m; sourceTree = "<group>"; };
|
||||
04FC956E2EB09516007BD342 /* KBFunctionView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBFunctionView.h; sourceTree = "<group>"; };
|
||||
04FC956F2EB09516007BD342 /* KBFunctionView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBFunctionView.m; sourceTree = "<group>"; };
|
||||
04FC95712EB09570007BD342 /* KBFunctionBarView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBFunctionBarView.h; sourceTree = "<group>"; };
|
||||
04FC95722EB09570007BD342 /* KBFunctionBarView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBFunctionBarView.m; sourceTree = "<group>"; };
|
||||
04FC95742EB095DE007BD342 /* KBFunctionPasteView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBFunctionPasteView.h; sourceTree = "<group>"; };
|
||||
04FC95752EB095DE007BD342 /* KBFunctionPasteView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBFunctionPasteView.m; sourceTree = "<group>"; };
|
||||
A1B2C3D22EB0A0A100000001 /* KBFunctionTagCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBFunctionTagCell.h; sourceTree = "<group>"; };
|
||||
A1B2C3D32EB0A0A100000001 /* KBFunctionTagCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBFunctionTagCell.m; sourceTree = "<group>"; };
|
||||
2C1092FB2B452F95B15D4263 /* Pods_CustomKeyboard.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_CustomKeyboard.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
51FE7C4C42C2255B3C1C4128 /* Pods-keyBoard.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-keyBoard.release.xcconfig"; path = "Target Support Files/Pods-keyBoard/Pods-keyBoard.release.xcconfig"; sourceTree = "<group>"; };
|
||||
727EC7532EAF848B00B36487 /* keyBoard.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = keyBoard.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@@ -183,6 +195,14 @@
|
||||
04FC95692EB05497007BD342 /* KBKeyButton.m */,
|
||||
04FC956B2EB054B7007BD342 /* KBKeyboardView.h */,
|
||||
04FC956C2EB054B7007BD342 /* KBKeyboardView.m */,
|
||||
04FC956E2EB09516007BD342 /* KBFunctionView.h */,
|
||||
04FC956F2EB09516007BD342 /* KBFunctionView.m */,
|
||||
04FC95712EB09570007BD342 /* KBFunctionBarView.h */,
|
||||
04FC95722EB09570007BD342 /* KBFunctionBarView.m */,
|
||||
04FC95742EB095DE007BD342 /* KBFunctionPasteView.h */,
|
||||
04FC95752EB095DE007BD342 /* KBFunctionPasteView.m */,
|
||||
A1B2C3D22EB0A0A100000001 /* KBFunctionTagCell.h */,
|
||||
A1B2C3D32EB0A0A100000001 /* KBFunctionTagCell.m */,
|
||||
);
|
||||
path = View;
|
||||
sourceTree = "<group>";
|
||||
@@ -420,10 +440,14 @@
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-keyBoard/Pods-keyBoard-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-keyBoard/Pods-keyBoard-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-keyBoard/Pods-keyBoard-frameworks.sh\"\n";
|
||||
@@ -459,7 +483,10 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
04C6EADD2EAF8CEB0089C901 /* KBToolBar.m in Sources */,
|
||||
04FC95732EB09570007BD342 /* KBFunctionBarView.m in Sources */,
|
||||
04C6EAD82EAF870B0089C901 /* KeyboardViewController.m in Sources */,
|
||||
04FC95762EB095DE007BD342 /* KBFunctionPasteView.m in Sources */,
|
||||
A1B2C3D42EB0A0A100000001 /* KBFunctionTagCell.m in Sources */,
|
||||
04FC956A2EB05497007BD342 /* KBKeyButton.m in Sources */,
|
||||
04FC95582EAFAF51007BD342 /* MASConstraintMaker.m in Sources */,
|
||||
04FC95592EAFAF51007BD342 /* MASViewConstraint.m in Sources */,
|
||||
@@ -467,6 +494,7 @@
|
||||
04FC955B2EAFAF51007BD342 /* NSArray+MASAdditions.m in Sources */,
|
||||
04FC955C2EAFAF51007BD342 /* View+MASAdditions.m in Sources */,
|
||||
04FC955D2EAFAF51007BD342 /* MASCompositeConstraint.m in Sources */,
|
||||
04FC95702EB09516007BD342 /* KBFunctionView.m in Sources */,
|
||||
04FC956D2EB054B7007BD342 /* KBKeyboardView.m in Sources */,
|
||||
04FC95672EB0546C007BD342 /* KBKey.m in Sources */,
|
||||
04FC955E2EAFAF51007BD342 /* MASConstraint.m in Sources */,
|
||||
|
||||
Reference in New Issue
Block a user