1
This commit is contained in:
@@ -43,29 +43,35 @@
|
||||
}
|
||||
|
||||
// Cell 布局:
|
||||
// 左边距(68) + 头像(28) + 间距(8) + 内容区域 + 间距(8) + 点赞按钮(40) + 右边距(16)
|
||||
// 内容区域宽度 = maxWidth - 68 - 28 - 8 - 8 - 40 - 16
|
||||
CGFloat contentWidth = maxWidth - 68 - 28 - 8 - 8 - 40 - 16;
|
||||
// 左边距(68) + 头像(28) + 间距(8) + 内容区域 + 右边距(50)
|
||||
// 内容区域宽度 = maxWidth - 68 - 28 - 8 - 50
|
||||
CGFloat contentWidth = maxWidth - 68 - 28 - 8 - 50;
|
||||
|
||||
// 构建富文本计算高度
|
||||
NSMutableString *fullText = [NSMutableString stringWithString:self.userName];
|
||||
// 用户名高度(可能包含 "回复 @xxx")
|
||||
NSMutableString *userNameText = [NSMutableString stringWithString:self.userName];
|
||||
if (self.replyToUserName.length > 0) {
|
||||
[fullText appendFormat:@" 回复 @%@", self.replyToUserName];
|
||||
[userNameText appendFormat:@" 回复 @%@", self.replyToUserName];
|
||||
}
|
||||
[fullText appendFormat:@":%@", self.content];
|
||||
UIFont *userNameFont = [UIFont systemFontOfSize:13 weight:UIFontWeightMedium];
|
||||
CGRect userNameRect = [userNameText boundingRectWithSize:CGSizeMake(contentWidth, CGFLOAT_MAX)
|
||||
options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
|
||||
attributes:@{NSFontAttributeName: userNameFont}
|
||||
context:nil];
|
||||
CGFloat userNameHeight = ceil(userNameRect.size.height);
|
||||
|
||||
// 内容高度
|
||||
UIFont *contentFont = [UIFont systemFontOfSize:14];
|
||||
CGRect contentRect = [fullText boundingRectWithSize:CGSizeMake(contentWidth, CGFLOAT_MAX)
|
||||
options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
|
||||
attributes:@{NSFontAttributeName: contentFont}
|
||||
context:nil];
|
||||
CGRect contentRect = [self.content boundingRectWithSize:CGSizeMake(contentWidth, CGFLOAT_MAX)
|
||||
options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
|
||||
attributes:@{NSFontAttributeName: contentFont}
|
||||
context:nil];
|
||||
CGFloat contentHeight = ceil(contentRect.size.height);
|
||||
|
||||
// 时间高度(单行)
|
||||
CGFloat timeHeight = 14; // 11号字体
|
||||
|
||||
// 总高度 = 上边距(8) + 内容 + 间距(4) + 时间 + 下边距(8)
|
||||
CGFloat totalHeight = 8 + contentHeight + 4 + timeHeight + 8;
|
||||
// 总高度 = 上边距(8) + 用户名 + 间距(4) + 内容 + 间距(6) + 时间 + 下边距(8)
|
||||
CGFloat totalHeight = 8 + userNameHeight + 4 + contentHeight + 6 + timeHeight + 8;
|
||||
|
||||
// 最小高度(头像高度 + 上下边距)
|
||||
CGFloat minHeight = 8 + 28 + 8;
|
||||
|
||||
@@ -20,6 +20,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
/// 点赞按钮点击回调
|
||||
@property(nonatomic, copy, nullable) void (^onLikeAction)(void);
|
||||
|
||||
/// 回复按钮点击回调
|
||||
@property(nonatomic, copy, nullable) void (^onReplyAction)(void);
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#import "KBAICommentHeaderView.h"
|
||||
#import "KBAICommentModel.h"
|
||||
#import "KBTopImageButton.h"
|
||||
#import <Masonry/Masonry.h>
|
||||
#import <SDWebImage/SDWebImage.h>
|
||||
|
||||
@@ -14,9 +15,10 @@
|
||||
|
||||
@property(nonatomic, strong) UIImageView *avatarImageView;
|
||||
@property(nonatomic, strong) UILabel *userNameLabel;
|
||||
@property(nonatomic, strong) UILabel *timeLabel;
|
||||
@property(nonatomic, strong) UILabel *contentLabel;
|
||||
@property(nonatomic, strong) UIButton *likeButton;
|
||||
@property(nonatomic, strong) UILabel *timeLabel;
|
||||
@property(nonatomic, strong) UIButton *replyButton;
|
||||
@property(nonatomic, strong) KBTopImageButton *likeButton;
|
||||
|
||||
@end
|
||||
|
||||
@@ -37,8 +39,9 @@
|
||||
|
||||
[self.contentView addSubview:self.avatarImageView];
|
||||
[self.contentView addSubview:self.userNameLabel];
|
||||
[self.contentView addSubview:self.timeLabel];
|
||||
[self.contentView addSubview:self.contentLabel];
|
||||
[self.contentView addSubview:self.timeLabel];
|
||||
[self.contentView addSubview:self.replyButton];
|
||||
[self.contentView addSubview:self.likeButton];
|
||||
|
||||
[self.avatarImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
@@ -53,24 +56,31 @@
|
||||
make.right.lessThanOrEqualTo(self.likeButton.mas_left).offset(-10);
|
||||
}];
|
||||
|
||||
|
||||
|
||||
[self.timeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.userNameLabel);
|
||||
make.top.equalTo(self.userNameLabel.mas_bottom).offset(2);
|
||||
make.top.equalTo(self.contentLabel.mas_bottom).offset(8);
|
||||
make.bottom.equalTo(self.contentView).offset(-12).priority(MASLayoutPriorityDefaultHigh);
|
||||
}];
|
||||
|
||||
[self.contentLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.userNameLabel);
|
||||
make.top.equalTo(self.timeLabel.mas_bottom).offset(8);
|
||||
make.right.equalTo(self.contentView).offset(-50);
|
||||
make.bottom.equalTo(self.contentView).offset(-12).priority(MASLayoutPriorityDefaultHigh);
|
||||
[self.replyButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.timeLabel.mas_right).offset(16);
|
||||
make.centerY.equalTo(self.timeLabel);
|
||||
}];
|
||||
|
||||
[self.likeButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.equalTo(self.contentView).offset(-16);
|
||||
make.top.equalTo(self.contentView).offset(12);
|
||||
make.width.mas_equalTo(50);
|
||||
make.width.mas_equalTo(30);
|
||||
make.height.mas_equalTo(40);
|
||||
}];
|
||||
|
||||
[self.contentLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.userNameLabel);
|
||||
make.top.equalTo(self.userNameLabel.mas_bottom).offset(6);
|
||||
make.right.equalTo(self.likeButton.mas_left).offset(-5);
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Configuration
|
||||
@@ -80,19 +90,19 @@
|
||||
sd_setImageWithURL:[NSURL URLWithString:comment.avatarUrl]
|
||||
placeholderImage:[UIImage imageNamed:@"default_avatar"]];
|
||||
self.userNameLabel.text = comment.userName;
|
||||
self.timeLabel.text = [comment formattedTime];
|
||||
self.contentLabel.text = comment.content;
|
||||
self.timeLabel.text = [comment formattedTime];
|
||||
|
||||
// 点赞按钮
|
||||
NSString *likeText =
|
||||
comment.likeCount > 0 ? [self formatLikeCount:comment.likeCount] : @"赞";
|
||||
[self.likeButton setTitle:likeText forState:UIControlStateNormal];
|
||||
self.likeButton.textLabel.text = likeText;
|
||||
|
||||
UIImage *likeImage = comment.isLiked
|
||||
? [UIImage systemImageNamed:@"heart.fill"]
|
||||
: [UIImage systemImageNamed:@"heart"];
|
||||
[self.likeButton setImage:likeImage forState:UIControlStateNormal];
|
||||
self.likeButton.tintColor =
|
||||
self.likeButton.iconView.image = likeImage;
|
||||
self.likeButton.iconView.tintColor =
|
||||
comment.isLiked ? [UIColor systemRedColor] : [UIColor grayColor];
|
||||
}
|
||||
|
||||
@@ -113,6 +123,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)replyButtonTapped {
|
||||
if (self.onReplyAction) {
|
||||
self.onReplyAction();
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Lazy Loading
|
||||
|
||||
- (UIImageView *)avatarImageView {
|
||||
@@ -129,22 +145,12 @@
|
||||
- (UILabel *)userNameLabel {
|
||||
if (!_userNameLabel) {
|
||||
_userNameLabel = [[UILabel alloc] init];
|
||||
_userNameLabel.font = [UIFont systemFontOfSize:14
|
||||
weight:UIFontWeightMedium];
|
||||
_userNameLabel.textColor = [UIColor labelColor];
|
||||
_userNameLabel.font = [UIFont systemFontOfSize:14 weight:UIFontWeightMedium];
|
||||
_userNameLabel.textColor = [UIColor secondaryLabelColor];
|
||||
}
|
||||
return _userNameLabel;
|
||||
}
|
||||
|
||||
- (UILabel *)timeLabel {
|
||||
if (!_timeLabel) {
|
||||
_timeLabel = [[UILabel alloc] init];
|
||||
_timeLabel.font = [UIFont systemFontOfSize:12];
|
||||
_timeLabel.textColor = [UIColor secondaryLabelColor];
|
||||
}
|
||||
return _timeLabel;
|
||||
}
|
||||
|
||||
- (UILabel *)contentLabel {
|
||||
if (!_contentLabel) {
|
||||
_contentLabel = [[UILabel alloc] init];
|
||||
@@ -155,19 +161,37 @@
|
||||
return _contentLabel;
|
||||
}
|
||||
|
||||
- (UIButton *)likeButton {
|
||||
if (!_likeButton) {
|
||||
_likeButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
_likeButton.titleLabel.font = [UIFont systemFontOfSize:12];
|
||||
[_likeButton setTitleColor:[UIColor grayColor]
|
||||
forState:UIControlStateNormal];
|
||||
[_likeButton setImage:[UIImage systemImageNamed:@"heart"]
|
||||
forState:UIControlStateNormal];
|
||||
_likeButton.tintColor = [UIColor grayColor];
|
||||
- (UILabel *)timeLabel {
|
||||
if (!_timeLabel) {
|
||||
_timeLabel = [[UILabel alloc] init];
|
||||
_timeLabel.font = [UIFont systemFontOfSize:12];
|
||||
_timeLabel.textColor = [UIColor secondaryLabelColor];
|
||||
}
|
||||
return _timeLabel;
|
||||
}
|
||||
|
||||
// 图片在上,文字在下的布局
|
||||
_likeButton.contentHorizontalAlignment =
|
||||
UIControlContentHorizontalAlignmentCenter;
|
||||
- (UIButton *)replyButton {
|
||||
if (!_replyButton) {
|
||||
_replyButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
_replyButton.titleLabel.font = [UIFont systemFontOfSize:12];
|
||||
[_replyButton setTitle:@"回复" forState:UIControlStateNormal];
|
||||
[_replyButton setTitleColor:[UIColor secondaryLabelColor] forState:UIControlStateNormal];
|
||||
[_replyButton addTarget:self
|
||||
action:@selector(replyButtonTapped)
|
||||
forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _replyButton;
|
||||
}
|
||||
|
||||
- (KBTopImageButton *)likeButton {
|
||||
if (!_likeButton) {
|
||||
_likeButton = [[KBTopImageButton alloc] init];
|
||||
_likeButton.iconSize = CGSizeMake(20, 20);
|
||||
_likeButton.spacing = 2;
|
||||
_likeButton.iconView.image = [UIImage systemImageNamed:@"heart"];
|
||||
_likeButton.iconView.tintColor = [UIColor grayColor];
|
||||
_likeButton.textLabel.font = [UIFont systemFontOfSize:11];
|
||||
_likeButton.textLabel.textColor = [UIColor grayColor];
|
||||
[_likeButton addTarget:self
|
||||
action:@selector(likeButtonTapped)
|
||||
forControlEvents:UIControlEventTouchUpInside];
|
||||
|
||||
@@ -35,6 +35,11 @@ static NSString *const kCommentFooterIdentifier = @"CommentFooter";
|
||||
/// 输入框底部约束
|
||||
@property(nonatomic, strong) MASConstraint *inputBottomConstraint;
|
||||
|
||||
/// 当前回复的目标(一级评论)
|
||||
@property(nonatomic, weak) KBAICommentModel *replyToComment;
|
||||
/// 当前回复的目标(二级评论)
|
||||
@property(nonatomic, weak) KBAIReplyModel *replyToReply;
|
||||
|
||||
@end
|
||||
|
||||
@implementation KBAICommentView
|
||||
@@ -246,6 +251,10 @@ static NSString *const kCommentFooterIdentifier = @"CommentFooter";
|
||||
withRowAnimation:UITableViewRowAnimationNone];
|
||||
};
|
||||
|
||||
cell.onReplyAction = ^{
|
||||
[weakSelf setReplyToComment:comment reply:reply];
|
||||
};
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
@@ -268,6 +277,10 @@ static NSString *const kCommentFooterIdentifier = @"CommentFooter";
|
||||
withRowAnimation:UITableViewRowAnimationNone];
|
||||
};
|
||||
|
||||
header.onReplyAction = ^{
|
||||
[weakSelf setReplyToComment:comment reply:nil];
|
||||
};
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
@@ -481,12 +494,55 @@ static NSInteger const kRepliesLoadCount = 5;
|
||||
return _inputView;
|
||||
}
|
||||
|
||||
#pragma mark - Reply
|
||||
|
||||
- (void)setReplyToComment:(KBAICommentModel *)comment reply:(KBAIReplyModel *)reply {
|
||||
self.replyToComment = comment;
|
||||
self.replyToReply = reply;
|
||||
|
||||
if (reply) {
|
||||
// 回复二级评论
|
||||
self.inputView.placeholder = [NSString stringWithFormat:@"回复 @%@", reply.userName];
|
||||
} else if (comment) {
|
||||
// 回复一级评论
|
||||
self.inputView.placeholder = [NSString stringWithFormat:@"回复 @%@", comment.userName];
|
||||
} else {
|
||||
// 普通评论
|
||||
self.inputView.placeholder = @"说点什么...";
|
||||
}
|
||||
}
|
||||
|
||||
- (void)clearReplyTarget {
|
||||
self.replyToComment = nil;
|
||||
self.replyToReply = nil;
|
||||
self.inputView.placeholder = @"说点什么...";
|
||||
}
|
||||
|
||||
#pragma mark - Send Comment
|
||||
|
||||
- (void)sendCommentWithText:(NSString *)text {
|
||||
if (text.length == 0) return;
|
||||
|
||||
// 创建新评论
|
||||
CGFloat tableWidth = self.tableView.bounds.size.width;
|
||||
if (tableWidth <= 0) {
|
||||
tableWidth = [UIScreen mainScreen].bounds.size.width;
|
||||
}
|
||||
|
||||
if (self.replyToComment) {
|
||||
// 回复评论(添加二级评论)
|
||||
[self sendReplyWithText:text tableWidth:tableWidth];
|
||||
} else {
|
||||
// 发送一级评论
|
||||
[self sendNewCommentWithText:text tableWidth:tableWidth];
|
||||
}
|
||||
|
||||
// 清空输入框和回复目标
|
||||
[self.inputView clearText];
|
||||
[self clearReplyTarget];
|
||||
}
|
||||
|
||||
- (void)sendNewCommentWithText:(NSString *)text tableWidth:(CGFloat)tableWidth {
|
||||
// 创建新一级评论
|
||||
KBAICommentModel *newComment = [[KBAICommentModel alloc] init];
|
||||
newComment.commentId = [NSUUID UUID].UUIDString;
|
||||
newComment.userId = @"current_user";
|
||||
@@ -499,10 +555,6 @@ static NSInteger const kRepliesLoadCount = 5;
|
||||
newComment.replies = @[];
|
||||
|
||||
// 计算高度缓存
|
||||
CGFloat tableWidth = self.tableView.bounds.size.width;
|
||||
if (tableWidth <= 0) {
|
||||
tableWidth = [UIScreen mainScreen].bounds.size.width;
|
||||
}
|
||||
newComment.cachedHeaderHeight = [newComment calculateHeaderHeightWithMaxWidth:tableWidth];
|
||||
|
||||
// 插入到数组第一个
|
||||
@@ -516,9 +568,69 @@ static NSInteger const kRepliesLoadCount = 5;
|
||||
|
||||
// 滚动到顶部
|
||||
[self.tableView setContentOffset:CGPointZero animated:YES];
|
||||
}
|
||||
|
||||
// 清空输入框
|
||||
[self.inputView clearText];
|
||||
- (void)sendReplyWithText:(NSString *)text tableWidth:(CGFloat)tableWidth {
|
||||
KBAICommentModel *comment = self.replyToComment;
|
||||
if (!comment) return;
|
||||
|
||||
// 创建新二级评论
|
||||
KBAIReplyModel *newReply = [[KBAIReplyModel alloc] init];
|
||||
newReply.replyId = [NSUUID UUID].UUIDString;
|
||||
newReply.userId = @"current_user";
|
||||
newReply.userName = @"我";
|
||||
newReply.avatarUrl = @"";
|
||||
newReply.content = text;
|
||||
newReply.likeCount = 0;
|
||||
newReply.isLiked = NO;
|
||||
newReply.createTime = [[NSDate date] timeIntervalSince1970];
|
||||
|
||||
// 如果是回复二级评论,设置被回复用户
|
||||
if (self.replyToReply) {
|
||||
newReply.replyToUserName = self.replyToReply.userName;
|
||||
}
|
||||
|
||||
// 计算高度缓存
|
||||
newReply.cachedCellHeight = [newReply calculateCellHeightWithMaxWidth:tableWidth];
|
||||
|
||||
// 添加到 replies 数组
|
||||
NSMutableArray *newReplies = [NSMutableArray arrayWithArray:comment.replies];
|
||||
[newReplies addObject:newReply];
|
||||
comment.replies = newReplies;
|
||||
comment.totalReplyCount = newReplies.count;
|
||||
|
||||
// 找到该评论的 section
|
||||
NSInteger section = [self.comments indexOfObject:comment];
|
||||
if (section == NSNotFound) return;
|
||||
|
||||
// 如果已展开,添加到 displayedReplies 并插入行
|
||||
if (comment.isRepliesExpanded) {
|
||||
NSInteger newRowIndex = comment.displayedReplies.count;
|
||||
[comment.displayedReplies addObject:newReply];
|
||||
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:newRowIndex inSection:section];
|
||||
[self.tableView insertRowsAtIndexPaths:@[indexPath]
|
||||
withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||
|
||||
// 刷新 Footer
|
||||
KBAICommentFooterView *footerView =
|
||||
(KBAICommentFooterView *)[self.tableView footerViewForSection:section];
|
||||
if (footerView) {
|
||||
[footerView configureWithComment:comment];
|
||||
}
|
||||
|
||||
// 滚动到新回复
|
||||
[self.tableView scrollToRowAtIndexPath:indexPath
|
||||
atScrollPosition:UITableViewScrollPositionBottom
|
||||
animated:YES];
|
||||
} else {
|
||||
// 未展开,刷新 Footer 显示新的回复数
|
||||
KBAICommentFooterView *footerView =
|
||||
(KBAICommentFooterView *)[self.tableView footerViewForSection:section];
|
||||
if (footerView) {
|
||||
[footerView configureWithComment:comment];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -20,6 +20,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
/// 点赞按钮点击回调
|
||||
@property(nonatomic, copy, nullable) void (^onLikeAction)(void);
|
||||
|
||||
/// 回复按钮点击回调
|
||||
@property(nonatomic, copy, nullable) void (^onReplyAction)(void);
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -7,15 +7,18 @@
|
||||
|
||||
#import "KBAIReplyCell.h"
|
||||
#import "KBAIReplyModel.h"
|
||||
#import "KBTopImageButton.h"
|
||||
#import <Masonry/Masonry.h>
|
||||
#import <SDWebImage/SDWebImage.h>
|
||||
|
||||
@interface KBAIReplyCell ()
|
||||
|
||||
@property(nonatomic, strong) UIImageView *avatarImageView;
|
||||
@property(nonatomic, strong) UILabel *userNameLabel;
|
||||
@property(nonatomic, strong) UILabel *contentLabel;
|
||||
@property(nonatomic, strong) UILabel *timeLabel;
|
||||
@property(nonatomic, strong) UIButton *likeButton;
|
||||
@property(nonatomic, strong) UIButton *replyButton;
|
||||
@property(nonatomic, strong) KBTopImageButton *likeButton;
|
||||
|
||||
@end
|
||||
|
||||
@@ -36,36 +39,48 @@
|
||||
|
||||
- (void)setupUI {
|
||||
[self.contentView addSubview:self.avatarImageView];
|
||||
[self.contentView addSubview:self.userNameLabel];
|
||||
[self.contentView addSubview:self.contentLabel];
|
||||
[self.contentView addSubview:self.timeLabel];
|
||||
[self.contentView addSubview:self.replyButton];
|
||||
[self.contentView addSubview:self.likeButton];
|
||||
|
||||
// 左侧缩进 48pt(对齐一级评论内容)
|
||||
// 左侧缩进(对齐一级评论内容)
|
||||
[self.avatarImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.contentView).offset(68); // 16 + 40 + 12 = 68
|
||||
make.top.equalTo(self.contentView).offset(8);
|
||||
make.width.height.mas_equalTo(28);
|
||||
}];
|
||||
|
||||
[self.contentLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
[self.userNameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.avatarImageView.mas_right).offset(8);
|
||||
make.top.equalTo(self.avatarImageView);
|
||||
make.right.equalTo(self.likeButton.mas_left).offset(-8);
|
||||
make.right.equalTo(self.contentView).offset(-50);
|
||||
}];
|
||||
|
||||
[self.timeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.contentLabel);
|
||||
make.top.equalTo(self.contentLabel.mas_bottom).offset(4);
|
||||
// 降低优先级,避免与 TableView 设置的固定高度约束冲突
|
||||
make.left.equalTo(self.userNameLabel);
|
||||
make.top.equalTo(self.contentLabel.mas_bottom).offset(6);
|
||||
make.bottom.equalTo(self.contentView).offset(-8).priority(MASLayoutPriorityDefaultHigh);
|
||||
}];
|
||||
|
||||
[self.replyButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.timeLabel.mas_right).offset(16);
|
||||
make.centerY.equalTo(self.timeLabel);
|
||||
}];
|
||||
|
||||
[self.likeButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.equalTo(self.contentView).offset(-16);
|
||||
make.top.equalTo(self.contentView).offset(8);
|
||||
make.width.mas_equalTo(40);
|
||||
make.width.mas_equalTo(30);
|
||||
make.height.mas_equalTo(30);
|
||||
}];
|
||||
|
||||
[self.contentLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.userNameLabel);
|
||||
make.top.equalTo(self.userNameLabel.mas_bottom).offset(4);
|
||||
make.right.equalTo(self.likeButton.mas_left).offset(-5);
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Configuration
|
||||
@@ -75,58 +90,54 @@
|
||||
sd_setImageWithURL:[NSURL URLWithString:reply.avatarUrl]
|
||||
placeholderImage:[UIImage imageNamed:@"default_avatar"]];
|
||||
|
||||
// 构建富文本:用户名(蓝色)+ @回复用户(蓝色)+ 内容
|
||||
NSMutableAttributedString *attrText =
|
||||
[[NSMutableAttributedString alloc] init];
|
||||
|
||||
// 用户名
|
||||
NSDictionary *nameAttrs = @{
|
||||
NSFontAttributeName : [UIFont systemFontOfSize:14
|
||||
weight:UIFontWeightMedium],
|
||||
NSForegroundColorAttributeName : [UIColor labelColor]
|
||||
};
|
||||
[attrText appendAttributedString:[[NSAttributedString alloc]
|
||||
initWithString:reply.userName
|
||||
attributes:nameAttrs]];
|
||||
|
||||
// @回复用户
|
||||
// 用户名(如果有回复对象,显示 "用户名 回复 @被回复用户")
|
||||
if (reply.replyToUserName.length > 0) {
|
||||
NSMutableAttributedString *attrName = [[NSMutableAttributedString alloc] init];
|
||||
|
||||
NSDictionary *nameAttrs = @{
|
||||
NSFontAttributeName : [UIFont systemFontOfSize:13 weight:UIFontWeightMedium],
|
||||
NSForegroundColorAttributeName : [UIColor secondaryLabelColor]
|
||||
};
|
||||
[attrName appendAttributedString:[[NSAttributedString alloc]
|
||||
initWithString:reply.userName
|
||||
attributes:nameAttrs]];
|
||||
|
||||
NSDictionary *replyAttrs = @{
|
||||
NSFontAttributeName : [UIFont systemFontOfSize:14],
|
||||
NSFontAttributeName : [UIFont systemFontOfSize:13],
|
||||
NSForegroundColorAttributeName : [UIColor secondaryLabelColor]
|
||||
};
|
||||
[attrName appendAttributedString:[[NSAttributedString alloc]
|
||||
initWithString:@" 回复 "
|
||||
attributes:replyAttrs]];
|
||||
|
||||
NSDictionary *toUserAttrs = @{
|
||||
NSFontAttributeName : [UIFont systemFontOfSize:13],
|
||||
NSForegroundColorAttributeName : [UIColor systemBlueColor]
|
||||
};
|
||||
NSString *replyTo =
|
||||
[NSString stringWithFormat:@" 回复 @%@", reply.replyToUserName];
|
||||
[attrText appendAttributedString:[[NSAttributedString alloc]
|
||||
initWithString:replyTo
|
||||
attributes:replyAttrs]];
|
||||
[attrName appendAttributedString:[[NSAttributedString alloc]
|
||||
initWithString:[NSString stringWithFormat:@"@%@", reply.replyToUserName]
|
||||
attributes:toUserAttrs]];
|
||||
|
||||
self.userNameLabel.attributedText = attrName;
|
||||
} else {
|
||||
self.userNameLabel.attributedText = nil;
|
||||
self.userNameLabel.text = reply.userName;
|
||||
}
|
||||
|
||||
// 内容
|
||||
NSDictionary *contentAttrs = @{
|
||||
NSFontAttributeName : [UIFont systemFontOfSize:14],
|
||||
NSForegroundColorAttributeName : [UIColor labelColor]
|
||||
};
|
||||
NSString *content = [NSString stringWithFormat:@":%@", reply.content];
|
||||
[attrText appendAttributedString:[[NSAttributedString alloc]
|
||||
initWithString:content
|
||||
attributes:contentAttrs]];
|
||||
|
||||
self.contentLabel.attributedText = attrText;
|
||||
// 评论内容
|
||||
self.contentLabel.text = reply.content;
|
||||
|
||||
// 时间
|
||||
self.timeLabel.text = [reply formattedTime];
|
||||
|
||||
// 点赞
|
||||
NSString *likeText =
|
||||
reply.likeCount > 0 ? [self formatLikeCount:reply.likeCount] : @"";
|
||||
[self.likeButton setTitle:likeText forState:UIControlStateNormal];
|
||||
NSString *likeText = reply.likeCount > 0 ? [self formatLikeCount:reply.likeCount] : @"";
|
||||
self.likeButton.textLabel.text = likeText;
|
||||
|
||||
UIImage *likeImage = reply.isLiked ? [UIImage systemImageNamed:@"heart.fill"]
|
||||
: [UIImage systemImageNamed:@"heart"];
|
||||
[self.likeButton setImage:likeImage forState:UIControlStateNormal];
|
||||
self.likeButton.tintColor =
|
||||
reply.isLiked ? [UIColor systemRedColor] : [UIColor grayColor];
|
||||
self.likeButton.iconView.image = likeImage;
|
||||
self.likeButton.iconView.tintColor = reply.isLiked ? [UIColor systemRedColor] : [UIColor grayColor];
|
||||
}
|
||||
|
||||
- (NSString *)formatLikeCount:(NSInteger)count {
|
||||
@@ -146,6 +157,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)replyButtonTapped {
|
||||
if (self.onReplyAction) {
|
||||
self.onReplyAction();
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Lazy Loading
|
||||
|
||||
- (UIImageView *)avatarImageView {
|
||||
@@ -159,9 +176,21 @@
|
||||
return _avatarImageView;
|
||||
}
|
||||
|
||||
- (UILabel *)userNameLabel {
|
||||
if (!_userNameLabel) {
|
||||
_userNameLabel = [[UILabel alloc] init];
|
||||
_userNameLabel.font = [UIFont systemFontOfSize:13 weight:UIFontWeightMedium];
|
||||
_userNameLabel.textColor = [UIColor secondaryLabelColor];
|
||||
_userNameLabel.numberOfLines = 0;
|
||||
}
|
||||
return _userNameLabel;
|
||||
}
|
||||
|
||||
- (UILabel *)contentLabel {
|
||||
if (!_contentLabel) {
|
||||
_contentLabel = [[UILabel alloc] init];
|
||||
_contentLabel.font = [UIFont systemFontOfSize:14];
|
||||
_contentLabel.textColor = [UIColor labelColor];
|
||||
_contentLabel.numberOfLines = 0;
|
||||
}
|
||||
return _contentLabel;
|
||||
@@ -176,22 +205,31 @@
|
||||
return _timeLabel;
|
||||
}
|
||||
|
||||
- (UIButton *)likeButton {
|
||||
- (UIButton *)replyButton {
|
||||
if (!_replyButton) {
|
||||
_replyButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
_replyButton.titleLabel.font = [UIFont systemFontOfSize:11];
|
||||
[_replyButton setTitle:@"回复" forState:UIControlStateNormal];
|
||||
[_replyButton setTitleColor:[UIColor secondaryLabelColor] forState:UIControlStateNormal];
|
||||
[_replyButton addTarget:self
|
||||
action:@selector(replyButtonTapped)
|
||||
forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _replyButton;
|
||||
}
|
||||
|
||||
- (KBTopImageButton *)likeButton {
|
||||
if (!_likeButton) {
|
||||
_likeButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
_likeButton.titleLabel.font = [UIFont systemFontOfSize:11];
|
||||
[_likeButton setTitleColor:[UIColor grayColor]
|
||||
forState:UIControlStateNormal];
|
||||
[_likeButton setImage:[UIImage systemImageNamed:@"heart"]
|
||||
forState:UIControlStateNormal];
|
||||
_likeButton.tintColor = [UIColor grayColor];
|
||||
_likeButton = [[KBTopImageButton alloc] init];
|
||||
_likeButton.iconSize = CGSizeMake(16, 16);
|
||||
_likeButton.spacing = 2;
|
||||
_likeButton.iconView.image = [UIImage systemImageNamed:@"heart"];
|
||||
_likeButton.iconView.tintColor = [UIColor grayColor];
|
||||
_likeButton.textLabel.font = [UIFont systemFontOfSize:10];
|
||||
_likeButton.textLabel.textColor = [UIColor grayColor];
|
||||
[_likeButton addTarget:self
|
||||
action:@selector(likeButtonTapped)
|
||||
forControlEvents:UIControlEventTouchUpInside];
|
||||
|
||||
// 设置图片和文字间距
|
||||
_likeButton.imageEdgeInsets = UIEdgeInsetsMake(0, -2, 0, 2);
|
||||
_likeButton.titleEdgeInsets = UIEdgeInsetsMake(0, 2, 0, -2);
|
||||
}
|
||||
return _likeButton;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user