Files
keyboard/CustomKeyboard/KeyboardViewControllerHelp/KeyboardViewController+UI.m
2026-03-09 17:34:08 +08:00

144 lines
4.6 KiB
Objective-C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//
// KeyboardViewController+UI.m
// CustomKeyboard
//
// Created by Codex on 2026/02/22.
//
#import "KeyboardViewController+Private.h"
#import "KBChatMessage.h"
#import "KBChatPanelView.h"
#import "KBFunctionView.h"
#import "KBKeyBoardMainView.h"
#import "KBKeyboardSubscriptionView.h"
#import "Masonry.h"
@implementation KeyboardViewController (UI)
- (void)setupUI {
self.view.translatesAutoresizingMaskIntoConstraints = NO;
// 按“短边”宽度等比缩放,横屏保持竖屏布局比例
CGFloat portraitWidth = [self kb_portraitWidth];
CGFloat keyboardHeight = [self kb_keyboardHeightForWidth:portraitWidth];
CGFloat keyboardBaseHeight = [self kb_keyboardBaseHeightForWidth:portraitWidth];
CGFloat screenWidth = CGRectGetWidth([UIScreen mainScreen].bounds);
// FIX: iOS 26 键盘闪烁问题
// iOS 26 在键盘滑入动画开始前,会对 self.view 做一次离屏预渲染快照(非实时 view
// 该快照会短暂显示在屏幕中间。如果此时 view 已有完整高度和内容,用户就会看到
// 键盘 UI 在屏幕中间闪现一帧,然后键盘才从底部正常滑入。
// 解决方案:初始高度设为 0让系统快照时无内容可渲染
// 在 viewWillAppear: 中恢复正确高度,此时系统已准备好滑入动画。
// iOS 18 及更早版本无此预渲染机制,不受影响)
NSLayoutConstraint *h = [self.view.heightAnchor constraintEqualToConstant:0];
NSLayoutConstraint *w =
[self.view.widthAnchor constraintEqualToConstant:screenWidth];
self.kb_heightConstraint = h;
self.kb_widthConstraint = w;
h.priority = UILayoutPriorityRequired;
w.priority = UILayoutPriorityRequired;
[NSLayoutConstraint activateConstraints:@[ h, w ]];
// 关闭 UIInputView 自适应(某些系统版本会尝试放大为全屏高度导致冲突)
if ([self.view isKindOfClass:[UIInputView class]]) {
UIInputView *iv = (UIInputView *)self.view;
if ([iv respondsToSelector:@selector(setAllowsSelfSizing:)]) {
iv.allowsSelfSizing = NO;
}
}
// 内容容器:横屏时保持竖屏宽度,居中显示
[self.view addSubview:self.contentView];
[self.contentView mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self.view);
make.bottom.equalTo(self.view);
self.contentWidthConstraint = make.width.mas_equalTo(portraitWidth);
self.contentHeightConstraint = make.height.mas_equalTo(keyboardHeight);
}];
// 背景图铺底(仅在内容容器内)
[self.contentView addSubview:self.bgImageView];
[self.bgImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.contentView);
}];
[self.contentView addSubview:self.keyBoardMainView];
[self.keyBoardMainView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.equalTo(self.contentView);
make.bottom.equalTo(self.contentView);
self.keyBoardMainHeightConstraint =
make.height.mas_equalTo(keyboardBaseHeight);
}];
// 初始隐藏,避免布局完成前闪烁
self.contentView.hidden = YES;
}
#pragma mark - Lazy
- (nullable KBFunctionView *)kb_functionViewIfCreated {
return _functionView;
}
- (UIView *)contentView {
if (!_contentView) {
_contentView = [[UIView alloc] init];
_contentView.backgroundColor = [UIColor clearColor];
}
return _contentView;
}
- (UIImageView *)bgImageView {
if (!_bgImageView) {
_bgImageView = [[UIImageView alloc] init];
_bgImageView.contentMode = UIViewContentModeScaleAspectFill;
_bgImageView.clipsToBounds = YES;
}
return _bgImageView;
}
- (KBKeyBoardMainView *)keyBoardMainView {
if (!_keyBoardMainView) {
_keyBoardMainView = [[KBKeyBoardMainView alloc] init];
_keyBoardMainView.delegate = self;
}
return _keyBoardMainView;
}
- (KBFunctionView *)functionView {
if (!_functionView) {
_functionView = [[KBFunctionView alloc] init];
_functionView.delegate = self; // 监听功能面板顶部Bar点击
}
return _functionView;
}
- (KBChatPanelView *)chatPanelView {
if (!_chatPanelView) {
NSLog(@"[Keyboard] ⚠️ chatPanelView 被创建!");
_chatPanelView = [[KBChatPanelView alloc] init];
_chatPanelView.delegate = self;
}
return _chatPanelView;
}
- (NSMutableArray<KBChatMessage *> *)chatMessages {
if (!_chatMessages) {
_chatMessages = [NSMutableArray array];
}
return _chatMessages;
}
- (KBKeyboardSubscriptionView *)subscriptionView {
if (!_subscriptionView) {
_subscriptionView = [[KBKeyboardSubscriptionView alloc] init];
_subscriptionView.delegate = self;
_subscriptionView.hidden = YES;
_subscriptionView.alpha = 0.0;
}
return _subscriptionView;
}
@end