屏幕快照 2018-01-30 下午2.24.32.png
2.DTAttributedTextView
其实,DTAttributedTextView和DTAttributedLabel的用法几乎一样。从其源码上就能看出,DTAttributedLabel继承于DTAttributedTextContentView的,而DTAttributedTextView包含DTAttributedTextContentView属性。可以说DTAttributedTextView就是借助DTAttributedLabel实现的视图。
DTAttributedTextView是支持滑动显示的富文本视图,在使用时计算富文本的Frame也就没那么必要了,一般我们都会指定它的Frame。其在这里的用法就不累述了。
3.DTAttributedTextCell
如果我们需要在单元格上显示富文本,DTCoretText也为我们提供了特有的类来解决这个问题,那就是DTAttributedTextCell。通过这个单元格类,我们可以方便的设置富文本以及获取单元格高度。以下是使用DTAttributedTextCell显示富文本的核心代码:
3.1. 声明控制器内属性
@interface TestTableViewController ()<UITableViewDataSource,UITableViewDelegate,DTAttributedTextContentViewDelegate,DTLazyImageViewDelegate>
@property(nonatomic,strong)UITableView *tableView;
//普通单元格与富文本单元格
@property (nonatomic, copy) NSString *cellID_Normal;
@property (nonatomic, copy) NSString *cellID_DTCoreText;
//类似tabelView的缓冲池,用于存放图片大小
@property (nonatomic, strong) NSCache *imageSizeCache;
@property (nonatomic,strong)NSCache *cellCache;
//表视图数据源
@property (nonatomic, strong) NSArray *dataSource;
//当前表视图是否在滑动
@property (nonatomic,assign)BOOL isScrolling;
@end
3.2.表视图代理方法返回单元格及其高度
//代理方法:返回单元格
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
switch (indexPath.section) {
case 0:{
//普通单元格
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:_cellID_Normal];
cell.textLabel.text = self.dataSource[indexPath.section][indexPath.row];
return cell;
break;
}
case 1:{
//自定义方法,创建富文本类型的单元格
ZSDTCoreTextCell *dtCell = (ZSDTCoreTextCell *) [self tableView:tableView prepareCellForIndexPath:indexPath];
return dtCell;
break;
}
default:
break;
}
return nil;
}
//返回单元格高度
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(nonnull NSIndexPath *)indexPath{
switch (indexPath.section) {
case 0:{
return 50;
break;
}
case 1:{
//返回富文本类型单元格的方法
ZSDTCoreTextCell *cell = (ZSDTCoreTextCell *)[self tableView:tableView prepareCellForIndexPath:indexPath];
return [cell requiredRowHeightInTableView:tableView];
break;
}
default:
break;
}
return 0;
}
3.3.懒加载处理无宽高属性的图片
#pragma mark - DTAttributedTextContentViewDelegate
//对于没有在Html标签里设置宽高的图片,在这里为其设置占位
- (UIView *)attributedTextContentView:(DTAttributedTextContentView *)attributedTextContentView viewForAttachment:(DTTextAttachment *)attachment frame:(CGRect)frame{
if([attachment isKindOfClass:[DTImageTextAttachment class]]){
//自定义的ZSDTLazyImageView继承于DTLazyImageView,增加了一个属性textContentView
//用于更新图片大小
ZSDTLazyImageView *imageView = [[ZSDTLazyImageView alloc] initWithFrame:frame];
imageView.delegate = self;
imageView.image = [(DTImageTextAttachment *)attachment image];
imageView.textContentView = attributedTextContentView;
imageView.url = attachment.contentURL;
return imageView;
}
return nil;
}
//对于无宽高的图片懒加载,缓存记录其大小,然后执行表视图更新
- (void)lazyImageView:(ZSDTLazyImageView *)lazyImageView didChangeImageSize:(CGSize)size{
BOOL needUpdate = NO;
NSURL *url = lazyImageView.url;
NSPredicate *pred = [NSPredicate predicateWithFormat:@"contentURL == %@", url];
/* update all attachments that matchin this URL (possibly multiple
images with same size)
*/
for (DTTextAttachment *oneAttachment in [lazyImageView.textContentView.layoutFrame textAttachmentsWithPredicate:pred]){
// update attachments that have no original size, that also sets the display size
if (CGSizeEqualToSize(oneAttachment.originalSize, CGSizeZero)){
oneAttachment.originalSize = size;
NSValue *sizeValue = [_imageSizeCache objectForKey:oneAttachment.contentURL];
if (!sizeValue) {
//将图片大小记录在缓存中,但是这种图片的原始尺寸可能很大,所以这里设置图片的最大宽
//并且计算高
CGFloat aspectRatio = size.height / size.width;
CGFloat width = ZSToolScreenWidth - 15*2;
CGFloat height = width * aspectRatio;
CGSize newSize = CGSizeMake(width, height);
[_imageSizeCache setObject:[NSValue valueWithCGSize:newSize]forKey:url];
}
needUpdate = YES;
}
}
if (needUpdate){
//有新的图片尺寸被缓存记录的时候,需要刷新表视图
[self reloadCurrentCell];
}
}
3.4.创建富文本单元格的方法
#pragma mark - private Methods
//创建富文本单元格,并更新单元格上的数据
//ZSDTCoreTextCell是自定义的继承于DTCoreTextCell的单元格
- (ZSDTCoreTextCell *)tableView:(UITableView *)tableView prepareCellForIndexPath:(NSIndexPath *)indexPath{
NSString *key = [NSString stringWithFormat:@"dtCoreTextCellKEY%ld-%ld", (long)indexPath.section, (long)indexPath.row];
ZSDTCoreTextCell *cell = [_cellCache objectForKey:key];
if (!cell){
cell = [[ZSDTCoreTextCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:_cellID_DTCoreText];
cell.attributedTextContextView.edgeInsets = UIEdgeInsetsMake(0, 15, 0, 15);
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
cell.accessoryType = UITableViewCellAccessoryNone;
cell.hasFixedRowHeight = NO;
cell.textDelegate = self;
cell.attributedTextContextView.shouldDrawImages = YES;
//记录在缓存中
[_cellCache setObject:cell forKey:key];
}
//2.设置数据
//2.1为富文本单元格设置Html数据
[cell setHTMLString:self.dataSource[indexPath.section][indexPath.row]];
//2.2为每个占位图(图片)设置大小,并更新
for (DTTextAttachment *oneAttachment in cell.attributedTextContextView.layoutFrame.textAttachments) {
NSValue *sizeValue = [_imageSizeCache objectForKey:oneAttachment.contentURL];
if (sizeValue) {
cell.attributedTextContextView.layouter=nil;
oneAttachment.displaySize = [sizeValue CGSizeValue];
[cell.attributedTextContextView relayoutText];
}
}
[cell.attributedTextContextView relayoutText];
return cell;
}
3.5.处理表视图的刷新
如果当前表视图在滑动就不执行刷新,因为滑动时候会自动调用表视图的刷新方法
- (void)reloadCurrentCell{
if (self.isScrolling) {
return;
}
//如果当前表视图没有在滑动,就手动刷新当前在屏幕显示的单元格
NSArray *indexPaths = [self.tableView indexPathsForVisibleRows];
if(indexPaths){
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
});
}
}
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView{
_isScrolling = NO;
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
_isScrolling = YES;
}
3.6.set方法创建表视图与数据源
#pragma mark - set/get方法
- (UITableView *)tableView{
if (_tableView == nil) {
_tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, ZSToolScreenWidth, ZSToolScreenHeight-64) style:UITableViewStylePlain];
_tableView.dataSource = self;
_tableView.delegate = self;
[_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:_cellID_Normal];
//[_tableView registerClass:[ZSDTCoreTextCell class] forCellReuseIdentifier:_cellID_DTCoreText];
}
return _tableView;
}
- (NSArray *)dataSource{
if(_dataSource == nil){
NSMutableArray *noramDataArray = @[].mutableCopy;
NSMutableArray *htmlDataArray = @[].mutableCopy;
NSArray *images = @[@"https://i0.hdslb.com/bfs/archive/d5ad3cf95d32f3d2f2e3471a39120237200d84d8.jpg",
@"https://i0.hdslb.com/bfs/archive/71d2fed927d9351e759f408ca7d66c556c37a6b4.jpg",
@"https://i0.hdslb.com/bfs/archive/7f520b31b67cd5d89dd30b61b40711327bb00288.png",
@"https://i0.hdslb.com/bfs/archive/6edbe81bf74c106087ad139aca169d6e8d9d963b.jpg",
@"https://i0.hdslb.com/bfs/archive/805aa8f7ae722fcc277f425bb9927e29ec1d2468.jpg",
@"https://i0.hdslb.com/bfs/archive/a7c61d94c583363a970d2a2e339eea97f8f32317.jpg",
@"https://i0.hdslb.com/bfs/archive/b447ee1fd63b4cf6f4465a5621cc12898867d26b.jpg"];
for(int i = 0;i<1000;i++){
if(i <6){
[noramDataArray addObject:[NSString stringWithFormat:@"测试普通单元格:%d",i]];
}
//这里提供的Html图片链接,没有宽高属性,代码中已经演示了如何处理
int k = i % 6;
NSString *htmlString =[NSString stringWithFormat:@"<span style="color:#333;font-size:15px;"><strong>测试富文本单元格%d:</strong></span><br/><span style="color:#333;font-size:15px;">记住!砍价是由你自己先砍,砍不动时再由砍价师继续砍;由砍价师多砍下的部分,才按照下列标准收费:</span><br/><span style="color:#333;font-size:15px;"><img src=%@ _src=%@></span>",i,images[k],images[k]];
[htmlDataArray addObject:htmlString];
}
_dataSource = @[noramDataArray,htmlDataArray];
}
return _dataSource;
}
使用上述方法使用DTAttributedTextCell的效果图如下: