iOSCell根据文字自适应高度,实现点击收起展开
2016-04-07 本文已影响5298人
罗小耳
一、Cell点开收起
Dem演示.gif设计思路:
笔者考虑的是点击展开的操作放到tableView的头视图上,通过头视图的点击事件来控制Cell的个数显示。当然,也可以放到尾视图上,具体可灵活应用,此文只是提供一个
大体的思路。
1、首先创建一个Model类,用来返回Cell个数
+ (NSInteger)cellNumberWith:(NSArray *)array andIsShow:(BOOL)isShow{
// 判断传进来的数组中元素的个数是否大于设定的值
// 大于则根据footerView的展开收起按钮,来控制cell的个数
if (array.count > MAXNUMBER) {
if (isShow) {
// 展开状态下显示数组中的所有元素
return array.count;
}else{
// 收起状态下只显示预先设定的个数
return MAXNUMBER;
}
}else{
// 小于预先设定的数值,则展示数组中的所有元素
return array.count;
}
return 0;
}
2、设置三个属性,分别用来存放头视图、头视图展开状态和是否全部展开
// 存放头视图展开状态的字典
@property (nonatomic, strong) NSMutableDictionary *sectionIsShowAll;
// 存放头视图的字典
@property (nonatomic, strong) NSMutableDictionary *sectionHeaderView;
@property (nonatomic, copy) NSString *showAll; // YES展开全部,NO收起全部
3、在tableView的协议方法中,根据不同的展开收起状态返回Cell的个数
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSArray *rowAr = [[_orderArray objectAtIndex:section] objectForKey:@"array"];
// 先判断是否存放过该secion分组对应的展开状态,若没存过则先默认为收起状态
if ([self.sectionIsShowAll objectForKey:[NSString stringWithFormat:@"%ld", section]] == nil) {
[self.sectionIsShowAll setObject:[NSNumber numberWithBool:NO] forKey:[NSString stringWithFormat:@"%ld", section]];
}
return [CellNumberModel cellNumberWith:rowAr andIsShow:[[self.sectionIsShowAll objectForKey:[NSString stringWithFormat:@"%ld", section]] boolValue]];
}
4、自定义头视图中要注意Section属性的设置
@property (nonatomic, assign) NSInteger section;
- (void)setCellNumber:(NSArray *)array section:(NSInteger)section
{
self.section = section;
[_moreBtn mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.mas_equalTo(self.mas_centerX);
make.width.mas_equalTo(self.mas_width);
make.height.mas_equalTo(self.mas_height);
}];
}
4、头视图中另一个重要的地方就是显示所有Cell按钮的点击事件
- (void)footerButtonAction
{
NSLog(@"显示所有cell");
self.moreBtn.selected = !self.moreBtn.selected;
NSLog(@"selected===%zi", self.moreBtn.selected);
NSMutableDictionary *dic = [NSMutableDictionary dictionary];
[dic setObject:[NSNumber numberWithBool:self.moreBtn.selected] forKey:@"isShow"];
[dic setObject:[NSNumber numberWithInteger:self.section] forKey:@"section"];
// 笔者是通过block更改的controller中的展开收起的存储状态,实际中也可使用协议代理的方法
self.MoreBlock (dic);
}
5、Controller中block的实现方式
__weak FoldCellViewController *weakSelf = self;
headerView.MoreBlock = ^ (NSDictionary *dic)
{
[weakSelf.sectionIsShowAll setObject:[dic objectForKey:@"isShow"] forKey:[NSString stringWithFormat:@"%@",[dic objectForKey:@"section"]]];
// 为了更好的展示给用户,此处加了一个展开全部和收起全部的按钮,该按钮的显示及操作如下所示
int showNum = 0;
int closeNum = 0;
for (int i = 0; i < self.sectionHeaderView.count; i++) {
bool selected = [[weakSelf.sectionIsShowAll objectForKey:[NSString stringWithFormat:@"%d",i]] boolValue];
if (selected == 1) {
showNum++;
} else if (selected == 0) {
closeNum++;
}
}
if (showNum == weakSelf.sectionHeaderView.count) {
[rightBtn setTitle:@"全部收起" forState:UIControlStateNormal];
} else if (closeNum == weakSelf.sectionHeaderView.count) {
[rightBtn setTitle:@"全部展开" forState:UIControlStateNormal];
}
[_orderTable reloadData];
};
#pragma 展开全部、收起全部按钮点击事件
- (void)rightBarButtonItemAction:(UIButton *)sender
{
if ([sender.titleLabel.text isEqualToString:@"全部展开"]) {
[sender setTitle:@"全部收起" forState:UIControlStateNormal];
self.showAll = @"show";
} else {
[sender setTitle:@"全部展开" forState:UIControlStateNormal];
self.showAll = @"close";
}
// 将存放Cell展开状态的字典中所有对象都改为展开或收起
for (int i = 0; i < self.sectionHeaderView.count; i++) {
OrderHeaderView *headerView = [self.sectionHeaderView objectForKey:[NSString stringWithFormat:@"%d", i]];
if ([self.showAll isEqualToString:@"show"]) {
NSMutableDictionary *showDic = [NSMutableDictionary dictionary];
[showDic setObject:[NSNumber numberWithBool:1] forKey:@"isShow"];
[showDic setObject:[NSNumber numberWithInteger:i] forKey:@"section"];
headerView.MoreBlock(showDic);
headerView.moreBtn.selected = 1;
} else if ([self.showAll isEqualToString:@"close"]) {
NSMutableDictionary *closeDic = [NSMutableDictionary dictionary];
[closeDic setObject:[NSNumber numberWithBool:0] forKey:@"isShow"];
[closeDic setObject:[NSNumber numberWithInteger:i] forKey:@"section"];
headerView.MoreBlock(closeDic);
headerView.moreBtn.selected = 0;
}
}
}
二、Cell中文字高度自适应
其实实现原理与上一部分是一样的,只是上面的Model中是改变数量,在这里变为改变高度
1、首先创建一个Model类,用来返回Cell高度
#import <Foundation/Foundation.h>
@interface RemarksCellHeightModel : NSObject
/*
* contentStr:Lable内容
* isShow:是否展开
* width:Lable的宽度
* font:字号
* defaultHeight:默认高度,若大于该高度则显示展开收起按钮,低于该高度则正常显示文字高度
* fixedHeight:其他控件固定高度
* btnHeight:展开收起按钮高度
*/
+ (CGFloat)cellHeightWith:(NSString *)contentStr andIsShow:(BOOL)isShow andLableWidth:(CGFloat)width andFont:(CGFloat)font andDefaultHeight:(CGFloat)defaultHeight andFixedHeight:(CGFloat)fixedHeight andIsShowBtn:(CGFloat)btnHeight;
@end
______________________________________________________________________________________________________________________
#import "RemarksCellHeightModel.h"
@implementation RemarksCellHeightModel
+ (CGFloat)cellHeightWith:(NSString *)contentStr andIsShow:(BOOL)isShow andLableWidth:(CGFloat)width andFont:(CGFloat)font andDefaultHeight:(CGFloat)defaultHeight andFixedHeight:(CGFloat)fixedHeight andIsShowBtn:(CGFloat)btnHeight
{
CGRect rect = [contentStr boundingRectWithSize:CGSizeMake(width, 1000) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:font]} context:nil];
if (rect.size.height > defaultHeight) {
if (isShow) {
return fixedHeight + btnHeight + rect.size.height;
}else{
return fixedHeight + btnHeight + defaultHeight;
}
} else {
return fixedHeight + rect.size.height;
}
return 100;
}
@end
2、设置一个属性,存放cell视图展开状态的字典
// 存放cell视图展开状态的字典
@property (nonatomic, strong) NSMutableDictionary *cellIsShowAll;
3、在tableView的协议方法中,根据不同的展开收起状态返回Cell的高度
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
// 返回Cell高度
return [RemarksCellHeightModel cellHeightWith:[self.dataSource objectAtIndex:indexPath.row] andIsShow:[[self.cellIsShowAll objectForKey:[NSString stringWithFormat:@"%ld", indexPath.row]] boolValue] andLableWidth:BOUNDS.size.width-30 andFont:12 andDefaultHeight:52 andFixedHeight:42 andIsShowBtn:8];
}
4、自定义Cell中要注意控件的赋值操作
- (void)setCellContent:(NSString *)contentStr andIsShow:(BOOL)isShow andCellIndexPath:(NSIndexPath *)indexPath
{
_textsLabel.text = contentStr;
_cellIndexPath = indexPath;
// 获取文字高度
CGRect rect = [_textsLabel.text boundingRectWithSize:CGSizeMake(BOUNDS.size.width-30, 1000) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:12]} context:nil];
if (rect.size.height > 52) {
// 文字大于三行,显示展开收起按钮
self.moreBtn.hidden = NO;
if (isShow) {
_textsLabel.numberOfLines = 0;
[_textsLabel mas_remakeConstraints:^(MASConstraintMaker *make){
make.left.mas_equalTo(self.contentView.mas_left).offset(15);
make.top.mas_equalTo(_infolable.mas_bottom).offset(5);
make.width.mas_equalTo(BOUNDS.size.width-30);
make.height.mas_equalTo(rect.size.height);
}];
} else {
[_textsLabel mas_remakeConstraints:^(MASConstraintMaker *make){
make.left.mas_equalTo(self.contentView.mas_left).offset(15);
make.top.mas_equalTo(_infolable.mas_bottom).offset(5);
make.width.mas_equalTo(BOUNDS.size.width-30);
make.height.mas_equalTo(52);
}];
}
} else {
// 文字小于三行,隐藏展开收起按钮
_textsLabel.numberOfLines = 3;
self.moreBtn.hidden = YES;
[_textsLabel mas_remakeConstraints:^(MASConstraintMaker *make){
make.left.mas_equalTo(self.contentView.mas_left).offset(15);
make.top.mas_equalTo(_infolable.mas_bottom).offset(5);
make.width.mas_equalTo(BOUNDS.size.width-30);
make.height.mas_equalTo(rect.size.height+1); // 由于系统计算的那个高度有时候会有1像素到2像素的误差,所以这里把高度+1
}];
}
}
5、显示更多按钮点击事件
#pragma mark - 显示更多按钮点击事件
- (void)moreButtonClicked
{
self.moreBtn.selected = !self.moreBtn.selected;
if (self.moreBtn.selected) {
[self.moreBtn setImage:[UIImage imageNamed:@"xiala"] forState:UIControlStateNormal];
}else{
[self.moreBtn setImage:[UIImage imageNamed:@"shq"] forState:UIControlStateNormal];
}
// 记录当前按钮的选中状态,并传递给Controller
NSMutableDictionary *dic = [NSMutableDictionary dictionary];
[dic setObject:[NSNumber numberWithInteger:_cellIndexPath.row] forKey:@"row"];
[dic setObject:[NSNumber numberWithBool:self.moreBtn.selected] forKey:@"isShow"];
// 协议回调,改变Controller中存放Cell展开收起状态的字典
if (self.delegate && [self.delegate respondsToSelector:@selector(remarksCellShowContrntWithDic:andCellIndexPath:)]) {
[self.delegate remarksCellShowContrntWithDic:dic andCellIndexPath:_cellIndexPath];
}
}
6、Controller中代理方法实现
#pragma mark -- Dalegate
- (void)remarksCellShowContrntWithDic:(NSDictionary *)dic andCellIndexPath:(NSIndexPath *)indexPath
{
[self.cellIsShowAll setObject:[dic objectForKey:@"isShow"] forKey:[NSString stringWithFormat:@"%@",[dic objectForKey:@"row"]]];
[_tableView reloadData];
}
三、整个TableView中只有一个Cell有展开收起功能
实现原理同二,只是本部分更简单,不用字典来存放那么多的Cell的展开收起状态,只需一个全局的属性来存放Cell的展开收起状态
核心代码如下
{
BOOL _isShow; // 是否展开
NSString *_cellContentStr; // 备注消息
}
______________________________________________________________________________________________________________________
______________________________________________________________________________________________________________________
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0) {
return 174;
} else if (indexPath.section == 1) {
return [RemarksCellHeightModel cellHeightWith:_cellContentStr andIsShow:_isShow andLableWidth:BOUNDS.size.width-30 andFont:12 andDefaultHeight:52 andFixedHeight:42 andIsShowBtn:8];
} else {
return 38;
}
}
______________________________________________________________________________________________________________________
______________________________________________________________________________________________________________________
static NSString *cellName = @"meTableViewCell";
RemarksTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellName];
if (!cell) {
cell = [[RemarksTableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellName];
cell.delegate = self;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
[cell setCellContent:_cellContentStr andIsShow:_isShow andCellIndexPath:indexPath];
return cell;
______________________________________________________________________________________________________________________
______________________________________________________________________________________________________________________
#pragma mark -- Dalegate
- (void)remarksCellShowContrntWithDic:(NSDictionary *)dic andCellIndexPath:(NSIndexPath *)indexPath
{
_isShow = [[NSString stringWithFormat:@"%@",[dic objectForKey:@"isShow"]] boolValue];
[_tableView reloadData];
}
Demo中的代码约束使用的是Masonry三方约束,Masonry使用详解