Files
keyboard/keyBoard/Class/AiTalk/V/KBAiRecordButton.m

249 lines
7.3 KiB
Objective-C

//
// 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