2026-01-26 18:17:02 +08:00
|
|
|
|
# KBVoiceInputBar 使用说明
|
|
|
|
|
|
|
|
|
|
|
|
## 📦 组件概述
|
|
|
|
|
|
|
|
|
|
|
|
`KBVoiceInputBar` 是一个封装好的底部语音输入栏组件,包含:
|
|
|
|
|
|
- ✅ 毛玻璃背景(带渐变 mask)
|
|
|
|
|
|
- ✅ 状态标签(显示当前状态)
|
|
|
|
|
|
- ✅ 录音按钮(支持长按、波形动画)
|
|
|
|
|
|
- ✅ 代理回调(开始/结束/取消录音)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 🎨 UI 结构
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
┌─────────────────────────────┐
|
|
|
|
|
|
│ 毛玻璃背景(渐变透明) │
|
|
|
|
|
|
│ ┌─────────────────────┐ │
|
|
|
|
|
|
│ │ 状态标签 │ │
|
|
|
|
|
|
│ │ "按住按钮开始对话" │ │
|
|
|
|
|
|
│ └─────────────────────┘ │
|
|
|
|
|
|
│ ┌─────────────────────┐ │
|
|
|
|
|
|
│ │ 录音按钮 │ │
|
|
|
|
|
|
│ │ [按住说话] │ │
|
|
|
|
|
|
│ └─────────────────────┘ │
|
|
|
|
|
|
└─────────────────────────────┘
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 📝 使用方式
|
|
|
|
|
|
|
|
|
|
|
|
### 1. 导入头文件
|
|
|
|
|
|
|
|
|
|
|
|
```objc
|
|
|
|
|
|
#import "KBVoiceInputBar.h"
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 2. 在 VC 中声明属性
|
|
|
|
|
|
|
|
|
|
|
|
```objc
|
|
|
|
|
|
@interface YourViewController () <KBVoiceInputBarDelegate>
|
|
|
|
|
|
@property (nonatomic, strong) KBVoiceInputBar *voiceInputBar;
|
|
|
|
|
|
@end
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 3. 初始化和布局
|
|
|
|
|
|
|
|
|
|
|
|
```objc
|
|
|
|
|
|
- (void)setupUI {
|
|
|
|
|
|
// 创建语音输入栏
|
|
|
|
|
|
self.voiceInputBar = [[KBVoiceInputBar alloc] init];
|
|
|
|
|
|
self.voiceInputBar.delegate = self;
|
|
|
|
|
|
self.voiceInputBar.statusText = @"按住按钮开始对话";
|
|
|
|
|
|
|
|
|
|
|
|
[self.view addSubview:self.voiceInputBar];
|
|
|
|
|
|
[self.voiceInputBar mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
|
make.left.right.equalTo(self.view);
|
|
|
|
|
|
make.bottom.equalTo(self.view);
|
|
|
|
|
|
make.height.mas_equalTo(150); // 根据实际需要调整
|
|
|
|
|
|
}];
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 4. 实现代理方法
|
|
|
|
|
|
|
|
|
|
|
|
```objc
|
|
|
|
|
|
#pragma mark - KBVoiceInputBarDelegate
|
|
|
|
|
|
|
|
|
|
|
|
- (void)voiceInputBarDidBeginRecording:(KBVoiceInputBar *)inputBar {
|
|
|
|
|
|
NSLog(@"开始录音");
|
|
|
|
|
|
inputBar.statusText = @"正在聆听...";
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: 开始录音逻辑
|
|
|
|
|
|
// 1. 检查登录状态
|
|
|
|
|
|
// 2. 连接语音识别服务
|
|
|
|
|
|
// 3. 开始录音
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (void)voiceInputBarDidEndRecording:(KBVoiceInputBar *)inputBar {
|
|
|
|
|
|
NSLog(@"结束录音");
|
|
|
|
|
|
inputBar.statusText = @"正在识别...";
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: 结束录音逻辑
|
|
|
|
|
|
// 1. 停止录音
|
|
|
|
|
|
// 2. 发送音频数据
|
|
|
|
|
|
// 3. 等待识别结果
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (void)voiceInputBarDidCancelRecording:(KBVoiceInputBar *)inputBar {
|
|
|
|
|
|
NSLog(@"取消录音");
|
|
|
|
|
|
inputBar.statusText = @"已取消";
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: 取消录音逻辑
|
|
|
|
|
|
// 1. 停止录音
|
|
|
|
|
|
// 2. 清理资源
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 🔧 API 说明
|
|
|
|
|
|
|
|
|
|
|
|
### 属性
|
|
|
|
|
|
|
|
|
|
|
|
| 属性 | 类型 | 说明 |
|
|
|
|
|
|
|------|------|------|
|
|
|
|
|
|
| `delegate` | `id<KBVoiceInputBarDelegate>` | 代理对象 |
|
|
|
|
|
|
| `statusText` | `NSString *` | 状态文本(显示在按钮上方) |
|
|
|
|
|
|
| `enabled` | `BOOL` | 是否启用(禁用时按钮不可点击) |
|
|
|
|
|
|
|
|
|
|
|
|
### 方法
|
|
|
|
|
|
|
|
|
|
|
|
| 方法 | 说明 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| `- (void)updateVolumeRMS:(float)rms` | 更新音量(用于波形动画) |
|
|
|
|
|
|
| `- (void)setRecording:(BOOL)recording` | 设置录音状态 |
|
|
|
|
|
|
|
|
|
|
|
|
### 代理方法
|
|
|
|
|
|
|
|
|
|
|
|
| 方法 | 说明 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| `- (void)voiceInputBarDidBeginRecording:` | 开始录音 |
|
|
|
|
|
|
| `- (void)voiceInputBarDidEndRecording:` | 结束录音 |
|
|
|
|
|
|
| `- (void)voiceInputBarDidCancelRecording:` | 取消录音 |
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 💡 使用示例
|
|
|
|
|
|
|
|
|
|
|
|
### 示例 1:更新状态文本
|
|
|
|
|
|
|
|
|
|
|
|
```objc
|
|
|
|
|
|
// 开始录音
|
|
|
|
|
|
self.voiceInputBar.statusText = @"正在聆听...";
|
|
|
|
|
|
|
|
|
|
|
|
// 识别中
|
|
|
|
|
|
self.voiceInputBar.statusText = @"正在识别...";
|
|
|
|
|
|
|
|
|
|
|
|
// AI 思考中
|
|
|
|
|
|
self.voiceInputBar.statusText = @"AI 正在思考...";
|
|
|
|
|
|
|
|
|
|
|
|
// 完成
|
|
|
|
|
|
self.voiceInputBar.statusText = @"完成";
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 示例 2:更新音量波形
|
|
|
|
|
|
|
|
|
|
|
|
```objc
|
|
|
|
|
|
// 在录音过程中,定时更新音量
|
|
|
|
|
|
- (void)onVolumeUpdate:(float)rms {
|
|
|
|
|
|
[self.voiceInputBar updateVolumeRMS:rms];
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 示例 3:禁用/启用按钮
|
|
|
|
|
|
|
|
|
|
|
|
```objc
|
|
|
|
|
|
// 禁用(比如未登录时)
|
|
|
|
|
|
self.voiceInputBar.enabled = NO;
|
|
|
|
|
|
|
|
|
|
|
|
// 启用
|
|
|
|
|
|
self.voiceInputBar.enabled = YES;
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 示例 4:手动设置录音状态
|
|
|
|
|
|
|
|
|
|
|
|
```objc
|
|
|
|
|
|
// 开始录音
|
|
|
|
|
|
[self.voiceInputBar setRecording:YES];
|
|
|
|
|
|
|
|
|
|
|
|
// 结束录音
|
|
|
|
|
|
[self.voiceInputBar setRecording:NO];
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-03-08 21:29:10 +08:00
|
|
|
|
## 🎯 完整示例(桥接录音事件)
|
2026-01-26 18:17:02 +08:00
|
|
|
|
|
|
|
|
|
|
```objc
|
|
|
|
|
|
#import "YourViewController.h"
|
|
|
|
|
|
#import "KBVoiceInputBar.h"
|
2026-03-08 21:29:10 +08:00
|
|
|
|
#import "KBVoiceToTextManager.h"
|
|
|
|
|
|
#import "KBVoiceRecordManager.h"
|
2026-01-26 18:17:02 +08:00
|
|
|
|
|
2026-03-08 21:29:10 +08:00
|
|
|
|
@interface YourViewController () <KBVoiceToTextManagerDelegate, KBVoiceRecordManagerDelegate>
|
2026-01-26 18:17:02 +08:00
|
|
|
|
@property (nonatomic, strong) KBVoiceInputBar *voiceInputBar;
|
2026-03-08 21:29:10 +08:00
|
|
|
|
@property (nonatomic, strong) KBVoiceToTextManager *voiceToTextManager;
|
|
|
|
|
|
@property (nonatomic, strong) KBVoiceRecordManager *voiceRecordManager;
|
2026-01-26 18:17:02 +08:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
@implementation YourViewController
|
|
|
|
|
|
|
|
|
|
|
|
- (void)viewDidLoad {
|
|
|
|
|
|
[super viewDidLoad];
|
|
|
|
|
|
[self setupUI];
|
2026-03-08 21:29:10 +08:00
|
|
|
|
[self setupVoiceManagers];
|
2026-01-26 18:17:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (void)setupUI {
|
|
|
|
|
|
self.voiceInputBar = [[KBVoiceInputBar alloc] init];
|
|
|
|
|
|
self.voiceInputBar.delegate = self;
|
|
|
|
|
|
[self.view addSubview:self.voiceInputBar];
|
|
|
|
|
|
[self.voiceInputBar mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
|
make.left.right.bottom.equalTo(self.view);
|
|
|
|
|
|
make.height.mas_equalTo(150);
|
|
|
|
|
|
}];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-08 21:29:10 +08:00
|
|
|
|
- (void)setupVoiceManagers {
|
|
|
|
|
|
self.voiceToTextManager = [[KBVoiceToTextManager alloc] initWithInputBar:self.voiceInputBar];
|
|
|
|
|
|
self.voiceToTextManager.delegate = self;
|
|
|
|
|
|
|
|
|
|
|
|
self.voiceRecordManager = [[KBVoiceRecordManager alloc] init];
|
|
|
|
|
|
self.voiceRecordManager.delegate = self;
|
2026-01-26 18:17:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-08 21:29:10 +08:00
|
|
|
|
#pragma mark - KBVoiceToTextManagerDelegate
|
2026-01-26 18:17:02 +08:00
|
|
|
|
|
2026-03-08 21:29:10 +08:00
|
|
|
|
- (void)voiceToTextManagerDidBeginRecording:(KBVoiceToTextManager *)manager {
|
|
|
|
|
|
[self.voiceRecordManager startRecording];
|
2026-01-26 18:17:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-08 21:29:10 +08:00
|
|
|
|
- (void)voiceToTextManagerDidEndRecording:(KBVoiceToTextManager *)manager {
|
|
|
|
|
|
[self.voiceRecordManager stopRecording];
|
2026-01-26 18:17:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-08 21:29:10 +08:00
|
|
|
|
- (void)voiceToTextManagerDidCancelRecording:(KBVoiceToTextManager *)manager {
|
|
|
|
|
|
[self.voiceRecordManager cancelRecording];
|
2026-01-26 18:17:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-08 21:29:10 +08:00
|
|
|
|
#pragma mark - KBVoiceRecordManagerDelegate
|
2026-01-26 18:17:02 +08:00
|
|
|
|
|
2026-03-08 21:29:10 +08:00
|
|
|
|
- (void)voiceRecordManager:(KBVoiceRecordManager *)manager
|
|
|
|
|
|
didFinishRecordingAtURL:(NSURL *)fileURL
|
|
|
|
|
|
duration:(NSTimeInterval)duration {
|
|
|
|
|
|
NSLog(@"录音完成:%@ %.2fs", fileURL, duration);
|
|
|
|
|
|
// TODO: 上传音频文件并处理转写结果
|
2026-01-26 18:17:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-08 21:29:10 +08:00
|
|
|
|
- (void)voiceRecordManagerDidRecordTooShort:(KBVoiceRecordManager *)manager {
|
|
|
|
|
|
NSLog(@"录音过短");
|
2026-01-26 18:17:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-08 21:29:10 +08:00
|
|
|
|
- (void)voiceRecordManager:(KBVoiceRecordManager *)manager
|
|
|
|
|
|
didFailWithError:(NSError *)error {
|
|
|
|
|
|
NSLog(@"录音失败:%@", error.localizedDescription);
|
2026-01-26 18:17:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 🎨 自定义样式
|
|
|
|
|
|
|
|
|
|
|
|
### 修改毛玻璃效果
|
|
|
|
|
|
|
|
|
|
|
|
```objc
|
|
|
|
|
|
// 在 KBVoiceInputBar.m 中修改
|
|
|
|
|
|
UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; // 改为深色
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 修改按钮样式
|
|
|
|
|
|
|
|
|
|
|
|
```objc
|
|
|
|
|
|
// 在 KBVoiceInputBar.m 的 recordButton 懒加载中修改
|
|
|
|
|
|
_recordButton.normalTitle = @"点击说话";
|
|
|
|
|
|
_recordButton.recordingTitle = @"正在录音...";
|
|
|
|
|
|
_recordButton.tintColor = [UIColor systemBlueColor];
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 修改高度
|
|
|
|
|
|
|
|
|
|
|
|
```objc
|
|
|
|
|
|
// 在布局时调整
|
|
|
|
|
|
[self.voiceInputBar mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
|
make.height.mas_equalTo(200); // 调整为 200
|
|
|
|
|
|
}];
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 📌 注意事项
|
|
|
|
|
|
|
|
|
|
|
|
1. **代理必须设置**:否则无法接收录音事件
|
|
|
|
|
|
2. **高度建议**:推荐高度 150-200,根据实际需要调整
|
|
|
|
|
|
3. **状态文本**:及时更新 `statusText` 提升用户体验
|
|
|
|
|
|
4. **音量更新**:定时调用 `updateVolumeRMS:` 显示波形动画
|
|
|
|
|
|
5. **禁用状态**:未登录或其他情况下记得禁用按钮
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 🚀 优势
|
|
|
|
|
|
|
|
|
|
|
|
1. ✅ **开箱即用**:无需关心内部实现细节
|
|
|
|
|
|
2. ✅ **高度封装**:毛玻璃背景、按钮、状态标签一体化
|
|
|
|
|
|
3. ✅ **易于集成**:只需实现 3 个代理方法
|
|
|
|
|
|
4. ✅ **样式统一**:与 KBAiMainVC 保持一致
|
|
|
|
|
|
5. ✅ **易于扩展**:可以轻松添加更多功能
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 📂 文件位置
|
|
|
|
|
|
|
|
|
|
|
|
- **头文件**:`keyBoard/Class/AiTalk/V/KBVoiceInputBar.h`
|
|
|
|
|
|
- **实现文件**:`keyBoard/Class/AiTalk/V/KBVoiceInputBar.m`
|
|
|
|
|
|
- **依赖**:`KBAiRecordButton`(已存在)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 🔗 相关组件
|
|
|
|
|
|
|
|
|
|
|
|
- `KBAiRecordButton`:录音按钮(支持长按、波形动画)
|
2026-03-08 21:29:10 +08:00
|
|
|
|
- `KBVoiceToTextManager`:语音输入事件桥接层
|
|
|
|
|
|
- `KBVoiceRecordManager`:录音文件管理器
|
2026-01-26 18:17:02 +08:00
|
|
|
|
- `VoiceChatStreamingManager`:语音聊天管理器
|