// // KBKeyboardMaskView.m // keyBoard // // Created by Mac on 2025/11/27. // #import "KBKeyboardMaskView.h" @interface KBKeyboardMaskView () @property (nonatomic, strong) UIButton *backButton; @property (nonatomic, strong) FLAnimatedImageView *gifView; @property (nonatomic, strong) UIImageView *tipLabel; // 顶部提示图 @property (nonatomic, assign) CGFloat keyboardHeight; @end @implementation KBKeyboardMaskView static const CGFloat KGifViewH = (209); - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (!self) return nil; self.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.5]; self.userInteractionEnabled = YES; // 返回按钮 _backButton = [UIButton buttonWithType:UIButtonTypeCustom]; UIImage *backImg = [UIImage imageNamed:@"close_white2_icon"]; [_backButton setImage:backImg forState:UIControlStateNormal]; [self addSubview:_backButton]; [_backButton mas_makeConstraints:^(MASConstraintMaker *make) { make.left.equalTo(self).offset(9); make.top.equalTo(self.mas_safeAreaLayoutGuideTop).offset(4); make.width.height.mas_equalTo(40); }]; // GIF 区域 _gifView = [FLAnimatedImageView new]; _gifView.contentMode = UIViewContentModeScaleAspectFit; _gifView.clipsToBounds = YES; _gifView.layer.cornerRadius = 30; // _gifView.clipsToBounds = true; _gifView.layer.masksToBounds = true; [self addSubview:_gifView]; [_gifView mas_makeConstraints:^(MASConstraintMaker *make) { make.centerX.equalTo(self); make.width.mas_equalTo(KBFit(316)); make.height.mas_equalTo(KBFit(KGifViewH)); // 竖直方向不在这里约束,由 layoutSubviews 手动布局 }]; // 顶部提示图 _tipLabel = [UIImageView new]; _tipLabel.image = [UIImage imageNamed:@"mask_top_title"]; _tipLabel.contentMode = UIViewContentModeScaleAspectFit; [self addSubview:_tipLabel]; // 整个蒙层点击:激活输入框 UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTapMask:)]; [self addGestureRecognizer:tap]; // 加载 GIF 资源(占位名,可按需更换为实际文件名) NSString *gifPath = [[NSBundle mainBundle] pathForResource:@"kb_guide_keyboard" ofType:@"gif"]; if (gifPath.length > 0) { NSData *data = [NSData dataWithContentsOfFile:gifPath]; if (data.length > 0) { FLAnimatedImage *img = [FLAnimatedImage animatedImageWithGIFData:data]; _gifView.animatedImage = img; } } return self; } - (void)layoutSubviews { [super layoutSubviews]; // 根据键盘高度,保证 GIF 不被遮挡: // - 无键盘:居中显示; // - 有键盘:底部距离键盘上方 20pt,若空间不足则向上顶到顶部预留的 safe 区域。 CGFloat viewH = CGRectGetHeight(self.bounds); CGFloat gifH = KBFit(KGifViewH); CGFloat topMargin = 80.0; // 预留给返回按钮和标题等 CGFloat bottomMargin = 20.0; CGFloat y = 0; if (self.keyboardHeight <= 0) { // 无键盘:垂直居中 y = (viewH - gifH) * 0.5; if (y < topMargin) y = topMargin; } else { CGFloat maxBottom = viewH - self.keyboardHeight - bottomMargin; y = maxBottom - gifH; if (y < topMargin) y = topMargin; } CGRect gifFrame = self.gifView.frame; gifFrame.origin.y = y; self.gifView.frame = gifFrame; // 布局顶部提示图:底部距离 gifView 顶部 20pt,居中显示 CGFloat labelMaxWidth = CGRectGetWidth(self.bounds) - 40.0; // 左右各留 20 if (labelMaxWidth < 0) { labelMaxWidth = 0; } UIImage *tipImage = self.tipLabel.image; if (!tipImage) { return; } CGFloat imgW = tipImage.size.width; CGFloat imgH = tipImage.size.height; if (imgW <= 0 || imgH <= 0) { return; } CGFloat scale = 1.0; if (imgW > labelMaxWidth && labelMaxWidth > 0) { scale = labelMaxWidth / imgW; } CGFloat labelW = imgW * scale; CGFloat labelH = imgH * scale; CGFloat labelX = (CGRectGetWidth(self.bounds) - labelW) * 0.5; CGFloat labelBottom = CGRectGetMinY(self.gifView.frame) - 20.0; CGFloat labelY = labelBottom - labelH; self.tipLabel.frame = CGRectMake(labelX, labelY, labelW, labelH); } - (void)onTapMask:(UITapGestureRecognizer *)gr { CGPoint p = [gr locationInView:self]; // 如果点在返回按钮区域内,则不走 tapHandler(交由按钮自己的事件处理) if (CGRectContainsPoint(self.backButton.frame, p)) { return; } if (self.tapHandler) { self.tapHandler(); } } - (void)updateForKeyboardHeight:(CGFloat)kbHeight duration:(NSTimeInterval)duration curve:(UIViewAnimationOptions)curve { self.keyboardHeight = MAX(kbHeight, 0); // 触发布局刷新,以便在 layoutSubviews 里根据最新键盘高度重算 gifView 的 Y 值 [self setNeedsLayout]; [UIView animateWithDuration:duration delay:0 options:curve animations:^{ [self layoutIfNeeded]; } completion:nil]; } @end