首页 > 代码库 > iOS_21团购_真正封装的团购详情控制器

iOS_21团购_真正封装的团购详情控制器

最终效果图:



DealDetailController控制器

//
//  DealDetailController.h
//  帅哥_团购
//
//  Created by beyond on 14-8-20.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  真正的通过xib显示一个订单的详情的控制器

#import <UIKit/UIKit.h>
@class Deal;
@interface DealDetailController : UIViewController

// 数据源,提供给内部的子view数据,内部子view拿到数据后,又会重写setter方法,再为它的子控件们设置数据,层层传递
@property (nonatomic, strong) Deal *deal;
@end

//
//  DealDetailController.m
//  帅哥_团购
//
//  Created by beyond on 14-8-20.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  真正的通过xib显示一个订单的详情的控制器,顶部有一个固定的半透明的buyDock

#import "DealDetailController.h"
#import "TopDock.h"
#import "RightDock.h"
#import "RightDockDelegate.h"
#import "Deal.h"
// 团购简介控制器
#import "SummaryController.h"
// 网页控制器
#import "WebViewController.h"
// 商家详情控制器
#import "MerchantController.h"
// 团购收藏工具类
#import "DealCollectionTool.h"
@interface DealDetailController ()<RightDockDelegate>
{
    // 详情控制器右侧的dock,里面有三个按钮,竖线排列,分别对应三个不同的子控制器(如:团购简介,图文详情,商家详情)
    RightDock *_rightDock;
    TopDock *_topDock;
}
@end

@implementation DealDetailController
- (void)viewDidLoad
{
    [super viewDidLoad];
    
    // 1.基本设置
    [self baseSetting];
    
    // 2.添加顶部的购买栏
    [self addTopDock];
    
    // 3.添加右边的选项卡栏
    [self addRightDock];
    
    // 4.初始化子控制器
    [self addAllChildControllers];
}
#pragma 基本设置
- (void)baseSetting
{
    // 1.背景色
    self.view.backgroundColor = kGlobalBg;
    
    // 2.设置标题
    self.title = _deal.title;
    
    // 3.判断并添加 传入的团购对象的收藏属性
    [[DealCollectionTool sharedDealCollectionTool] updateCollectedPropertyForDeal:_deal];
    
    // 4.右上角的2个按钮(收藏按钮)
    NSString *collectIcon = _deal.collected ? @"ic_collect_suc.png" : @"ic_deal_collect.png";
    self.navigationItem.rightBarButtonItems = @[
                                                [UIBarButtonItem itemWithIcon:@"btn_share.png" highlightedIcon:@"btn_share_pressed.png" target:nil action:nil],
                                                [UIBarButtonItem itemWithIcon:collectIcon highlightedIcon:@"ic_deal_collect_pressed.png" target:self action:@selector(collectBtnClicked)]];
    
    // 5.监听收藏按钮点击时侯,发出的通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(collectChange) name:kCollectChangeNote object:nil];
}
#pragma mark 2.添加顶部的购买栏
- (void)addTopDock
{
    // 类方法创建一个TopDock对象(内部会从xib创建顶部的购买dock)
    _topDock = [TopDock topDock];
    // 为view提供数据源Model
    _topDock.deal = _deal;
    // 设置它在订在顶部(导航高 44 )
    _topDock.frame = CGRectMake(0,44, self.view.frame.size.width, 60);
    [self.view addSubview:_topDock];
}
#pragma mark 3.添加右边的选项卡栏
- (void)addRightDock
{
    // 类方法创建一个RightDock对象(内部会从xib创建右侧的dock,dock内部已经包含了三个item,分别是团购简介、图文详情、商家详情)
    RightDock *rightDock = [RightDock rightDock];
    // rightDock一直贴着最右、下方
    CGSize size = rightDock.frame.size;
    CGFloat x = self.view.frame.size.width - size.width;
    CGFloat y = self.view.frame.size.height - size.height - 100;
    rightDock.frame = CGRectMake(x, y, 0, 0);
    // 为了监听rightDock的里面的三个item之间的切换(点击事件),设置当前控制器为其代理,遵守协议并实现其代理方法
    rightDock.delegate = self;
    [self.view addSubview:rightDock];
    // ????? 当监听到rightDock内部的点击事件时,要当前控制器移除旧的控制器,并添加对应的新控制器,为了确定新控制器的frame,(也可以不记住....)因此要用成员变量记住rightDock
    _rightDock = rightDock;
}
#pragma mark 4.初始化子控制器
- (void)addAllChildControllers
{
    // 1.创建 团购简介 控制器
    SummaryController *summaryVC = [[SummaryController alloc] init];
    // 设置数据源
    summaryVC.deal = _deal;
    [self addChildViewController:summaryVC];
    // 默认选中第0个控制器
    [self rightDock:nil btnClickedFrom:0 to:0];
    
    // 2.创建图文详情控制器
    WebViewController *webVC = [[WebViewController alloc] init];
    webVC.deal = _deal;
    [self addChildViewController:webVC];
    
    // 3.创建商家详情控制器
    MerchantController *merchant = [[MerchantController alloc] init];
    merchant.view.backgroundColor = [UIColor greenColor];
    [self addChildViewController:merchant];
}

#pragma mark - RightDock的代理方法,由rightDock告诉代理(即控制器)它内部的item被切换了(点击了)
- (void)rightDock:(RightDock *)rightDock btnClickedFrom:(int)from to:(int)to
{
    if (to == 1) {
        _topDock.hidden = YES;
    } else {
        _topDock.hidden = NO;
    }
    
    // 1.移除旧控制器的view
    UIViewController *old = self.childViewControllers[from];
    [old.view removeFromSuperview];
    
    // 2.添加新控制器的view
    UIViewController *new = self.childViewControllers[to];
    new.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    // 占据除了右侧的dock之外的所有区域
    CGFloat w = self.view.frame.size.width - _rightDock.frame.size.width;
    CGFloat h = self.view.frame.size.height;
    new.view.frame = CGRectMake(0, 0, w, h);
    [self.view insertSubview:new.view atIndex:0];
}





#pragma mark 收藏按钮被点击
- (void)collectBtnClicked
{
    // 如果 是收藏 的,则取消收藏,并且发出通知,告诉自己要更新收藏按钮的背景图片,并且告诉收藏控制器里面重新reloadData
    if (_deal.collected) {
        // 取消收藏
        [[DealCollectionTool sharedDealCollectionTool] uncollectDeal:_deal];
    } else {
        // 加入收藏
        [[DealCollectionTool sharedDealCollectionTool] collectDeal:_deal];
    }
    
    // 发出通知,告诉自己要更新收藏按钮的背景图片,并且告诉收藏控制器里面重新reloadData
    [[NSNotificationCenter defaultCenter] postNotificationName:kCollectChangeNote object:nil];
}

#pragma mark 接收到收藏状态改变的通知,重新设置按钮背景图片
- (void)collectChange
{
    [[DealCollectionTool sharedDealCollectionTool] updateCollectedPropertyForDeal:_deal];
    UIButton *btn = (UIButton *)[self.navigationItem.rightBarButtonItems[1] customView];
    if (_deal.collected) {
        [btn setBackgroundImage:[UIImage imageNamed:@"ic_collect_suc.png"] forState:UIControlStateNormal];
    } else {
        [btn setBackgroundImage:[UIImage imageNamed:@"ic_deal_collect.png"] forState:UIControlStateNormal];
    }
}
@end


封装的子控件们


TopDock


//
//  TopDock.h
//  帅哥_团购
//
//  Created by beyond on 14-8-20.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  真正的通过xib显示一个订单的详情的控制器,顶部的购买dock,包含原价,现价,立即购买按钮


#import <UIKit/UIKit.h>
@class Deal, CrossLineLabel;
@interface TopDock : UIView

// 自绘标签,文字自带删除线 (列出的价格,贵的)
@property (weak, nonatomic) IBOutlet CrossLineLabel *listPrice;
// 当前价格 (便宜的)
@property (weak, nonatomic) IBOutlet UILabel *currentPrice;

// 依赖的数据源
@property (nonatomic, strong) Deal *deal;

// 类方法,快速从xib文件中,生成一个对应的TopDock对象
+ (id)topDock;

// 点击了xib上最右边的购买按钮
- (IBAction)buyBtnClicked;
@end

//
//  TopDock.m
//  帅哥_团购
//
//  Created by beyond on 14-8-20.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  真正的通过xib显示一个订单的详情的控制器,顶部的购买dock,包含原价,现价,立即购买按钮


#import "TopDock.h"
#import "Deal.h"
// 带删除线的Label
#import "CrossLineLabel.h"


@implementation TopDock

// 为本Dock绘制一个拉伸的背景图片(TopDock的背景是一张半透明的图片)
- (void)drawRect:(CGRect)rect
{
    [[UIImage imageStretchedWithName:@"bg_buyBtn.png"] drawInRect:rect];
}


// 类方法,创建一个从xib中实例化的TopDock对象
+ (id)topDock
{
    return [[NSBundle mainBundle] loadNibNamed:@"TopDock" owner:nil options:nil][0];
}

// 拦截数据源的setter方法,为内部子控件们提供数据
- (void)setDeal:(Deal *)deal
{
    _deal = deal;
    // 原价
    _listPrice.text = [NSString stringWithFormat:@" %@ 元 ", deal.list_price_text];
    // 现价
    _currentPrice.text = deal.current_price_text;
}




// 点击立即购买之后,打开safari进入官网购买
- (IBAction)buyBtnClicked
{
    NSString *ID = [_deal.deal_id substringFromIndex:[_deal.deal_id rangeOfString:@"-"].location + 1];
    NSString *url = [NSString stringWithFormat:@"http://o.p.dianping.com/buy/d%@", ID];
    // 应该程序 openURL,会自动调用safari进行访问
    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:url]];
}
@end


一个带删除线的文本标签

//
//  CrossLineLabel.h
//  帅哥_团购
//
//  Created by beyond on 14-8-20.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  一个带删除线的文本标签

#import <UIKit/UIKit.h>

@interface CrossLineLabel : UILabel

@end


//
//  CrossLineLabel.m
//  帅哥_团购
//
//  Created by beyond on 14-8-20.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  一个带删除线的文本标签
#import "CrossLineLabel.h"
@implementation CrossLineLabel
// 重点~~~带删除线的文字标签
- (void)drawRect:(CGRect)rect
{
    // 调用super的目的,就是先把文字画上去
    [super drawRect:rect];
    
    // 1.获得上下文
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    // 2.设置线条颜色就是标签的文字颜色
    [self.textColor setStroke];
    
    // 3.设置线的宽度
    // CGContextSetLineWidth(context, 3);
    
    // 3.画线的起点
    CGFloat y = rect.size.height * 0.5;
    CGContextMoveToPoint(context, 0, y);
    
    // 4.短标题,根据字体确定宽度(即线条将要画多长)----不用折行的
    CGSize size = [self.text sizeWithAttributes:[NSDictionary dictionaryWithObjectsAndKeys:self.font,NSFontAttributeName, nil]];

    // 5.线条的终点(文字有多长就画多长)
    CGContextAddLineToPoint(context, size.width, y);
    
    // 6.最后,渲染到上下文中
    CGContextStrokePath(context);
}
@end


右侧Dock


//
//  RightDock.h
//  帅哥_团购
//
//  Created by beyond on 14-8-21.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  真正的通过xib显示一个订单的详情的控制器,右边的三个按钮竖向排列组成的dock,包含简介、图文详情、商家详情
// 本view就是 右边的dock,内含三个按钮竖向排列的按钮RightDockItem,包含团购简介、图文详情、商家详情

#import <UIKit/UIKit.h>
@class RightDockItem;
@protocol RightDockDelegate;
@interface RightDock : UIView


// 内部的item  团购简介  排在首个
@property (weak, nonatomic) IBOutlet RightDockItem *dealSummaryItem;
// 内部的item  【商家详情】 排在最后一个
@property (weak, nonatomic) IBOutlet RightDockItem *merchantItem;

// 代理用weak,避免循环引用,告诉外界本Dock内部item被点击时的切换信息
@property (nonatomic, weak) id<RightDockDelegate> delegate;

// 类方法,从xib中生成一个实例对象
+ (id)rightDock;
// 本方法,监听三个RightDockItem的点击状态切换

- (IBAction)rightDockItemClicked:(RightDockItem *)sender;


@end


//
//  RightDock.m
//  帅哥_团购
//
//  Created by beyond on 14-8-21.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  真正的通过xib显示一个订单的详情的控制器,右边的三个按钮竖向排列组成的dock,包含简介、图文详情、商家详情
// 本view就是 右边的dock,内含三个按钮竖向排列的按钮RightDockItem,包含团购简介、图文详情、商家详情

#import "RightDock.h"
#import "RightDockItem.h"
#import "RightDockDelegate.h"
@interface RightDock ()
{
    // 三步曲,切换按钮的点击事件
    UIButton *_selectedBtn;
}
@end

@implementation RightDock

// 类方法,从xib中生成一个实例对象
+ (id)rightDock
{
    return [[NSBundle mainBundle] loadNibNamed:@"RightDock" owner:nil options:nil][0];
}

// 默认一开始就选中第一个【团购简介】
- (void)awakeFromNib
{
    [self rightDockItemClicked:_dealSummaryItem];
}
// 重写setFrame,避免外界改变右侧边栏的宽高
- (void)setFrame:(CGRect)frame
{
    frame.size = self.frame.size;
    [super setFrame:frame];
}





// 右侧dock的内部的三个item的 点击事件
- (IBAction)rightDockItemClicked:(RightDockItem *)sender
{
    // 0.通知代理,调用代理的方法,将前一个选中按钮 和 被点击的按钮传递给外界
    if ([_delegate respondsToSelector:@selector(rightDock:btnClickedFrom:to:)]) {
        [_delegate rightDock:self btnClickedFrom:_selectedBtn.tag to:sender.tag];
    }
    
    // 1.标准三步曲,切换按钮状态
    _selectedBtn.enabled = YES;
    sender.enabled = NO;
    _selectedBtn = sender;
    
    // 2.更改三个按钮的叠放层次,即将被点击的按钮放到最上面
    if (sender == _dealSummaryItem) {
        // 当点击了第1个按钮 团购简介,就要把第3个【商家详情】放到最下面,即最前面
        [self insertSubview:_merchantItem atIndex:0];
    } else if (sender == _merchantItem) {
        // 当点击了第3个按钮 商家详情,就要把第1个【团购简介】放到最下面,即最前面
        [self insertSubview:_dealSummaryItem atIndex:0];
    }
    // 3.将被点击的这个item放到最上面,将指定的view推送到最前面(用户面前)
    [self bringSubviewToFront:sender];
}

@end


右侧Dock的代理 

//
//  RightDockDelegate.h
//  帅哥_团购
//
//  Created by beyond on 14-8-21.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  真正的通过xib显示一个订单的详情的控制器,右边的三个按钮竖向排列组成的dock,包含简介、图文详情、商家详情
//  右边的dock,内含三个按钮竖向排列的按钮RightDockItem,包含简介、图文详情、商家详情


//  右边的Dock的代理,点击了RightDockItem时侯,告诉外界调用者,点击了哪一个,From btn To btn

#import <Foundation/Foundation.h>
@class RightDock;
@protocol RightDockDelegate <NSObject>

// 协议方法,点击RightDock里面的item时侯,Dock会调用代理delegate的方法,告诉外界,我内部被点击的按钮是从哪一个切换到了哪一个
@optional
- (void)rightDock:(RightDock *)rightDock btnClickedFrom:(int)from to:(int)to;
@end


右侧DockItem

//
//  RightDockItem.h
//  帅哥_团购
//
//  Created by beyond on 14-8-21.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  真正的通过xib显示一个订单的详情的控制器,右边的三个按钮竖向排列组成的dock,包含简介、图文详情、商家详情
// 本按钮就是右边的RightDockItem
#import <UIKit/UIKit.h>

@interface RightDockItem : UIButton

@end

//
//  RightDockItem.m
//  帅哥_团购
//
//  Created by beyond on 14-8-21.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  真正的通过xib显示一个订单的详情的控制器,右边的三个按钮竖向排列组成的dock,包含简介、图文详情、商家详情
// 本按钮就是右边的RightDockItem

#import "RightDockItem.h"

@implementation RightDockItem

// 取消默认的点击高亮状态
- (void)setHighlighted:(BOOL)highlighted
{
    // do nothing...
}
@end

团购简介控制器

SummaryController

//
//  SummaryController.h
//  帅哥_团购
//
//  Created by beyond on 14-8-21.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  团购简介控制器,当点击右侧dock里面的第一个rightDockItem按钮时,创建并显示本控制器

#import <UIKit/UIKit.h>
@class Deal;
@interface SummaryController : UIViewController

// 数据源
@property (nonatomic, strong) Deal *deal;
@end

//
//  SummaryController.m
//  帅哥_团购
//
//  Created by beyond on 14-8-21.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  团购简介控制器,当点击右侧dock里面的第一个rightDockItem按钮时,创建并显示本控制器
//  本控制器,最上面是SummaryHeaderView,下面是若干个SummaryTextView,一个SummaryTextView 代表一个组 如团购详情、购买须知、重要通知

#import "SummaryController.h"
#import "SummaryHeader.h"
#import "DealRequestTool.h"
#import "Deal.h"
#import "Restriction.h"
// 一个SummaryTextView 代表一个组 如团购详情、购买须知、重要通知
#import "SummaryText.h"

#define kVMargin 15
@interface SummaryController ()
{
    UIScrollView *_scrollView;
    // 本控制器,最上面是SummaryHeaderView,下面是若干个SummaryTextView
    SummaryHeader *_header;
}
@end

@implementation SummaryController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    // 1.添加滚动视图
    [self addScrollView];
    
    // 2.添加头部控件
    [self addHeaderView];
    
    // 3.通过工具,加载更详细的单个团购数据
    [self loadSingleDealData];
}
#pragma mark - 1.添加scrollView
- (void)addScrollView
{
    // 其他几个控件,全加到scrollView里
    _scrollView = [[UIScrollView alloc] init];
    _scrollView.showsVerticalScrollIndicator = NO;
    // scrollView的宽随便给个 430
    _scrollView.bounds = CGRectMake(0, 0, 430, self.view.frame.size.height);
    CGFloat x = self.view.frame.size.width * 0.5;
    CGFloat y = self.view.frame.size.height * 0.5;
    _scrollView.center = CGPointMake(x, y);
    // 宽度固定,左边距,右边距拉伸,高度也拉伸
    _scrollView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
    // 额外的滚动距离
    CGFloat height = 70;
    _scrollView.contentInset = UIEdgeInsetsMake(height, 0, 0, 0);
    _scrollView.contentOffset = CGPointMake(0, -height);
    [self.view addSubview:_scrollView];
}
#pragma mark 2.添加简介头控件
- (void)addHeaderView
{
    _header = [SummaryHeader summaryHeader];
    // 重要~~~保持开始高度为上一次的高度
    _header.frame = CGRectMake(0, 0, _scrollView.frame.size.width, _header.frame.size.height);
    // 内部会拦截赋值
    _header.deal = _deal;
    // 添加到scrollView
    [_scrollView addSubview:_header];
}
#pragma mark 加载更详细的单个团购数据
- (void)loadSingleDealData
{
    // 1.添加圈圈
    UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
    indicator.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
    CGFloat x = _scrollView.frame.size.width * 0.5;
    CGFloat y = CGRectGetMaxY(_header.frame) + kVMargin;
    indicator.center = CGPointMake(x, y);
    [_scrollView addSubview:indicator];
    [indicator startAnimating];
    
    // 2.发送请求
    [[DealRequestTool sharedDealRequestTool] dealRequestWithID:_deal.deal_id success:^(Deal *deal) {
        // 请求成功,返回单个团购信息,用成员变量记住最新的团购数据
        _deal = deal;
        // 提供数据源,内部会拦截赋值
        _header.deal = deal;
        // 添加详情数据
        [self addSummaryTextViews];
        // 移除圈圈
        [indicator removeFromSuperview];
    } error:^(NSError *error) {
        log(@"%@",error);
    }];
    
}

#pragma mark 根据请求返回的结果,添加若干个详情(简介文本控件)
- (void)addSummaryTextViews
{
    _scrollView.contentSize = CGSizeMake(0, CGRectGetMaxY(_header.frame) + kVMargin);
    
    // 1.团购详情
    [self addSummaryTextView:@"ic_content.png" title:@"团购详情" content:_deal.details];
    
    // 2.购买须知
    [self addSummaryTextView:@"ic_tip.png" title:@"购买须知" content:_deal.restrictions.special_tips];
    
    // 3.重要通知
    [self addSummaryTextView:@"ic_tip.png" title:@"重要通知" content:_deal.notice];
}

#pragma mark 抽取的,添加一个简介文本控件,参数:图片名,该组的标题,下文
- (void)addSummaryTextView:(NSString *)icon title:(NSString *)title content:(NSString *)content
{
    if (content.length == 0) return;
    
    // 0.创建TextView
    SummaryText *textView = [SummaryText summaryText];
    
    // 重要,先得到scrollView的高度,因为每一次添加都是将一组SummaryTextView,添加到scrollView的最后面
    CGFloat y = _scrollView.contentSize.height;
    CGFloat w = _scrollView.frame.size.width;
    CGFloat h = textView.frame.size.height;
    textView.frame = CGRectMake(0, y, w, h);
    
    // 2.基本文字属性
    textView.title = title;
    textView.content = content;
    textView.icon = icon;
    
    // 3.添加
    [_scrollView addSubview:textView];
    
    // 4.每次添加一组SummaryTextView之后,就要再次增设scrollView的内容尺寸
    _scrollView.contentSize = CGSizeMake(0, CGRectGetMaxY(textView.frame) + kVMargin);
}

@end

封装的简介头

SummaryHeader.xib


//
//  SummaryHeader.h
//  帅哥_团购
//
//  Created by beyond on 14-8-21.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  背景是一个四周圆角图片,点击【团购简介】rightDockItem创建出来的控制器的上面一个图文并茂的view,成员有:剩余时间,购买人数,是否支持过期退款,随时退款,以及一张大图

#import <UIKit/UIKit.h>
@class Deal;
@interface SummaryHeader : UIView

// 数据源
@property (nonatomic, strong) Deal *deal;
// 与xib进行拖线的控件们
// 大图
@property (weak, nonatomic) IBOutlet UIImageView *image;
// 描述,可根据文字行数动态确定高度
@property (weak, nonatomic) IBOutlet UILabel *desc;
// 随时退款
@property (weak, nonatomic) IBOutlet UIButton *anyTimeRefund;
// 过期退款
@property (weak, nonatomic) IBOutlet UIButton *expireRefund;
// 剩余时间
@property (weak, nonatomic) IBOutlet UIButton *timeLeft;
// 购买人数
@property (weak, nonatomic) IBOutlet UIButton *purchaseCount;

// 类方法提供一个实例对象,内部会加载对应的xib
+ (id)summaryHeader;

@end

//
//  SummaryHeader.m
//  帅哥_团购
//
//  Created by beyond on 14-8-21.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  背景是一个四周圆角图片,点击【团购简介】rightDockItem创建出来的控制器的上面一个图文并茂的view,成员有:剩余时间,购买人数,是否支持过期退款,随时退款,以及一张大图

#import "SummaryHeader.h"
#import "Deal.h"
// 限制条件,如(是否需要预约、是否支持随时退款、(购买须知)附加信息)
#import "Restriction.h"
#import "ImgDownloadTool.h"

@implementation SummaryHeader
// 背景是一个四周圆角图片
- (void)drawRect:(CGRect)rect
{
    [[UIImage imageStretchedWithName:@"bg_order_cell.png"] drawInRect:rect];
}
// 类方法提供一个实例对象,内部会加载对应的xib
+ (id)summaryHeader
{
    return [[NSBundle mainBundle] loadNibNamed:@"SummaryHeader" owner:nil options:nil][0];
}
// 拦截setter,为子控件赋值
- (void)setDeal:(Deal *)deal
{
    _deal = deal;
    
    if (deal.restrictions) { // 有约束(完整的数据)
        // 1.设置是否支持退款
        _anyTimeRefund.enabled = deal.restrictions.is_refundable;
        _expireRefund.enabled = _anyTimeRefund.enabled;
    } else { // 不完整的数据
        // 2.下载图片
        [ImgDownloadTool imgDownloadWithUrl:deal.image_url tmpImgName:kImgPlaceHolder imageView:_image];
        
        
        // 3.设置剩余时间
        // 设置格式器,将字符串形式的时间转成NSDate对象
        NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
        fmt.dateFormat = @"yyyy-MM-dd";
        NSDate *dealline = [fmt dateFromString:deal.purchase_deadline];
        // 例如过期时间是:2014-08-21,意思是2014-08-22 00:00:00过期
        // 因此真正过期时间,还要加上24小时
        dealline = [dealline dateByAddingTimeInterval:24 * 3600];
        // 取得当前日期,比如2014-08-21 16:44
        NSDate *now = [NSDate date];
        // 调用NSDate的分类方法,内部通过公历calendar计算出NSDateComponents
        NSDateComponents *dateComponents = [now compareWithOther:dealline];
        // 从计算好的dateComponents中取出 天 时  分 等
        NSString *timeStr = [NSString stringWithFormat:@"%d 天 %d 小时 %d 分钟", dateComponents.day, dateComponents.hour, dateComponents.minute];
        [_timeLeft setTitle:timeStr forState:UIControlStateNormal];
    }
    
    // 4.购买人数
    NSString *pc = [NSString stringWithFormat:@"%d 人已购买", deal.purchase_count];
    [_purchaseCount setTitle:pc forState:UIControlStateNormal];
    
    // 5.设置描述
    _desc.text = deal.desc;
    // 根据字体和宽度,限制描述Label的高度
    CGRect tmpRect = [_desc.text boundingRectWithSize:CGSizeMake(_desc.frame.size.width, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:[NSDictionary dictionaryWithObjectsAndKeys:_desc.font,NSFontAttributeName, nil] context:nil];
    // 描述的高度
    CGFloat descH = tmpRect.size.height +20;
    
    CGRect descF = _desc.frame;
    
    // 重要~~~根据最新的文字显示的高度与旧的高度的差值,确定整个View的高差变化,这句必须在赋值之前
    CGFloat descDeltaH = descH - descF.size.height;
    
    descF.size.height = descH;
    _desc.frame = descF;
    
    // 6.设置整体的高度
    CGRect selfF = self.frame;
    selfF.size.height += descDeltaH;
    self.frame = selfF;
}



@end


抽取后的简介文本SummaryText.xib




//
//  SummaryText.h
//  帅哥_团购
//
//  Created by beyond on 14-8-21.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  最上面是SummaryHeaderView,下面是若干个SummaryTextView,一个SummaryTextView 代表一个组 如团购详情、购买须知、重要通知

#import <UIKit/UIKit.h>

@interface SummaryText : UIView


// 标题
@property (weak, nonatomic) IBOutlet UIButton *titleView;
// 内容
@property (weak, nonatomic) IBOutlet UILabel *contentView;

// 数据源,为子控件提供数据
@property (nonatomic, copy) NSString *icon; // 图标
@property (nonatomic, copy) NSString *title; // 标题
@property (nonatomic, copy) NSString *content; // 内容


// 类方法提供一个实例对象,内部会加载对应的xib
+ (id)summaryText;
@end

//
//  SummaryText.m
//  帅哥_团购
//
//  Created by beyond on 14-8-21.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  最上面是SummaryHeaderView,下面是若干个SummaryTextView,一个SummaryTextView 代表一个组 如团购详情、购买须知、重要通知

#import "SummaryText.h"

@implementation SummaryText
// 背景是一个四周圆角图片
- (void)drawRect:(CGRect)rect
{
    [[UIImage imageStretchedWithName:@"bg_order_cell.png"] drawInRect:rect];
}
// 类方法提供一个实例对象,内部会加载对应的xib
+ (id)summaryText
{
    return [[NSBundle mainBundle] loadNibNamed:@"SummaryText" owner:nil options:nil][0];
}
// 拦截数据源,为对应子控件设置标题
- (void)setIcon:(NSString *)icon
{
    _icon = icon;
    
    [_titleView setImage:[UIImage imageNamed:icon] forState:UIControlStateNormal];
}
// 拦截数据源,为对应子控件设置标题
- (void)setTitle:(NSString *)title
{
    _title = title;
    
    [_titleView setTitle:title forState:UIControlStateNormal];
}
// 拦截数据源,为对应子控件设置标题
- (void)setContent:(NSString *)content
{
    _content = content;
    
    // 1.设置label的文字
    _contentView.text = content;
    
    // 2.计算文字的高度
    // 根据字体和宽度,限制描述Label的高度
    CGRect tmpRect = [_contentView.text boundingRectWithSize:CGSizeMake(_contentView.frame.size.width, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:[NSDictionary dictionaryWithObjectsAndKeys:_contentView.font,NSFontAttributeName, nil] context:nil];
    
    CGFloat textH = tmpRect.size.height + 20;
    
    CGRect contentF = _contentView.frame;
    // 重要~~~根据最新的文字显示的高度与旧的高度的差值,确定整个View的高差变化,这句必须在赋值之前
    CGFloat contentDeltaH = textH - contentF.size.height;
    contentF.size.height = textH;
    _contentView.frame = contentF;
    
    // 3.重要~~~调整整体的高度
    CGRect selfF = self.frame;
    selfF.size.height += contentDeltaH;
    self.frame = selfF;
}



@end








iOS_21团购_真正封装的团购详情控制器