年年有"余"

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 12648|回复: 28

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

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

    [LV.9]以坛为家II

    发表于 2014-4-22 01:42:51 | 显示全部楼层 |阅读模式
    1、效果演示



    2、更新说明

    2.1、增加下拉刷新功能
    2.2、增加上拉加载更多功能
    2.3、增加显示刷新微博条数提示功能
    2.4、增加功能菜单相关数据显示功能

    3、设计说明

    3.1 下拉刷新及上拉加载更多引用第三方框架MJRefresh
    3.1.1 下拉刷新加载比当前第一次条微博更新的微博数据添加到数据模型数组最前端并刷新Table数据重新展示
    3.1.2 下拉加载更多加载比当前展示的最后一条微博更早的数据添加到数据模型的末端,并刷新Table数据重新展示
    3.2 下拉刷新如果有更新数据,通过弹出提示栏将当前更新的信息展示出来,并设计淡入淡出提示框效果
    3.3 将评论、转发、赞数据内容展示到功能菜单栏中,显示当前相关数据

    4、关键代码
    SAHomeController.h
    [Objective-C] 纯文本查看 复制代码
    //
    //  SAHomeController.h
    //  SianWeibo
    //
    //  Created by yusian on 14-4-12.
    //  Copyright (c) 2014年 小龙虾论坛. All rights reserved.
    //  首页控制器
    
    #import <UIKit/UIKit.h>
    
    @interface SAHomeController : UITableViewController
    
    @end
    

    SAHomeController.m
    [Objective-C] 纯文本查看 复制代码
    //
    //  SAHomeController.m
    //  SianWeibo
    //
    //  Created by yusian on 14-4-12.
    //  Copyright (c) 2014年 小龙虾论坛. All rights reserved.
    //  首页控制器
    
    #import "SAHomeController.h"
    #import "NSString+SA.h"
    #import "UIBarButtonItem+SA.h"
    #import "SAStatusTool.h"
    #import "SAStatusCell.h"
    #import "MJRefresh.h"
    #import "UIImage+SA.h"
    
    
    @interface SAHomeController () <MJRefreshBaseViewDelegate>
    {
        NSMutableArray          *_statusFrameArray;  // 框架模型数组
        MJRefreshBaseView       *_head;
    }
    
    @end
    
    @implementation SAHomeController
    
    #pragma mark - 初始化方法
    - (id)initWithStyle:(UITableViewStyle)style
    {
        self = [super initWithStyle:style];
        if (self) {
            
            self.view.backgroundColor = kBGColor;
            
        }
        return self;
    }
    
    #pragma mark - 界面内容展示
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
        
        _statusFrameArray = [NSMutableArray array];
        
        // 1、设置基本界面
        [self loadBasicUI];
        
        // 2、添加上拉下拉刷新控件
        MJRefreshHeaderView *head = [MJRefreshHeaderView header];
        head.scrollView = self.tableView;
        head.delegate = self;
        _head = head;
        
        MJRefreshFooterView *foot = [MJRefreshFooterView footer];
        foot.scrollView = self.tableView;
        foot.delegate = self;
        
        // 3、自动刷新加载数据
        [head beginRefreshing];
    }
    
    #pragma mark 加载基本界面
    - (void)loadBasicUI
    {
        
        self.title = @"首页";
        
        // 用自定的分类方法给导航条添加左边按钮
        self.navigationItem.leftBarButtonItem = [UIBarButtonItem barButtonItemWithImageName:@"navigationbar_compose.png" highLightedImageName:@"navigationbar_compose_highlighted.png" addTarget:self action:@selector(leftButtonClick) forControlEvents:UIControlEventTouchUpInside];
        
        // 用自定的分类方法给导航条添加右边按钮
        self.navigationItem.rightBarButtonItem = [UIBarButtonItem barButtonItemWithImageName:@"navigationbar_pop.png" highLightedImageName:@"navigationbar_pop_highlighted.png" addTarget:self action:@selector(rightButtonClick) forControlEvents:UIControlEventTouchUpInside];
        
    }
    
    #pragma mark - 自动刷新加载数据
    - (void)refreshViewBeginRefreshing:(MJRefreshBaseView *)refreshView
    {
        
        if ([refreshView isKindOfClass:[MJRefreshHeaderView class]]) {
            
            // 下拉操作加载最新数据
            [self loadNewStatus:refreshView];
            
        } else {
            
            // 上拉操作加载更多数据
            [self loadMoreStatus:refreshView];
        }
    }
    
    #pragma mark 下拉操作加载最新数据
    - (void) loadNewStatus:(MJRefreshBaseView *)refreshView
    {
        // 1、取出首个模型数据
        SAStatusFrame *tempStatus = [_statusFrameArray firstObject];
        long long firstStatusID = tempStatus.status.ID;
        
        // 2、发送请求,请求比首个模型数据更新的数据内容
        [SAStatusTool statusToolGetStatusWithSinceID:firstStatusID maxID:0 Success:^(NSArray *array) {
            
            // 3、将新请求到的数据添加到数据模型前端
            NSArray *newFrame = [NSArray arrayWithArray:array];
            [_statusFrameArray insertObjects:newFrame atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, newFrame.count)]];
            
            // 4、刷新数据,停止刷新
            [self.tableView reloadData];
            [refreshView endRefreshing];
            
            // 5、显示提示
            if (newFrame.count) [self showNewStatusMessage:newFrame.count];
            
        } failurs:^(NSError *error) {
            
            [refreshView endRefreshing];    // 停止刷新
            
            MyLog(@"%@", [error localizedDescription]);
            
        }];
        
    }
    
    #pragma mark 显示上拉刷新结果
    - (void)showNewStatusMessage:(NSUInteger)count
    {
        // 1、创建按钮设置基本属性
        UIButton *msgButton = [UIButton buttonWithType:UIButtonTypeCustom];
        msgButton.enabled = NO;
        msgButton.adjustsImageWhenDisabled = NO;
        NSString *title = [NSString stringWithFormat:@"%d 条新微博", count];
        msgButton.titleLabel.font = [UIFont systemFontOfSize:14];
        [msgButton setTitle:title forState:UIControlStateNormal];
        [msgButton setBackgroundImage:[UIImage resizeImage:@"timeline_new_status_background.png"] forState:UIControlStateNormal];
        [self.navigationController.view insertSubview:msgButton belowSubview:self.navigationController.navigationBar];
        
        // 2、设置显示动画
        CGFloat height = 44;
        CGFloat y = 20;
        if ([[[UIDevice currentDevice] systemVersion] floatValue] < 7.0) { // ios7.0以下版本包含状态栏
            y = 0;
        }
        msgButton.frame = CGRectMake(0, y, self.tableView.frame.size.width, height);
        msgButton.alpha = 0;
        
        [UIView animateWithDuration:0.5 animations:^{   // 半秒时间淡出效果
            
            msgButton.alpha = 0.9;
            msgButton.transform = CGAffineTransformTranslate(msgButton.transform, 0, height);
            
        } completion:^(BOOL finished) {                 // 停留1.5秒后弹回
            [UIView animateWithDuration:1.0 delay:1.5 options:UIViewAnimationOptionCurveEaseOut animations:^{
                
                msgButton.transform = CGAffineTransformTranslate(msgButton.transform, 0, -height);
                msgButton.alpha = 0;
                
            } completion:^(BOOL finished) {             // 动画结束移除控件
                [msgButton removeFromSuperview];
            }];
        }];
        
        
    }
    
    #pragma mark 上拉操作加载更多数据
    - (void)loadMoreStatus:(MJRefreshBaseView *)refreshView
    {
        
        SAStatusFrame *tempStatus = [_statusFrameArray lastObject];
        long long lastStatusID = tempStatus.status.ID;
        
        // 调用SAStatusTool方法直接加载数据到模型数组
        [SAStatusTool statusToolGetStatusWithSinceID:0 maxID:lastStatusID - 1 Success:^(NSArray *array) {
            
            NSArray *newFrame = [NSArray arrayWithArray:array];
            
            [_statusFrameArray addObjectsFromArray:newFrame];
            
            [self.tableView reloadData];    // 加载数据后刷新表格
            
            [refreshView endRefreshing];    // 停止刷新
            
        } failurs:^(NSError *error) {
            
            [refreshView endRefreshing];    // 停止刷新
            
            MyLog(@"%@", [error localizedDescription]);
            
        }];
    
    }
    
    
    #pragma mark - 单元格属性
    #pragma mark 总单元格行数
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        // 框架模型个数即为单元格数
        return _statusFrameArray.count;
    }
    
    #pragma mark 单元格内容
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        SAStatusCell *cell = [tableView dequeueReusableCellWithIdentifier:[SAStatusCell ID]];
        
        if (cell == nil){
            cell = [[SAStatusCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:[SAStatusCell ID]];
        }
        
        // 单元格内容由框架模型提供
        cell.statusFrame = _statusFrameArray[indexPath.row];
        
        return cell;
    }
    
    #pragma mark 单元格高度
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        // 取对应框架模型中的单元格高度属性
        return [_statusFrameArray[indexPath.row] cellHeight];
    }
    
    
    #pragma mark - 按钮事件处理
    #pragma mark 首页导航左按钮事件
    - (void)leftButtonClick
    {
        MyLog(@"首页左按钮");
    }
    
    #pragma mark 首页导航右按钮事件
    - (void)rightButtonClick
    {
        MyLog(@"首页右按钮");
    }
    
    @end
    

    SAStatusDock.h
    [Objective-C] 纯文本查看 复制代码
    //
    //  SAStatusDock.h
    //  SianWeibo
    //
    //  Created by yusian on 14-4-20.
    //  Copyright (c) 2014年 小龙虾论坛. All rights reserved.
    //  微博Dock
    
    #import <UIKit/UIKit.h>
    @class SAStatus;
    @interface SAStatusDock : UIImageView
    
    @property (nonatomic, strong) SAStatus *status;
    
    @end
    

    SAStatusDock.m
    [Objective-C] 纯文本查看 复制代码
    //
    //  SAStatusDock.m
    //  SianWeibo
    //
    //  Created by yusian on 14-4-20.
    //  Copyright (c) 2014年 小龙虾论坛. All rights reserved.
    //  微博Dock
    
    #import "SAStatusDock.h"
    #import "UIImage+SA.h"
    #import "NSString+SA.h"
    #import "SAStatus.h"
    
    @interface SAStatusDock ()
    {
        UIButton    *_reposts;
        UIButton    *_comments;
        UIButton    *_attitudes;
    }
    @end
    
    @implementation SAStatusDock
    
    - (id)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
        if (self) {
            
            // 设置Dock的尺寸位置
            CGFloat dockWidth = [UIScreen mainScreen].bounds.size.width - 2 * kCellMargins;
            self.frame = CGRectMake(0, kCellDefaultHeight - kCellMargins - kStatusDockHeight, dockWidth, kStatusDockHeight);
            
            // Dock贴紧父控件底部,即保持在Cell底部
            self.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
            
            // 接受用户交互
            self.userInteractionEnabled = YES;
            
            // 添加3个按钮
            _reposts = [self addButtonWithImage:@"timeline_icon_comment.png"
                                backgroundImage:@"timeline_card_leftbottom.png" buttonIndex:0];
            
            _comments = [self addButtonWithImage:@"timeline_icon_retweet.png"
                                 backgroundImage:@"timeline_card_middlebottom.png" buttonIndex:1];
            
            _attitudes = [self addButtonWithImage:@"timeline_icon_unlike.png"
                                  backgroundImage:@"timeline_card_rightbottom.png" buttonIndex:2];
        }
        return self;
    }
    
    #pragma mark 添加功能菜单栏按钮
    - (UIButton *)addButtonWithImage:(NSString *)imageName backgroundImage:(NSString *)backgroundImageName buttonIndex:(NSInteger)index
    {
        // 按钮基本属性设置
        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        [button setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];       // 文字颜色
        button.titleLabel.font = [UIFont systemFontOfSize:12];                          // 文字大小
        [button setImage:[UIImage imageNamed:imageName] forState:UIControlStateNormal]; // 按钮图标
        button.titleEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);                         // 图文间距
        
        // 按钮背景图片
        [button setBackgroundImage:[UIImage resizeImage:backgroundImageName] forState:UIControlStateNormal];
        [button setBackgroundImage:[UIImage resizeImage:[backgroundImageName fileAppend:@"_highlight"]] forState:UIControlStateHighlighted];
        
        // 按钮尺寸位置
        CGFloat buttonWidth = self.frame.size.width / 3;
        button.frame = CGRectMake(index * buttonWidth, 0, buttonWidth, kStatusDockHeight);
        
        // 添加按钮间间隔图片
        if (index) {
            UIImageView *cardButton = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"timeline_card_bottom_line.png"]];
            [self addSubview:cardButton];
            cardButton.center = CGPointMake(button.frame.origin.x, kStatusDockHeight * 0.5);
        }
        [self addSubview:button];
        return button;
    }
    
    #pragma mark - 模型数据传递
    -(void)setStatus:(SAStatus *)status
    {
        _status = status;
        
        // 根据模型数据内容设置菜单栏按钮文字
        [self setButton:_reposts withTitle:@"转发" forCounts:status.repostsCount];
        [self setButton:_comments withTitle:@"评论" forCounts:status.commentsCount];
        [self setButton:_attitudes withTitle:@"赞" forCounts:status.attitudesCount];
    }
    
    #pragma mark 设置功能菜单栏数据
    // 如果有数值,将数值替代文字
    - (void)setButton:(UIButton *)button withTitle:(NSString *)title forCounts:(NSUInteger)number
    {
        if (number > 10000) {       // 一万条以上数据简约显示
            NSString *title = [NSString stringWithFormat:@"%.1f万", number / 10000.0];
            title = [title stringByReplacingOccurrencesOfString:@".0" withString:@""];
            [button setTitle:title forState:UIControlStateNormal];
        } else if(number > 0) {     // 一万条以下数据显示实际数值
            [button setTitle:[NSString stringWithFormat:@"%d", number] forState:UIControlStateNormal];
        } else {                    // 数值为0则显示文字
            [button setTitle:title forState:UIControlStateNormal];
        }
    }
    
    @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 09:48:53 | 显示全部楼层
    支持楼主,学到好多东西

    该用户从未签到

    发表于 2014-11-5 19:00:28 | 显示全部楼层

    支持楼主,学到好多东西
  • TA的每日心情
    发光
    2014-11-26 14:19
  • 签到天数: 4 天

    [LV.2]偶尔看看I

    发表于 2014-12-3 20:12:37 | 显示全部楼层
    好东西、、、、、、、
  • TA的每日心情
    得瑟
    2015-1-8 17:35
  • 签到天数: 3 天

    [LV.2]偶尔看看I

    发表于 2014-12-22 10:19:34 | 显示全部楼层
    持续关注下载
  • TA的每日心情

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

    [LV.2]偶尔看看I

    发表于 2014-12-22 17:25:05 | 显示全部楼层
    前一个demo下下来运行报错 看看这个demo~~
  • TA的每日心情
    犯困
    2015-1-11 14:36
  • 签到天数: 5 天

    [LV.2]偶尔看看I

    发表于 2015-1-10 21:45:39 | 显示全部楼层

    支持楼主,希望继续更新

    该用户从未签到

    发表于 2015-1-15 10:35:18 | 显示全部楼层
    楼主好人,楼主好人,楼主好人
  • TA的每日心情
    开心
    2015-1-23 11:49
  • 签到天数: 1 天

    [LV.1]初来乍到

    发表于 2015-1-26 15:01:24 | 显示全部楼层
    感谢分享~~~
    回复

    使用道具 举报

    该用户从未签到

    发表于 2015-3-1 12:32:15 | 显示全部楼层
    下载,,,,,,,,,,
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

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

    GMT+8, 2024-4-27 11:30 , Processed in 0.057631 second(s), 23 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

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