一 评论刷新
- 加载更多评论,加载到最后一页,隐藏拉新控件
// 判断评论数据是否已经加载完全
if (self.latestComments.count >= [responseObject[@"total"] intValue]) {
// 已经完全加载完毕(2种写法)
[weakSelf.tableView.footer noticeNoMoreData]; // 显示已经全部加载完毕
weakSelf.tableView.footer.hidden = YES; // 直接隐藏掉
} else { // 应该还会有下一页数据
// 结束刷新(恢复到普通状态,仍旧可以继续刷新)
[weakSelf.tableView.footer endRefreshing];
}
- 视频、声音模块实现
- 5个模块代码相似度很高,重构代码
- 重构方法1:继承
- 传输数据,引用枚举头文件
params[@"type"] = @(self.type);
- 传输数据,引用枚举头文件
if ([self isKindOfClass:NSClassFromString(@"XMGAllViewController")]) {
params[@"type"] = @(XMGTopicTypeAll);
} else if ([self isKindOfClass:NSClassFromString(@"XMGVideoViewController")]) {
params[@"type"] = @(XMGTopicTypeVideo);
} else if ([self isKindOfClass:[XMGVoiceViewController class]]) {
params[@"type"] = @(XMGTopicTypeVoice);
}
注意:上述做法,父类过度依赖子类,需要知道子类内容
- 重构方法2:抽取变量
- 各子板块不同点就是帖子的类型,每个控制器都有自己的type
/** 帖子的类型 */
@property (nonatomic, assign) XMGTopicType type;
上述方法优点:一个控制器搞定多个小模块,节省代码;
缺点:不利于扩展,不方便给每个子类加一些特性内容
注意点:type可以随意修改,子类代码调用顺序问题(viewDidload)
解决上述注意点
- 顺序问题
// 父控制器 params[@"type"] = @(self.type); // 只要父类self.type就会调用子控制器的下面方法 // 子控制器 - (XMGTopicType)type { return XMGTopicTypeWord; }
修改type问题
// 重写get方法,只能访问不能赋值 - (XMGTopicType)type
二 新帖评论
- (NSString *)aParam
{
// [a isKindOfClass:c] 判断a是否为c类型或者c的子类类型
if ([self.parentViewController isKindOfClass:[XMGNewViewController class]]) {
return @"newlist";
}
return @"list";
}
- 没有评论数据,服务器返回不是字典,而是nil
if ([responseObject isKindOfClass:[NSArray class]]) {
// 意味着没有评论数据
// 结束刷新
[weakSelf.tableView.header endRefreshing];
// 返回
return;
}
- 评论cell添加分割线
- (void)awakeFromNib
{
self.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"mainCellBackground"]];
}
三 UIMenuController
- (void)labelClick
{
// 获得菜单
UIMenuController *menu = [UIMenuController sharedMenuController];
// 菜单最终显示的位置
CGRect rect = CGRectMake(100, 100, 100, 100);
[menu setTargetRect:rect inView:self.label];
/*
targetRect:menuController指向的矩形框
targetView:targetRect以targetView的左上角为坐标原点
*/
// 显示菜单
[menu setMenuVisible:YES animated:YES];
}
- 需要通过第一响应者,来告诉MenuController它内部应该显示什么内容
/**
* 说明控制器可以成为第一响应者
*/
- (BOOL)canBecomeFirstResponder
{
return YES;
}
- 通过这个方法告诉UIMenuController它内部应该显示什么内容
// 返回YES,就代表支持action这个操作
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
if (action == @selector(cut:)
|| action == @selector(copy:)
|| action == @selector(paste:)) {
return YES;
}
return NO;
}
- 其它控件要想成为第一响应者,需要调这行代码(控制器不需要)
[self becomeFirstResponder];
- 菜单最终显示位置,可以指向自己
// 方法1
[menu setTargetRect:self.bounds inView:self];
// 方法2
[menu setTargetRect:self.frame inView:self.superview];
- 全局粘贴板:UIPasteboard generalPasteboard
- (void)cut:(UIMenuController *)menu
{
// 将label的文字存储到粘贴板
[UIPasteboard generalPasteboard].string = self.text;
// 清空文字
self.text = nil;
}
- 拷贝功能
- (void)copy:(UIMenuController *)menu
{
// 将label的文字存储到粘贴板
[UIPasteboard generalPasteboard].string = self.text;
}
- 粘贴功能
- (void)paste:(UIMenuController *)menu
{
// 将粘贴板的文字赋值给label
self.text = [UIPasteboard generalPasteboard].string;
}
弹窗文字语言选择
cell弹窗实现
- (void)labelClick
{
// 让label成为第一响应者
[self becomeFirstResponder];
// 获得菜单
UIMenuController *menu = [UIMenuController sharedMenuController];
// 设置菜单内容
menu.menuItems = @[
[[UIMenuItem alloc] initWithTitle:@"顶" action:@selector(ding:)],
[[UIMenuItem alloc] initWithTitle:@"回复" action:@selector(reply:)],
[[UIMenuItem alloc] initWithTitle:@"举报" action:@selector(warn:)]
];
// 菜单最终显示的位置
[menu setTargetRect:self.bounds inView:self];
// 显示菜单
[menu setMenuVisible:YES animated:YES];
}
#pragma mark - UIMenuController相关
/**
* 让Label具备成为第一响应者的资格
*/
- (BOOL)canBecomeFirstResponder
{
return YES;
}
/**
* 通过第一响应者的这个方法告诉UIMenuController可以显示什么内容
*/
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
if ( (action == @selector(copy:) && self.text) // 需要有文字才能支持复制
|| (action == @selector(cut:) && self.text) // 需要有文字才能支持剪切
|| action == @selector(paste:)
|| action == @selector(ding:)
|| action == @selector(reply:)
|| action == @selector(warn:)) return YES;
return NO;
}
四 评论模块增加UIMenuController
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// 取出cell
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
UIMenuController *menu = [UIMenuController sharedMenuController];
// 设置菜单内容
menu.menuItems = @[
[[UIMenuItem alloc] initWithTitle:@"顶" action:@selector(ding:)],
[[UIMenuItem alloc] initWithTitle:@"回复" action:@selector(reply:)],
[[UIMenuItem alloc] initWithTitle:@"举报" action:@selector(warn:)]
];
// 显示位置
CGRect rect = CGRectMake(0, cell.height * 0.5, cell.width, 1);
[menu setTargetRect:rect inView:cell];
// 显示出来
[menu setMenuVisible:YES animated:YES];
}
- 获得当前选中行的评论
- (XMGComment *)selectedComment
{
// 获得被选中的cell的行号
NSIndexPath *indexPath = self.tableView.indexPathForSelectedRow;
NSInteger row = indexPath.row;
// 获得评论数据
NSArray *comments = self.latestComments;
if (indexPath.section == 0 && self.hotComments.count) {
comments = self.hotComments;
}
return comments[row];
}
- 键盘文本框不需要弹窗设置
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
if (!self.isFirstResponder) { // 文本框弹出键盘, 文本框才是第一响应者
if (action == @selector(ding:)
|| action == @selector(reply:)
|| action == @selector(warn:)) return NO;
}
return [super canPerformAction:action withSender:sender];
}