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;@endImageListView.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
#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;}
- iOS新浪微博客户端开发(4)——自定义微博Cell的实现
- ios开发——新浪微博客户端
- 猫猫学IOS(十七)UI之纯代码自定义Cell实现新浪微博UI
- AJ学IOS(17)UI之纯代码自定义Cell实现新浪微博UI
- iOS开发-新浪微博自定义tabbar的实现
- 自定义cell的高度(新浪微博)
- 通过代码自定义cell(cell的高度不一致)实现新浪微博界面
- iOS新浪微博客户端开发(1)——新特性界面
- iOS新浪微博客户端开发(2)——OAuth授权
- iOS新浪微博客户端开发(3)——主界面搭建与动画
- iOS新浪微博客户端开发(1)——新特性界面
- iOS新浪微博客户端开发(2)——OAuth授权
- iOS新浪微博客户端开发(3)——主界面搭建与动画
- (素材源码)猫猫学IOS(十七)UI之纯代码自定义Cell实现新浪微博UI
- 新浪微博客户端的开发
- iphone开发我的新浪微博客户端-用户登录自定义弹出窗口篇(1.2)
- iphone开发我的新浪微博客户端-用户登录自定义弹出窗口篇(1.2)
- 新浪微博客户端开发之主界面实现
- 蓝桥杯 算法训练 出现次数最多的整数
- URAL 1385 Interesting Number
- JAVA 枚举类型
- C++中new和delete用法
- RatingBar简单介绍
- iOS新浪微博客户端开发(4)——自定义微博Cell的实现
- 【MOOC】程序设计入门-C 语言 作业汇总
- 第二周阅读程序(1)
- 当ListView有Header时,onItemClick里的position不正确
- 把数组排成最小数
- hdu1068 二分图的最大独立集
- grub rescue
- Scala-3 - 5 - Lecture 2.5 - Functions and Data (11_50)
- 进程与线程间的通信方式