处理键盘崩溃
This commit is contained in:
@@ -30,6 +30,9 @@
|
||||
#import "UIImage+KBColor.h"
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import <SDWebImage/SDWebImage.h>
|
||||
#if DEBUG
|
||||
#import <mach/mach.h>
|
||||
#endif
|
||||
|
||||
// #import "KBLog.h"
|
||||
|
||||
@@ -94,6 +97,8 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
|
||||
@property(nonatomic, assign) CGFloat kb_lastKeyboardHeight;
|
||||
@property(nonatomic, strong) UIImage *kb_cachedGradientImage;
|
||||
@property(nonatomic, assign) CGSize kb_cachedGradientSize;
|
||||
@property(nonatomic, strong, nullable) CAGradientLayer *kb_defaultGradientLayer;
|
||||
@property(nonatomic, copy, nullable) NSString *kb_lastAppliedThemeKey;
|
||||
@property(nonatomic, strong) NSMutableArray<KBChatMessage *> *chatMessages;
|
||||
@property(nonatomic, strong) AVAudioPlayer *chatAudioPlayer;
|
||||
@property(nonatomic, assign) BOOL chatPanelVisible;
|
||||
@@ -101,14 +106,45 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
|
||||
@property(nonatomic, strong, nullable) id kb_skinObserverToken;
|
||||
@end
|
||||
|
||||
#if DEBUG
|
||||
static NSInteger sKBKeyboardVCAliveCount = 0;
|
||||
|
||||
static uint64_t KBPhysFootprintBytes(void) {
|
||||
task_vm_info_data_t vmInfo;
|
||||
mach_msg_type_number_t count = TASK_VM_INFO_COUNT;
|
||||
kern_return_t kr = task_info(mach_task_self(), TASK_VM_INFO,
|
||||
(task_info_t)&vmInfo, &count);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
return 0;
|
||||
}
|
||||
return (uint64_t)vmInfo.phys_footprint;
|
||||
}
|
||||
|
||||
static NSString *KBFormatMB(uint64_t bytes) {
|
||||
double mb = (double)bytes / 1024.0 / 1024.0;
|
||||
return [NSString stringWithFormat:@"%.1fMB", mb];
|
||||
}
|
||||
#endif
|
||||
|
||||
@implementation KeyboardViewController
|
||||
|
||||
{
|
||||
BOOL _kb_didTriggerLoginDeepLinkOnce;
|
||||
#if DEBUG
|
||||
BOOL _kb_debugDidCountAlive;
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
#if DEBUG
|
||||
if (!_kb_debugDidCountAlive) {
|
||||
_kb_debugDidCountAlive = YES;
|
||||
sKBKeyboardVCAliveCount += 1;
|
||||
}
|
||||
NSLog(@"[Keyboard] KeyboardViewController viewDidLoad alive=%ld self=%p mem=%@",
|
||||
(long)sKBKeyboardVCAliveCount, self, KBFormatMB(KBPhysFootprintBytes()));
|
||||
#endif
|
||||
// 撤销删除是“上一段删除操作”的临时状态;键盘被系统回收/重建或跨页面回来时应当清空,避免误显示。
|
||||
[[KBBackspaceUndoManager shared] registerNonClearAction];
|
||||
[self setupUI];
|
||||
@@ -149,12 +185,30 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
|
||||
[self kb_applyDefaultSkinIfNeeded];
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning {
|
||||
[super didReceiveMemoryWarning];
|
||||
// 扩展进程内存上限较小:在系统发出内存警告时主动清理可重建的缓存,降低被系统杀死概率。
|
||||
self.kb_cachedGradientImage = nil;
|
||||
[self.kb_defaultGradientLayer removeFromSuperlayer];
|
||||
self.kb_defaultGradientLayer = nil;
|
||||
[[KBSkinManager shared] clearRuntimeImageCaches];
|
||||
[[SDImageCache sharedImageCache] clearMemory];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
// 进入/重新进入输入界面时,清理上一次会话残留的撤销状态与缓存,避免显示“撤销删除”但实际上已不可撤销。
|
||||
[[KBBackspaceUndoManager shared] registerNonClearAction];
|
||||
[[KBInputBufferManager shared] resetWithText:@""];
|
||||
[[KBLocalizationManager shared] reloadFromSharedStorageIfNeeded];
|
||||
// 键盘再次出现时,恢复 HUD 容器与主题(viewDidDisappear 里可能已清理图片/缓存)。
|
||||
[KBHUD setContainerView:self.view];
|
||||
[self kb_ensureKeyBoardMainViewIfNeeded];
|
||||
[self kb_applyTheme];
|
||||
#if DEBUG
|
||||
NSLog(@"[Keyboard] viewWillAppear self=%p mem=%@",
|
||||
self, KBFormatMB(KBPhysFootprintBytes()));
|
||||
#endif
|
||||
// 注意:微信/QQ 等宿主的 documentContext 可能是“截断窗口”,这里只更新
|
||||
// liveText,不要把它当作全文 manualSnapshot。
|
||||
[[KBInputBufferManager shared]
|
||||
@@ -167,6 +221,17 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
[super viewWillDisappear:animated];
|
||||
[[KBBackspaceUndoManager shared] registerNonClearAction];
|
||||
[self kb_releaseMemoryWhenKeyboardHidden];
|
||||
#if DEBUG
|
||||
NSLog(@"[Keyboard] viewWillDisappear self=%p mem=%@",
|
||||
self, KBFormatMB(KBPhysFootprintBytes()));
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)viewDidDisappear:(BOOL)animated {
|
||||
[super viewDidDisappear:animated];
|
||||
// 再兜底一次,防止某些宿主只触发 willDisappear 而未触发 didDisappear。
|
||||
[self kb_releaseMemoryWhenKeyboardHidden];
|
||||
}
|
||||
|
||||
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
|
||||
@@ -196,9 +261,7 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
|
||||
CGFloat portraitWidth = [self kb_portraitWidth];
|
||||
CGFloat keyboardHeight = [self kb_keyboardHeightForWidth:portraitWidth];
|
||||
CGFloat keyboardBaseHeight = [self kb_keyboardBaseHeightForWidth:portraitWidth];
|
||||
CGFloat chatPanelHeight = [self kb_chatPanelHeightForWidth:portraitWidth];
|
||||
CGFloat screenWidth = CGRectGetWidth([UIScreen mainScreen].bounds);
|
||||
CGFloat outerVerticalInset = KBFit(4.0f);
|
||||
|
||||
NSLayoutConstraint *h =
|
||||
[self.view.heightAnchor constraintEqualToConstant:keyboardHeight];
|
||||
@@ -231,12 +294,6 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
|
||||
[self.bgImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.equalTo(self.contentView);
|
||||
}];
|
||||
// 预置功能面板(默认隐藏),与键盘区域共享相同布局
|
||||
self.functionView.hidden = YES;
|
||||
[self.contentView addSubview:self.functionView];
|
||||
[self.functionView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.equalTo(self.contentView);
|
||||
}];
|
||||
|
||||
[self.contentView addSubview:self.keyBoardMainView];
|
||||
[self.keyBoardMainView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
@@ -246,15 +303,6 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
|
||||
make.height.mas_equalTo(keyboardBaseHeight);
|
||||
}];
|
||||
|
||||
[self.contentView addSubview:self.chatPanelView];
|
||||
[self.chatPanelView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.right.equalTo(self.contentView);
|
||||
make.bottom.equalTo(self.keyBoardMainView.mas_top);
|
||||
self.chatPanelHeightConstraint =
|
||||
make.height.mas_equalTo(chatPanelHeight);
|
||||
}];
|
||||
self.chatPanelView.hidden = YES;
|
||||
|
||||
// 初始隐藏,避免布局完成前闪烁
|
||||
self.contentView.hidden = YES;
|
||||
}
|
||||
@@ -396,8 +444,14 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
|
||||
// 简单显隐切换,复用相同的布局区域
|
||||
if (show) {
|
||||
[self showChatPanel:NO];
|
||||
[self kb_ensureFunctionViewIfNeeded];
|
||||
}
|
||||
if (_functionView) {
|
||||
_functionView.hidden = !show;
|
||||
} else if (show) {
|
||||
// ensure 后按理已存在;这里兜底一次,避免异常情况下状态不一致
|
||||
self.functionView.hidden = NO;
|
||||
}
|
||||
self.functionView.hidden = !show;
|
||||
self.keyBoardMainView.hidden = show;
|
||||
|
||||
if (show) {
|
||||
@@ -417,7 +471,9 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
|
||||
|
||||
// 可选:把当前显示的视图置顶,避免层级遮挡
|
||||
if (show) {
|
||||
[self.contentView bringSubviewToFront:self.functionView];
|
||||
if (_functionView) {
|
||||
[self.contentView bringSubviewToFront:_functionView];
|
||||
}
|
||||
} else {
|
||||
[self.contentView bringSubviewToFront:self.keyBoardMainView];
|
||||
}
|
||||
@@ -492,10 +548,13 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
|
||||
}
|
||||
self.chatPanelVisible = show;
|
||||
if (show) {
|
||||
[self kb_ensureChatPanelViewIfNeeded];
|
||||
self.chatPanelView.hidden = NO;
|
||||
self.chatPanelView.alpha = 0.0;
|
||||
[self.contentView bringSubviewToFront:self.chatPanelView];
|
||||
self.functionView.hidden = YES;
|
||||
if (_functionView) {
|
||||
_functionView.hidden = YES;
|
||||
}
|
||||
[self hideSubscriptionPanel];
|
||||
[self showSettingView:NO];
|
||||
[UIView animateWithDuration:0.2
|
||||
@@ -506,6 +565,11 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
|
||||
}
|
||||
completion:nil];
|
||||
} else {
|
||||
// 从未创建过聊天面板时,直接返回,避免 show/hide 触发额外内存分配
|
||||
if (!_chatPanelView) {
|
||||
[self kb_updateKeyboardLayoutIfNeeded];
|
||||
return;
|
||||
}
|
||||
[UIView animateWithDuration:0.18
|
||||
delay:0
|
||||
options:UIViewAnimationOptionCurveEaseIn
|
||||
@@ -519,6 +583,114 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
|
||||
[self kb_updateKeyboardLayoutIfNeeded];
|
||||
}
|
||||
|
||||
// 延迟创建:仅在用户真正打开功能面板时才创建/布局,降低默认内存占用。
|
||||
- (void)kb_ensureFunctionViewIfNeeded {
|
||||
if (_functionView && _functionView.superview) {
|
||||
return;
|
||||
}
|
||||
KBFunctionView *v = self.functionView;
|
||||
if (!v.superview) {
|
||||
v.hidden = YES;
|
||||
[self.contentView addSubview:v];
|
||||
[v mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.equalTo(self.contentView);
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
// 延迟创建:仅在用户打开聊天面板时才创建/布局。
|
||||
- (void)kb_ensureChatPanelViewIfNeeded {
|
||||
if (_chatPanelView && _chatPanelView.superview) {
|
||||
return;
|
||||
}
|
||||
CGFloat portraitWidth = [self kb_portraitWidth];
|
||||
CGFloat chatPanelHeight = [self kb_chatPanelHeightForWidth:portraitWidth];
|
||||
KBChatPanelView *v = self.chatPanelView;
|
||||
if (!v.superview) {
|
||||
[self.contentView addSubview:v];
|
||||
[v mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.right.equalTo(self.contentView);
|
||||
make.bottom.equalTo(self.keyBoardMainView.mas_top);
|
||||
self.chatPanelHeightConstraint =
|
||||
make.height.mas_equalTo(chatPanelHeight);
|
||||
}];
|
||||
v.hidden = YES;
|
||||
}
|
||||
}
|
||||
|
||||
// 延迟创建:键盘主面板(按键区)在隐藏时会被释放;再次显示时需要重建。
|
||||
- (void)kb_ensureKeyBoardMainViewIfNeeded {
|
||||
if (_keyBoardMainView && _keyBoardMainView.superview) {
|
||||
return;
|
||||
}
|
||||
CGFloat portraitWidth = [self kb_portraitWidth];
|
||||
CGFloat keyboardBaseHeight =
|
||||
[self kb_keyboardBaseHeightForWidth:portraitWidth];
|
||||
KBKeyBoardMainView *v = self.keyBoardMainView;
|
||||
if (!v.superview) {
|
||||
[self.contentView addSubview:v];
|
||||
[v mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.right.equalTo(self.contentView);
|
||||
make.bottom.equalTo(self.contentView);
|
||||
self.keyBoardMainHeightConstraint =
|
||||
make.height.mas_equalTo(keyboardBaseHeight);
|
||||
}];
|
||||
}
|
||||
[self.contentView bringSubviewToFront:v];
|
||||
}
|
||||
|
||||
// 键盘隐藏时释放可重建资源(背景图/缓存/非必需面板),降低扩展内存峰值。
|
||||
- (void)kb_releaseMemoryWhenKeyboardHidden {
|
||||
[KBHUD setContainerView:nil];
|
||||
self.bgImageView.image = nil;
|
||||
self.kb_cachedGradientImage = nil;
|
||||
[self.kb_defaultGradientLayer removeFromSuperlayer];
|
||||
self.kb_defaultGradientLayer = nil;
|
||||
[[SDImageCache sharedImageCache] clearMemory];
|
||||
|
||||
// 聊天相关可能持有音频数据/临时文件,键盘隐藏时直接清空,避免累计占用。
|
||||
if (self.chatAudioPlayer) {
|
||||
[self.chatAudioPlayer stop];
|
||||
self.chatAudioPlayer = nil;
|
||||
}
|
||||
if (_chatMessages.count > 0) {
|
||||
NSString *tmpRoot = NSTemporaryDirectory();
|
||||
for (KBChatMessage *msg in _chatMessages.copy) {
|
||||
if (tmpRoot.length > 0 && msg.audioFilePath.length > 0 &&
|
||||
[msg.audioFilePath hasPrefix:tmpRoot]) {
|
||||
[[NSFileManager defaultManager] removeItemAtPath:msg.audioFilePath
|
||||
error:nil];
|
||||
}
|
||||
}
|
||||
[_chatMessages removeAllObjects];
|
||||
}
|
||||
|
||||
if (_keyBoardMainView) {
|
||||
[_keyBoardMainView removeFromSuperview];
|
||||
_keyBoardMainView = nil;
|
||||
}
|
||||
self.keyBoardMainHeightConstraint = nil;
|
||||
|
||||
if (_functionView) {
|
||||
[_functionView removeFromSuperview];
|
||||
_functionView = nil;
|
||||
}
|
||||
if (_chatPanelView) {
|
||||
[_chatPanelView removeFromSuperview];
|
||||
_chatPanelView = nil;
|
||||
}
|
||||
self.chatPanelVisible = NO;
|
||||
|
||||
if (_subscriptionView) {
|
||||
[_subscriptionView removeFromSuperview];
|
||||
_subscriptionView = nil;
|
||||
}
|
||||
if (_settingView) {
|
||||
[_settingView removeFromSuperview];
|
||||
_settingView = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)showSubscriptionPanel {
|
||||
// 1) 先判断权限:未开启“完全访问”则走引导逻辑
|
||||
if (![[KBFullAccessManager shared] hasFullAccess]) {
|
||||
@@ -831,7 +1003,7 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
|
||||
|
||||
- (void)chatPanelViewDidTapClose:(KBChatPanelView *)view {
|
||||
// 清空 chatPanelView 内部的消息
|
||||
[self.chatPanelView kb_reloadWithMessages:@[]];
|
||||
[view kb_reloadWithMessages:@[]];
|
||||
if (self.chatAudioPlayer.isPlaying) {
|
||||
[self.chatAudioPlayer stop];
|
||||
}
|
||||
@@ -1553,7 +1725,11 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
|
||||
(__bridge const void *)(self),
|
||||
(__bridge CFStringRef)KBDarwinSkinInstallRequestNotification, NULL);
|
||||
#if DEBUG
|
||||
NSLog(@"[Keyboard] KeyboardViewController dealloc");
|
||||
if (_kb_debugDidCountAlive) {
|
||||
sKBKeyboardVCAliveCount -= 1;
|
||||
}
|
||||
NSLog(@"[Keyboard] KeyboardViewController dealloc alive=%ld self=%p mem=%@",
|
||||
(long)sKBKeyboardVCAliveCount, self, KBFormatMB(KBPhysFootprintBytes()));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1578,6 +1754,9 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
|
||||
if (self.contentView.hidden) {
|
||||
self.contentView.hidden = NO;
|
||||
}
|
||||
if (self.kb_defaultGradientLayer) {
|
||||
self.kb_defaultGradientLayer.frame = self.bgImageView.bounds;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)viewWillTransitionToSize:(CGSize)size
|
||||
@@ -1611,93 +1790,133 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
|
||||
#pragma mark - Theme
|
||||
|
||||
- (void)kb_applyTheme {
|
||||
KBSkinTheme *t = [KBSkinManager shared].current;
|
||||
UIImage *img = [[KBSkinManager shared] currentBackgroundImage];
|
||||
BOOL isDefaultTheme = [self kb_isDefaultKeyboardTheme:t];
|
||||
BOOL isDarkMode = [self kb_isDarkModeActive];
|
||||
CGSize size = self.bgImageView.bounds.size;
|
||||
if (isDefaultTheme) {
|
||||
if (isDarkMode) {
|
||||
@autoreleasepool {
|
||||
KBSkinTheme *t = [KBSkinManager shared].current;
|
||||
UIImage *img = nil;
|
||||
BOOL isDefaultTheme = [self kb_isDefaultKeyboardTheme:t];
|
||||
BOOL isDarkMode = [self kb_isDarkModeActive];
|
||||
|
||||
NSString *skinId = t.skinId ?: @"";
|
||||
NSString *themeKey =
|
||||
[NSString stringWithFormat:@"%@|default=%d|dark=%d",
|
||||
skinId, isDefaultTheme, isDarkMode];
|
||||
BOOL themeChanged =
|
||||
(self.kb_lastAppliedThemeKey.length == 0 ||
|
||||
![self.kb_lastAppliedThemeKey isEqualToString:themeKey]);
|
||||
if (themeChanged) {
|
||||
self.kb_lastAppliedThemeKey = themeKey;
|
||||
}
|
||||
|
||||
CGSize size = self.bgImageView.bounds.size;
|
||||
if (isDefaultTheme) {
|
||||
if (isDarkMode) {
|
||||
// 暗黑模式:直接使用背景色,不使用图片渲染
|
||||
// 这样可以避免图片渲染时的色彩空间转换导致颜色不一致
|
||||
img = nil;
|
||||
self.bgImageView.image = nil;
|
||||
[self.kb_defaultGradientLayer removeFromSuperlayer];
|
||||
self.kb_defaultGradientLayer = nil;
|
||||
// 使用与系统键盘底部完全相同的颜色
|
||||
if (@available(iOS 13.0, *)) {
|
||||
// iOS 系统键盘使用的实际颜色 (RGB: 44, 44, 46 in sRGB, 或 #2C2C2E)
|
||||
// 但为了完美匹配,我们使用动态颜色并直接设置为背景
|
||||
UIColor *kbBgColor =
|
||||
[UIColor colorWithDynamicProvider:^UIColor *_Nonnull(
|
||||
UITraitCollection *_Nonnull traitCollection) {
|
||||
if (traitCollection.userInterfaceStyle ==
|
||||
UIUserInterfaceStyleDark) {
|
||||
// 暗黑模式下系统键盘实际背景色
|
||||
return [UIColor colorWithRed:43.0 / 255.0
|
||||
green:43.0 / 255.0
|
||||
blue:43.0 / 255.0
|
||||
alpha:1.0];
|
||||
} else {
|
||||
return [UIColor colorWithRed:209.0 / 255.0
|
||||
green:211.0 / 255.0
|
||||
blue:219.0 / 255.0
|
||||
alpha:1.0];
|
||||
}
|
||||
}];
|
||||
self.contentView.backgroundColor = kbBgColor;
|
||||
self.bgImageView.backgroundColor = kbBgColor;
|
||||
} else {
|
||||
UIColor *darkColor = [UIColor colorWithRed:43.0 / 255.0
|
||||
green:43.0 / 255.0
|
||||
blue:43.0 / 255.0
|
||||
alpha:1.0];
|
||||
self.contentView.backgroundColor = darkColor;
|
||||
self.bgImageView.backgroundColor = darkColor;
|
||||
}
|
||||
// iOS 系统键盘使用的实际颜色 (RGB: 44, 44, 46 in sRGB, 或 #2C2C2E)
|
||||
// 但为了完美匹配,我们使用动态颜色并直接设置为背景
|
||||
UIColor *kbBgColor =
|
||||
[UIColor colorWithDynamicProvider:^UIColor *_Nonnull(
|
||||
UITraitCollection *_Nonnull traitCollection) {
|
||||
if (traitCollection.userInterfaceStyle ==
|
||||
UIUserInterfaceStyleDark) {
|
||||
// 暗黑模式下系统键盘实际背景色
|
||||
return [UIColor colorWithRed:43.0 / 255.0
|
||||
green:43.0 / 255.0
|
||||
blue:43.0 / 255.0
|
||||
alpha:1.0];
|
||||
} else {
|
||||
return [UIColor colorWithRed:209.0 / 255.0
|
||||
green:211.0 / 255.0
|
||||
blue:219.0 / 255.0
|
||||
alpha:1.0];
|
||||
}
|
||||
}];
|
||||
self.contentView.backgroundColor = kbBgColor;
|
||||
self.bgImageView.backgroundColor = kbBgColor;
|
||||
} else {
|
||||
UIColor *darkColor = [UIColor colorWithRed:43.0 / 255.0
|
||||
green:43.0 / 255.0
|
||||
blue:43.0 / 255.0
|
||||
alpha:1.0];
|
||||
self.contentView.backgroundColor = darkColor;
|
||||
self.bgImageView.backgroundColor = darkColor;
|
||||
}
|
||||
} else {
|
||||
// 浅色模式:使用渐变图片
|
||||
if (size.width <= 0 || size.height <= 0) {
|
||||
[self.view layoutIfNeeded];
|
||||
size = self.bgImageView.bounds.size;
|
||||
// 浅色模式:使用渐变层(避免生成大位图导致内存上涨)
|
||||
if (size.width <= 0 || size.height <= 0) {
|
||||
[self.view layoutIfNeeded];
|
||||
size = self.bgImageView.bounds.size;
|
||||
}
|
||||
if (size.width <= 0 || size.height <= 0) {
|
||||
size = self.view.bounds.size;
|
||||
}
|
||||
if (size.width <= 0 || size.height <= 0) {
|
||||
size = [UIScreen mainScreen].bounds.size;
|
||||
}
|
||||
UIColor *topColor = [UIColor colorWithHex:0xDEDFE4];
|
||||
UIColor *bottomColor = [UIColor colorWithHex:0xD1D3DB];
|
||||
UIColor *resolvedTopColor = topColor;
|
||||
UIColor *resolvedBottomColor = bottomColor;
|
||||
if (@available(iOS 13.0, *)) {
|
||||
resolvedTopColor =
|
||||
[topColor resolvedColorWithTraitCollection:self.traitCollection];
|
||||
resolvedBottomColor = [bottomColor
|
||||
resolvedColorWithTraitCollection:self.traitCollection];
|
||||
}
|
||||
CAGradientLayer *layer = self.kb_defaultGradientLayer;
|
||||
if (!layer) {
|
||||
layer = [CAGradientLayer layer];
|
||||
layer.startPoint = CGPointMake(0.5, 0.0);
|
||||
layer.endPoint = CGPointMake(0.5, 1.0);
|
||||
[self.bgImageView.layer insertSublayer:layer atIndex:0];
|
||||
self.kb_defaultGradientLayer = layer;
|
||||
}
|
||||
layer.colors = @[
|
||||
(id)resolvedTopColor.CGColor,
|
||||
(id)resolvedBottomColor.CGColor
|
||||
];
|
||||
layer.frame = (CGRect){CGPointZero, size};
|
||||
img = nil;
|
||||
self.bgImageView.image = nil;
|
||||
self.contentView.backgroundColor = [UIColor clearColor];
|
||||
self.bgImageView.backgroundColor = [UIColor clearColor];
|
||||
}
|
||||
if (size.width <= 0 || size.height <= 0) {
|
||||
size = self.view.bounds.size;
|
||||
}
|
||||
if (size.width <= 0 || size.height <= 0) {
|
||||
size = [UIScreen mainScreen].bounds.size;
|
||||
}
|
||||
UIColor *topColor = [UIColor colorWithHex:0xDEDFE4];
|
||||
UIColor *bottomColor = [UIColor colorWithHex:0xD1D3DB];
|
||||
// img = [self kb_defaultGradientImageWithSize:size
|
||||
// topColor:topColor
|
||||
// bottomColor:bottomColor];
|
||||
NSLog(@"===");
|
||||
} else {
|
||||
// 自定义皮肤:清除背景色,使用皮肤图片
|
||||
self.contentView.backgroundColor = [UIColor clearColor];
|
||||
self.bgImageView.backgroundColor = [UIColor clearColor];
|
||||
[self.kb_defaultGradientLayer removeFromSuperlayer];
|
||||
self.kb_defaultGradientLayer = nil;
|
||||
img = [[KBSkinManager shared] currentBackgroundImage];
|
||||
}
|
||||
NSLog(@"===");
|
||||
} else {
|
||||
// 自定义皮肤:清除背景色,使用皮肤图片
|
||||
self.contentView.backgroundColor = [UIColor clearColor];
|
||||
self.bgImageView.backgroundColor = [UIColor clearColor];
|
||||
}
|
||||
NSLog(@"⌨️[Keyboard] apply theme id=%@ hasBg=%d", t.skinId, (img != nil));
|
||||
[self kb_logSkinDiagnosticsWithTheme:t backgroundImage:img];
|
||||
self.bgImageView.image = img;
|
||||
NSLog(@"⌨️[Keyboard] apply theme id=%@ hasBg=%d", t.skinId, (img != nil));
|
||||
[self kb_logSkinDiagnosticsWithTheme:t backgroundImage:img];
|
||||
self.bgImageView.image = img;
|
||||
|
||||
// [self.chatPanelView kb_setBackgroundImage:img];
|
||||
BOOL hasImg = (img != nil);
|
||||
// 触发键区按主题重绘
|
||||
if ([self.keyBoardMainView respondsToSelector:@selector(kb_applyTheme)]) {
|
||||
// 触发键区按主题重绘
|
||||
if (themeChanged &&
|
||||
[self.keyBoardMainView respondsToSelector:@selector(kb_applyTheme)]) {
|
||||
// method declared in KBKeyBoardMainView.h
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
|
||||
[self.keyBoardMainView performSelector:@selector(kb_applyTheme)];
|
||||
[self.keyBoardMainView performSelector:@selector(kb_applyTheme)];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
if ([self.functionView respondsToSelector:@selector(kb_applyTheme)]) {
|
||||
}
|
||||
// 注意:这里不能直接访问 self.functionView,否则会导致功能面板提前创建,占用内存。
|
||||
if (themeChanged && _functionView &&
|
||||
[_functionView respondsToSelector:@selector(kb_applyTheme)]) {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
|
||||
[self.functionView performSelector:@selector(kb_applyTheme)];
|
||||
[_functionView performSelector:@selector(kb_applyTheme)];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user