iOS新浪微博客户端开发(4)——自定义微博Cell的实现

来源:互联网 发布:2016无限申请淘宝小号 编辑:程序博客网 时间:2024/05/18 02:38

首先看一下效果图(不带转发微博和带转发微博):

 

一、微博Cell布局分析

微博Cell的详细布局如下图所示,其主要控件有:头像、昵称、微博时间、来源、微博正文。如果有被转发微博,还包括被转发微博的整体框架、转发微博的用户昵称、转发微博的内容以及Cell下方的操作条(转发、评论、赞)等。

二、用户头像的封装——HeadIconView类

用过新浪微博APP的朋友们都知道,微博用户一共有4种认证:无认证、微博达人、个人vip、企业vip。针对不同的认证,微博会在用户头像的右下角显示不同的图标。同时,应用中不同的地方用户头像的尺寸大小也不尽相同,为了应用更好的扩展性和后期维护性,需要对用户头像进行封装。

用户头像的显示中包括头像、认证图标。HeadIconView类应继承自UIView,其持有User对象,并重写setUser方法,当HeadIconView拿到User对象后,根据User中的

profile_image_url等信息设置用户的头像、头像大小以及认证图标等。

HeadIconView.h

#import <UIKit/UIKit.h>typedef enum{    kHeadIconTypeSmall,    kHeadIconTypeDefault,    kHeadIconTypeBig}HeadIconType;@class User;@interface HeadIconView : UIView@property (strong, nonatomic)User *user;@property (assign, nonatomic)HeadIconType headIconType;+(CGSize)headIconSizeWithType:(HeadIconType)iconType;-(void)setUser:(User *)user type:(HeadIconType)type;@end

HeadIconView.m

#import "HeadIconView.h"#import "Macro.h"#import "User.h"#import "HttpTool.h"@interface HeadIconView(){    UIImageView *_headIcon;    // 头像图片    UIImageView *_verifyIcon;  // 认证图标        NSString *_placeHolder;    // 占位图片名称}@end@implementation HeadIconView-(instancetype)initWithFrame:(CGRect)frame{    if (self = [super initWithFrame:frame]) {        // 1. 用户头像图片        _headIcon = [[UIImageView alloc]init];        [self addSubview:_headIcon];                // 2. 认证图标        _verifyIcon = [[UIImageView alloc]init];        [self addSubview:_verifyIcon];    }        return self;}-(void)setUser:(User *)user{    _user = user;        // 1. 设置用户头像    [HttpTool downloadImage:user.profile_image_url placeholderImage:[UIImage imageNamed:_placeHolder] imageView:_headIcon];        // 2. 设置认证图标    NSString *verifiedIcon = nil;    switch (user.verified_type) {        case kVerifiedTypeNone:            _verifyIcon.hidden = YES;            break;                    case kVerifiedTypeDaren:            _verifyIcon.hidden = NO;            verifiedIcon = @"avatar_grassroot.png";            break;                case kVerifiedTypePersonal:            _verifyIcon.hidden = NO;            verifiedIcon = @"avatar_vip.png";            break;                    default:            _verifyIcon.hidden = NO;            verifiedIcon = @"avatar_enterprise_vip.png";            break;    }        if (verifiedIcon) {        _verifyIcon.hidden = NO;        _verifyIcon.image = [UIImage imageNamed:verifiedIcon];    }}-(void)setUser:(User *)user type:(HeadIconType)type{    self.headIconType = type;    self.user = user;}#pragma mark 设置头像和认证图标的类型-(void)setHeadIconType:(HeadIconType)headIconType{    _headIconType = headIconType;        // 1. 判断认证类型    CGSize headIconSize;        switch (headIconType) {        case kHeadIconTypeSmall:            headIconSize = CGSizeMake(kHeadIconSmallW, kHeadIconSmallH);            _placeHolder = @"avatar_default_small.png";            break;                    case kHeadIconTypeDefault:            headIconSize = CGSizeMake(kHeadIconDefaultW, kHeadIconDefaultH);            _placeHolder = @"avatar_default.png";            break;                    case kHeadIconTypeBig:            headIconSize = CGSizeMake(kHeadIconBigW, kHeadIconBigH);            _placeHolder =  @"avatar_default_big.png";            break;    }        // 2. 设置frame    _headIcon.frame = (CGRect){CGPointZero, headIconSize};    _verifyIcon.bounds = CGRectMake(0, 0, kVerifyIconW, kVerifyIconH);    _verifyIcon.center = CGPointMake(headIconSize.width, headIconSize.height);        CGFloat width = headIconSize.width + kVerifyIconW*0.5;    CGFloat height = headIconSize.height + kVerifyIconH*0.5;    self.bounds = CGRectMake(0, 0, width, height);}#pragma mark 设置头像的大小+(CGSize)headIconSizeWithType:(HeadIconType)iconType{    CGSize headIconSize;        switch (iconType) {        case kHeadIconTypeSmall:            headIconSize = CGSizeMake(kHeadIconSmallW, kHeadIconSmallH);            break;                    case kHeadIconTypeDefault:            headIconSize = CGSizeMake(kHeadIconDefaultW, kHeadIconDefaultH);            break;                case kHeadIconTypeBig:            headIconSize = CGSizeMake(kHeadIconBigW, kHeadIconBigH);            break;    }        CGFloat width = headIconSize.width + kVerifyIconW * 0.5;    CGFloat height = headIconSize.height + kVerifyIconH*0.5;        return CGSizeMake(width, height);}@end

三、微博配图的封装(ImageItemView和ImageListView)

当一条微博有配图时,我们需要判断微博配图的数目并将这些配图以正确的方式显示出来。

这些配图可能是Gif图片或普通静态图片,当拿到微博配图数据时,要判断其图片类型,并设置相应的gif标志。首先对单个配图进行封装,ImageItemView类设置一个NSString类型的对象——imageUrl,并重写setImageUrl方法,当拿到图片的URL时,自动加载图片并判断图片是否gif。

ImageItemView.h

#import <UIKit/UIKit.h>@interface ImageItemView : UIImageView@property (copy, nonatomic)NSString *imageUrl;@end

ImageItemView.m
#import "ImageItemView.h"#import "HttpTool.h"@interface ImageItemView(){    UIImageView *_gifFlagImage;}@end@implementation ImageItemView-(instancetype)initWithFrame:(CGRect)frame{    if (self = [super initWithFrame:frame]) {        _gifFlagImage = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"timeline_image_gif.png"]];        [self addSubview:_gifFlagImage];    }    return self;}-(void)setImageUrl:(NSString *)imageUrl{    _imageUrl = imageUrl;        // 1. 加载图片    [HttpTool downloadImage:imageUrl placeholderImage:[UIImage imageNamed:@"timeline_image_loading.png"] imageView:self];        // 2. 判断该图片是否时gif    _gifFlagImage.hidden = ![imageUrl.lowercaseString hasSuffix:@"gif"];}-(void)setFrame:(CGRect)frame{    // 设置gifView的位置    CGRect gifViewFrame = _gifFlagImage.frame;    gifViewFrame.origin.x = frame.size.width - gifViewFrame.size.width;    gifViewFrame.origin.y = frame.size.height - gifViewFrame.size.height;    _gifFlagImage.frame = gifViewFrame;        [super setFrame:frame];}@end

由于微博的配图数目范围为0~9,对于不同数目的配图单独处理其布局显然是不合适的,因此,需要也需要对配图类进行封装。ImageListView类中有一个NSArray类型的对象用于接收外部传入的微博配图信息(配图的URL),并根据配图的数目自动确定显示配图控件的CGSize大小。

ImageListView.h

#import <UIKit/UIKit.h>@interface ImageListView : UIView@property (strong, nonatomic)NSArray *imageUrlList;+(CGSize)imageListSizeWithCount:(int)count;@end
ImageListView.m
#define kCount 9#define kSingleImageW 120#define kSingleImageH 120#define kMultiImageW 80#define kMultiImageH 80#define kMargin 5#import "ImageListView.h"#import "UIImageView+WebCache.h"#import "ImageItemView.h"@implementation ImageListView-(instancetype)initWithFrame:(CGRect)frame{    if (self = [super initWithFrame:frame]) {        // 先把有可能显示的空间都加入        for (int i = 0; i < kCount; i++) {            ImageItemView *imageView = [[ImageItemView alloc]init];            [self addSubview:imageView];        }    }        return  self;}-(void)setImageUrlList:(NSArray *)imageUrlList{    _imageUrlList = imageUrlList;    int count = (int)imageUrlList.count;        for (int i = 0; i < kCount; i++) {        // 1. 取出对应位置的子控件        ImageItemView *child = self.subviews[i];                // 2. 判断配图的数量        if (i >= count) {            child.hidden = YES; // 多余的位置隐藏        }else{            child.hidden = NO;                        // 3. 设置图片            child.imageUrl = imageUrlList[i][@"thumbnail_pic"];                        // 4. 设置frame            if (count == 1) {                child.contentMode = UIViewContentModeScaleAspectFit; // 自适应图片的大小                child.frame = CGRectMake(0, 0, kSingleImageW, kSingleImageH);            }else{                int temp = (count == 4 ? 2 : 3);                int row = i / temp;                int column = i % temp;                                CGFloat x = (kMultiImageW + kMargin)*column;                CGFloat y = (kMultiImageH + kMargin)*row;                child.frame = CGRectMake(x, y, kMultiImageW, kMultiImageH);                child.contentMode = UIViewContentModeScaleAspectFill; // 图片适应内容拉伸                child.clipsToBounds = YES; // 剪去图片的多余部分                            }        }    }}+(CGSize)imageListSizeWithCount:(int)count{    // 1. 只有一张配图    if (count == 1) {        return CGSizeMake(kSingleImageW, kSingleImageH);    }        // 2. 至少有两张配图    int countRow = ((count == 4) ? 2 : 3);        // 总行数    int rows = (count + countRow - 1) / countRow;        // 总列数    int columns = (count >= 3 ? 3 : 2);        CGFloat width = columns * kMultiImageW + (columns - 1) * kMargin;    CGFloat height = rows * kMultiImageH + (rows - 1) * kMargin;        return CGSizeMake(width, height);}@end

四、微博底部状态条(CellOptionBar)

状态条中得数据是由微博(Status)的信息得到的,CellOptionBar持有Status对象,并用status中的repost_count、comments_count和attitudes_count设置button上显示的数字。

CellOptionBar.h

#import <UIKit/UIKit.h>@class Status;@interface CellOptionBar : UIImageView@property (strong, nonatomic)Status *status;@end


CellOptionBar.m
#import "CellOptionBar.h"#import "Status.h"#import "UIImage+Extended.h"#import "NSString+Extended.h"#import "Macro.h"@interface CellOptionBar(){    UIButton *_repostButton;    UIButton *_commentButton;    UIButton *_attitudeButton;}@end@implementation CellOptionBar-(instancetype)initWithFrame:(CGRect)frame{    if (self = [super initWithFrame:frame]) {        // 设置自动伸缩,粘在cell的底部        //self.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;                // 设置可以接收用户点击        self.userInteractionEnabled = YES;                // 设置背景        self.image = [UIImage resizedImage:@"timeline_card_background.png"];        self.highlightedImage = [UIImage resizedImage:@"timeline_card_background_highlighted.png"];                // 添加底部的三个按钮        _repostButton = [self addButtonWithTitle:@"转发" iconImage:@"timeline_icon_retweet.png" backgroundImage:@"timeline_card_middle_background.png"buttonIndex:0];        _commentButton = [self addButtonWithTitle:@"评论" iconImage:@"timeline_icon_comment.png" backgroundImage:@"timeline_card_middle_background.png" buttonIndex:1];        _attitudeButton = [self addButtonWithTitle:@"赞" iconImage:@"timeline_icon_like_disable.png" backgroundImage:@"timeline_card_middle_background.png" buttonIndex:2];    }        return self;}-(UIButton *)addButtonWithTitle:(NSString*)title iconImage:(NSString*)iconImage backgroundImage:(NSString*)bgImage buttonIndex:(NSInteger)index{    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];        // 标题    [button setTitle:title forState:UIControlStateNormal];        // 图标    [button setImage:[UIImage imageNamed:iconImage] forState:UIControlStateNormal];        // 背景图片    [button setBackgroundImage:[UIImage resizedImage:bgImage] forState:UIControlStateNormal];    [button setBackgroundImage:[UIImage resizedImage:[bgImage fileNameAppend:@"_highlighted"]] forState:UIControlStateHighlighted];        // 文字颜色    [button setTitleColor:[UIColor colorWithWhite:0.647 alpha:1.000] forState:UIControlStateNormal];    button.titleLabel.font = [UIFont systemFontOfSize:12];        // 设置按钮的frame    CGFloat width = self.frame.size.width / 3;    button.frame = CGRectMake(width * index, 0, width, kCellBarHeight);        // 设置文字左边与图片的间距    button.titleEdgeInsets = UIEdgeInsetsMake(0, 5, 0, 0);        [self addSubview:button];        if (index) {        UIImage * dividerImage = [UIImage imageNamed:@"timeline_card_bottom_line.png"];        UIImageView *divider = [[UIImageView alloc]initWithImage:dividerImage];        divider.center = CGPointMake(button.frame.origin.x, kCellBarHeight * 0.5);                [self addSubview:divider];    }        return button;}-(void)setButton:(UIButton*)button withTitle:(NSString*)title withCount:(int)count{    if (count >= 10000) {        NSString *title = [NSString stringWithFormat:@"%.1f万", count / 10000.0];        title = [title stringByReplacingOccurrencesOfString:@".0" withString:@""];        [button setTitle:title forState:UIControlStateNormal];    }else if (count > 0){        [button setTitle:[NSString stringWithFormat:@"%d", count] forState:UIControlStateNormal];    }else{        [button setTitle:title forState:UIControlStateNormal];    }}-(void)setFrame:(CGRect)frame{    frame.size.width = [UIScreen mainScreen].bounds.size.width;    frame.size.height = kCellBarHeight;    [super setFrame:frame];}-(void)setStatus:(Status *)status{    _status = status;        // 1. 转发    [self setButton:_repostButton withTitle:@"转发" withCount:status.repost_count];        // 2. 评论    [self setButton:_commentButton withTitle:@"评论" withCount:status.comments_count];        // 3. 赞    [self setButton:_attitudeButton withTitle:@"赞" withCount:status.attitudes_count];}@end

五、Cell及内部frame的计算

首先,StatusCellFrame类负责计算每条微博中各个子控件的frame,它有一个Status类型的变量,拿到微博的详细数据后开始计算frame;

StatusCell持有StatusCellFrame对象,使用cell.statusCellFrame设置各个Cell的frame。

StatusCellFrame.h

#import <Foundation/Foundation.h>#import <UIKit/UIKit.h>@class Status;@interface StatusCellFrame : NSObject{    CGFloat _cellHeight;    CGRect _repostFrame; // 被转发微博的父控件}@property (strong, nonatomic)Status *status;  // 微博数据@property (readonly, nonatomic) CGFloat cellHeight;@property (readonly, nonatomic) CGRect headIconFrame; // 头像的frame@property (readonly, nonatomic) CGRect screenNameFrame;@property (readonly, nonatomic) CGRect mbIconFrame;@property (readonly, nonatomic) CGRect timeFrame;@property (readonly, nonatomic) CGRect sourceFrame;@property (readonly, nonatomic) CGRect textFrame;@property (readonly, nonatomic) CGRect imageFrame;@property (readonly, nonatomic) CGRect repostedFrame; // 被转发微博的父控件@property (readonly, nonatomic) CGRect repostedScreenNameFrame;@property (readonly, nonatomic) CGRect repostedTextFrame;@property (readonly, nonatomic) CGRect repostedImageFrame;@property (readonly, nonatomic) CGRect cellBarFrame;@property (readonly, nonatomic) CGRect blankBarFrame;@end

StatusCellFrame.m

#import "StatusCellFrame.h"#import "Status.h"#import "User.h"#import "HeadIconView.h"#import "ImageListView.h"#import "Macro.h"@implementation StatusCellFrame-(void)setStatus:(Status *)status{    _status = status;        // 拿到微博数据即计算其内部各控件的frame        // 整个cell的宽度    CGFloat cellWidth = [UIScreen mainScreen].bounds.size.width;        // 1. 头像    CGFloat headIconX = kCellBorderWidth_Cell;    CGFloat headIconY = kCellBorderWidth_Cell;    CGSize iconSize = [HeadIconView headIconSizeWithType:kHeadIconTypeSmall];    _headIconFrame = CGRectMake(headIconX, headIconY, iconSize.width, iconSize.height);        // 2. 昵称    CGFloat screenNameX = CGRectGetMaxX(_headIconFrame) + kCellBorderWidth;    CGFloat screenNameY = headIconY;    CGSize screenNameSize = [status.user.screenName sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:kGlobalTitleSizeBig]}];    _screenNameFrame = (CGRect){{screenNameX, screenNameY}, screenNameSize};        // 3. 会员图标    if (status.user.mbType != kMBTypeNone) {        CGFloat mbIconX = CGRectGetMaxX(_screenNameFrame) + kCellBorderWidth;        CGFloat mbIconY = screenNameY + (screenNameSize.height - kMBIconH)*0.5;        _mbIconFrame = CGRectMake(mbIconX, mbIconY, kMBIconW, kMBIconH);    }        // 4. 时间    CGFloat timeX = screenNameX;    CGFloat timeY = CGRectGetMaxY(_screenNameFrame) + kCellBorderWidth;    CGSize timeSize = [status.create_at sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:kGlobalTitleSizeSuperSmall]}];    _timeFrame = (CGRect) {{timeX, timeY}, timeSize};        // 5. 微博来源    CGFloat sourceX = CGRectGetMaxX(_timeFrame) + kCellBorderWidth;    CGFloat sourceY = timeY;    CGSize sourceSize = [status.source sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:kGlobalTitleSizeSuperSmall]}];    _sourceFrame = (CGRect){{sourceX, sourceY}, sourceSize};        // 6. 微博内容    CGFloat textX = headIconX;    CGFloat maxY = MAX(CGRectGetMaxY(_sourceFrame), CGRectGetMaxY(_headIconFrame));    CGFloat textY = maxY + kCellBorderWidth;    CGSize textSize = [status.statusContent boundingRectWithSize:CGSizeMake(cellWidth - 2*kCellBorderWidth, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:kGlobalTitleSizeBig]} context:nil].size;    _textFrame = (CGRect) {{textX, textY}, textSize};        if (status.picUrls.count) {// 7. 判断是否有配图        CGFloat imageX = textX;        CGFloat imageY = CGRectGetMaxY(_textFrame) + kCellBorderWidth;        CGSize imageSize = [ImageListView imageListSizeWithCount:(int)status.picUrls.count];        _imageFrame = CGRectMake(imageX, imageY, imageSize.width, imageSize.height);    }else if (status.repostStatus){// 8. 有转发的微博        // 被转发微博的整体框架        CGFloat repostedX = 2;        CGFloat repostedY = CGRectGetMaxY(_textFrame) + kCellBorderWidth;        CGFloat repostedWidth = cellWidth - 4;        CGFloat repostedHeight = 0;                // 9. 被转发微博的昵称        CGFloat repostedScreenNameX = kCellBorderWidth_Cell;        CGFloat repostedScreenNameY = kCellBorderWidth_Cell;        NSString *name = [NSString stringWithFormat:@"@%@", status.repostStatus.user.screenName];        CGSize repostedScreenNameSize = [name sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:kGlobalTitleSizeMiddle]}];        _repostedScreenNameFrame = (CGRect){{repostedScreenNameX, repostedScreenNameY}, repostedScreenNameSize};                // 9. 被转发微博的内容        CGFloat repostedTextX = repostedScreenNameX;        CGFloat repostedTextY = CGRectGetMaxY(_repostedScreenNameFrame) + kCellBorderWidth;        CGSize repostedTextSize = [status.repostStatus.statusContent boundingRectWithSize:CGSizeMake(repostedWidth - 2*kCellBorderWidth, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:kGlobalTitleSizeMiddle]} context:nil].size;        _repostedTextFrame = (CGRect){{repostedTextX, repostedTextY}, repostedTextSize};                // 10. 被转发微博的配图        if (status.repostStatus.picUrls.count) {            CGFloat repostedImageX = repostedTextX;            CGFloat repostedImageY = CGRectGetMaxY(_repostedTextFrame) + kCellBorderWidth;            CGSize imageSize = [ImageListView imageListSizeWithCount:(int)status.repostStatus.picUrls.count];            _repostedImageFrame = CGRectMake(repostedImageX, repostedImageY, imageSize.width, imageSize.height);                        // 11. 计算被转发微博的整体高度            repostedHeight += CGRectGetMaxY(_repostedImageFrame) + kCellBorderWidth;        }else{            repostedHeight += CGRectGetMaxY(_repostedTextFrame) + kCellBorderWidth;        }                _repostedFrame = CGRectMake(repostedX, repostedY, repostedWidth, repostedHeight);    }        // 12. 整个cell的高度    _cellHeight = kCellBarHeight + kCellMargin;    //_cellHeight = kCellBorderWidth + kCellMargin;    if (status.picUrls.count) {        _cellHeight += CGRectGetMaxY(_imageFrame) + kCellBorderWidth;    }else if (status.repostStatus){        _cellHeight += CGRectGetMaxY(_repostedFrame);    }else{        _cellHeight += CGRectGetMaxY(_textFrame) + kCellBorderWidth;    }        // 底部操作条    CGFloat cellbarX = 0;    CGFloat cellbarY = _cellHeight - kCellBarHeight - kCellMargin;    _cellBarFrame = CGRectMake(cellbarX, cellbarY, cellWidth, kCellBarHeight);        // 底部间距栏    CGFloat blankX = 0;    CGFloat blankY = _cellHeight - kCellMargin;    CGFloat blankWidth = cellWidth;    CGFloat blankHeight = 10;    _blankBarFrame = CGRectMake(blankX, blankY, blankWidth, blankHeight);}@end

StatusCell.h

#import <UIKit/UIKit.h>@class StatusCellFrame;@class StatusCell;@protocol StatusCellDelegate <NSObject>@optional-(void)StatusTap:(StatusCell *)cell;-(void)RepostStatusTap:(StatusCell *)cell;@end@interface StatusCell : UITableViewCell{    UIImageView *_background;    UIImageView *_selectedBackground;        UIImageView *_reposted; // 被转发的微博的父控件}@property (strong, nonatomic)StatusCellFrame *cellFrame;@property (assign, nonatomic)id<StatusCellDelegate> delegate;@end

StatusCell.m

#import "StatusCell.h"#import "HeadIconView.h"#import "ImageListView.h"#import "UIImage+Extended.h"#import "Status.h"#import "User.h"#import "StatusCellFrame.h"#import "Macro.h"#import "CellOptionBar.h"@interface StatusCell(){    HeadIconView *_headIcon;          // 头像    UILabel *_screenName;             // 昵称    UIImageView *_mbIcon;             // 会员图标    UILabel *_time;                   // 时间    UILabel *_source;                 // 来源    UILabel *_statusContent;          // 微博内容    ImageListView *_images;           // 微博配图        UILabel *_repostedScreenName;     // 转发微博用户昵称    UILabel *_repostedStatusContent;  // 转发微博内容    ImageListView *_repostedImages;   // 转发微博配图        CellOptionBar *_cellBar;    UIImageView *_blankBar;}@end@implementation StatusCell-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{    if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {                // 1. 添加当前微博的子控件        [self addAllSubViews];                // 2. 添加被转发微博的子控件        [self addRepostAllSubviews];                // 3. 设置背景        [self setBackground];                // 4. 底部的操作条(转发、评论、赞)        _cellBar = [[CellOptionBar alloc]init];        [self.contentView addSubview:_cellBar];    }        return self;}#pragma mark 设置cell的背景-(void)setBackground{    self.backgroundColor = [UIColor clearColor];        // 1. 默认背景    UIImageView *background = [[UIImageView alloc]init];    self.backgroundView = background;    _background = background;    _background.image = [UIImage resizedImage:@"common_card_background.png"];        // 2. 长按背景    UIImageView *selectedBackground = [[UIImageView alloc]init];    self.selectedBackgroundView = selectedBackground;    _selectedBackground = selectedBackground;    _selectedBackground.image = [UIImage resizedImage:@"common_card_background_highlighted.png"];}#pragma mark 添加cell中的子控件-(void)addAllSubViews{    // 1. 头像    _headIcon = [[HeadIconView alloc]init];    [self.contentView addSubview:_headIcon];        // 2. 昵称    _screenName = [[UILabel alloc]init];    _screenName.font = kScreenNameFont;    _screenName.backgroundColor = [UIColor clearColor];    [self.contentView addSubview:_screenName];        // 3. 会员图标    _mbIcon = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"common_icon_membership.png"]];    [self.contentView addSubview:_mbIcon];        // 4. 时间    _time = [[UILabel alloc]init];    _time.font = kTimeFont;    _time.textColor = kColor(246, 165, 68);    _time.backgroundColor = [UIColor clearColor];    [self.contentView addSubview:_time];        // 5. 来源    _source = [[UILabel alloc]init];    _source.font = kSourceFont;    _source.backgroundColor = [UIColor clearColor];    [self.contentView addSubview:_source];        // 6. 微博内容    _statusContent = [[UILabel alloc]init];    _statusContent.font = kStatusContentFont;    _statusContent.numberOfLines = 0;  // 换行    _statusContent.backgroundColor = [UIColor clearColor];    [self.contentView addSubview:_statusContent];        // 7. 微博配图    _images = [[ImageListView alloc]init];    [self.contentView addSubview:_images];        // 8. cell间距图片    _blankBar = [[UIImageView alloc]init];    _blankBar.image = [UIImage resizedImage:@"timeline_card_bottom_background_highlighted.png"];    //_blankBar.backgroundColor = kGlobalBackgroundColor;    [self.contentView addSubview:_blankBar];}#pragma mark 添加被转发的微博的子控件-(void)addRepostAllSubviews{    UITapGestureRecognizer *repostStatusTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(repostStatusTap)];        // 1. 被转发微博的父控件    _reposted = [[UIImageView alloc]init];    _reposted.image = [UIImage resizedImage:@"timeline_retweet_background.png"];    _reposted.userInteractionEnabled = YES;    [_reposted addGestureRecognizer:repostStatusTap];    [self.contentView addSubview:_reposted];        // 2. 被转发微博的用户昵称    _repostedScreenName = [[UILabel alloc]init];    _repostedScreenName.font = kRepostedScreenNameFont;    _repostedScreenName.textColor = kRepostScreenNameColor;    _repostedScreenName.backgroundColor = [UIColor clearColor];    [_reposted addSubview:_repostedScreenName];        // 3. 被转发微博的内容    _repostedStatusContent = [[UILabel alloc]init];    _repostedStatusContent.font = kRepostedTextFont;    _repostedStatusContent.numberOfLines = 0;    _repostedStatusContent.backgroundColor = [UIColor clearColor];    [_reposted addSubview:_repostedStatusContent];        // 4. 被转发微博的配图    _repostedImages = [[ImageListView alloc]init];    [_reposted addSubview:_repostedImages];}-(void)setCellFrame:(StatusCellFrame *)cellFrame{    _cellFrame = cellFrame;        Status *s = cellFrame.status;        // 1. 头像    [_headIcon setUser:s.user type:kHeadIconTypeSmall];    _headIcon.frame = cellFrame.headIconFrame;        // 2. 昵称    _screenName.frame = cellFrame.screenNameFrame;    _screenName.text = s.user.screenName;        // 2.1 判断是否会员    if (s.user.mbType == kMBTypeNone) {        _screenName.textColor = kScreenNameColor;        _mbIcon.hidden = YES;    }else{        _screenName.textColor = kMBScreenNameColor;        _mbIcon.hidden = NO;        _mbIcon.frame = cellFrame.mbIconFrame;    }        // 3. 时间    _time.text = s.create_at;    CGFloat timeX = cellFrame.screenNameFrame.origin.x;    CGFloat timeY = CGRectGetMaxY(cellFrame.screenNameFrame) + kCellBorderWidth;    CGSize timeSize = [_time.text sizeWithAttributes:@{NSFontAttributeName:kTimeFont}];    _time.frame = (CGRect){{timeX, timeY}, timeSize};        // 4. 来源    _source.text = s.source;    CGFloat sourceX = CGRectGetMaxX(_time.frame) + kCellBorderWidth;    CGFloat sourceY = timeY;;    CGSize sourceSize = [_source.text sizeWithAttributes:@{NSFontAttributeName:kSourceFont}];    _source.frame = (CGRect){{sourceX, sourceY}, sourceSize};        // 5. 内容    _statusContent.frame = cellFrame.textFrame;    _statusContent.text = s.statusContent;        // 6. 微博配图    if (s.picUrls.count) {        _images.hidden = NO;        _images.frame = cellFrame.imageFrame;        _images.imageUrlList = s.picUrls;    }else{        _images.hidden = YES;    }        // 7. 被转发的微博    if (s.repostStatus) {                // 父控件是否隐藏        _reposted.hidden = NO;        _reposted.frame = cellFrame.repostedFrame;                // 昵称        _repostedScreenName.frame = cellFrame.repostedScreenNameFrame;        _repostedScreenName.text = [NSString stringWithFormat:@"@%@", s.repostStatus.user.screenName];        // 微博内容        _repostedStatusContent.frame = cellFrame.repostedTextFrame;        _repostedStatusContent.text = s.repostStatus.statusContent;                // 是否有配图        if (s.repostStatus.picUrls.count) {            _repostedImages.hidden = NO;            _repostedImages.frame = cellFrame.repostedImageFrame;            _repostedImages.imageUrlList = s.repostStatus.picUrls;        }else{            _repostedImages.hidden = YES;        }    }else{        _reposted.hidden = YES;    }        // 8. 底部操作条    _cellBar.status = cellFrame.status;    _cellBar.frame = cellFrame.cellBarFrame;            _blankBar.frame = cellFrame.blankBarFrame;}#pragma mark 外部微博的点击事件-(void)statusTap{    if (_delegate && [_delegate respondsToSelector:@selector(StatusTap:)]) {        [_delegate StatusTap:self];    }}#pragma mark 被转发微博的点击事件-(void)repostStatusTap{    if (_delegate && [_delegate respondsToSelector:@selector(RepostStatusTap:)]) {        [_delegate RepostStatusTap:self];    }}@end

下面看看StatusCell类如何使用:

// 获取最新的微博数据    [StatusTool statusesWithSinceId:sinceId maxId:0 success:^(NSArray *statuses) {        // 1. 拿到最新的微博数据时,计算它的frame        NSMutableArray *newFrames = [NSMutableArray array];        for (Status *s in statuses) {            StatusCellFrame *cellFrame = [[StatusCellFrame alloc]init];            cellFrame.status = s;                        [newFrames addObject:cellFrame];        }                // 2. 将newFrames整体插入到旧数据前面        [_statusFrames insertObjects:newFrames atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, newFrames.count)]];                // 3. 刷新表格        [self.tableView reloadData];                // 4. 结束刷新        [self.tableView headerEndRefreshing];                // 5. 在顶部展示最新微博的数目        [self showNewStatusCount:(int)statuses.count];        #warning 播放声音不应该在这里        // 播放声音        if (_wavPath) {            NSURL *soundURL = [NSURL fileURLWithPath:_wavPath];            _audioPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:soundURL error:nil];            [_audioPlayer play];        }    } failure:^(NSError *err) {        // 结束刷新        [self.tableView headerEndRefreshing];    }];

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {        static NSString *CellIdentifier = @"Cell";        StatusCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];        // Configure the cell...    if (cell == nil) {        cell = [[StatusCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];        cell.delegate = self;    }        cell.cellFrame = _statusFrames[indexPath.row];        return cell;}

0 0