添加语音websocket等,还没测试
This commit is contained in:
248
keyBoard/Class/AiTalk/V/KBAiRecordButton.m
Normal file
248
keyBoard/Class/AiTalk/V/KBAiRecordButton.m
Normal file
@@ -0,0 +1,248 @@
|
||||
//
|
||||
// KBAiRecordButton.m
|
||||
// keyBoard
|
||||
//
|
||||
// Created by Mac on 2026/1/15.
|
||||
//
|
||||
|
||||
#import "KBAiRecordButton.h"
|
||||
#import "KBAiWaveformView.h"
|
||||
|
||||
@interface KBAiRecordButton ()
|
||||
|
||||
@property(nonatomic, strong) UIView *backgroundView;
|
||||
@property(nonatomic, strong) UILabel *titleLabel;
|
||||
@property(nonatomic, strong) KBAiWaveformView *waveformView;
|
||||
@property(nonatomic, strong) UIImageView *micIconView;
|
||||
@property(nonatomic, assign) BOOL isPressing;
|
||||
|
||||
@end
|
||||
|
||||
@implementation KBAiRecordButton
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self setup];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder {
|
||||
self = [super initWithCoder:coder];
|
||||
if (self) {
|
||||
[self setup];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setup {
|
||||
_state = KBAiRecordButtonStateNormal;
|
||||
_normalTitle = @"按住说话";
|
||||
_recordingTitle = @"松开结束";
|
||||
_tintColor = [UIColor systemBlueColor];
|
||||
|
||||
// 背景视图
|
||||
self.backgroundView = [[UIView alloc] init];
|
||||
self.backgroundView.backgroundColor = [UIColor systemGray6Color];
|
||||
self.backgroundView.layer.cornerRadius = 25;
|
||||
self.backgroundView.layer.masksToBounds = YES;
|
||||
self.backgroundView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
[self addSubview:self.backgroundView];
|
||||
|
||||
// 麦克风图标
|
||||
self.micIconView = [[UIImageView alloc] init];
|
||||
self.micIconView.image = [UIImage systemImageNamed:@"mic.fill"];
|
||||
self.micIconView.tintColor = self.tintColor;
|
||||
self.micIconView.contentMode = UIViewContentModeScaleAspectFit;
|
||||
self.micIconView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
[self.backgroundView addSubview:self.micIconView];
|
||||
|
||||
// 标题标签
|
||||
self.titleLabel = [[UILabel alloc] init];
|
||||
self.titleLabel.text = self.normalTitle;
|
||||
self.titleLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightMedium];
|
||||
self.titleLabel.textColor = [UIColor labelColor];
|
||||
self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
[self.backgroundView addSubview:self.titleLabel];
|
||||
|
||||
// 波形视图(录音时显示)
|
||||
self.waveformView = [[KBAiWaveformView alloc] init];
|
||||
self.waveformView.waveColor = self.tintColor;
|
||||
self.waveformView.alpha = 0;
|
||||
self.waveformView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
[self.backgroundView addSubview:self.waveformView];
|
||||
|
||||
// 布局约束
|
||||
[NSLayoutConstraint activateConstraints:@[
|
||||
[self.backgroundView.topAnchor constraintEqualToAnchor:self.topAnchor],
|
||||
[self.backgroundView.bottomAnchor
|
||||
constraintEqualToAnchor:self.bottomAnchor],
|
||||
[self.backgroundView.leadingAnchor
|
||||
constraintEqualToAnchor:self.leadingAnchor],
|
||||
[self.backgroundView.trailingAnchor
|
||||
constraintEqualToAnchor:self.trailingAnchor],
|
||||
|
||||
[self.micIconView.leadingAnchor
|
||||
constraintEqualToAnchor:self.backgroundView.leadingAnchor
|
||||
constant:20],
|
||||
[self.micIconView.centerYAnchor
|
||||
constraintEqualToAnchor:self.backgroundView.centerYAnchor],
|
||||
[self.micIconView.widthAnchor constraintEqualToConstant:24],
|
||||
[self.micIconView.heightAnchor constraintEqualToConstant:24],
|
||||
|
||||
[self.titleLabel.leadingAnchor
|
||||
constraintEqualToAnchor:self.micIconView.trailingAnchor
|
||||
constant:12],
|
||||
[self.titleLabel.centerYAnchor
|
||||
constraintEqualToAnchor:self.backgroundView.centerYAnchor],
|
||||
|
||||
[self.waveformView.trailingAnchor
|
||||
constraintEqualToAnchor:self.backgroundView.trailingAnchor
|
||||
constant:-20],
|
||||
[self.waveformView.centerYAnchor
|
||||
constraintEqualToAnchor:self.backgroundView.centerYAnchor],
|
||||
[self.waveformView.widthAnchor constraintEqualToConstant:60],
|
||||
[self.waveformView.heightAnchor constraintEqualToConstant:30],
|
||||
]];
|
||||
|
||||
// 添加手势
|
||||
UILongPressGestureRecognizer *longPress =
|
||||
[[UILongPressGestureRecognizer alloc]
|
||||
initWithTarget:self
|
||||
action:@selector(handleLongPress:)];
|
||||
longPress.minimumPressDuration = 0.05;
|
||||
[self addGestureRecognizer:longPress];
|
||||
}
|
||||
|
||||
#pragma mark - Setters
|
||||
|
||||
- (void)setState:(KBAiRecordButtonState)state {
|
||||
if (_state == state)
|
||||
return;
|
||||
_state = state;
|
||||
|
||||
[self updateAppearance];
|
||||
}
|
||||
|
||||
- (void)setTintColor:(UIColor *)tintColor {
|
||||
_tintColor = tintColor;
|
||||
self.micIconView.tintColor = tintColor;
|
||||
self.waveformView.waveColor = tintColor;
|
||||
}
|
||||
|
||||
#pragma mark - Public Methods
|
||||
|
||||
- (void)updateVolumeRMS:(float)rms {
|
||||
[self.waveformView updateWithRMS:rms];
|
||||
}
|
||||
|
||||
#pragma mark - Private Methods
|
||||
|
||||
- (void)updateAppearance {
|
||||
switch (self.state) {
|
||||
case KBAiRecordButtonStateNormal:
|
||||
self.titleLabel.text = self.normalTitle;
|
||||
self.backgroundView.backgroundColor = [UIColor systemGray6Color];
|
||||
self.micIconView.alpha = 1;
|
||||
self.waveformView.alpha = 0;
|
||||
[self.waveformView stopAnimation];
|
||||
break;
|
||||
|
||||
case KBAiRecordButtonStateRecording:
|
||||
self.titleLabel.text = self.recordingTitle;
|
||||
self.backgroundView.backgroundColor =
|
||||
[self.tintColor colorWithAlphaComponent:0.15];
|
||||
self.micIconView.alpha = 1;
|
||||
self.waveformView.alpha = 1;
|
||||
[self.waveformView startIdleAnimation];
|
||||
break;
|
||||
|
||||
case KBAiRecordButtonStateDisabled:
|
||||
self.titleLabel.text = self.normalTitle;
|
||||
self.backgroundView.backgroundColor = [UIColor systemGray5Color];
|
||||
self.alpha = 0.5;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)handleLongPress:(UILongPressGestureRecognizer *)gesture {
|
||||
if (self.state == KBAiRecordButtonStateDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
CGPoint location = [gesture locationInView:self];
|
||||
BOOL isInside = CGRectContainsPoint(self.bounds, location);
|
||||
|
||||
switch (gesture.state) {
|
||||
case UIGestureRecognizerStateBegan:
|
||||
self.isPressing = YES;
|
||||
[self animateScale:0.95];
|
||||
self.state = KBAiRecordButtonStateRecording;
|
||||
|
||||
if ([self.delegate
|
||||
respondsToSelector:@selector(recordButtonDidBeginPress:)]) {
|
||||
[self.delegate recordButtonDidBeginPress:self];
|
||||
}
|
||||
break;
|
||||
|
||||
case UIGestureRecognizerStateChanged:
|
||||
if (!isInside && self.isPressing) {
|
||||
// 手指滑出
|
||||
[self animateScale:1.0];
|
||||
} else if (isInside && self.isPressing) {
|
||||
// 手指滑回
|
||||
[self animateScale:0.95];
|
||||
}
|
||||
break;
|
||||
|
||||
case UIGestureRecognizerStateEnded:
|
||||
if (self.isPressing) {
|
||||
self.isPressing = NO;
|
||||
[self animateScale:1.0];
|
||||
self.state = KBAiRecordButtonStateNormal;
|
||||
[self.waveformView reset];
|
||||
|
||||
if (isInside) {
|
||||
if ([self.delegate
|
||||
respondsToSelector:@selector(recordButtonDidEndPress:)]) {
|
||||
[self.delegate recordButtonDidEndPress:self];
|
||||
}
|
||||
} else {
|
||||
if ([self.delegate
|
||||
respondsToSelector:@selector(recordButtonDidCancelPress:)]) {
|
||||
[self.delegate recordButtonDidCancelPress:self];
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case UIGestureRecognizerStateCancelled:
|
||||
case UIGestureRecognizerStateFailed:
|
||||
if (self.isPressing) {
|
||||
self.isPressing = NO;
|
||||
[self animateScale:1.0];
|
||||
self.state = KBAiRecordButtonStateNormal;
|
||||
[self.waveformView reset];
|
||||
|
||||
if ([self.delegate
|
||||
respondsToSelector:@selector(recordButtonDidCancelPress:)]) {
|
||||
[self.delegate recordButtonDidCancelPress:self];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)animateScale:(CGFloat)scale {
|
||||
[UIView animateWithDuration:0.15
|
||||
animations:^{
|
||||
self.backgroundView.transform =
|
||||
CGAffineTransformMakeScale(scale, scale);
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user