From db869552e4a5cb9354c77f8d746c0bb5b166a3a0 Mon Sep 17 00:00:00 2001 From: CodeST <694468528@qq.com> Date: Tue, 27 Jan 2026 18:53:19 +0800 Subject: [PATCH] 1 --- keyBoard.xcodeproj/project.pbxproj | 6 + .../AI/ai_comment_icon.imageset/Contents.json | 22 +++ .../ai_comment_icon@2x.png | Bin 0 -> 847 bytes .../ai_comment_icon@3x.png | Bin 0 -> 1482 bytes .../AI/ai_live_icon.imageset/Contents.json | 22 +++ .../ai_live_icon.imageset/ai_live_icon@2x.png | Bin 0 -> 1040 bytes .../ai_live_icon.imageset/ai_live_icon@3x.png | Bin 0 -> 1733 bytes .../AI/ai_livesel_icon.imageset/Contents.json | 22 +++ .../ai_livesel_icon@2x.png | Bin 0 -> 1179 bytes .../ai_livesel_icon@3x.png | Bin 0 -> 1973 bytes keyBoard/Class/AiTalk/M/KBPersonaModel.h | 7 + keyBoard/Class/AiTalk/V/KBChatTableView.m | 3 +- keyBoard/Class/AiTalk/V/KBPersonaChatCell.m | 90 ++++++++- keyBoard/Class/AiTalk/VC/KBAIHomeVC.m | 7 +- .../Class/Common/V/KBImagePositionButton.h | 39 ++++ .../Class/Common/V/KBImagePositionButton.m | 187 ++++++++++++++++++ 16 files changed, 402 insertions(+), 3 deletions(-) create mode 100644 keyBoard/Assets.xcassets/AI/ai_comment_icon.imageset/Contents.json create mode 100644 keyBoard/Assets.xcassets/AI/ai_comment_icon.imageset/ai_comment_icon@2x.png create mode 100644 keyBoard/Assets.xcassets/AI/ai_comment_icon.imageset/ai_comment_icon@3x.png create mode 100644 keyBoard/Assets.xcassets/AI/ai_live_icon.imageset/Contents.json create mode 100644 keyBoard/Assets.xcassets/AI/ai_live_icon.imageset/ai_live_icon@2x.png create mode 100644 keyBoard/Assets.xcassets/AI/ai_live_icon.imageset/ai_live_icon@3x.png create mode 100644 keyBoard/Assets.xcassets/AI/ai_livesel_icon.imageset/Contents.json create mode 100644 keyBoard/Assets.xcassets/AI/ai_livesel_icon.imageset/ai_livesel_icon@2x.png create mode 100644 keyBoard/Assets.xcassets/AI/ai_livesel_icon.imageset/ai_livesel_icon@3x.png create mode 100644 keyBoard/Class/Common/V/KBImagePositionButton.h create mode 100644 keyBoard/Class/Common/V/KBImagePositionButton.m diff --git a/keyBoard.xcodeproj/project.pbxproj b/keyBoard.xcodeproj/project.pbxproj index c87673b..cc591c5 100644 --- a/keyBoard.xcodeproj/project.pbxproj +++ b/keyBoard.xcodeproj/project.pbxproj @@ -144,6 +144,7 @@ 048FFD1D2F277486005D62AE /* KBChatHistoryPageModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD1C2F277486005D62AE /* KBChatHistoryPageModel.m */; }; 048FFD1E2F277486005D62AE /* KBChatHistoryModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD1A2F277486005D62AE /* KBChatHistoryModel.m */; }; 048FFD242F28A836005D62AE /* KBChatLimitPopView.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD232F28A836005D62AE /* KBChatLimitPopView.m */; }; + 048FFD272F28C6CF005D62AE /* KBImagePositionButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD262F28C6CF005D62AE /* KBImagePositionButton.m */; }; 0498BD622EDFFC12006CC1D5 /* KBMyVM.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD612EDFFC12006CC1D5 /* KBMyVM.m */; }; 0498BD652EE0116D006CC1D5 /* KBEmailLoginVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD642EE0116D006CC1D5 /* KBEmailLoginVC.m */; }; 0498BD682EE01180006CC1D5 /* KBEmailRegistVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD672EE01180006CC1D5 /* KBEmailRegistVC.m */; }; @@ -544,6 +545,8 @@ 048FFD1C2F277486005D62AE /* KBChatHistoryPageModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBChatHistoryPageModel.m; sourceTree = ""; }; 048FFD222F28A836005D62AE /* KBChatLimitPopView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBChatLimitPopView.h; sourceTree = ""; }; 048FFD232F28A836005D62AE /* KBChatLimitPopView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBChatLimitPopView.m; sourceTree = ""; }; + 048FFD252F28C6CF005D62AE /* KBImagePositionButton.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBImagePositionButton.h; sourceTree = ""; }; + 048FFD262F28C6CF005D62AE /* KBImagePositionButton.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBImagePositionButton.m; sourceTree = ""; }; 0498BD5E2EDF2157006CC1D5 /* KBBizCode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBBizCode.h; sourceTree = ""; }; 0498BD602EDFFC12006CC1D5 /* KBMyVM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBMyVM.h; sourceTree = ""; }; 0498BD612EDFFC12006CC1D5 /* KBMyVM.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBMyVM.m; sourceTree = ""; }; @@ -1234,6 +1237,8 @@ 049FB20D2EC1CD2800FAB05D /* KBAlert.m */, 042869FD2ECAEF2B00CE730C /* KBMoneyBtn.h */, 042869FE2ECAEF2B00CE730C /* KBMoneyBtn.m */, + 048FFD252F28C6CF005D62AE /* KBImagePositionButton.h */, + 048FFD262F28C6CF005D62AE /* KBImagePositionButton.m */, ); path = V; sourceTree = ""; @@ -2444,6 +2449,7 @@ 0477BEA22EBCF0000055D639 /* KBTopImageButton.m in Sources */, A1B2E1012EBC7AAA00000001 /* KBTopThreeView.m in Sources */, A1B2E1022EBC7AAA00000001 /* HomeHotCell.m in Sources */, + 048FFD272F28C6CF005D62AE /* KBImagePositionButton.m in Sources */, 0459D1B72EBA287900F2D189 /* KBSkinManager.m in Sources */, 04286A002ECAEF2B00CE730C /* KBMoneyBtn.m in Sources */, 048908F52EC0496400FABA60 /* KBShopItemVC.m in Sources */, diff --git a/keyBoard/Assets.xcassets/AI/ai_comment_icon.imageset/Contents.json b/keyBoard/Assets.xcassets/AI/ai_comment_icon.imageset/Contents.json new file mode 100644 index 0000000..1e3d484 --- /dev/null +++ b/keyBoard/Assets.xcassets/AI/ai_comment_icon.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "ai_comment_icon@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "ai_comment_icon@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/keyBoard/Assets.xcassets/AI/ai_comment_icon.imageset/ai_comment_icon@2x.png b/keyBoard/Assets.xcassets/AI/ai_comment_icon.imageset/ai_comment_icon@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d2179a0ff2c1a8d5268cf2a53b37ea761b708a86 GIT binary patch literal 847 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 tK7`%@00960NAfBG00006NklE ze~jEk75}{1AJ_H{ZTX>63pVG;!S1!G_G<4g8i)o>j0OnB#5M>hfkX*bMWTeH4H`^? zU<8AW2BNk`qx_-4ASjY*+S}W5M@#R=UQ2CG1rsYZ)pGRq$M^gAyl-#sZs~4sx4W0S z+nv1kotZZ?Z{FuSGjHZQyABlwU5|)%$1c>3v6yzpzpOnSyU7Q#8?Sm*d*TyJE9HOJ z?v6d$72lER`oKp0$eI-jl+_pOiJJZmS8SlZ`vX1Q@xNudu2SYFv^)M9`6&C@&3J2i zLoBWzzVafr3s(rGJcCTBu3o)FyJH_mH2w(0JqPCwLga@m+d^I!4u#$eNE0lGTn@q2 zaB^?NHSLA3&!DH{Te`7rl@*s_?QCyHPyF6Me>l1ikZ%WiL|P**1eku2l@NJ9fGv!_ zAC1tCaOin-bv#V_ZZbPrRu;K(YVplpflHfraqxb@4)0={P6#55%OM+)E-1FaE%^ft z+^pBYWK(Sw2x(7j6C#mcL*)S$RH$Fp!QpPcv>%(D+PS8cI%cJFg4edTCK`1c!l6A7 z*#yD6XVqA$g79StIw0~S(y{OA`qp<^RgJ}3INI9**$u&3aunwumc#6f`Y&r&Y>QsA zdday|l?1PA)~vuKOTGihqvT6bv%sYx?jA&!J*D&+SWeK8`(aZWwF=S#Cr=>V{E%*l zy{DAcqTqGq%4M16+|MD(DNaQ*T4#N4Ms7M;xjgqV2)+l!XQs6PmFp>Gk8l3x4usuL zb?w^bnSJEbXMqo<%KKLQB}p2CBChq(}ZPJ|d#S-Nn)rK~;vD97YmPQbV2wy-U{1Ofcbs;yrIkY)I)}s+a*nQN2tG*Gj)4{hpdivIe z1P^za%lY0V#lY9M!y{tR6)x;T!Ho*D1ymP~tpL%P%rq{!%+b?da7NsCPp*0WcjLh( zV#RR>NMnKr#$8r(gD4W}-{GOxMby1e1Usf3Lt$y%$bCQQ`18T@0CMEUA;mbs?st&T zDJJ^KjYKa(-I&AP!T%BU?|IV8GOmA8^@+6?$)OWY0H3q|1qhDML|(TJPrd&_y{Cyg z=K{e0nmE9Nej-RuKI+D?P2$N%5eYqmWGYzZ0eBf3n*coiI;yqa^YeW!jMyCAX>Xg2 zx)~IJw}d1{2l+etcFq7U1C!Jpb4Sx1a&UAkk8BEjAjnSqlJQ^3^+l@6L46jP?2l#w zD*!J8$LRTW2fg9(`f_;kfB5nk29BI43Em1MG4d?Lf1D1F)5Ii&OnISTGPi)`#G$(+ zIrK-ab)7UfhzdqNkl5pd_XwxSV@$FkpNp4rQ2%H6Px_u>5Q>7A!-r3CeLM)&zZ7e< zXk=!81`o*5qv>Kc7X@z>W#Gu`$m%x$9k%=;f(=cg107;936m>20&j{Wnfen)|7NDAmH^WWiTWYl=D^M}ttuP5 z>664zFC=>_)BWUyME%I=?b4g7=yX~Uctb1u4j+c+-@HFZzSD8Oau9nJZuczSS zYmykgD>#Ui(V|q9s=%94J34YJ+{rEGCgyD?DE?Or7FI=E-<)B4q5kLDpM7^!rOp~x z4c?Rl+?V<@r{S$o-4o;|AK6;{QCYn~(Z11jvVZi5^;0A4s2TXYL2~HOI1)qm!NYBo9VAyl@)GYBZik#K z_=98>3JaRn9K31g=;V+b{w*?kJ=EXHSy1$o((0CE#c%jK(hb;`dP)+no-SFhih?-- zZ}#v7c){mnX5?<>w{a00000NkvXX Hu0mjfCjr%n literal 0 HcmV?d00001 diff --git a/keyBoard/Class/AiTalk/M/KBPersonaModel.h b/keyBoard/Class/AiTalk/M/KBPersonaModel.h index 85d6b0e..7823ee5 100644 --- a/keyBoard/Class/AiTalk/M/KBPersonaModel.h +++ b/keyBoard/Class/AiTalk/M/KBPersonaModel.h @@ -74,6 +74,13 @@ typedef NS_ENUM(NSInteger, KBPersonaVisibility) { /// 更新时间 @property (nonatomic, copy) NSString *updatedAt; +/// 评论数 +@property (nonatomic, copy) NSString *commentCount; +/// 喜欢数 +@property (nonatomic, copy) NSString *likeCount; +/// 是否喜欢 +@property (nonatomic, assign) BOOL liked; + #pragma mark - 扩展属性 diff --git a/keyBoard/Class/AiTalk/V/KBChatTableView.m b/keyBoard/Class/AiTalk/V/KBChatTableView.m index 81f60c0..daf157e 100644 --- a/keyBoard/Class/AiTalk/V/KBChatTableView.m +++ b/keyBoard/Class/AiTalk/V/KBChatTableView.m @@ -89,7 +89,8 @@ static const NSTimeInterval kTimestampInterval = 5 * 60; // 5 分钟 make.edges.equalTo(self); }]; - self.contentBottomInset = KB_TABBAR_HEIGHT + 40 + 10; + // 关键修复:减少初始 contentBottomInset,因为 chatView 已经通过约束避开了底部 + self.contentBottomInset = 20; // 简单的缓冲空间 [self updateContentBottomInset:self.contentBottomInset]; __weak typeof(self) weakSelf = self; diff --git a/keyBoard/Class/AiTalk/V/KBPersonaChatCell.m b/keyBoard/Class/AiTalk/V/KBPersonaChatCell.m index 5f05f7c..724974d 100644 --- a/keyBoard/Class/AiTalk/V/KBPersonaChatCell.m +++ b/keyBoard/Class/AiTalk/V/KBPersonaChatCell.m @@ -10,6 +10,7 @@ #import "KBAiChatMessage.h" #import "KBChatHistoryPageModel.h" #import "AiVM.h" +#import "KBImagePositionButton.h" #import #import @@ -48,6 +49,12 @@ /// AiVM 实例 @property (nonatomic, strong) AiVM *aiVM; +/// 评论按钮 +@property (nonatomic, strong) KBImagePositionButton *commentButton; + +/// 喜欢按钮 +@property (nonatomic, strong) KBImagePositionButton *likeButton; + @end @implementation KBPersonaChatCell @@ -113,6 +120,24 @@ make.centerY.equalTo(self.avatarImageView); }]; + // 评论按钮(最右侧) + [self.contentView addSubview:self.commentButton]; + [self.commentButton mas_makeConstraints:^(MASConstraintMaker *make) { + make.right.equalTo(self.contentView).offset(-20); + make.centerY.equalTo(self.avatarImageView); + make.width.mas_equalTo(40); + make.height.mas_equalTo(50); + }]; + + // 喜欢按钮(评论按钮左侧,间距20px) + [self.contentView addSubview:self.likeButton]; + [self.likeButton mas_makeConstraints:^(MASConstraintMaker *make) { + make.right.equalTo(self.commentButton.mas_left).offset(-20); + make.centerY.equalTo(self.avatarImageView); + make.width.mas_equalTo(40); + make.height.mas_equalTo(50); + }]; + // 聊天列表 [self.contentView addSubview:self.chatView]; [self.chatView mas_makeConstraints:^(MASConstraintMaker *make) { @@ -147,6 +172,10 @@ // 关键修复:清空消息时停止音频播放,避免状态混乱 [self.chatView stopPlayingAudio]; [self.chatView clearMessages]; + [self.commentButton setTitle:persona.commentCount forState:UIControlStateNormal]; + [self.likeButton setTitle:persona.likeCount forState:UIControlStateNormal]; + self.likeButton.selected = persona.liked; + } #pragma mark - 2:数据加载 @@ -350,7 +379,7 @@ - (UILabel *)nameLabel { if (!_nameLabel) { _nameLabel = [[UILabel alloc] init]; - _nameLabel.font = [UIFont boldSystemFontOfSize:20]; + _nameLabel.font = [UIFont boldSystemFontOfSize:12]; _nameLabel.textColor = [UIColor whiteColor]; _nameLabel.textAlignment = NSTextAlignmentCenter; } @@ -377,4 +406,63 @@ return _chatView; } +- (KBImagePositionButton *)commentButton { + if (!_commentButton) { + // 创建上图下文的按钮 + _commentButton = [[KBImagePositionButton alloc] initWithImagePosition:KBImagePositionTop spacing:4]; + + // 关键修复:先设置字体,再设置文字,避免循环调用 + _commentButton.titleLabel.font = [UIFont systemFontOfSize:10]; + + // 设置图片 + [_commentButton setImage:[UIImage imageNamed:@"ai_comment_icon"] forState:UIControlStateNormal]; + + // 设置文字 + [_commentButton setTitle:@"0" forState:UIControlStateNormal]; + [_commentButton setTitleColor:[[UIColor whiteColor] colorWithAlphaComponent:0.8] forState:UIControlStateNormal]; + + // 添加点击事件 + [_commentButton addTarget:self action:@selector(commentButtonTapped:) forControlEvents:UIControlEventTouchUpInside]; + } + return _commentButton; +} + +- (KBImagePositionButton *)likeButton { + if (!_likeButton) { + // 创建上图下文的按钮 + _likeButton = [[KBImagePositionButton alloc] initWithImagePosition:KBImagePositionTop spacing:4]; + + // 关键修复:先设置字体,再设置文字,避免循环调用 + _likeButton.titleLabel.font = [UIFont systemFontOfSize:10]; + + // 设置图片 + [_likeButton setImage:[UIImage imageNamed:@"ai_live_icon"] forState:UIControlStateNormal]; + [_likeButton setImage:[UIImage imageNamed:@"ai_livesel_icon"] forState:UIControlStateSelected]; + + // 设置文字 + [_likeButton setTitle:@"0" forState:UIControlStateNormal]; + [_likeButton setTitleColor:[[UIColor whiteColor] colorWithAlphaComponent:0.8] forState:UIControlStateNormal]; + + // 添加点击事件 + [_likeButton addTarget:self action:@selector(likeButtonTapped:) forControlEvents:UIControlEventTouchUpInside]; + } + return _likeButton; +} + +#pragma mark - Button Actions + +- (void)commentButtonTapped:(KBImagePositionButton *)sender { + sender.selected = !sender.selected; + NSLog(@"[KBPersonaChatCell] 评论按钮点击,选中状态:%d", sender.selected); + + // TODO: 在这里添加评论逻辑 +} + +- (void)likeButtonTapped:(KBImagePositionButton *)sender { + sender.selected = !sender.selected; + NSLog(@"[KBPersonaChatCell] 喜欢按钮点击,选中状态:%d", sender.selected); + + // TODO: 在这里添加喜欢逻辑 +} + @end diff --git a/keyBoard/Class/AiTalk/VC/KBAIHomeVC.m b/keyBoard/Class/AiTalk/VC/KBAIHomeVC.m index 9dec325..86dc119 100644 --- a/keyBoard/Class/AiTalk/VC/KBAIHomeVC.m +++ b/keyBoard/Class/AiTalk/VC/KBAIHomeVC.m @@ -422,7 +422,12 @@ - (void)updateChatViewBottomInset { CGFloat bottomSpacing = (self.currentKeyboardHeight > 0.0) ? (self.currentKeyboardHeight + 8.0) : self.baseInputBarBottomSpacing; - CGFloat bottomInset = self.voiceInputBarHeight + bottomSpacing; + + // 关键修复:减少 bottomInset,因为 chatView 已经通过约束避开了底部的 avatar 区域 + // 只需要留出一点空间(比如20)让最后一条消息不紧贴 chatView 底部即可 + CGFloat bottomInset = 20; // 简单的缓冲空间 + + NSLog(@"[KBAIHomeVC] 更新 ChatView bottomInset: %.2f", bottomInset); for (NSIndexPath *indexPath in self.collectionView.indexPathsForVisibleItems) { KBPersonaChatCell *cell = (KBPersonaChatCell *)[self.collectionView cellForItemAtIndexPath:indexPath]; diff --git a/keyBoard/Class/Common/V/KBImagePositionButton.h b/keyBoard/Class/Common/V/KBImagePositionButton.h new file mode 100644 index 0000000..de09e09 --- /dev/null +++ b/keyBoard/Class/Common/V/KBImagePositionButton.h @@ -0,0 +1,39 @@ +// +// KBImagePositionButton.h +// keyBoard +// +// Created by Kiro on 2026/1/27. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// 图片位置枚举 +typedef NS_ENUM(NSInteger, KBImagePosition) { + KBImagePositionTop, // 图片在上,文字在下 + KBImagePositionBottom, // 图片在下,文字在上 + KBImagePositionLeft, // 图片在左,文字在右(默认) + KBImagePositionRight // 图片在右,文字在左 +}; + +/// 可以指定图片位置的按钮 +@interface KBImagePositionButton : UIButton + +/// 图片位置(默认 KBImagePositionLeft) +@property (nonatomic, assign) KBImagePosition imagePosition; + +/// 图片和文字之间的间距(默认 8) +@property (nonatomic, assign) CGFloat spacing; + +/** + 便捷初始化方法 + + @param imagePosition 图片位置 + @param spacing 图片和文字之间的间距 + */ +- (instancetype)initWithImagePosition:(KBImagePosition)imagePosition spacing:(CGFloat)spacing; + +@end + +NS_ASSUME_NONNULL_END diff --git a/keyBoard/Class/Common/V/KBImagePositionButton.m b/keyBoard/Class/Common/V/KBImagePositionButton.m new file mode 100644 index 0000000..25fde43 --- /dev/null +++ b/keyBoard/Class/Common/V/KBImagePositionButton.m @@ -0,0 +1,187 @@ +// +// KBImagePositionButton.m +// keyBoard +// +// Created by Kiro on 2026/1/27. +// + +#import "KBImagePositionButton.h" + +@implementation KBImagePositionButton + +- (instancetype)initWithFrame:(CGRect)frame { + if (self = [super initWithFrame:frame]) { + [self setupDefault]; + } + return self; +} + +- (instancetype)initWithCoder:(NSCoder *)coder { + if (self = [super initWithCoder:coder]) { + [self setupDefault]; + } + return self; +} + +- (instancetype)initWithImagePosition:(KBImagePosition)imagePosition spacing:(CGFloat)spacing { + if (self = [super initWithFrame:CGRectZero]) { + _imagePosition = imagePosition; + _spacing = spacing; + [self setupDefault]; + } + return self; +} + +- (void)setupDefault { + // 关键修复:不要判断 _imagePosition == 0,因为 KBImagePositionTop 的值就是 0 + // 如果是通过 initWithFrame 或 initWithCoder 初始化,_imagePosition 默认就是 0 (KBImagePositionTop) + // 只有通过 initWithImagePosition 初始化时,才会明确设置 _imagePosition + + // 为非自定义初始化设置默认值 + if (self.spacing == 0) { + _spacing = 8; + } + + [self updateEdgeInsets]; +} + +#pragma mark - Setter + +- (void)setImagePosition:(KBImagePosition)imagePosition { + _imagePosition = imagePosition; + [self updateEdgeInsets]; + [self setNeedsLayout]; +} + +- (void)setSpacing:(CGFloat)spacing { + _spacing = spacing; + [self updateEdgeInsets]; + [self setNeedsLayout]; +} + +- (void)setImage:(UIImage *)image forState:(UIControlState)state { + [super setImage:image forState:state]; + // 延迟更新,确保 image 已经设置好 + dispatch_async(dispatch_get_main_queue(), ^{ + [self updateEdgeInsets]; + }); +} + +- (void)setTitle:(NSString *)title forState:(UIControlState)state { + [super setTitle:title forState:state]; + // 延迟更新,确保 title 已经设置好 + dispatch_async(dispatch_get_main_queue(), ^{ + [self updateEdgeInsets]; + }); +} + +#pragma mark - EdgeInsets + +- (void)updateEdgeInsets { + CGSize imageSize = self.currentImage.size; + CGSize titleSize = CGSizeZero; + + if (self.currentTitle.length > 0 && self.titleLabel.font) { + NSDictionary *attributes = @{NSFontAttributeName: self.titleLabel.font}; + titleSize = [self.currentTitle sizeWithAttributes:attributes]; + } + + switch (self.imagePosition) { + case KBImagePositionTop: { + // 图片在上,文字在下 + self.imageEdgeInsets = UIEdgeInsetsMake( + -(titleSize.height + self.spacing), // top: 向上移动 + 0, // left + 0, // bottom + -titleSize.width // right: 向左移动文字的宽度 + ); + + self.titleEdgeInsets = UIEdgeInsetsMake( + imageSize.height + self.spacing, // top: 向下移动 + -imageSize.width, // left: 向左移动图片的宽度 + 0, // bottom + 0 // right + ); + break; + } + + case KBImagePositionBottom: { + // 图片在下,文字在上 + self.imageEdgeInsets = UIEdgeInsetsMake( + titleSize.height + self.spacing, // top: 向下移动 + 0, // left + 0, // bottom + -titleSize.width // right + ); + + self.titleEdgeInsets = UIEdgeInsetsMake( + -(imageSize.height + self.spacing), // top: 向上移动 + -imageSize.width, // left + 0, // bottom + 0 // right + ); + break; + } + + case KBImagePositionLeft: { + // 图片在左,文字在右(默认) + self.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, self.spacing); + self.titleEdgeInsets = UIEdgeInsetsMake(0, self.spacing, 0, 0); + break; + } + + case KBImagePositionRight: { + // 图片在右,文字在左 + self.imageEdgeInsets = UIEdgeInsetsMake( + 0, + titleSize.width + self.spacing, + 0, + -(titleSize.width + self.spacing) + ); + + self.titleEdgeInsets = UIEdgeInsetsMake( + 0, + -(imageSize.width + self.spacing), + 0, + imageSize.width + self.spacing + ); + break; + } + } + NSLog(@"imageEdgeInsets: %@", NSStringFromUIEdgeInsets(self.imageEdgeInsets)); + NSLog(@"titleEdgeInsets: %@", NSStringFromUIEdgeInsets(self.titleEdgeInsets)); +} + +- (CGSize)intrinsicContentSize { + CGSize imageSize = self.currentImage ? self.currentImage.size : CGSizeZero; + CGSize titleSize = CGSizeZero; + + if (self.currentTitle.length > 0 && self.titleLabel.font) { + NSDictionary *attributes = @{NSFontAttributeName: self.titleLabel.font}; + titleSize = [self.currentTitle sizeWithAttributes:attributes]; + } + + CGSize size = CGSizeZero; + + switch (self.imagePosition) { + case KBImagePositionTop: + case KBImagePositionBottom: { + // 垂直排列 + size.width = MAX(imageSize.width, titleSize.width); + size.height = imageSize.height + self.spacing + titleSize.height; + break; + } + + case KBImagePositionLeft: + case KBImagePositionRight: { + // 水平排列 + size.width = imageSize.width + self.spacing + titleSize.width; + size.height = MAX(imageSize.height, titleSize.height); + break; + } + } + + return size; +} + +@end