年年有"余"

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 20871|回复: 41

[新浪微博] ios实战开发之仿新浪微博(第十讲:微博功能完善二)

[复制链接]
  • TA的每日心情
    奋斗
    2022-12-13 21:26
  • 签到天数: 371 天

    [LV.9]以坛为家II

    发表于 2014-4-24 00:31:12 | 显示全部楼层 |阅读模式
    1、效果演示



    2、更新说明

    2.1、增加点击微博显示详细信息
    2.2、优化微博展示功能
    2.3、增加各按钮点击事件(演示事件)

    3、设计说明

    3.1 点击某条微博,进入该微博的详细信息,通过新窗口展示
    3.1.1 该新窗口通过监听微博的点击事件触发,新窗口为导航控制器的子控制器,将首页控制器弹出
    3.1.1.1 首页控制器下面有主管理器的Dock栏,而新窗口不需要该导航条,因此在新窗口进入主屏幕时需要完成去掉Dock栏并调节新窗口高度;
    3.1.1.2 导航控制器有两个代理方法,分别在新控制器即将进入主屏幕完全进入主屏幕时调用;
    3.1.1.3 实现这两个方法,即将进入主屏幕时将Dock栏从主管理器上撤出,调整Dock的位置并加到Home控制器(导航控制器的根控制器)上,视觉上Dock栏与根控制器一起并推出;
    3.1.1.4 在切回根控制器时,实现第二个方法,让根控制器即回到主屏幕时(即完全进入主屏幕)后将Dock归还给主管理器并调整Dock位置,视觉上Dock栏与根控制器一起并退回;

    3.2 微博详细信息界面设计
    3.2.1 详细页面的内容除了首页展示的微博信息外,附加该微博的转发详细信息与评论详细信息以及点赞数
    3.2.2 两者对比图:
    iOS 模拟器屏幕快照“2014年4月23日 下午11.21.24”副本.png iOS 模拟器屏幕快照“2014年4月23日 下午11.21.31”副本.png

    3.2.3 由于两者相似性很高,因此抽取出一个用来描述该对象的父类,将其共性在父类中实现,特性各自实现
    3.2.4 该对象为微博数据对象,微博对象包括数据模型(M)与展示视图(V),遵循MVC设计模式,逻辑继承图如下所示:
    Status.png

    3.2.5 两者的区别在于微博的工具栏,首页微博信息工具栏在微博视图的最下方,并显示为当前微博的转发、评论、点赞信息,详情中微博工具栏显示的是被转发的微博转发、评论、点赞信息,如果该微博没有转发信息则详细信息中无工具栏,区别在于计算微博视图高度被转发信息视图高度被转发信息中工具栏数据,这三者都在子类中实现,实现细节代码中有注释说明
    3.2.6 两个工具栏又极其类似,因此也抽取共性创建父类,两者通过继承将特性在子类中实现,逻辑图如下:
    Dock.png

    3.2.7 详细信息展示无疑通过UITableView展示,总体体分为两部分,一部分展示原微博信息,另一部分展示评论、转发、点赞信息,因为Table分组展示,UITableView内部实现原理错综复杂,尤其是各方法调用顺序,实现原理,相信很多码友一直都很困惑,看下图:
    UITableView.png

    3.2.8 以2组表格为例,参照上图说明下表格的绘制过程
    [Objective-C] 纯文本查看 复制代码
    1、计算表格组数(得出2组,即第0组与第1组)
    
    2.1、计算第1组 表格高度(倒序额,从后面算起)
    2.2、计算第1组 头部高度(可选,如果有的话)
    2.3、计算第1组 尾部高度(可选,如果有的话)
    2.4、计算第1组 行数
    2.5、计算第1组 第0行高度
    2.6、计算第1组 第1行高度
    2.7、计算第1组 第n行高度
    
    3.1、计算第0组 表格高度
    3.2、计算第0组 头部高度(可选,如果有的话)
    3.3、计算第0组 尾部高度(可选,如果有的话)
    3.4、计算第0组 行数
    3.5、计算第0组 第0行高度
    3.6、计算第0组 第1行高度
    3.7、计算第0组 第n行高度
    
    4.1、计算第0组 第0行内容 (计算内容为正序)
    4.2、计算第0组 第1行内容
    4.3、计算第0组 第n行内容
    4.4、计算第1组 第0行内容 
    4.5、计算第1组 第1行内容
    4.6、计算第1组 第n行内容
    
    5.1、计算头部及尾部内容(这个不重要了,关键在于前面的)
    

    3.2.9 本微博的评论、转发、点赞详细信息后续实现,待续.....

    3.3 点击微博内容转到其它视图在主控制器中实现,并且其他控制器都为UITableView类型,其他控制器中点击事件也发生在Table中,因此复制到所有的点击事件(这便是模型的好处MVC设计思想)

    4、关键代码
    文件目录:
    SABaseCell.h
    SABaseCell.m
    SABaseFrame.h
    SABaseFrame.m
    SAStatusCell.h
    SAStatusFrame.m
    SAStatusDetailCell.h
    SAStatusDetailCell.m
    SAStatusDetailFrame.h
    SAStatusDetailFrame.m
    SAMainController.h
    SAMainController.m
    SAStatusDetailController.h
    SAStatusDetailController.m
    ==================================
    SABaseCell.h
    [Objective-C] 纯文本查看 复制代码
    //
    //  SABaseCell.h
    //  SianWeibo
    //
    //  Created by yusian on 14-4-23.
    //  Copyright (c) 2014年 小龙虾论坛. All rights reserved.
    //
    
    #import <UIKit/UIKit.h>
    #import "SABaseFrame.h"
    
    @interface SABaseCell : UITableViewCell
    {
        SABaseFrame     *_cellFrame;    // 数据模型
        UIImageView     *_retweet;      // 转发体视图
    }
    
    @property (nonatomic, strong) SABaseFrame *cellFrame;
    
    @end
    

    SABaseCell.m
    [Objective-C] 纯文本查看 复制代码
    //
    //  SABaseCell.m
    //  SianWeibo
    //
    //  Created by yusian on 14-4-23.
    //  Copyright (c) 2014年 小龙虾论坛. All rights reserved.
    //
    
    #import "SABaseCell.h"
    #import "SAAvata.h"
    #import "SAStatus.h"
    #import "SAStatusFrame.h"
    #import "SAImageListView.h"
    
    @interface SABaseCell ()
    {
        SAAvata         *_profile;      // 头像
        UILabel         *_screenName;   // 昵称
        UIImageView     *_mbIcon;       // 会员图标
        UILabel         *_time;         // 时间
        UILabel         *_source;       // 来源
        UILabel         *_text;         // 正文
        SAImageListView *_image;        // 配图
        UILabel         *_reScreenName; // 转发体昵称
        UILabel         *_reText;       // 转发体正文
        SAImageListView *_reImage;      // 转发体配图
    }
    @end
    
    @implementation SABaseCell
    
    #pragma mark 初始化单元格元素
    - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
    {
        self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
        if (self) {
            
            self.backgroundColor = [UIColor clearColor];
            self.backgroundView = [[UIImageView alloc] initWithImage:[[UIImage imageNamed:@"common_card_background.png"] stretchableImageWithLeftCapWidth:5 topCapHeight:5]];
            self.selectedBackgroundView = [[UIImageView alloc] initWithImage:[[UIImage imageNamed:@"common_card_background_highlighted.png"] stretchableImageWithLeftCapWidth:5 topCapHeight:5]];
            
            // 1、头像
            _profile = [[SAAvata alloc] init];
            _profile.backgroundColor = [UIColor clearColor];
            [self.contentView addSubview:_profile];
            
            // 2、昵称
            _screenName = [[UILabel alloc] init];
            _screenName.backgroundColor = [UIColor clearColor];
            _screenName.font = kScreenNameFount;
            [self.contentView addSubview:_screenName];
            
            // 2.1 会员图标
            _mbIcon = [[UIImageView alloc] init];
            _mbIcon.image = [UIImage imageNamed:@"common_icon_membership.png"];
            [self.contentView addSubview:_mbIcon];
            
            // 3、时间
            _time = [[UILabel alloc] init];
            _time.backgroundColor = [UIColor clearColor];
            _time.font = kTimeFont;
            _time.textColor = kTimeColor;
            [self.contentView addSubview:_time];
            
            // 4、来源
            _source = [[UILabel alloc] init];
            _source.backgroundColor = [UIColor clearColor];
            _source.font = kSourceFont;
            _source.textColor = [UIColor grayColor];
            [self.contentView addSubview:_source];
            
            // 5、正文
            _text = [[UILabel alloc] init];
            _text.backgroundColor = [UIColor clearColor];
            _text.font = kTextFount;
            _text.numberOfLines = 0;
            [self.contentView addSubview:_text];
            
            // 6、配图
            _image = [[SAImageListView alloc] init];
            _image.contentMode = UIViewContentModeScaleAspectFit;
            [self.contentView addSubview:_image];
            
            // 7、转发体视图
            _retweet = [[UIImageView alloc] init];
            _retweet.image = [[UIImage imageNamed:@"timeline_retweet_background.png"] stretchableImageWithLeftCapWidth:25 topCapHeight:10];
            [self.contentView addSubview:_retweet];
            
            // 8、转发体昵称
            _reScreenName = [[UILabel alloc] init];
            _reScreenName.font = kReScreenNameFont;
            _reScreenName.backgroundColor = [UIColor clearColor];
            _reScreenName.textColor = [UIColor blueColor];
            [_retweet addSubview:_reScreenName];
            
            // 9、转发体正文
            _reText = [[UILabel alloc] init];
            _reText.numberOfLines = 0;
            _reText.font = kReTextFont;
            _reText.backgroundColor = [UIColor clearColor];
            [_retweet addSubview:_reText];
            
            // 10、转发体配图
            _reImage = [[SAImageListView alloc] init];
            _reImage.contentMode = UIViewContentModeScaleAspectFit;
            [_retweet addSubview:_reImage];
            
        }
        return self;
    }
    
    #pragma mark - 设置单元格
    -(void)setCellFrame:(SABaseFrame *)cellFrame
    {
        _cellFrame = cellFrame;
        
        // 1、设置子控件内容
        [self cellFrameSettingView];
        
        // 2、计算子控件Frame
        [self cellFrameSettingFrame];
    }
    
    #pragma mark 设置单元格内容
    - (void)cellFrameSettingView
    {
        SAStatus *status = self.cellFrame.status;
        
        // 1、设置头像
        [_profile setUser:status.user ofType:kAvataTypeSmall];
        
        // 2、设置昵称
        _screenName.text = status.user.screenName;
        if (status.user.mbtype == kMbTypeNone) {
            _screenName.textColor = kScreenNameColor;
        } else {
            _screenName.textColor = kMBScreenNameColor;
        }
        
        // 2.1 设置会员图标
        if (status.user.mbtype == kMbTypeNone) {
            _mbIcon.hidden = YES;
        } else {
            _mbIcon.hidden = NO;
        }
        
        // 3、设置时间
        _time.text = status.createdAt;
        
        // 4、设置来源
        _source.text = status.source;
        
        // 5、设置正文
        _text.text = status.text;
        
        // 6、设置配图
        if (status.picUrls.count) {                     // 第一种情况:带有配图的微博
            
            _image.hidden = NO;
            _retweet.hidden = YES;
            
            _image.imageList = status.picUrls;
            
        } else if (status.retweetedStatus) {            // 第二种情况:转发的微博
            
            _image.hidden = YES;
            _retweet.hidden = NO;
            
            // 7、设置转发体昵称
            _reScreenName.text = [NSString stringWithFormat:@"@%@", status.retweetedStatus.user.screenName];
            
            // 8、转发体正文
            _reText.text = status.retweetedStatus.text;
            
            // 9、转发体配图
            if (status.retweetedStatus.picUrls.count) { // 第二种情况:1、转发的微博带配图
                
                // 设置转发体图片内容(暂时取一张为例)
                _reImage.hidden = NO;
                _reImage.imageList = status.retweetedStatus.picUrls;
                
            } else {                                    // 第二种情况:2、转发的微博不带配图
                
                // 无配图则清空属性并隐藏
                _reImage.hidden = YES;
            }
            
        } else {                                        // 第三种情况:不带配图的微博
            
            _image.hidden = YES;
            _retweet.hidden = YES;
        }
        
    }
    
    #pragma mark 单元格子控件布局
    - (void)cellFrameSettingFrame
    {
        // 1、设置头像尺寸位置
        _profile.frame = _cellFrame.profile;
        
        // 2、设置昵称尺寸位置
        _screenName.frame = _cellFrame.screenName;
        
        // 2.1 设置会员图标尺寸位置
        _mbIcon.frame = _cellFrame.mbIcon;
        
        // 3、设置时间尺寸位置
        CGRect timeDynamicFrame =  _cellFrame.time;
        timeDynamicFrame.size = [_cellFrame.status.createdAt sizeWithFont:kTimeFont]; // 时间动态显示,时间尺寸动态计算
        _time.frame = timeDynamicFrame;
        
        // 4、设置来源尺寸位置
        CGRect sourceDynamicFrame = _cellFrame.source;
        sourceDynamicFrame.origin.x = CGRectGetMaxX(timeDynamicFrame) + kInterval;      // 时间尺寸动态计算,来源位置动态计算
        _source.frame = sourceDynamicFrame;
        
        // 5、设置正文尺寸位置
        _text.frame = _cellFrame.text;
        
        // 6、设置配图尺寸位置
        _image.frame = _cellFrame.image;
        
        // 7、设置转发体尺寸位置
        _retweet.frame = _cellFrame.retweet;
        
        // 8、设置转发体昵称尺寸位置
        _reScreenName.frame = _cellFrame.reScreenName;
        
        // 9、转发体正文尺寸位置
        _reText.frame = _cellFrame.reText;
        
        // 10、转发体配图尺寸位置
        _reImage.frame = _cellFrame.reImage;
        
    }
    
    #pragma mark 重写frame方法设置Cell宽度
    // 该方法会被调用2次
    -(void)setFrame:(CGRect)frame
    {
        frame.origin.x += kCellMargins;
        frame.size.width -= (2 *kCellMargins);
        frame.origin.y += kCellMargins;
        frame.size.height -= kCellMargins;
        
        [super setFrame:frame];
    }
    
    @end

    SABaseFrame.h
    [Objective-C] 纯文本查看 复制代码
    //
    //  SABaseFrame.h
    //  SianWeibo
    //
    //  Created by yusian on 14-4-23.
    //  Copyright (c) 2014年 小龙虾论坛. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    #import "SAStatus.h"
    @interface SABaseFrame : NSObject
    {
        // 提供给子类访问的成员变量
        CGFloat     _cellHeight;        // 行高
        CGRect      _retweet;           // 转发体Frame
        SAStatus    *_status;           // 数据模型
    }
    
    @property (nonatomic, readonly) CGRect      profile;        // 头像
    @property (nonatomic, readonly) CGRect      screenName;     // 昵称
    @property (nonatomic, readonly) CGRect      mbIcon;         // 会员图标
    @property (nonatomic, readonly) CGRect      time;           // 时间
    @property (nonatomic, readonly) CGRect      source;         // 来源
    @property (nonatomic, readonly) CGRect      text;           // 正文
    @property (nonatomic, readonly) CGRect      image;          // 配图
    @property (nonatomic, readonly) CGRect      retweet;        // 转发体视图
    @property (nonatomic, readonly) CGRect      reScreenName;   // 转发体昵称
    @property (nonatomic, readonly) CGRect      reText;         // 转发体正文
    @property (nonatomic, readonly) CGRect      reImage;        // 转发体配图
    @property (nonatomic, readonly) CGFloat     cellHeight;     // 行高
    @property (nonatomic, strong)   SAStatus    *status;        // 数据模型
    
    @end
    

    SABaseFrame.m
    [Objective-C] 纯文本查看 复制代码
    //
    //  SABaseFrame.m
    //  SianWeibo
    //
    //  Created by yusian on 14-4-23.
    //  Copyright (c) 2014年 小龙虾论坛. All rights reserved.
    //
    
    #import "SABaseFrame.h"
    #import "SAAvata.h"
    #import "SAStatus.h"
    #import "SAImageListView.h"
    
    @implementation SABaseFrame
    
    -(void)setStatus:(SAStatus *)status
    {
        _status = status;
        
        CGSize screenSize = [UIScreen mainScreen].applicationFrame.size;
        CGFloat cellWidth = screenSize.width - 2 * kCellMargins;
        
        // 1、设置头像尺寸位置;
        CGFloat profileX = kInterval;
        CGFloat profileY = kInterval;
        _profile = (CGRect){{kInterval, kInterval}, [SAAvata sizeOfAvataType:kAvataTypeSmall]};
        
        // 2、设置昵称尺寸位置;
        CGFloat screenNameX = CGRectGetMaxX(_profile) + kInterval;
        CGFloat screenNameY = profileY;
        CGSize screenNameSize = [status.user.screenName sizeWithFont:kScreenNameFount];
        _screenName = (CGRect){{screenNameX, screenNameY}, screenNameSize};
        
        // 2.1 设置会员图标尺寸位置
        CGFloat mbIconX = CGRectGetMaxX(_screenName) + kInterval;
        CGFloat mbIconY = (screenNameSize.height - kMBIconWH) * 0.5 + screenNameY;
        _mbIcon = CGRectMake(mbIconX, mbIconY, kMBIconWH, kMBIconWH);
        
        // 3、设置时间尺寸位置
        CGFloat timeX = screenNameX;
        CGFloat timeY = CGRectGetMaxY(_screenName) + kInterval * 0.5;
        CGSize timeSize = [status.createdAt sizeWithFont:kTimeFont];
        _time = (CGRect){{timeX, timeY}, timeSize};
        
        // 4、设置来源尺寸位置
        CGFloat sourceX = CGRectGetMaxX(_time) + kInterval;
        CGFloat sourceY = timeY;
        CGSize sourceSize = [status.source sizeWithFont:kSourceFont];
        _source = (CGRect){{sourceX, sourceY}, sourceSize};
        
        // 5、设置正文尺寸位置;
        CGFloat textX = profileX;
        CGFloat textY = MAX (CGRectGetMaxY(_profile), CGRectGetMaxY(_time));
        CGFloat textW = cellWidth - 2 * kInterval;
        CGSize textSize = [_status.text sizeWithFont:kTextFount constrainedToSize:CGSizeMake(textW, MAXFLOAT)];
        _text = (CGRect){{textX, textY}, textSize};
        
        if (_status.picUrls.count) {                            // 第一种情况:带配图的微博
            
            // 6、设置配图尺寸位置
            CGFloat imageX = profileX;
            CGFloat imageY = CGRectGetMaxY(_text) + kInterval;
            CGSize imageSize = [SAImageListView sizeOfViewWithImageCount:_status.picUrls.count];
            _image = (CGRect){{imageX, imageY}, imageSize};
            
            // 有配图无转发体单元格高度
            _cellHeight = CGRectGetMaxY(_image) + kInterval  + kCellMargins;
            
        } else if (_status.retweetedStatus) {                   // 第二种情况:转发的微博
            
            // 7、设置转发体尺寸位置
            CGFloat retweetX = profileX;
            CGFloat retweetY = CGRectGetMaxY(_text) + kInterval;
            CGFloat retweetW = cellWidth - 2 * kInterval;
            
            // 8、设置转发体昵称尺寸位置
            CGFloat reScreenNameX = kInterval;
            CGFloat reScreenNameY = kInterval;
            CGSize reScreenNameSize = [[NSString stringWithFormat:@"@%@", _status.retweetedStatus.user.screenName] sizeWithFont:kReScreenNameFont];
            _reScreenName = (CGRect){{reScreenNameX, reScreenNameY}, reScreenNameSize};
            
            // 9、设置转发体正文尺寸位置
            CGFloat reTextX = reScreenNameX;
            CGFloat reTextY = CGRectGetMaxY(_reScreenName) + kInterval;
            CGSize reTextSize = [_status.retweetedStatus.text sizeWithFont:kReTextFont constrainedToSize:CGSizeMake((retweetW - 2 * kInterval), MAXFLOAT)];
            _reText = (CGRect){{reTextX, reTextY}, reTextSize};
            
            // 10、设置转发体配图尺寸位置
            if (_status.retweetedStatus.picUrls.count) {        // 第二种情况:1、转发的微博带图
                CGFloat reImageX = reScreenNameX;
                CGFloat reImageY = CGRectGetMaxY(_reText) + kInterval;
                CGSize reImageSize = [SAImageListView sizeOfViewWithImageCount:_status.retweetedStatus.picUrls.count];
                _reImage = (CGRect){{reImageX, reImageY}, reImageSize};
                
                // 转发体有配图转发体尺寸
                CGFloat retweetH = CGRectGetMaxY(_reImage) + kInterval;
                _retweet = CGRectMake(retweetX, retweetY, retweetW, retweetH);
                
            } else {                                            // 第二种情况:2、转发的微博不带图
                
                // 转发体无配图转发体尺寸
                CGFloat retweetH = CGRectGetMaxY(_reText) + kInterval;
                _retweet = CGRectMake(retweetX, retweetY, retweetW, retweetH);
            }
            
            // 有转发体的单元格高度
            _cellHeight = CGRectGetMaxY(_retweet) + kInterval + kCellMargins;
            
        } else {                                                // 第三种情况:不带配图的普通微博
            
            // 11、设置单元格高度尺寸位置
            // 无配图,无转发体单元格高度
            _cellHeight = CGRectGetMaxY(_text) + kInterval + kCellMargins;
        }
        
    }
    @end
    

    SAStatusCell.h
    [Objective-C] 纯文本查看 复制代码
    //
    //  SAStatusCell.h
    //  SianWeibo
    //
    //  Created by yusian on 14-4-18.
    //  Copyright (c) 2014年 小龙虾论坛. All rights reserved.
    //  微博单元格类
    
    #import "SABaseCell.h"
    #import "SAStatusFrame.h"
    
    @interface SAStatusCell : SABaseCell
    
    + (NSString *)ID;
    
    @end
    

    SAStatusFrame.m
    [Objective-C] 纯文本查看 复制代码
    //
    //  SAStatusCell.m
    //  SianWeibo
    //
    //  Created by yusian on 14-4-18.
    //  Copyright (c) 2014年 小龙虾论坛. All rights reserved.
    //  微博单元格类
    
    #import "SAStatusCell.h"
    #import "SAStatusDock.h"
    
    @interface SAStatusCell ()
    {
        SAStatusDock    *_statusDock;   // 功能菜单
    }
    @end
    
    @implementation SAStatusCell
    
    #pragma mark 初始化单元格元素
    - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
    {
        self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
        if (self) {
            
            // 1、添加功能菜单
            _statusDock = [[SAStatusDock alloc] init];
            [self.contentView addSubview:_statusDock];
        }
        return self;
    }
    
    
    #pragma mark - 设置单元格
    -(void)setCellFrame:(SAStatusFrame *)cellFrame
    {
        [super setCellFrame:cellFrame];
        
        // 1、设置功能菜单栏内容
        _statusDock.status = cellFrame.status;
        
    }
    
    
    #pragma mark 设置单元格标识
    + (NSString *)ID
    {
        return @"StatusCell";
    }
    
    @end
    

    SAStatusDetailCell.h
    [Objective-C] 纯文本查看 复制代码
    //
    //  SAStatusDetailCell.h
    //  SianWeibo
    //
    //  Created by yusian on 14-4-23.
    //  Copyright (c) 2014年 小龙虾论坛. All rights reserved.
    //
    
    #import "SABaseCell.h"
    
    @interface SAStatusDetailCell : SABaseCell
    
    + (NSString *)ID;
    
    @end
    

    SAStatusDetailCell.m
    [Objective-C] 纯文本查看 复制代码
    //
    //  SAStatusDetailCell.m
    //  SianWeibo
    //
    //  Created by yusian on 14-4-23.
    //  Copyright (c) 2014年 小龙虾论坛. All rights reserved.
    //
    
    #import "SAStatusDetailCell.h"
    #import "SADetailRetweetDock.h"
    #import "SAStatusDetailFrame.h"
    
    @interface SAStatusDetailCell ()
    {
        SADetailRetweetDock *_retweetDock;
    }
    @end
    
    @implementation SAStatusDetailCell
    
    #pragma mark 调用父类方法初始化
    -(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
    {
        if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
            
            // 在父类的基础上增加一个转发体Dock工具栏
            _retweetDock = [[SADetailRetweetDock alloc] init];
            
            [_retweet addSubview:_retweetDock];
        }
        return self;
    }
    
    #pragma mark 给转发体赋值
    -(void)setCellFrame:(SAStatusDetailFrame *)cellFrame
    {
        [super setCellFrame:cellFrame];
        
        // 调用父类的方法将共有的控件赋值,再将特有的控件赋值
        _retweetDock.status = cellFrame.status.retweetedStatus;
    }
    
    #pragma mark Cell标记写成类方法
    +(NSString *)ID
    {
        return @"StatusDetailCell";
    }
    @end
    

    SAStatusDetailFrame.h
    [Objective-C] 纯文本查看 复制代码
    //
    //  SAStatusDetailFrame.h
    //  SianWeibo
    //
    //  Created by yusian on 14-4-23.
    //  Copyright (c) 2014年 小龙虾论坛. All rights reserved.
    //
    
    #import "SABaseFrame.h"
    
    @interface SAStatusDetailFrame : SABaseFrame
    
    @end
    

    SAStatusDetailFrame.m
    [Objective-C] 纯文本查看 复制代码
    //
    //  SAStatusDetailFrame.m
    //  SianWeibo
    //
    //  Created by yusian on 14-4-23.
    //  Copyright (c) 2014年 小龙虾论坛. All rights reserved.
    //
    
    #import "SAStatusDetailFrame.h"
    
    @implementation SAStatusDetailFrame
    
    #pragma mark 调整转发体与Cell的高度
    -(void)setStatus:(SAStatus *)status
    {
        [super setStatus:status];
        
        // 在父类视图的基础上,如果有转发,则将转发体高度增加一个Dock高度,并将Cell总高度也增加一个Dock高度
        if (status.retweetedStatus){
            
            _retweet.size.height += kDetailReDockH + kInterval;
            
            _cellHeight += kDetailReDockH + kInterval;
        }
    }
    
    @end
    

    SAMainController.h
    [Objective-C] 纯文本查看 复制代码
    //
    //  SAMainController.h
    //  SianWeibo
    //
    //  Created by yusian on 14-4-11.
    //  Copyright (c) 2014年 小龙虾论坛. All rights reserved.
    //  主程序界面
    
    #import <UIKit/UIKit.h>
    #import "SADockController.h"
    
    @interface SAMainController : SADockController
    
    @end
    

    SAMainController.m
    [Objective-C] 纯文本查看 复制代码
    //
    //  SAMainController.m
    //  SianWeibo
    //
    //  Created by yusian on 14-4-11.
    //  Copyright (c) 2014年 小龙虾论坛. All rights reserved.
    //  主程序界面
    
    #import "SAMainController.h"
    #import "SAHomeController.h"
    #import "SAMessageController.h"
    #import "SAProfileController.h"
    #import "SADiscoverController.h"
    #import "SAMoreController.h"
    #import "SANavigationController.h"
    #import "UIBarButtonItem+SA.h"
    
    @interface SAMainController () <SADockDelegate, UINavigationControllerDelegate>
    
    @end
    
    @implementation SAMainController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        
        // 添加其他View
        [self addSubView];
        
        // 添加Dock控件元素
        [self addDockItems];
    
    }
    
    #pragma mark 添加子控件到首页控制器
    - (void)addSubView
    {
        // 添加"首页"视图
        SAHomeController *homeControl = [[SAHomeController alloc] init];
        SANavigationController *homeNav = [[SANavigationController alloc] initWithRootViewController:homeControl];
        homeNav.delegate = self;
        [self addChildViewController:homeNav];
        
        // 添加"消息"视图
        SAMessageController *messageControl = [[SAMessageController alloc] initWithStyle:UITableViewStyleGrouped];
        SANavigationController *messageNav = [[SANavigationController alloc] initWithRootViewController:messageControl];
        messageNav.delegate = self;
        [self addChildViewController:messageNav];
        
        // 添加"我"视图
        SAProfileController *profileControl = [[SAProfileController alloc] init];
        SANavigationController *profileNav = [[SANavigationController alloc] initWithRootViewController:profileControl];
        profileNav.delegate = self;
        [self addChildViewController:profileNav];
        
        // 添加"广场"视图
        SADiscoverController *discoverControl = [[SADiscoverController alloc] init];
        SANavigationController *discoverNav = [[SANavigationController alloc] initWithRootViewController:discoverControl];
        discoverNav.delegate = self;
        [self addChildViewController:discoverNav];
        
        // 添加"更多"视图
        SAMoreController *moreControl = [[SAMoreController alloc] initWithStyle:UITableViewStyleGrouped];
        SANavigationController *moreNav = [[SANavigationController alloc] initWithRootViewController:moreControl];
        moreNav.delegate = self;
        [self addChildViewController:moreNav];
    }
    
    #pragma mark 添加Dock控件到首页控制器
    - (void)addDockItems
    {
        [self.dock addItemWithIcon:@"tabbar_home.png" selectedIcon:@"tabbar_home_selected.png" title:@"首页"];
        [self.dock addItemWithIcon:@"tabbar_message_center.png" selectedIcon:@"tabbar_message_center_selected.png" title:@"消息"];
        [self.dock addItemWithIcon:@"tabbar_profile.png" selectedIcon:@"tabbar_profile_selected.png" title:@"我"];
        [self.dock addItemWithIcon:@"tabbar_discover.png" selectedIcon:@"tabbar_discover_selected.png" title:@"广场"];
        [self.dock addItemWithIcon:@"tabbar_more.png" selectedIcon:@"tabbar_more_selected.png" title:@"更多"];
        
    }
    
    #pragma mark - 导航控制器代理方法
    #pragma mark 即将展示下一控制器时调用
    - (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
    {
        // 从首页控制器内部切换需要调整控制器的高度及Dock栏的归属
        UIViewController *rootViewController = [navigationController.viewControllers firstObject];
        
        // 如果从根控制器切换到其他控制器需要把Dock栏移走,并调整切换后的控制器高度
        if (viewController != rootViewController) {
            
            // 1、调整控制器高度
            CGRect naConViewFrame = navigationController.view.frame;
            CGFloat naConY = navigationController.navigationBar.frame.origin.y;
            CGFloat appHeight = [UIScreen mainScreen].applicationFrame.size.height;
            naConViewFrame.size.height = appHeight + naConY;
            navigationController.view.frame = naConViewFrame;
            
            // 2、新控制器添加按钮
            viewController.navigationItem.leftBarButtonItem = [UIBarButtonItem barButtonItemWithImageName:@"navigationbar_back.png" highLightedImageName:@"navigationbar_back_highlight.png" addTarget:self action:@selector(back)];
            
            // 3、计算Dock的y值变化
            CGRect dockFrame = self.dock.frame;
            CGFloat AppHeight = [UIScreen mainScreen].applicationFrame.size.height;
            CGFloat navBarHeight = navigationController.navigationBar.frame.size.height;
            
            // 3.1 Dock的y值为应用程序的高度(460)-导航条高度-Dock自身的高度,考虑到ios7兼容性问题,这里不利用View自身的高度
            dockFrame.origin.y = AppHeight - navBarHeight - kDockHeight;
            
            // 3.2 TableView滚动后,View的y值发生变量,因此Dock的Y值也需要一起调整
            if ([rootViewController.view isKindOfClass:[UIScrollView class]]) {
            
                // 3.2.1 计算滚动的长度,y值自加该长度
                UIScrollView *scrollView = (UIScrollView *)rootViewController.view;
                CGFloat contentY = scrollView.contentOffset.y;
                
                // 3.2.2 ios下透明导航条特性,使得contentOffset自动往下移了64个像素(导航条高度+系统状态栏高度)
                if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) contentY +=64;
                dockFrame.origin.y += contentY;
            }
            
            // 4、调整Dock的位置
            [self.dock removeFromSuperview];
            self.dock.frame = dockFrame;
            [rootViewController.view addSubview:self.dock];
        }
        
    }
    
    #pragma mark 新控制器展示完毕时调用
    - (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated
    {
        
        UIViewController *rootViewController = [navigationController.viewControllers firstObject];
        // 如果切回到根控制器
        if (viewController == rootViewController) {
            
            // 1、把Dock栏返回给主控制器,并调整Dock的位置
            [self.dock removeFromSuperview];
            [self.view addSubview:self.dock];
            CGRect dockFrame = self.dock.frame;
            dockFrame.origin.y = self.view.frame.size.height - kDockHeight;
            self.dock.frame = dockFrame;
            
            // 2、调整控制器View高度
            CGRect naConViewFrame = navigationController.view.frame;
            CGFloat naConY = navigationController.navigationBar.frame.origin.y;
            CGFloat appHeight = [UIScreen mainScreen].applicationFrame.size.height;
            naConViewFrame.size.height = appHeight + naConY - kDockHeight;
            navigationController.view.frame = naConViewFrame;
            
        }
    }
    
    #pragma mark - 按钮事件处理
    - (void)back
    {
        // 利用Dock传过来的Dock序号(0 - 5),来确定当前需要操作的导航控制器,从而在当前控制器的子控制器数据组找到对应的导航控制器,弹出栈顶控制器
        [self.childViewControllers[self.dock.indexSelected] popToRootViewControllerAnimated:YES];
    }
    
    @end
    

    SAStatusDetailController.h
    [Objective-C] 纯文本查看 复制代码
    //
    //  SAStatusDetailController.h
    //  SianWeibo
    //
    //  Created by yusian on 14-4-22.
    //  Copyright (c) 2014年 小龙虾论坛. All rights reserved.
    //
    
    #import <UIKit/UIKit.h>
    @class SAStatus;
    
    @interface SAStatusDetailController : UITableViewController
    
    @property (nonatomic, strong) SAStatus *status;     // 数据模型,接收传进来的模型数据
    
    @end
    

    SAStatusDetailController.m
    [Objective-C] 纯文本查看 复制代码
    //
    //  SAStatusDetailController.m
    //  SianWeibo
    //
    //  Created by yusian on 14-4-22.
    //  Copyright (c) 2014年 小龙虾论坛. All rights reserved.
    //
    
    #import "SAStatusDetailController.h"
    #import "SAStatusDetailCell.h"
    #import "SAStatusDetailFrame.h"
    
    @interface SAStatusDetailController ()
    {
        SAStatusDetailFrame *_detailFrame;
    }
    @end
    
    @implementation SAStatusDetailController
    
    #pragma mark - Table view default setting
    - (id)initWithStyle:(UITableViewStyle)style
    {
        self = [super initWithStyle:style];
        if (self) {
            
            self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
            self.view.backgroundColor = kBGColor;
            self.title = @"微博详情";
            
        }
        return self;
    }
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        
    }
    
    #pragma mark 微博内容赋值
    -(void)setStatus:(SAStatus *)status
    {
        // 通过外界传进来的模型数据,调用自己的框架模型计算出各子视图的数据尺寸位置
        _status = status;
        _detailFrame = [[SAStatusDetailFrame alloc] init];
        _detailFrame.status = status;
    }
    
    #pragma mark - Table view data source
    #pragma mark 1、返回表格组数
    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    {
        return 2;
    }
    
    #pragma mark 2、返回每组头部高度
    - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
    {
        return 0;
    }
    
    #pragma mrak 3、返回每组表格行数
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        if (section == 0) return 1;
        return 2;
    }
    
    #pragma mark 4、返回每行高度
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        if (indexPath.section == 0) return _detailFrame.cellHeight;
        return 40;
    }
    
    
    #pragma mark 5、返回每行内容
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        
        SAStatusDetailCell *detailCell = [tableView dequeueReusableCellWithIdentifier:[SAStatusDetailCell ID]];
        UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
        
        if (detailCell == nil) {
            detailCell = [[SAStatusDetailCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:[SAStatusDetailCell ID]];
        }
    
        detailCell.cellFrame = _detailFrame;
        cell.textLabel.text = [NSString stringWithFormat:@"第%d行", indexPath.row];
        cell.textLabel.backgroundColor = [UIColor clearColor];
        cell.backgroundColor = [UIColor clearColor];
        
        if (indexPath.section == 0) return detailCell;
        
        return cell;
    }
    
    #pragma mark 6、返回每组头部视图
    - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
    {
        return nil;
    }
    
    #pragma mark 单元格点击事件
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    {
        [tableView deselectRowAtIndexPath:indexPath animated:NO];
    }
    
    @end
    

    5、源码下载
    游客,如果您要查看本帖隐藏内容请回复

    相关主题链接
    1、ios实战开发之仿新浪微博(第一讲:新特性展示)
    2、ios实战开发之仿新浪微博(第二讲:主框架搭建)
    3、ios实战开发之仿新浪微博(第三讲:更多界面搭建)
    4、ios实战开发之仿新浪微博(第四讲:OAuth认证)
    5、ios实战开发之仿新浪微博(第五讲:微博数据加载)
    6、ios实战开发之仿新浪微博(第六讲:微博数据展示一)
    7、ios实战开发之仿新浪微博(第七讲:微博数据展示二)
    8、ios实战开发之仿新浪微博(第八讲:微博数据展示三)
    9、ios实战开发之仿新浪微博(第九讲:微博功能完善一)
    10、ios实战开发之仿新浪微博(第十讲:微博功能完善二)
    11、ios实战开发之仿新浪微博(第十一讲:微博功能完善三)
    12、ios实战开发之仿新浪微博(小龙虾发布版)

  • TA的每日心情
    倒霉
    2014-11-11 21:18
  • 签到天数: 18 天

    [LV.4]偶尔看看III

    发表于 2014-10-19 18:10:13 | 显示全部楼层
    谢谢楼主,加紧学习了

    该用户从未签到

    发表于 2014-11-7 10:51:44 | 显示全部楼层
    学习中,很不错。。。

    该用户从未签到

    发表于 2014-11-10 20:27:32 | 显示全部楼层
    很好的学习材料,感谢楼主!

    该用户从未签到

    发表于 2014-11-10 21:07:57 | 显示全部楼层
    项目代码 怎么获取啊
    发表于 2014-11-11 12:43:59 | 显示全部楼层
    期待已久,希望能够学习
  • TA的每日心情
    发光
    2014-11-26 14:19
  • 签到天数: 4 天

    [LV.2]偶尔看看I

    发表于 2014-12-9 09:44:12 | 显示全部楼层
    先码完再说、、、、、、、、、、、、
  • TA的每日心情
    得瑟
    2015-1-8 17:35
  • 签到天数: 3 天

    [LV.2]偶尔看看I

    发表于 2014-12-22 10:21:59 | 显示全部楼层
    一次性下载下来完

    该用户从未签到

    发表于 2014-12-23 18:46:55 | 显示全部楼层
    牛人的实现
  • TA的每日心情

    2014-12-29 14:23
  • 签到天数: 6 天

    [LV.2]偶尔看看I

    发表于 2014-12-29 14:22:40 | 显示全部楼层
    已经第十课了!!!!!这个项目够我消化好久的说~
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    手机版|小黑屋|Archiver|iOS开发笔记 ( 湘ICP备14010846号 )

    GMT+8, 2024-4-17 06:51 , Processed in 0.061476 second(s), 26 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表