葡京网投哪个正规 > 首页 > iOS_21团购_顶部菜单和弹出菜单联动,iOS_31_cocos2d环境搭建

原标题:iOS_21团购_顶部菜单和弹出菜单联动,iOS_31_cocos2d环境搭建

浏览次数:133 时间:2019-11-30

iOS_仿QQ空间_控制器的切换_自定义segmentCtrol

最终效果图:

图片 1

< 喎?" target="_blank" class="keylink">vcD4KPHA+1ve/2NbGxvc8L3A+CjxwPjxpbWcgc3JjPQ=="" alt="">

//
//  BeyondViewController.m
//  28_QQ空间
//
//  Created by beyond on 14-9-1.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  主控制器包括两个部分:左边的Dock,右边的contentView,其中左边Dock又包括三个部分(顶部的头像按钮、中部的选项卡、底部的一个整体),其中底部的整体 包含三个按钮「说说、拍照、日记」,中部的选项卡包含六个自定义item「全部动态、与我相关、照片墙、电子相框、好友、更多」

#import "BeyondViewController.h"
// 控制器
#import "BeyondNavigationController.h"
#import "NanaController.h"

// Dock
#import "Dock.h"

#import "DockMiddleTabBar.h"
#import "DockBottomView.h"
#import "DockTopIconBtn.h"


// 协议
#import "DockMiddleTabBarDelegate.h"
#import "DockBottomViewDelegate.h"

@interface BeyondViewController () 
@property (nonatomic, weak) Dock *dock;
// 存放右边子控制器的view
@property (nonatomic, weak) UIView *contentView;
@end

@implementation BeyondViewController
#pragma mark - 生命周期方法
- (void)viewDidLoad
{
    [super viewDidLoad];
    // 0.设置控制器背景色 为全局深灰色
    self.view.backgroundColor = kGlobalBgColor;

    // 1.初始化Dock
    [self setupDock];

    // 2.初始化contentView
    [self setupContentView];

    // 3.初始化所有子控制器
    [self setupChildViewControllers];

    // 4.默认点击头像
    [self iconBtnClicked];
}
#pragma mark - 左边Dock
// 1.初始化Dock
- (void)setupDock
{
    // 1.添加dock
    Dock *dock = [Dock allocInit];
    // 重要~~~高度自动伸缩 
    dock.autoresizingMask = UIViewAutoresizingFlexibleHeight;
    dock.height = self.view.height;
    [self.view addSubview:dock];
    self.dock = dock;

    // 2.根据当前的屏幕方向设置dock的属性
    [self.dock rotate:UIInterfaceOrientationIsLandscape(self.interfaceOrientation)];

    // 3.设置tabbar的代理
    self.dock.tabBar.delegate = self;

    // 4.监听头像的点击
    [self.dock.iconBtn addTarget:self action:@selector(iconBtnClicked) forControlEvents:UIControlEventTouchUpInside];

    // 5.设置bottomView的代理,监听bottomView内部的三个按钮点击
    self.dock.bottomView.delegate = self;
}

// 4.点击头像
- (void)iconBtnClicked
{
    // 子控制器的个数 共 7个 0~5对应TabBar,索引为6才是头像对应的控制器
    int count = self.childViewControllers.count;

    // 遍历,获得当前正在显示的控制器的索引
    int from = 0;
    for (int i = 0; iing-->end)
- (void)dragContentView:(UIPanGestureRecognizer *)pan
{
    //  分类方法,弹簧效果,仅是可拖动的弹簧效果,没有进行边界检测
    [pan addFlexableEffect];

}
#pragma mark - 所有子控制器
// 3.初始化所有子控制器
- (void)setupChildViewControllers
{
    // tabbar对应的6个子控制器
    // 0~5 对应TabBar上6个item
    UIViewController *vc0 = [UIViewController allocInit];
    vc0.title = @"全部动态";
    [self setupOneChildViewController:vc0];

    UIViewController *vc1 = [UIViewController allocInit];
    vc1.title = @"与我相关";
    [self setupOneChildViewController:vc1];

    UIViewController *vc2 = [UIViewController allocInit];
    vc2.title = @"照片墙";
    [self setupOneChildViewController:vc2];

    UIViewController *vc3 = [UIViewController allocInit];
    vc3.title = @"电子相框";
    [self setupOneChildViewController:vc3];

    UIViewController *vc4 = [UIViewController allocInit];
    vc4.title = @"好友";
    [self setupOneChildViewController:vc4];

    UIViewController *vc5 = [UIViewController allocInit];
    vc5.title = @"更多";
    [self setupOneChildViewController:vc5];

    //  7.点击主控制器左边Dock 最上方的头像,来到nana控制器
    NanaController *nana =[NanaController allocInit];
    [self setupOneChildViewController:nana];
}

// 3.1.自定义方法,用导航控制器,包装一个子控制器 (也可以重写父类的addChildViewController方法)
- (void)setupOneChildViewController:(UIViewController *)vc
{
    // 不要自动扩张至全屏
    vc.edgesForExtendedLayout = UIRectEdgeNone;
    BeyondNavigationController *nav = [[BeyondNavigationController alloc] initWithRootViewController:vc];
    [self addChildViewController:nav];
}


#pragma mark - 父类方法-屏幕即将旋转
//  当屏幕即将旋转的时候调用
//  toInterfaceOrientation 旋转完毕后的最终方向
//  duration               旋转动画所花费的时间
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{

        // 1.设置Dock
        //控制器监测到了 屏幕旋转的事件,通知内部子控件Dock
        [self.dock rotate:UIInterfaceOrientationIsLandscape(toInterfaceOrientation)];


        // 2.设置contentView
        // dock宽
        CGFloat dockW = self.dock.width;
        // x
        self.contentView.x = dockW;
        // 屏幕宽 (因为是willRotate,所以要反着来)
        CGFloat screenW = UIInterfaceOrientationIsLandscape(self.interfaceOrientation) ?768:1024;
        // 宽
        self.contentView.width = screenW - dockW;



}



#pragma mark - TabBar的代理方法
- (void)tabBar:(DockMiddleTabBar *)tabBar didSelectButtonFrom:(int)from to:(int)to
{
    // 1.新控制器(实为导航控制器)
    BeyondNavigationController *newNaviVC = self.childViewControllers[to];
    // 防止重复点击
    if (newNaviVC.view.superview) return;
    // 2.设置新控制器的frame填充整个contentView
    newNaviVC.view.frame = self.contentView.bounds;

    // 3.取出导航控制器的根控制器设置背景色
    UIViewController *newRootVC = [newNaviVC.childViewControllers firstObject];
    newRootVC.view.backgroundColor = kColor(212, 212, 212);

    // 4.旧控制器
    BeyondNavigationController *oldNaviVC;
    // 取出最后一个子控制器 (即头像按钮控制器)
    BeyondNavigationController *lastNaviVC = [self.childViewControllers lastObject];
    if (lastNaviVC.view.superview) {
        // 特例,如果是最后一个添加的头像控制器在显示 (头像按钮控制器正在显示,则旧控制器就是头像控制器)
        oldNaviVC = lastNaviVC;
    } else {
        // 如果是 0 ~ 5这几个TabBar里面的控制器,则可以直接 统一切换
        oldNaviVC = self.childViewControllers[from];
    }

    // 5.转场动画   调用UIView的分类方法,实现三维转场动画
    [self.contentView switchOldView:oldNaviVC.view toNewView:newNaviVC.view];


}

#pragma mark - bottomView代理方法
- (void)bottomMenu:(DockBottomView *)bottomView didClickButton:(BottomViewBtnType)btnType
{
    switch (btnType) {
        case BottomViewBtnTypeBlog: // 日志
        case BottomViewBtnTypeMood: // 心情
        case BottomViewBtnTypePhoto: // 照片
        {
            NanaController *nanaVC = [NanaController allocInit];
            BeyondNavigationController *nav = [[BeyondNavigationController alloc] initWithRootViewController:nanaVC];
            // 设置modal 的类型:
            nav.modalPresentationStyle = UIModalPresentationFormSheet;
            [self presentViewController:nav animated:YES completion:nil];
            break;
        }

        default:
            break;
    }
}



@end

View的封装

图片 2

图片 3

Dock

//
//  Dock.h
//  28_QQ空间
//
//  Created by beyond on 14-9-1.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  主控制器左边的Dock,其包括三个部分(顶部的头像按钮、中部的选项卡、底部的一个整体),其中底部的整体 包含三个按钮「说说、拍照、日记」,中部的选项卡包含六个自定义item「全部动态、与我相关、照片墙、电子相框、好友、更多」

#import 

@class  DockTopIconBtn, DockMiddleTabBar,DockBottomView;

@interface Dock : UIView

// 当外界收到屏幕旋转的消息时,会调用该方法 告之我,我会拦截此方法,调整好自己在相应的屏幕下的frame,接着我再把此消息传达给我自己内部的子控件们,让其调整frame
- (void)rotate:(BOOL)lanscape;
#pragma mark - 全部提供给控制器访问,设置代理等
@property (weak, nonatomic, readonly) DockTopIconBtn *iconBtn;

@property (weak, nonatomic, readonly) DockMiddleTabBar *tabBar;

@property (weak, nonatomic, readonly) DockBottomView *bottomView;

@end



//
//  Dock.m
//  28_QQ空间
//
//  Created by beyond on 14-9-1.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  主控制器左边的Dock,其包括三个部分(顶部的头像按钮、中部的选项卡、底部的一个整体),其中底部的整体 包含三个按钮「说说、拍照、日记」,中部的选项卡包含六个自定义item「全部动态、与我相关、照片墙、电子相框、好友、更多」

#import "Dock.h"

#import "DockTopIconBtn.h"
#import "DockMiddleTabBar.h"
#import "DockBottomView.h"


@implementation Dock
#pragma mark - 生命周期方法
- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // 1.添加子控件 头像
        [self setupiconBtn];

        // 2.添加子控件 选项卡
        [self setupTabBar];

        // 3.添加子控件 底部整体
        [self setupBottomView];
    }
    return self;
}
// 1.添加子控件 头像
- (void)setupiconBtn
{
    DockTopIconBtn *iconBtn = [[DockTopIconBtn alloc] init];
    [self addSubview:iconBtn];
    _iconBtn = iconBtn;
}

// 2.添加子控件 选项卡
- (void)setupTabBar
{
    DockMiddleTabBar *tabBar = [[DockMiddleTabBar alloc] init];
    // 粘着底部
    tabBar.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
    [self addSubview:tabBar];
    _tabBar = tabBar;
}

// 3.添加子控件 底部整体
- (void)setupBottomView
{
    DockBottomView *bottomView = [[DockBottomView alloc] init];
    // 粘着底部
    bottomView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
    [self addSubview:bottomView];
    _bottomView = bottomView;
}

#pragma mark - 拦截外部屏幕变化时的传递过来的消息
// 当外界收到屏幕旋转的消息时,会调用该方法 告之我,我会拦截此方法,调整好自己在相应的屏幕下的frame,接着我再把此消息传达给我自己内部的子控件们,让其调整frame
- (void)rotate:(BOOL)lanscape
{
    // 1.转达消息,首先 调整底部菜单,才能设置其他的子控件
    [self.bottomView rotate:lanscape];

    // 2.然后才 设置dock自己的宽度 跟随 底部的宽度
    self.width = self.bottomView.width;

    // 3.转达消息,然后才调整 tabbar
    [self.tabBar rotate:lanscape];
    self.tabBar.y = self.bottomView.y - self.tabBar.height;

    // 4.转达消息,最后才调整 头像
    [self.iconBtn rotate:lanscape];
}

@end

Dock的底部三个按钮作为一个整体

//
//  DockBottomView.h
//  28_QQ空间
//
//  Created by beyond on 14-9-1.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  左侧dock 的底部的一个整体,包含 三个按钮,分别是 说说、拍照、日记

#import 
@protocol DockBottomViewDelegate;
@interface DockBottomView : UIView
// 定义枚举,分别代表底部整体里面的三个按钮,它们是 说说、拍照、日记
typedef enum {
    BottomViewBtnTypeMood, // 心情
    BottomViewBtnTypePhoto, // 照片
    BottomViewBtnTypeBlog // 日志
} BottomViewBtnType;

// 代理,告诉代理点击的按钮类型
@property (nonatomic, weak) id delegate;


// 当外界收到屏幕旋转的消息时,会调用该方法 告之我,我会拦截此方法,调整好自己在相应的屏幕下的frame,接着我再把此消息传达给我自己内部的子控件们,让其调整frame
- (void)rotate:(BOOL)lanscape;



@end



//
//  DockBottomView.m
//  28_QQ空间
//
//  Created by beyond on 14-9-1.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//

#import "DockBottomView.h"
// 通知代理,点击的按钮类型
#import "DockBottomViewDelegate.h"
@implementation DockBottomView
#pragma mark - 生命周期
- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // 初始化3个按钮,并且绑定tag为定义好的枚举类型(通知代理时用)
        [self setupButtonWithIcon:@"tabbar_mood" tag:BottomViewBtnTypeMood];
        [self setupButtonWithIcon:@"tabbar_photo" tag:BottomViewBtnTypePhoto];
        [self setupButtonWithIcon:@"tabbar_blog" tag:BottomViewBtnTypeBlog];
    }
    return self;
}
// 自定义方法,创建一个按钮,参数:图片名,绑定的tag为按钮枚举类型(通知代理时用)
- (void)setupButtonWithIcon:(NSString *)icon tag:(BottomViewBtnType)tag
{
    UIButton *button = [[UIButton alloc] init];
    // 绑定的tag为按钮枚举类型(通知代理时用)
    button.tag = tag;
    // 图标按原始大小,文字无
    // 选中时的背景图片  拉伸
    // 监听点击事件,好通知代理,并且传递按钮的tag过去
    [button setBtnIcon:icon title:nil selectedBgImg:@"tabbar_separate_selected_bg" target:self action:@selector(buttonClick:) event:UIControlEventTouchUpInside];

    [self addSubview:button];
}
#pragma mark - 监听点击
- (void)buttonClick:(UIButton *)button
{
    if ([self.delegate respondsToSelector:@selector(bottomMenu:didClickButton:)]) {
        [self.delegate bottomMenu:self didClickButton:button.tag];
    }
}
#pragma mark - 拦截外部屏幕变化时的传递过来的消息
// 当外界收到屏幕旋转的消息时,会调用该方法 告之我,我会拦截此方法,调整好自己在相应的屏幕下的frame,接着我再把此消息传达给我自己内部的子控件们,让其调整frame
- (void)rotate:(BOOL)lanscape
{
    // 三个按钮
    int count = self.subviews.count;
    if (lanscape) {
        // 横屏时,横着排,宽度大一些
        self.width = kBottomBtnLanscapeW * count;
        self.height = kBottomBtnH;
        // 一一设置frame,横着排
        for (int i = 0; i

Dock底部整体 代理协议

//
//  DockBottomViewDelegate.h
//  28_QQ空间
//
//  Created by beyond on 14-9-1.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  左侧dock 的底部的一个整体,包含 三个按钮,分别是 说说、拍照、日记
//  定义协议,目的是通知外界:底部的一个整体中某一个按钮被点击了

#import 
@class DockBottomView;
@protocol DockBottomViewDelegate 


@optional
- (void)bottomMenu:(DockBottomView *)bottomView didClickButton:(BottomViewBtnType)btnType;

@end

Dock中部的TabBar

//
//  DockMiddleTabBar.h
//  28_QQ空间
//
//  Created by beyond on 14-9-1.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  左侧dock 的中部的 TabBar,选项卡,共有 6个,
//  它们分别是:「全部动态」「与我相关」「照片墙」「电子相框」「好友」「更多」


#import 
@protocol DockMiddleTabBarDelegate;
@interface DockMiddleTabBar : UIView


// 当外界收到屏幕旋转的消息时,会调用该方法 告之我,我会拦截此方法,调整好自己在相应的屏幕下的frame,接着我再把此消息传达给我自己内部的子控件们,让其调整frame
- (void)rotate:(BOOL)lanscape;

@property (nonatomic, weak) id delegate;

// 供控制器调用,取消选中 当前选中的Btn
- (void)deSelectCurrentItem;

@end




//
//  DockMiddleTabBar.m
//  28_QQ空间
//
//  Created by beyond on 14-9-1.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//

#import "DockMiddleTabBar.h"
// 监听点击,通知代理
#import "DockMiddleTabBarDelegate.h"
#import "DockMiddleTabBarItem.h"
// BeyondViewController成为DockMiddleTabBar的代理
// BeyondViewController监听DockMiddleTabBar内部按钮的点击事件




@interface DockMiddleTabBar()
// 选中的那个item
@property (weak, nonatomic) DockMiddleTabBarItem *selectedButton;
@end

@implementation DockMiddleTabBar



#pragma mark - 生命周期
- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // 一次性,初始化6个按钮
        [self setupButtonWithIcon:@"tab_bar_feed_icon" title:@"全部动态"];
        [self setupButtonWithIcon:@"tab_bar_passive_feed_icon" title:@"与我相关"];
        [self setupButtonWithIcon:@"tab_bar_pic_wall_icon" title:@"照片墙"];
        [self setupButtonWithIcon:@"tab_bar_e_album_icon" title:@"电子相框"];
        [self setupButtonWithIcon:@"tab_bar_friend_icon" title:@"好友"];
        [self setupButtonWithIcon:@"tab_bar_e_more_icon" title:@"更多"];
    }
    return self;
}
// 自定义方法,添加一个item
- (void)setupButtonWithIcon:(NSString *)icon title:(NSString *)title
{
    DockMiddleTabBarItem *button = [[DockMiddleTabBarItem alloc] init];
    // 绑定tag 0~5
    button.tag = self.subviews.count;
    // 设置标题
    // 监听点击
    // 图标按原始大小
    // 选中时的背景图片  拉伸
    [button setBtnIcon:icon title:title selectedBgImg:@"tabbar_separate_selected_bg" target:self action:@selector(buttonClick:) event:UIControlEventTouchDown];

    [self addSubview:button];
}

#pragma mark - 监听点击,通知代理
- (void)buttonClick:(DockMiddleTabBarItem *)button
{
    // 1.通知代理
    if ([self.delegate respondsToSelector:@selector(tabBar:didSelectButtonFrom:to:)]) {
        [self.delegate tabBar:self didSelectButtonFrom:self.selectedButton.tag to:button.tag];
    }

    // 2.标准三步曲,切换按钮状态
    [button switchSelectedStatusWithOldBtn:self.selectedButton];
}

#pragma mark - 拦截外部屏幕变化时的传递过来的消息
// 当外界收到屏幕旋转的消息时,会调用该方法 告之我,我会拦截此方法,调整好自己在相应的屏幕下的frame,接着我再把此消息传达给我自己内部的子控件们,让其调整frame
- (void)rotate:(BOOL)lanscape
{
    // 根据子控件个数,设置不同屏幕下的frame
    int count = self.subviews.count;
    // 选项卡的 宽 始终为dock的宽
    self.width = self.superview.width;
    // 选项卡的 高 和 子item的个数有关
    self.height = kBottomBtnH * count;
    // 遍历子控件,一一设置frame,立着排列
    for (int i = 0; i

Dock中部TabBar的代理要实现的协议

//
//  DockMiddleTabBarDelegate.h
//  28_QQ空间
//
//  Created by beyond on 14-9-1.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  DockMiddleTabBar定义好的协议,到时候监听到点击时,通知代理

#import 
@class DockMiddleTabBar;
@protocol DockMiddleTabBarDelegate 


@optional
- (void)tabBar:(DockMiddleTabBar *)tabBar didSelectButtonFrom:(int)from to:(int)to;

@end

Dock中部的选项卡里面的一个按钮

//
//  DockMiddleTabBarItem.m
//  28_QQ空间
//
//  Created by beyond on 14-9-1.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  Dock中部的选项卡里面的一个按钮

#import "DockMiddleTabBarItem.h"
// 横屏时,图片所占的宽度比
#define kImageLanscpaeWidthRatio 0.4

@implementation DockMiddleTabBarItem



#pragma mark - 生命周期
- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // 图片的伸缩 模式
        self.imageView.contentMode = UIViewContentModeCenter;
        // 标题的字体
        self.titleLabel.font = [UIFont systemFontOfSize:20];
    }
    return self;
}
#pragma mark - 父类方法
// 不需要高亮状态,只要选中即可
- (void)setHighlighted:(BOOL)highlighted {}

//  调整 图片的frame
- (CGRect)imageRectForContentRect:(CGRect)contentRect
{
    if (self.width > kBottomBtnLanscapeW) {
        // 横屏时,左图,右文字
        CGFloat imageW = self.width * kImageLanscpaeWidthRatio;
        CGFloat imageH = self.height;
        return CGRectMake(0, 0, imageW, imageH);
    } else {
        // 竖屏时,只有图片,没有文字
        return self.bounds;
    }
}

//  调整 标题的frame
- (CGRect)titleRectForContentRect:(CGRect)contentRect
{
    if (self.width > kBottomBtnLanscapeW) {
        // 横屏时,左图,右文字
        CGFloat titleX = self.width * kImageLanscpaeWidthRatio;
        CGFloat titleW = self.width - titleX;
        CGFloat titleH = self.height;
        return CGRectMake(titleX, 0, titleW, titleH);
    } else {
        // 竖屏时,只有图片,没有文字
        return CGRectZero;
    }
}


@end

Dock顶部的头像按钮

//
//  DockTopIconBtn.h
//  28_QQ空间
//
//  Created by beyond on 14-9-1.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  左侧dock 的顶部的 头像按钮

#import 

@interface DockTopIconBtn : UIButton


// 当外界收到屏幕旋转的消息时,会调用该方法 告之我,我会拦截此方法,调整好自己在相应的屏幕下的frame,接着我再把此消息传达给我自己内部的子控件们,让其调整frame
- (void)rotate:(BOOL)lanscape;

@end



//
//  DockTopIconBtn.m
//  28_QQ空间
//
//  Created by beyond on 14-9-1.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  左侧dock 的顶部的 头像按钮

#import "DockTopIconBtn.h"

@implementation DockTopIconBtn
#pragma mark - 生命周期方法
- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // 设置头像按钮 的图片
        [self setImage:[UIImage imageStretchedWithName:@"nanaLogo.jpg"] forState:UIControlStateNormal];
        // 设置头像按钮 的标题
        [self setTitle:@"nana" forState:UIControlStateNormal];
        // 设置头像按钮 的标题对齐方式
        self.titleLabel.textAlignment = NSTextAlignmentCenter;
        // 给图层加圆角
        self.imageView.layer.cornerRadius = 10;
    }
    return self;
}

#pragma mark - 父类方法
//  调整 图片的frame
- (CGRect)imageRectForContentRect:(CGRect)contentRect
{
    if (self.width > kBottomBtnPortraitW) {
        // 横屏
        // 图片宽为按钮宽,正方形
        CGFloat imageW = self.width;
        CGFloat imageH = imageW;
        return CGRectMake(0, 0, imageW, imageH);
    } else {
        // 竖屏时,图片占据整个按钮
        return self.bounds;
    }
}
//  调整 标题的frame
- (CGRect)titleRectForContentRect:(CGRect)contentRect
{
    if (self.width > kBottomBtnPortraitW) {
        // 横屏
        // 标题在图片下方,占据按钮除图片以外的空间
        CGFloat titleY = self.width;
        CGFloat titleW = self.width;
        CGFloat titleH = self.height - titleY;
        return CGRectMake(0, titleY, titleW, titleH);
    } else {
        // 竖屏时,标题隐藏
        return CGRectZero;
    }
}
#pragma mark - 拦截外部屏幕变化时的传递过来的消息
// 当外界收到屏幕旋转的消息时,会调用该方法 告之我,我会拦截此方法,调整好自己在相应的屏幕下的frame,接着我再把此消息传达给我自己内部的子控件们,让其调整frame
- (void)rotate:(BOOL)lanscape
{
    if (lanscape) {
        // 横屏
        // 头像按钮的宽为 父控件Dock的宽度的三分之一
        self.width = self.superview.width * 0.35;
        // 头像按钮的高为 宽+40, 其中40是为标题预留的
        self.height = self.width + 40;
        // 头像按钮居dock的顶部中心
        self.y = 60;
        self.x = (self.superview.width - self.width) * 0.5;
    } else {
        // 竖屏时,仍占dock的顶部中心,但此时宽高一致,标题不再显示
        self.y = 40;
        self.x = 10;
        self.width = self.superview.width - 2 * self.x;
        self.height = self.width;
    }
}

@end

自定义Segement控件及其使用

图片 4

//
//  BeyondSegment.h
//  28_QQ空间
//
//  Created by beyond on 14-9-2.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  自定义控件 segmentControl,每一个按钮都是segmentBarBtn

#import 

@interface SegmentBar : UIView

// 字串 数组,根据数组长度 决定 生成多少个SegmentBarBtn,并为其title赋值
@property (nonatomic, strong) NSArray *titlesArr;


//  设置当前选中的segmentBarBtn
@property (nonatomic, assign) int selectedSegmentIndex;


@end



//
//  BeyondSegment.m
//  28_QQ空间
//
//  Created by beyond on 14-9-2.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  自定义控件 segmentControl,每一个按钮都是segmentBarBtn

#import "SegmentBar.h"

#import "SegmentBarBtn.h"

@interface SegmentBar()
@property (nonatomic, weak) SegmentBarBtn *selectedSegment;
@end

@implementation SegmentBar
#pragma 拦截setter,添加内部子控件
- (void)setTitlesArr:(NSArray *)titlesArr
{
    _titlesArr = titlesArr;

    // 1.为健壮性,先移除以前创建的所有按钮
    [self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];

    // 2.添加新的按钮
    int count = titlesArr.count;
    for (int i = 0; i< 0 || selectedSegmentIndex >= count) return;

    // 取出对应位置的按钮
    SegmentBarBtn *segment = self.subviews[selectedSegmentIndex];

    // 调用自定义方法,选中该索引下的按钮
    [self segmentClick:segment];
}
// 开放接口,供外界调用 getter
- (int)selectedSegmentIndex
{
    return self.selectedSegment.tag;
}

@end

在Nana控制器中使用自定义控件segment,

及用代码创建storyboard中描述的控制器

//
//  NanaController.m
//  28_QQ空间
//
//  Created by beyond on 14-9-1.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  点击主控制器左边Dock 最上方的头像,来到此控制器

#import "NanaController.h"

#import "SegmentBar.h"

@interface NanaController ()
//@property (nonatomic, weak) SegmentBar *sc;
@end

@implementation NanaController

// 1.设置导航栏左边按钮
- (void)setupLeftBarBtn
{
    self.title = @"I'm nana";
    // 分类方法
    self.navigationItem.leftBarButtonItem = [UIBarButtonItem barButtonItemwithTitle:@"退出系统" style:UIBarButtonItemStyleDone target:self action:@selector(logout)];
}
#pragma mark - 生命周期
- (void)viewDidLoad
{
    [super viewDidLoad];
    // 1.设置导航栏左边按钮
    [self setupLeftBarBtn];
    // 2.设置导航栏的titleView为自定义的segment控件
    [self setupSegmentBar];

}
// 2.设置导航栏的titleView为自定义的segment控件
- (void)setupSegmentBar
{
    // 数据源模型决定 view
    NSArray *titlesArr = @[@"全部", @"好友动态", @"我的关注"];
    if (iOS7) {
        // iOS7使用自定义的扁平化风格
        UISegmentedControl *sc = [[UISegmentedControl alloc] initWithItems:titlesArr];
        sc.frame = CGRectMake(0, 0, 300, 32);
        sc.selectedSegmentIndex = 0;
        // 使用tintColor进行着色
        sc.tintColor = [UIColor grayColor];
        self.navigationItem.titleView = sc;
    } else {
        SegmentBar *sc = [[SegmentBar alloc] init];
        sc.titlesArr = titlesArr;
        sc.frame = CGRectMake(0, 0, 300, 32);
        sc.selectedSegmentIndex = 0;
        self.navigationItem.titleView = sc;
    }

}
// 点击退出登录,回到登录控制器,即创建Main.storyboard里面的初始控制器
- (void)logout
{
    // 调用控制器的分类方法从storyboard中创建指定ID的控制器
    self.view.window.rootViewController = [UIViewController allocInitFromStoryboard:nil withID:@"LoginController" bundle:nil];
}


@end

最终效果图: vcD4KPHA+1ve/2NbGxvc8L3A+CjxwPjxpbWcgc3JjPQ=="...

iOS_31_cocos2d环境搭建

最终效果图如:

图片 5

< 喎?" target="_blank" class="keylink">vcD4KPHA+MS6000dpdMnPz8LU2CBjb2NvczJktcTRucv1sPwstPO4xTEwME08L3A+CjxwPjxpbWcgc3JjPQ=="" alt="">

2.解压后,进入cocos2d主目录,复制路径到终端

3.执行./install.sh开始安装(实质是拷贝至XCode目录)

图片 6

图片 7

安装前XCode,新建项目时界面如下

图片 8

安装后XCode,新建项目时界面如下

图片 9

建好的工程目录结构如下

图片 10

直接运行程序,效果如下:

图片 11

应用代理

//
//  AppDelegate.h
//  31_cocos2D入门
//
//  Created by beyond on 14-9-5.
//  Copyright com.beyond 2014年. All rights reserved.

//  AppDelegate 继承自 CCAppDelegate
/*
    CCAppDelegate 继承自NSObect,遵守协议:
    CCAppDelegate 拥有成员:UIWindow *window_

 *  大多 Cocos2d 应用 应该重写 CCAppDelegate, CCAppDelegate作为应用的程序入口.
    至少应该复写 startScene 方法,以便 返回应用要展示的首个场景
    如果想更进一步定制 Cocos2d(例如自定义显示的像素模式), 
    请复写 applicaton:didFinishLaunchingWithOptions: 方法
 */


#import "cocos2d.h"

@interface AppDelegate : CCAppDelegate
@end




//
//  AppDelegate.m
//  31_cocos2D入门
//
//  Created by beyond on 14-9-5.
//  Copyright com.beyond 2014年. All rights reserved.
//  AppDelegate 继承自 CCAppDelegate
/*
 CCAppDelegate 继承自NSObect,遵守协议:
 CCAppDelegate 拥有成员:UIWindow *window_

 *  大多 Cocos2d 应用 应该重写 CCAppDelegate, CCAppDelegate作为应用的程序入口.
 至少应该复写 startScene 方法,以便 返回应用要展示的首个场景
 如果想更进一步定制 Cocos2d(例如自定义显示的像素模式),
 请复写 applicaton:didFinishLaunchingWithOptions: 方法
 */


#import "AppDelegate.h"
#import "IntroScene.h"
#import "HelloWorldScene.h"

@implementation AppDelegate

// 
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
 // 当继承自CCAppDelegate,唯一要实现的方法就是这一个方法,应用首次启动就会第一个执行本方法

 // 在这儿,可以设置 Cocos2D 各参数的默认值
 // There are a number of simple options you can change.
 // 如果你还嫌调用setupCocos2dWithOptions方法,不够灵活自由,那么你可以自己顶置 Cocos2D
 [self setupCocos2dWithOptions:@{
  // 显示 FPS
  CCSetupShowDebugStats: @(YES),

        // 使用降低了的帧率
        // CCSetupAnimationInterval: @(1.0/30.0),
        // 使用一个加快的帧率
        //  CCSetupFixedUpdateInterval: @(1.0/180.0),

        // 设置屏幕为竖屏模式
        //  CCSetupScreenOrientation: CCScreenOrientationPortrait,

        // 使用16位颜色:
        //  CCSetupPixelFormat: kEAGLColorFormatRGB565,
  // 使用一个统一的固定的坐标系统
        //  CCSetupScreenMode: CCScreenModeFixed,
  // Make iPad's act like they run at a 2x content scale. (iPad retina 4x)
        //  CCSetupTabletScale2X: @(YES),

        // 更多内容请参阅 CCAppDelegate.h
 }];

 return YES;
}

-(CCScene *)startScene
{
 // 本方法返回应用启动时,第一个要展示的场景
 return [IntroScene scene];
}

@end

场景一

//
//  IntroScene.h
//  31_cocos2D入门
//
//  Created by beyond on 14-9-5.
//  Copyright com.beyond 2014年. All rights reserved.
//

// Importing cocos2d.h and cocos2d-ui.h, will import anything you need to start using cocos2d-v3
#import "cocos2d.h"
#import "cocos2d-ui.h"

/**
 *  The intro scene
 *  Note, that scenes should now be based on CCScene, and not CCLayer, as previous versions
 *  Main usage for CCLayer now, is to make colored backgrounds (rectangles)
 *
 */
@interface IntroScene : CCScene

+ (IntroScene *)scene;
- (id)init;
@end





//
//  IntroScene.m
//  31_cocos2D入门
//
//  Created by beyond on 14-9-5.
//  Copyright com.beyond 2014年. All rights reserved.
//

#import "IntroScene.h"
#import "HelloWorldScene.h"



@implementation IntroScene


#pragma mark - 生命周期


+ (IntroScene *)scene
{
 return [[self alloc] init];
}



- (id)init
{

    self = [super init];
    if (!self) return(nil);

    // 创建背景颜色为深灰色
    CCNodeColor *background = [CCNodeColor nodeWithColor:[CCColor colorWithRed:0.2f green:0.2f blue:0.2f alpha:1.0f]];
    [self addChild:background];

    // 创建文字标签
    CCLabelTTF *label = [CCLabelTTF labelWithString:@"Hello Beyond" fontName:@"Chalkduster" fontSize:36.0f];
    label.positionType = CCPositionTypeNormalized;
    label.color = [CCColor redColor];
    // 屏幕的正中间 注意这里是笛卡尔坐标系,原点在左下方
    label.position = ccp(0.5f, 0.5f);
    [self addChild:label];

    // 创建一个开始按钮,点击后进入下一个场景
    CCButton *helloWorldButton = [CCButton buttonWithTitle:@"[ Start ]" fontName:@"Verdana-Bold" fontSize:18.0f];
    helloWorldButton.positionType = CCPositionTypeNormalized;
     // 屏幕的中间靠下方  注意这里是笛卡尔坐标系,原点在左下方
    helloWorldButton.position = ccp(0.5f, 0.35f);
     // 监听点击事件
    [helloWorldButton setTarget:self selector:@selector(onSpinningClicked:)];
    [self addChild:helloWorldButton];

    // 返回创建好的场景对象
 return self;
}


#pragma mark - 按钮点击事件,切换至下一场景


- (void)onSpinningClicked:(id)sender
{
    // 动画切换至下一个场景
    [[CCDirector sharedDirector] replaceScene:[HelloWorldScene scene]
                               withTransition:[CCTransition transitionPushWithDirection:CCTransitionDirectionLeft duration:1.0f]];
}


@end

场景二

//
//  HelloWorldScene.h
//  31_cocos2D入门
//
//  Created by beyond on 14-9-5.
//  Copyright com.beyond 2014年. All rights reserved.
//

// Importing cocos2d.h and cocos2d-ui.h, will import anything you need to start using Cocos2D v3
#import "cocos2d.h"
#import "cocos2d-ui.h"

/**
 *  主场景
 */
@interface HelloWorldScene : CCScene

+ (HelloWorldScene *)scene;
- (id)init;

@end




//
//  HelloWorldScene.m
//  31_cocos2D入门
//
//  Created by beyond on 14-9-5.
//  Copyright com.beyond 2014年. All rights reserved.
//

#import "HelloWorldScene.h"
#import "IntroScene.h"

@implementation HelloWorldScene
{
    CCSprite *_sprite;
}

#pragma mark - 生命周期
+ (HelloWorldScene *)scene
{
    return [[self alloc] init];
}


- (id)init
{


    if (!(self = [super init]) ) return(nil);

    // 场景模式下 允许交互
    self.userInteractionEnabled = YES;

    // 创建背景颜色为深灰色
    CCNodeColor *background = [CCNodeColor nodeWithColor:[CCColor colorWithRed:0.2f green:0.2f blue:0.2f alpha:1.0f]];
    [self addChild:background];

    // 添加一个精灵,并设置位置居中
    _sprite = [CCSprite spriteWithImageNamed:@"ColorCircle.png"];

    _sprite.position  = ccp(self.contentSize.width/2,self.contentSize.height/2);
    [self addChild:_sprite];

    // 为精灵创建一个旋转动作,并且调用精灵的runAction方法,重复执行动作
    CCActionRotateBy* actionSpin = [CCActionRotateBy actionWithDuration:1.5f angle:360];
    [_sprite runAction:[CCActionRepeatForever actionWithAction:actionSpin]];

    // 右上方,创建一个返回按钮,点击后,返回至上一个场景
    CCButton *backButton = [CCButton buttonWithTitle:@"[ Back ]" fontName:@"Verdana-Bold" fontSize:18.0f];
    backButton.positionType = CCPositionTypeNormalized;
    // 屏幕的右上方 注意这里是笛卡尔坐标系,原点在左下方
    backButton.position = ccp(0.85f, 0.95f);
    // 监听点击事件
    [backButton setTarget:self selector:@selector(onBackClicked:)];
    [self addChild:backButton];

    // 返回创建好的场景对象
 return self;
}

- (void)dealloc
{
    // clean up code goes here
}

#pragma mark - Enter & Exit
// -----------------------------------------------------------------------

- (void)onEnter
{
    // 必须总是先调用父类的onEnter方法
    [super onEnter];

    // In pre-v3, touch enable and scheduleUpdate was called here
    // In v3, touch is enabled by setting userInteractionEnabled for the individual nodes
    // Per frame update is automatically enabled, if update is overridden

}

- (void)onExit
{
    // 必须总是 最后才调用父类的onExit方法
    [super onExit];
}

#pragma mark - 用户触摸屏幕,精灵跟随手指移动

-(void) touchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
    CGPoint touchLoc = [touch locationInNode:self];

    // 输出触摸点的坐标
    CCLOG(@"Move sprite to @ %@",NSStringFromCGPoint(touchLoc));

    // 移动精灵到触摸点处 To表示绝对  By表示相对
    CCActionMoveTo *actionMove = [CCActionMoveTo actionWithDuration:1.0f position:touchLoc];
    // 调用精灵的runAction方法执行动作
    [_sprite runAction:actionMove];
}

#pragma mark - 按钮点击事件

- (void)onBackClicked:(id)sender
{
    // 使用转场动画,切换场景至 IntroScene
    [[CCDirector sharedDirector] replaceScene:[IntroScene scene]
                               withTransition:[CCTransition transitionPushWithDirection:CCTransitionDirectionRight duration:1.0f]];
}
@end

最终效果图如: vcD4KPHA+MS6000dpdMnPz8LU2CBjb2NvczJktcTRucv1sPwstPO4xTEwME08L3A+CjxwPjxpbWcgc3JjPQ=="...

iOS_21团购_顶部菜单和弹出菜单联动

最终效果图:

图片 12

< 喎?" target="_blank" class="keylink">vcD4KPHA+PGJyPgo8L3A+CjxwPjxicj4KPC9wPgo8cD6497/YvP652M+1zbwxOjwvcD4KPHA+PGltZyBzcmM9"" alt="">

各控件关系图2:

图片 13

点击Dock上面的按钮DockItem,

创建经导航控制器包装的DealListController,

并且添加到主控制器的右侧空间

//
//  DealListController.m
//  帅哥_团购
//
//  Created by beyond on 14-8-14.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  点击dock上面的【团购】按钮对应的控制器,上面是导航栏,导航栏右边是searchBar,导航栏左边是一个大按钮(TopMenu)(内部由三个小按钮组成)

#import "DealListController.h"
// 导航栏左边是一个大按钮(顶部菜单)
#import "TopMenu.h"

@interface DealListController ()

@end

@implementation DealListController


- (void)viewDidLoad
{
    [super viewDidLoad];
    // 1,设置上方的导航栏,右边是搜索bar,左边是一个大的VIEW(内有三个按钮),即TopMenu,内部的按钮是TopMenuItem
    [self addNaviBarBtn];

}
// 1,设置上方的导航栏,右边是搜索bar,左边是一个大的VIEW(内有三个按钮),即TopMenu,内部的按钮是TopMenuItem
- (void)addNaviBarBtn
{


    // 1.右边的搜索框
    UISearchBar *s = [[UISearchBar alloc] init];
    s.frame = CGRectMake(0, 0, 210, 35);
    s.placeholder = @"请输入商品名、地址等";
    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:s];

    // 2.左边的菜单栏,导航栏左边是一个大按钮(顶部菜单)
    TopMenu *topMenu = [[TopMenu alloc] init];
    // 3.用于点击顶部按钮时,容纳创建出来的底部弹出菜单(包括一个contentView和cover,contentView又包括scrollView和subTitleImgView),本成员是由创建此TopMenu的外部赋值传入, 这里是控制器的view,就是导航栏下面的所有区域
    // 重要~~~~~~~~~~
    topMenu.controllerView = self.view;

    self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:topMenu];
}
@end

TopMenu.h

//
//  TopMenu.h
//  帅哥_团购
//
//  Created by beyond on 14-8-15.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  点击dock上面的【团购】按钮时,创建出对应的经导航包装后的子控制器,子控制器的上面是导航栏,导航栏右边是searchBar,导航栏左边是一个大按钮(TopMenu)(内部只由三个小按钮组成它们分别是:全部频道,全部商区,默认排序),点击TopMenu中的某一个按钮,会在其下方,弹出一个PopMenu,PopMenu包括二个部分(上面是一个contentView:包括:scrollView和subTitleImgView,下:蒙板)

#import 

@interface TopMenu : UIView


//  用于点击顶部菜单项时,容纳创建出来的底部弹出菜单(包括一个contentView和cover,contentView又包括scrollView和subTitleImgView),本成员是由创建此TopMenu的控制器赋值传入, 本成员属性是用来接收控制器的view,就是导航栏下面的所有区域,目的是用于添加并展示PopMenu
@property (nonatomic, weak) UIView *controllerView;
@end

TopMenu.m

负责创建和添加3个TopMenuItem,

监听其内部三个TopMenuItem的点击事件,

并且根据点击的按钮的tag不同,创建出不同的PopMenu,并控制PopMenu的出现和隐藏,最后一个是注册到通知中心,监听所有通知,并且设置三个TopMenuItem的显示文字

//
//  TopMenu.m
//  帅哥_团购
//
//  Created by beyond on 14-8-15.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  点击dock上面的【团购】按钮对应的控制器,上面是导航栏,导航栏右边是searchBar,导航栏左边是一个大按钮(TopMenu)(内部只由三个小按钮组成它们分别是:全部频道,全部商区,默认排序),点击TopMenu中的某一个按钮,会在其下方,弹出一个PopMenu,PopMenu包括二个部分(上面是一个contentView:包括:scrollView和subTitleImgView,下:蒙板)

#import "TopMenu.h"


#import "TopMenuItem.h"
#import "CategoryPopMenu.h"
#import "DistrictPopMenu.h"
#import "OrderPopMenu.h"
#import "MetaDataTool.h"
#import "Order.h"

@interface TopMenu()
{
    // 三个顶部菜单项中当前选中的那一个,三个按钮:全部分类,全部商区,默认排序
    TopMenuItem *_currentTopMenuItem;



// 在点击不同的顶部菜单项的时候,因为要控制其对应的底部弹出菜单的出现和隐藏,因此,在创建它时,就要用成员变量,记住 弹出的分类菜单
    CategoryPopMenu *_categoryPopMenu;
// 在点击不同的顶部菜单项的时候,因为要控制其对应的底部弹出菜单的出现和隐藏,因此,在创建它时,就要用成员变量,记住 弹出的区域菜单
    DistrictPopMenu *_districtPopMenu;
// 在点击不同的顶部菜单项的时候,因为要控制其对应的底部弹出菜单的出现和隐藏,因此,在创建它时,就要用成员变量,记住 弹出的排序菜单
    OrderPopMenu *_orderPopMenu;


// 正在展示的底部弹出菜单,是个父类
    PopMenu *_showingPopMenu;




    // 因为要更改其显示文字,所以要成员变量记住创建出来的 分类菜单项
    TopMenuItem *_categoryTopMenuItem;
    // 因为要更改其显示文字,所以要成员变量记住创建出来的 区域菜单项
    TopMenuItem *_districtTopMenuItem;
    // 因为要更改其显示文字,所以要成员变量记住创建出来的 排序菜单项
    TopMenuItem *_orderTopMenuItem;
}
@end


@implementation TopMenu


- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {

        // 1.添加一个按钮:全部分类 (因为要更改其显示文字,所以要成员变量记住)
        _categoryTopMenuItem = [self addMenuItem:kAllCategory index:0];

        // 2.添加一个按钮:全部商区 (因为要更改其显示文字,所以要成员变量记住)
        _districtTopMenuItem = [self addMenuItem:kAllDistrict index:1];

        // 3.添加一个按钮:默认排序 (因为要更改其显示文字,所以要成员变量记住)
        _orderTopMenuItem = [self addMenuItem:@"默认排序" index:2];

        // 4.顶部菜单需要注册并监听所有通知,目的是更改其里面菜单项的文字,并且控制弹出菜单的显示和隐藏
        kAddAllNotes(dataChange)
    }
    return self;
}
// 5,抽取的方法,添加一个顶部菜单项(TopMenuItem),三个按钮:全部分类,全部商区,默认排序
- (TopMenuItem *)addMenuItem:(NSString *)title index:(int)index
{
    TopMenuItem *item = [[TopMenuItem alloc] init];
    item.title = title;
    item.tag = index;
    // 三个按钮:全部分类,全部商区,默认排序  水平排列
    item.frame = CGRectMake(kTopMenuItemW * index, 0, 0, 0);
    // 重要~~~顶部按钮(三个按钮:全部分类,全部商区,默认排序)被点击之后,都会调用此方法,根据tag进行区分,以便弹出不同的PopMenu
    [item addTarget:self action:@selector(topMenuItemClick:) forControlEvents:UIControlEventTouchUpInside];
    [self addSubview:item];
    return item;
}

// 4.注册并监听所有通知时调用此方法,更改按钮的文字,控制弹出菜单显示和隐藏
- (void)dataChange
{
    // 0.取消当前TopMenuItem的选中状态,并且置空_currentTopMenuItem ,因为监听到通知时,肯定是用户点击了一个子标题按钮,或者一个没有子标题的PopMenuItem
    _currentTopMenuItem.selected = NO;
    _currentTopMenuItem = nil;

    // 1.设置 分类按钮 要显示的文字,从工具中获得
    NSString *c = [MetaDataTool sharedMetaDataTool].currentCategoryName;
    if (c) {
        _categoryTopMenuItem.title = c;
    }

    // 2.设置 商区按钮 要显示的文字,从工具中获得
    NSString *d = [MetaDataTool sharedMetaDataTool].currentDistrictName;
    if (d) {
        _districtTopMenuItem.title = d;
    }

    // 3.设置 排序按钮 要显示的文字,从工具中获得
    NSString *o = [MetaDataTool sharedMetaDataTool].currentOrder.name;
    if (o) {
        _orderTopMenuItem.title = o;
    }

    // 4.最后,调用正在显示的弹出菜单的方法:隐藏底部弹出菜单,并置空正在显示的弹出菜单
    [_showingPopMenu hidePopMenu];
    _showingPopMenu = nil;
}



// 5-1,重要~~~监听顶部菜单项的点击,
// 顶部按钮(三个按钮:全部分类,全部商区,默认排序)被点击之后,都会调用此方法,根据tag进行区分,以便弹出不同的PopMenu
- (void)topMenuItemClick:(TopMenuItem *)item
{
    // 0.如果还没有选择好城市,则不允许点击顶部菜单按钮
    if ([MetaDataTool sharedMetaDataTool].currentCity == nil) return;
    // 1.控制选中状态的切换,先把前面记住的当前顶部菜单项取消选中
    _currentTopMenuItem.selected = NO;
    // 如果两次点击的是同一个顶部菜单项,则隐藏掉弹出的菜单,并且置空当前的选中TopMenuItem
    if (_currentTopMenuItem == item) {
        _currentTopMenuItem = nil;
        // 隐藏底部菜单
        [self hidePopMenu];
    } else {
        // 如果两次点击的是是不同的顶部菜单项,将TopMenuItem置为选中状态,且用成员变量记住,并且展示相应的底部弹出菜单
        item.selected = YES;
        _currentTopMenuItem = item;
        // 显示与顶部菜单项,对应的底部弹出菜单
        [self showPopMenu:item];
    }
}
// 5-2,点击了相同的TopMenuItem,要隐藏底部已经弹出的菜单,并且置其为空
- (void)hidePopMenu
{
    // 调用_showingPopMenu其自己的方法,隐藏并移除其内部的contentView(包括scrollView和subTitleImgView,并置cover透明),并置空_showingPopMenu
    [_showingPopMenu hidePopMenu];
    _showingPopMenu = nil;
}

// 5-3,点击了不同的TopMenuItem,要显示相应的底部弹出菜单
- (void)showPopMenu:(TopMenuItem *)item
{
    // 1,先判断 是否需要让弹出菜单执行出场动画(没有正在展示的弹出菜单时,才需要执行出场动画)
    BOOL animted;
    // 如果有正在显示的弹出菜单,如切换按钮点击的时候
    if (_showingPopMenu) {
        // 1-1,先移除当前正在显示的弹出菜单
        [_showingPopMenu removeFromSuperview];
        // 1-2,不要动画出场
        animted = NO;
    }else{
        // 没有正在展示的弹出菜单时,才需要执行出场动画
        animted = YES;
    }

    // 2,根据点击的顶部菜单项的tag,创建并显示不同的底部弹出菜单(三个按钮:全部分类,全部商区,默认排序)
    if (item.tag == 0) {
        // 创建分类弹出菜单,并且用成员记住,且置其为正在展示的PopMenu
        if (_categoryPopMenu == nil) {
            _categoryPopMenu = [[CategoryPopMenu alloc] init];
        }
        _showingPopMenu = _categoryPopMenu;
    } else if (item.tag == 1) { // 区域
        // 创建商区弹出菜单,并且用成员记住,且置其为正在展示的PopMenu
        if (_districtPopMenu == nil) {
            _districtPopMenu = [[DistrictPopMenu alloc] init];
        }
        _showingPopMenu = _districtPopMenu;
    } else {
        // 创建 排序弹出菜单,并且用成员记住,且置其为正在展示的PopMenu
        if (_orderPopMenu == nil) {
            _orderPopMenu = [[OrderPopMenu alloc] init];
        }
        _showingPopMenu = _orderPopMenu;
    }

    // 创建出来相应的底部弹出菜单后,就要设置_showingPopMenu   的frame
    // _showingPopMenu.frame = _controllerView.bounds;

    // PopMenu 占据导航栏以下所有的空间
    _showingPopMenu.frame = (CGRect){0,kTopMenuItemH-1,_controllerView.bounds.size.width,_controllerView.bounds.size.height- kTopMenuItemH};



    // 设置创建出来的PopMenu的block回调,传递的是XXXPopMenu隐藏后,顶部菜单要做的事情如更改顶部的TopMenu的按钮选中状态
    __unsafe_unretained TopMenu *menu = self;
    _showingPopMenu.hideBlock = ^{
        // 重要~~~当_showingPopMenu隐藏后,要更改顶部的TopMenu的按钮选中状态

        // 1.取消当前的TopMenuItem的选中状态,并置空
        menu->_currentTopMenuItem.selected = NO;
        menu->_currentTopMenuItem = nil;

        // 2._showingPopMenu隐藏后,就要清空_showingPopMenu
        menu->_showingPopMenu = nil;
    };

    // 添加创建出来的即将要显示的弹出菜单 到_controllerView(即导航栏下面的所有空间都是弹出菜单的)
    [_controllerView addSubview:_showingPopMenu];

    // 执行刚才创建出来的底部弹出菜单的 出场动画,注意:只有没有正在展示的弹出菜单时,才需要执行出场动画)
    if (animted) {
        [_showingPopMenu showPopMenu];
    }
}



// 顶部菜单宽度固定是三个按钮的宽高,因为只有三个按钮:全部分类,全部商区,默认排序
- (void)setFrame:(CGRect)frame
{
    frame.size = CGSizeMake(3 * kTopMenuItemW, kTopMenuItemH);
    [super setFrame:frame];
}
// 顶部菜单因为要改变其三个按钮的文字,因此在通知中心注册成为了监听者,因此dealloc时要在通知中心,移除掉监听者
- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
@end

TopMenuItem 顶部菜单项按钮

//
//  TopMenuItem.m
//  帅哥_团购
//
//  Created by beyond on 14-8-15.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  点击dock上面的【团购】按钮对应的控制器,上面是导航栏,导航栏右边是searchBar,导航栏左边是一个大按钮(TopMenu)(内部只由三个小按钮组成它们分别是:全部频道,全部商区,默认排序),点击TopMenu中的某一个按钮,会在其下方,弹出一个PopMenu,PopMenu包括二个部分(上面是一个contentView:包括:scrollView和subTitleImgView,下:蒙板)






#import 

@interface TopMenuItem : UIButton
// 设置按钮TopMenuItem显示的文字
@property (nonatomic, copy) NSString *title;
@end


// 左文字 如全部分类 、全部商区、默认排序
#define kTitleScale 0.8
@implementation TopMenuItem


- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // 1.文字颜色
        [self setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        self.titleLabel.textAlignment = NSTextAlignmentCenter;
        self.titleLabel.font = [UIFont systemFontOfSize:15];

        // 2.设置按钮右边的箭头
        [self setImage:[UIImage imageNamed:@"ic_arrow_down.png"] forState:UIControlStateNormal];
        self.imageView.contentMode = UIViewContentModeCenter;

        // 3.设置按钮右边的分割线
        UIImage *img = [UIImage imageNamed:@"separator_topbar_item.png"];
        UIImageView *divider = [[UIImageView alloc] initWithImage:img];
        divider.bounds = CGRectMake(0, 0, 2, kTopMenuItemH * 0.7);
        divider.center = CGPointMake(kTopMenuItemW, kTopMenuItemH * 0.5);
        [self addSubview:divider];

        // 4.设置按钮选中时的背景
        [self setBackgroundImage:[UIImage imageStretchedWithName:@"slider_filter_bg_normal.png"] forState:UIControlStateSelected];
    }
    return self;
}

- (void)setTitle:(NSString *)title
{
    _title = title;

    [self setTitle:title forState:UIControlStateNormal];
}
// 自己固定顶部菜单项按钮的好宽高
- (void)setFrame:(CGRect)frame
{
    frame.size = CGSizeMake(kTopMenuItemW, kTopMenuItemH);
    [super setFrame:frame];
}
// 左文字的frame
- (CGRect)titleRectForContentRect:(CGRect)contentRect
{
    CGFloat h = contentRect.size.height;
    CGFloat w = contentRect.size.width * kTitleScale;
    return CGRectMake(0, 0, w, h);
}
// 右图片的frame
- (CGRect)imageRectForContentRect:(CGRect)contentRect
{
    CGFloat h = contentRect.size.height;
    CGFloat x = contentRect.size.width * kTitleScale;
    CGFloat w = contentRect.size.width - x;
    return CGRectMake(x, 0, w, h);
}



@end

PopMenu.h

//
//  PopMenu.h
//  帅哥_团购
//
//  Created by beyond on 14-8-15.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  PopMenu是点击顶部按钮项,在其下方弹出的菜单的父类,成员有:下面是一个cover蒙板,上面是一个contentView(包含着scrollView和subTitleImgView,其中scrollView里面放的全是PopMenuItem,如美食,如海淀区.....subTitleImgView里面放的全是美食下面的所有子标题,如川菜 湘菜 粤菜)



//  点击dock上面的【团购】按钮,创建一个经过导航包装的DealList控制器,控制器的上面是导航栏,导航栏右边是searchBar,导航栏左边是一个大按钮(TopMenu)(内部由三个小按钮组成),点击TopMenu中的某一个按钮,会在其下方,弹出一个PopMenu,PopMenu包括二个部分,见上面

#import 
#import "SubTitleImgViewDelegate.h"
@class SubTitleImgView, PopMenuItem;

@interface PopMenu : UIView 
{
    // 以下成员是开放给子类访问和修改的

    // 容纳所有的分类或商区,如美食,如海淀区
    UIScrollView *_scrollView;

    // 容纳所有子标题的ImgView,里面全是一个个按钮,如美食下面的川菜、湘菜、粤菜等
    SubTitleImgView *_subTitleImgView;

    // item的父类,弹出菜单项:记录当前选中的菜单项,如美食,如海淀区(此是父类)
    PopMenuItem *_selectedPopMenuItem;
}

// 弹出菜单隐藏完毕之后,要通知顶部菜单
@property (nonatomic, copy) void (^hideBlock)();

// 供外部调用,通过动画显示 PopMenu
- (void)showPopMenu;
// 供外部调用,通过动画隐藏 PopMenu
- (void)hidePopMenu;


@end

PopMenu.m

图片 14

创建并添加一个cover,一个ContentView,并向ContentView添加一个ScrollView

//
//  PopMenu.m
//  帅哥_团购
//
//  Created by beyond on 14-8-15.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  PopMenu是点击顶部按钮项,在其下方弹出的菜单的父类,成员有:下面是一个cover蒙板,上面是一个contentView(包含着scrollView和subTitleImgView,其中scrollView里面放的全是PopMenuItem,如美食,如海淀区.....subTitleImgView里面放的全是美食下面的所有子标题,如川菜 湘菜 粤菜)



//  点击dock上面的【团购】按钮,创建一个经过导航包装的DealList控制器,控制器的上面是导航栏,导航栏右边是searchBar,导航栏左边是一个大按钮(TopMenu)(内部由三个小按钮组成),点击TopMenu中的某一个按钮,会在其下方,弹出一个PopMenu,PopMenu包括二个部分,见上面

#import "PopMenu.h"
// 遮罩
#import "Cover.h"


// subTitleImgView里面放的全是美食下面的所有子标题,如川菜湘菜粤菜
#import "SubTitleImgView.h"
// scrollView里面放的全是PopMenuItem,如美食,如海淀区
#import "PopMenuItem.h"
#import "MetaDataTool.h"




#import "CategoryPopMenuItem.h"
#import "DistrictPopMenuItem.h"
#import "OrderPopMenuItem.h"




@interface PopMenu()
{
    // 上面是_contentView,包括scrollView和subTitleImgView,其中scrollView里面放的全是PopMenuItem,如美食,如海淀区.....subTitleImgView里面放的全是美食下面的所有子标题,如川菜湘菜粤菜
    UIView *_contentView;
    // 遮罩
    Cover *_cover;

}
@end

@implementation PopMenu

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // 0.为适应横竖屏的变化,设置self PopMenu宽高自动伸缩
        self.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;

        // 1.添加蒙板(遮盖),并且点击蒙板后,隐藏并移除popMenu的contentView(内部是scrollView和subTitleImgView),并置cover透明
        [self addCover];

        // 2.添加内容view(内部是scrollView和subTitleImgView)
        [self addContentView];

        // 3.添加ScrollView到contentView
        [self addScrollView];

    }
    return self;
}


// 1.添加蒙板(遮盖),并且点击蒙板后,隐藏并移除popMenu的contentView(内部是scrollView和subTitleImgView),并置cover透明
- (void)addCover
{
    _cover = [Cover coverWithTarget:self action:@selector(hideContentView)];
    _cover.frame = self.bounds;
    [self addSubview:_cover];
}

// 2.添加内容view(内部是scrollView和subTitleImgView)
- (void)addContentView
{

    _contentView = [[UIView alloc] init];
    // 默认高度是一个popMenuItem高度
    _contentView.frame = CGRectMake(0, 0, self.frame.size.width, kBottomMenuItemH);
    // 宽度伸缩,但是高度其内部通过数据源的多少自动计算行数及总高度
    _contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
    [self addSubview:_contentView];
}

// 3.添加ScrollView到contentView
-(void)addScrollView
{
    _scrollView = [[UIScrollView alloc] init];
    _scrollView.showsHorizontalScrollIndicator = NO;
    // 宽高伸缩,高度固定死为一个popMenuItem高度
    _scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
    _scrollView.frame = CGRectMake(0, 0, self.frame.size.width, kBottomMenuItemH);
    _scrollView.backgroundColor = [UIColor whiteColor];
    [_contentView addSubview:_scrollView];
}

#pragma mark - 父类接口方法
// 本父类方法的作用:控制popMenuItem的状态切换,如果popMenuItem有子标题(如美食),显示子标题showSubTitleImgView,如果没有子标题(如电影),就可隐藏掉弹出按钮了
- (void)popMenuItemClicked:(PopMenuItem *)item
{
    // 父类提供的一个接口方法,当它子类中的MenuItem addTarget为 popMenuItemClicked时,如果子类 没有实现popMenuItemClicked方法,就会到父类这儿来找popMenuItemClicked方法,
    // 因此,本方法的目的是:监听所有它的子类(如CategoryPopMenu,DistrictPopMenu)的菜单项的点击


    // 1.控制item的状态切换
    _selectedPopMenuItem.selected = NO;
    item.selected = YES;
    _selectedPopMenuItem = item;

    // 2.查看是菜单项,如美食,如海淀区  否有子分类,如果有子分类才要显示SubTitleImgView,并为其提供数据源,子标题文字组成的数组
    if (item.subTitlesArr.count) {
        // 有子标题,才要动画显示所有的子标题
        [self showSubTitleImgView:item];
    } else { // 因为没有子标题,所以隐藏所有的子标题,并且就可以直接设置当前Category或District或Order为刚才点击的PopMenuItem
        [self hideSubTitleImgView:item];
    }
}

// 如果被点击的popMenuItem有子标题,才要创建并且动画显示SubTitleImgView,并为其提供数据源,即子标题文字组成的数组
- (void)showSubTitleImgView:(PopMenuItem *)item
{
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:kDefaultAnimDuration];
    // 所有的PopMenu子类(如CategoryPopMenu和DistrictPopMenu和OrderPopMenu)共用一个_subTitleImgView,展示子分类的所有子标题
    if (_subTitleImgView == nil) {
        _subTitleImgView = [[SubTitleImgView alloc] init];
        // 设置self PopMenu为_subTitleImgView的代理目的是:两个,当点击_subTitleImgView里面的按钮时,获知按钮的标题,另外一个就是告诉_subTitleImgView当前选中的PopMenu是哪一个类别,是美食?还是海淀区???
        // 并且代理方法,由相应的子类(如CategoryPopMenu和DistrictPopMenu和OrderPopMenu)去实现
        _subTitleImgView.delegate = self;
    }

    // 设置子标题的frame,y位于scrollView的下方,高度?????
    _subTitleImgView.frame = CGRectMake(0, kBottomMenuItemH, self.frame.size.width, _subTitleImgView.frame.size.height);
    // 设置子标题的主标题 ????
    _subTitleImgView.mainTitle = [item titleForState:UIControlStateNormal];
    // 设置子标题需要显示的内容(带去要显示的数据源,即所有的子标题组成的数组)
    // 重要~~~供子类 去实现的,内部会拦截此方法,添加所有的子标题按钮,并设置文字
    _subTitleImgView.titleArr = item.subTitlesArr;

    // 当前子标题没有正在展示的时候,就需要执行动画显示 _subTitleImgView
    if (_subTitleImgView.superview == nil) {
        [_subTitleImgView showSubTitleImgViewWithAnimation];
    }

    // 添加子标题到内容view-scrollView底部
    [_contentView insertSubview:_subTitleImgView belowSubview:_scrollView];

    // 重要~根据_subTitleImgView不同的高度,调整整个contentView的高度~~~
    CGRect cf = _contentView.frame;
    cf.size.height = CGRectGetMaxY(_subTitleImgView.frame);
    _contentView.frame = cf;

    [UIView commitAnimations];
}


// 因为如果被点击的popMenuItem没有子标题,所以隐藏所有的子标题,并且就可以直接设置当前Category或District或Order为刚才点击的PopMenuItem
- (void)hideSubTitleImgView:(PopMenuItem *)item
{
    // 1.通过动画隐藏子标题
    if (_subTitleImgView) {
        [_subTitleImgView hideSubTitleImgViewWithAnimation];
    }

    // 2.移除后,必须重新调整contentView的高度为默认的一个PopMenuItem的高度
    CGRect cf = _contentView.frame;
    cf.size.height = kBottomMenuItemH;
    _contentView.frame = cf;

    // 3.因为没有子标题,所以就可以直接设置工具类中的当前Category或District或Order为刚才点击的PopMenuItem,工具类内部会拦截,并发出通知,通知给TopMenu等
    NSString *title = [item titleForState:UIControlStateNormal];
    if ([item isKindOfClass:[CategoryPopMenuItem class]]) {
        // 如果点击的PopMenuItem是 分类PopMenuItem
        [MetaDataTool sharedMetaDataTool].currentCategoryName = title;
    } else if ([item isKindOfClass:[DistrictPopMenuItem class]]) {
        // 如果点击的PopMenuItem是 商区PopMenuItem
        [MetaDataTool sharedMetaDataTool].currentDistrictName = title;
    } else {
        // 如果点击的PopMenuItem是 排序PopMenuItem
        [MetaDataTool sharedMetaDataTool].currentOrder = [[MetaDataTool sharedMetaDataTool] orderWithName:title];
    }
}



#pragma mark 显示ContentView,供外部调用,如点击了TopMenu时调用,且当前没有PopMenu正在显示
- (void)showPopMenu
{
    _contentView.transform = CGAffineTransformMakeTranslation(0, -_contentView.frame.size.height);
    _contentView.alpha = 0;
    _cover.alpha = 0;
    [UIView animateWithDuration:kDefaultAnimDuration animations:^{
        // 1.scrollView从上面 -> 下面
        _contentView.transform = CGAffineTransformIdentity;
        _contentView.alpha = 1;

        // 2.遮盖(0 -> 0.4)
        [_cover alphaReset];
    }];
}
#pragma mark 隐藏ContentView,供外部调用,如点击了Cover或同一个TopMenuItem时调用,且当前没有PopMenu正在显示
// 如点击遮盖时,隐藏并移除popMenu的contentView(内部是scrollView和subTitleImgView),并置cover透明
- (void)hidePopMenu
{
    // 如果隐藏完毕弹出菜单的 _contentView之后,要通知调用者(顶部菜单)更改顶部菜单项文字
    if (_hideBlock) {
        _hideBlock();
    }
    [UIView animateWithDuration:kDefaultAnimDuration animations:^{
        // _contentView向上消失,即移动一个自身的高度
        _contentView.transform = CGAffineTransformMakeTranslation(0, -_contentView.frame.size.height);
        _contentView.alpha = 0;

        // 2.遮盖(0.4 -> 0)
        _cover.alpha = 0;
    } completion:^(BOOL finished) {
        // _contentView完全看不见了之后,就将弹出菜单从父控件中移除
        [self removeFromSuperview];

        // 并且恢复_contentView的属性
        _contentView.transform = CGAffineTransformIdentity;
        _contentView.alpha  = 1;
        [_cover alphaReset];
    }];
}

@end

PopMenuItem.h

//
//  PopMenuItem.h
//  帅哥_团购
//
//  Created by beyond on 14-8-16.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  底部弹出菜单的菜单项 (是一个父类)  抽取的特征:1,右边有分隔线,2.宽高全统一,3.选中时,背景图片统一,4文字颜色

#import 

@interface PopMenuItem : UIButton


// 本接口,专门交给子类实现
// 数据源,子标题数组,所有子标题的名字组成的数组,
// 比如 美食 下面有多少个category
// 比如 海淀区 下面有多少个place
- (NSArray *)subTitlesArr;
@end

PopMenuItem.m

//
//  PopMenuItem.m
//  帅哥_团购
//
//  Created by beyond on 14-8-16.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  底部弹出菜单的菜单项 (是一个父类)  抽取的特征:1,右边有分隔线,2.宽高全统一,3.选中时,背景图片统一,4文字颜色

#import "PopMenuItem.h"

@implementation PopMenuItem



- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // 1.右边的分割线
        UIImage *img = [UIImage imageNamed:@"separator_filter_item.png"];
        UIImageView *divider = [[UIImageView alloc] initWithImage:img];
        divider.bounds = CGRectMake(0, 0, 2, kBottomMenuItemH * 0.7);
        divider.center = CGPointMake(kBottomMenuItemW, kBottomMenuItemH * 0.5);
        [self addSubview:divider];

        // 2.文字颜色
        [self setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        self.titleLabel.font = [UIFont systemFontOfSize:16];

        // 3.设置被选中时的背景
        [self setBackgroundImage:[UIImage imageStretchedWithName:@"bg_filter_toggle_hl.png"] forState:UIControlStateSelected];
    }
    return self;
}

// 菜单项的宽高固定为一个按钮的宽和高
- (void)setFrame:(CGRect)frame
{
    frame.size = CGSizeMake(kBottomMenuItemW, kBottomMenuItemH);
    [super setFrame:frame];
}

// 取消高亮显示状态
- (void)setHighlighted:(BOOL)highlighted {}

// 本接口,专门交给子类实现
// 数据源,子标题数组,所有子标题的名字组成的数组
// 比如 美食 下面有多少个category
// 比如 海淀区 下面有多少个place
- (NSArray *)subTitlesArr
{
    return nil;
}

@end

Cover.h

//
//  Cover.h
//  帅哥_团购
//
//  Created by beyond on 14-8-16.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  PopMenu是点击顶部按钮项(TopMenuItem),在其下方弹出的菜单(XXXPopMenu)的父类,成员有:下面是一个cover蒙板,上面是一个contentView(包含着scrollView和subTitleImgView,其中scrollView里面放的全是PopMenuItem,如美食,如海淀区.....subTitleImgView里面放的全是美食下面的所有子标题,如川菜湘菜粤菜)

#import 

@interface Cover : UIView

+ (id)cover;
// 绑定tap手势
+ (id)coverWithTarget:(id)target action:(SEL)action;

- (void)alphaReset;
@end

Cover.m

//
//  Cover.m
//  帅哥_团购
//
//  Created by beyond on 14-8-16.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  PopMenu是点击顶部按钮项(TopMenuItem),在其下方弹出的菜单(XXXPopMenu)的父类,成员有:下面是一个cover蒙板,上面是一个contentView(包含着scrollView和subTitleImgView,其中scrollView里面放的全是PopMenuItem,如美食,如海淀区.....subTitleImgView里面放的全是美食下面的所有子标题,如川菜湘菜粤菜)

#import "Cover.h"


// 1为全黑
#define kAlpha 0.7
@implementation Cover


- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // 1.背景色
        self.backgroundColor = [UIColor blackColor];

        // 2.它是蒙在tableView上面,所以要同tableView一样,宽高自动伸缩
        self.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;

        // 3.透明度
        self.alpha = kAlpha;
    }
    return self;
}

- (void)alphaReset
{
    self.alpha = kAlpha;
}

+ (id)cover
{
    return [[self alloc] init];
}

+ (id)coverWithTarget:(id)target action:(SEL)action
{
    Cover *cover = [self cover];
    // 绑定一个,tap手势监听器
    [cover addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:target action:action]];
    return cover;
}


@end

SubTitleImgView.h

容纳所有子标题的ImgView,里面全是一个个按钮,

如美食下面的川菜、湘菜、粤菜等...

如海淀区下面的中关村、五棵松、香山等...

并且所有的弹出菜单PopMenu都共用此一个SubTitleImgView

//
//  SubTitleImgView.h
//  帅哥_团购
//
//  Created by beyond on 14-8-16.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
// 容纳所有子标题的ImgView,里面全是一个个按钮,如美食下面的川菜、湘菜、粤菜等...如海淀区下面的中关村、五棵松、香山等,注意所有的弹出菜单PopMenu共用此一个SubTitleImgView

#import 

@protocol SubTitleImgViewDelegate;


@interface SubTitleImgView : UIImageView

// 数据源,主标题,每一个子标题数组都有,且是在第一个位置---> 【全部】
@property (nonatomic, copy) NSString *mainTitle;

// 数据源,需要显示的所有的子标题按钮的文字组成的数组,外部传入,如美食下面的川菜、湘菜、粤菜等...如海淀区下面的中关村、五棵松、香山等
@property (nonatomic, strong) NSMutableArray *subTitlesArr;

@property (nonatomic, weak) id delegate;
// 代理和block的效果等价
//@property (nonatomic, copy) void (^setBtnTitleBlock)(NSString *title);
//@property (nonatomic, copy) NSString *(^getBtnTitleBlock)();

// 通过动画显示出来SubTitleImgView,供创建者调用
- (void)showSubTitleImgViewWithAnimation;
// 通过动画隐藏SubTitleImgView,供创建者调用
- (void)hideSubTitleImgViewWithAnimation;
@end

SubTitleImgView.h

容纳所有子标题的ImgView,里面全是一个个按钮,

如美食下面的川菜、湘菜、粤菜等...

如海淀区下面的中关村、五棵松、香山等...

并且所有的弹出菜单PopMenu都共用此一个SubTitleImgView

图片 15

//
//  SubTitleImgView.m
//  帅哥_团购
//
//  Created by beyond on 14-8-16.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
// 容纳所有子标题的ImgView,里面全是一个个按钮,如美食下面的川菜、湘菜、粤菜等...如海淀区下面的中关村、五棵松、香山等,注意所有的弹出菜单PopMenu共用此一个SubTitleImgView

#import "SubTitleImgView.h"
#import "MetaDataTool.h"
#import "SubTitleImgViewDelegate.h"

#define kSubTitleBtnW 100
#define kSubTitleBtnH 40

// 里面用到的所有按钮,因样式统一,所以抽取一个基类
@interface SubTitleBtn : UIButton
@end

@implementation SubTitleBtn
- (void)drawRect:(CGRect)rect
{
    // 设置选中状态下,SubTitleBtn的frame和背景
    if (self.selected) {
        CGRect frame = self.titleLabel.frame;
        frame.origin.x -= 5;
        frame.size.width += 10;
        frame.origin.y -= 5;
        frame.size.height += 10;
        [[UIImage imageStretchedWithName:@"slider_filter_bg_active.png"] drawInRect:frame];
    }
}
@end

@interface SubTitleImgView()
{
    // 记住当前选中的SubTitleBtn
    UIButton *_selectedSubTitleBtn;
}
@end

@implementation SubTitleImgView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // SubTitleImgView的宽度自由伸缩
        self.autoresizingMask = UIViewAutoresizingFlexibleWidth;
        // SubTitleImgView的背景图片
        self.image = [UIImage imageStretchedWithName:@"bg_subfilter_other.png"];

        // 重要~~~~裁剪掉超出父控件范围内的子控件(超出父控件范围内的子控件不显示)
        self.clipsToBounds = YES;
        // 让imageView里面的一个个按钮可以点击,如美食(PopMenuItem)下面的川菜、湘菜、粤菜等
        self.userInteractionEnabled = YES;
    }
    return self;
}
#pragma mark - 拦截setter数据源数组方法,创建所有对应个数的按钮
// 数据源,需要显示的所有的子标题按钮的文字组成的数组,外部传入,拦截setter方法
- (void)setTitleArr:(NSArray *)titleArr
{
    // 1.用成员变量,记住所有的子标题,如美食(PopMenuItem)下面的川菜、湘菜、粤菜等
    // 所有子标题中,排在首位的都是:固定字符串--->【全部】
    [_subTitlesArr addObject:kAll];
    // 将其他子标题加到后面,如美食(PopMenuItem)下面的川菜、湘菜、粤菜等
    [_subTitlesArr addObjectsFromArray:titleArr];


    // 2.遍历子标题数组,懒加载创建可重用的子标题按钮
    [self addAllSubTitlesBtn];


    // 3.每当setter数据源改变之后,按钮的位置和个数都要重新排布,所以手动调用一次 layoutSubviews方法
    [self layoutSubviews];

    /*
     layoutSubviews在以下情况下会被调用:
     1、init初始化不会触发layoutSubviews
     2、addSubview会触发layoutSubviews
     3、设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化
     4、滚动一个UIScrollView会触发layoutSubviews
     5、旋转Screen会触发父UIView上的layoutSubviews事件
     6、改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件
     */
}


// 2.遍历子标题数组,懒加载创建可重用的子标题按钮
- (void)addAllSubTitlesBtn
{

    int count = _subTitlesArr.count;
    // 遍历子标题数组,懒加载创建按钮,并设置按钮的文字
    for (int i = 0; i= self.subviews.count) {
            // 创建一个新的子标题按钮
            btn = [SubTitleBtn buttonWithType:UIButtonTypeCustom];
            // 绑定监听事件
            [btn addTarget:self action:@selector(subTitleBtnClicked:) forControlEvents:UIControlEventTouchUpInside];
            // 设置文字颜色
            [btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
            // 设置文字字体
            btn.titleLabel.font = [UIFont systemFontOfSize:13];
            // 添加到SubTitleImgView
            [self addSubview:btn];
        } else {
            // 如果子控件数组中有足量的按钮,就直接取出来,重用
            btn = self.subviews[i];
        }

        // 2.设置按钮独一无二的文字(并将按钮显示)
        [btn setTitle:_subTitlesArr[i] forState:UIControlStateNormal];
        btn.hidden = NO;

        // 3.判断该按钮要不要默认选中,根据是:该按钮文字是不是和当前选中的分类或商区名字一样,代理会负责告诉我subTitleImgView 当前的分类名或者商区名字
        if ([_delegate respondsToSelector:@selector(subTitleImgViewGetCurrentBtnTitle:)]) {
            // 代理会负责告诉我subTitleImgView 当前的分类名或者商区名字
            NSString *currentBtnTitle = [_delegate subTitleImgViewGetCurrentBtnTitle:self];

            // 选中了主标题,选中第0个按钮(“全部”)
            if ([currentBtnTitle isEqualToString:_mainTitle] && i == 0) {
                btn.selected = YES;
                _selectedSubTitleBtn = btn;
            } else {
                btn.selected = [_subTitlesArr[i] isEqualToString:currentBtnTitle];
                // 重要细节 ~~~~如果在不同的类别或商区,发现了同名的,则也视为选中了
                if (btn.selected) {
                    _selectedSubTitleBtn = btn;
                }
            }
        } else {
            btn.selected = NO;
        }
    }


    // 3.重要~~~隐藏子控件数组中多余的按钮,如子标题文字数组有8项,而子控件数组有10个,那么多余的两个按钮就要隐藏起来
    for (int i = count; i 大标题
            title = _mainTitle;
        }
        // 告诉代理(调用者),当前被点击的按钮的文字...
        [_delegate subTitleImgView:self btnClicked:title];
    }
}

#pragma mark - 覆盖UIView的方法,重新布局SubTitleImgView所有子控件的位置
// 控件SubTitleImgView本身的宽高发生改变等情况下就会自动触发layoutSubviews方法
- (void)layoutSubviews
{
    // 1.一定要调用super
    [super layoutSubviews];

    // 2.根据屏幕宽,算出总的列数,并对所有子标题按钮设置九宫格frame
    int columns = self.frame.size.width / kSubTitleBtnW;
    // 根据数据源的个数,遍历对应数目的按钮,根据i设置其frame
    for (int i = 0; i<_subtitlesarr.count animations="animations" bool="BOOL" btn="self.subviews[i];" btn.frame="CGRectMake(x," cgfloat="CGFloat" cgrect="CGRect" columns="columns" completion="completion" end="end" f="self.frame;" f.size.height="0;" finished="finished" frame="self.frame;" frame.size.height="rows" hidesubtitleimgviewwithanimation="hideSubTitleImgViewWithAnimation" i="i" int="int" kdefaultanimduration="kDefaultAnimDuration" ksubtitlebtnh="kSubTitleBtnH" ksubtitlebtnw="kSubTitleBtnW" layoutsubviews="layoutSubviews" mark="mark" pragma="pragma" removefromsuperview="removeFromSuperview" rows="(_subTitlesArr.count" self="self" self.alpha="1;" self.frame="f;" self.frame.size.height="self.frame.size.height" self.transform="CGAffineTransformIdentity;" showsubtitleimgviewwithanimation="showSubTitleImgViewWithAnimation" subtitleimgview="SubTitleImgView" uibutton="UIButton" uiview="UIView" void="void" x="i" y="y"/>

SubTitleImgView定义的协议

SubTitleImgViewDelegate.h

//
//  SubTitleViewDelegate.h
//  帅哥_团购
//
//  Created by beyond on 14-8-16.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  分类或商区的子标题的代理方法,当点击了【分类或商区的子标题按钮】时,通知代理

#import 

@class SubTitleImgView;
@protocol SubTitleImgViewDelegate 

@optional


// 当SubTitleImgView里面的按钮被点击了的时候调用,告诉其他所有想知道的类(即SubTitleImgView的代理):被点击的按钮的文字【被点击的分类或商区的子标题按钮上的文字】
- (void)subTitleImgView:(SubTitleImgView *)subTitleImgView btnClicked:(NSString *)btnTitle;




// 返回当前选中的文字(比如分类菜单,就返回当前选中的分类名称;区域菜单,就返回当前选中的区域名称),目的是子标题按钮出现前,将选中的那个高亮(回显)~~~
// 得到当前选中的分类或商区按钮上的文字,用于与新出现的按钮文字进行判断,如果相同,则在SubTitleImgView出现之前,将SubTitleImgView上面的该按钮置为高亮,其他全为普通
// 如果SubTileImgView的代理是CategoryPopMenu,说明应该从工具类返回currentCategoryName给SubTileImgView
- (NSString *)subTitleImgViewGetCurrentBtnTitle:(SubTitleImgView *)subTitleImgView;
@end

View的层级关系示意图:

父类:PopMenu

其子类:CategoryPopMenu、DistrictPopMenu、OrderPopMenu

父类:PopMenuItem

其子类:CategoryPopMenuItem、DistrictPopMenuItem、OrderPopMenuItem

图片 16

子类:CategoryPopMenu

//
//  CategoryPopMenu.h
//  帅哥_团购
//
//  Created by beyond on 14-8-15.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  点击顶部菜单中的分类频道 按钮(顶部菜单项),弹出的菜单,继承自PopMenu,包括二个部分(上:contentView,包括scrollView和SubTitleImgView,下:蒙板)

#import "PopMenu.h"

@interface CategoryPopMenu : PopMenu

@end

//
//  CategoryPopMenu.m
//  帅哥_团购
//
//  Created by beyond on 14-8-15.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  点击顶部菜单中的分类频道 按钮(顶部菜单项),弹出的菜单,继承自PopMenu,包括二个部分(上:contentView,包括scrollView和SubTitleImgView,下:蒙板)

#import "CategoryPopMenu.h"
// 分类菜单项如:美食
#import "CategoryPopMenuItem.h"
#import "MetaDataTool.h"

@implementation CategoryPopMenu

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // 1.往scrollView里面添加内容(CategoryPopMenuItem)
        [self addCategoryPopMenuItem];
    }
    return self;
}
// 1.往scrollView里面添加内容(CategoryPopMenuItem)
- (void)addCategoryPopMenuItem
{
    // 获取数据源,工具类提供allCategoriesArr对象数组
    NSArray *categories = [MetaDataTool sharedMetaDataTool].allCategoriesArr;

    // 1.往scrollView里面添加内容(CategoryPopMenuItem)
    int count = categories.count;
    for (int i = 0; i

子类:CategoryPopMenuItem

//
//  CategoryPopMenuItem.h
//  帅哥_团购
//
//  Created by beyond on 14-8-15.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  在CategoryPopMenu的第一层(即scrollView)里面的一个按钮,如美食,按钮图片在上面,文字在下面,且按钮右边是一根竖线

#import "PopMenuItem.h"
@class MyCategory;
@interface CategoryPopMenuItem : PopMenuItem

// 数据源,本按钮,需要显示的分类对象模型,一个PopMenuItem 对应一个分类,如美食
@property (nonatomic, strong) MyCategory *category;
@end



//
//  CategoryPopMenuItem.m
//  帅哥_团购
//
//  Created by beyond on 14-8-15.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  在CategoryPopMenu的第一层(即scrollView)里面的一个按钮,按钮图片在上面,文字在下面,且按钮右边是一根竖线

#import "CategoryPopMenuItem.h"
#import "MyCategory.h"

// 图片在上,文字在下
#define kTitleHeightRatio 0.3
@implementation CategoryPopMenuItem




- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // 1.文字居中对齐
        self.titleLabel.textAlignment = NSTextAlignmentCenter;

        // 2.图片中心缩放
        self.imageView.contentMode = UIViewContentModeCenter;
    }
    return self;
}


// 父类的方法,供子类实现
// 数据源,子标题数组,所有子标题的名字组成的数组,  本接口,专门交给子类实现
// 比如 美食 下面有多少个subCategory
// 比如 海淀区 下面有多少个place
- (NSArray *)subTitlesArr
{
    return _category.subcategories;
}

// 拦截数据源的setter方法,设置按钮的图片和文字
- (void)setCategory:(MyCategory *)category
{
    _category = category;

    // 1.图标
    [self setImage:[UIImage imageNamed:category.icon] forState:UIControlStateNormal];

    // 2.标题
    [self setTitle:category.name forState:UIControlStateNormal];
}


#pragma mark 设置按钮上面的图片的frame
- (CGRect)imageRectForContentRect:(CGRect)contentRect {
    return CGRectMake(0, 0, contentRect.size.width, contentRect.size.height * (1 - kTitleHeightRatio));
}

#pragma mark 设置按钮下面的标题的frame
- (CGRect)titleRectForContentRect:(CGRect)contentRect {
    CGFloat titleHeight = contentRect.size.height * kTitleHeightRatio;
    CGFloat titleY = contentRect.size.height - titleHeight;
    return CGRectMake(0, titleY, contentRect.size.width,  titleHeight);
}


@end

子类:DistrictPopMenu

//
//  DistrictPopMenu.h
//  帅哥_团购
//
//  Created by beyond on 14-8-15.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  点击顶部菜单中的 全部商区 按钮(顶部菜单项),弹出的菜单,继承自PopMenu,包括二个部分(上:contentView,包括scrollView和SubTitleImgView,下:蒙板)

#import "PopMenu.h"

@interface DistrictPopMenu : PopMenu

@end

//
//  DistrictPopMenu.m
//  帅哥_团购
//
//  Created by beyond on 14-8-15.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  点击顶部菜单中的 全部商区 按钮(顶部菜单项),弹出的菜单,继承自PopMenu,包括二个部分(上:contentView,包括scrollView和SubTitleImgView,下:蒙板)

#import "DistrictPopMenu.h"
#import "DistrictPopMenuItem.h"
#import "MetaDataTool.h"
#import "District.h"
// 商区依赖城市
#import "City.h"

#import "SubTitleImgView.h"

@interface DistrictPopMenu ()
{
    NSMutableArray *_menuItems;
}

@end
@implementation DistrictPopMenu


- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        _menuItems = [NSMutableArray array];

        [self cityChange];

        // 监听城市改变
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(cityChange) name:kCityChangeNote object:nil];
    }
    return self;
}

- (void)cityChange
{
    // 1.获取当前选中的城市对象,保存在工具中
    City *city = [MetaDataTool sharedMetaDataTool].currentCity;

    // 2.当前城市的所有区域,包括全部商区+下属商区数组(城市对应的成员)
    NSMutableArray *districts = [NSMutableArray array];
    // 2.1.全部商区
    District *all = [[District alloc] init];
    all.name = kAllDistrict;
    [districts addObject:all];
    // 2.2.其他商区,下属商区数组(城市对应的成员)
    [districts addObjectsFromArray:city.districts];

    // 3.遍历所有的商区对象,创建并设置按钮标题
    int count = districts.count;
    for (int i = 0; i= _menuItems.count) { // 不够
            item = [[DistrictPopMenuItem alloc] init];
            [item addTarget:self action:@selector(popMenuItemClicked:) forControlEvents:UIControlEventTouchUpInside];
            [_menuItems addObject:item];
            [_scrollView addSubview:item];
        } else {
            item = _menuItems[i];
        }

        item.hidden = NO;
        item.district = districts[i];
        item.frame = CGRectMake(i * kBottomMenuItemW, 0, 0, 0);

        // 默认选中第0个item
        if (i == 0) {
            item.selected = YES;
            _selectedPopMenuItem = item;
        } else {
            item.selected = NO;
        }
    }

    // 4.隐藏多余的item
    for (int i = count; i<_menuitems.count _scrollview.contentsize="CGSizeMake(count" _subtitleimgview="_subTitleImgView" btnclicked="btnClicked" btntitle="btnTitle" currentdistrictname="currentDistrictName" dealloc="dealloc" defaultcenter="defaultCenter" districtpopmenuitem="DistrictPopMenuItem" end="end" hidesubtitleimgviewwithanimation="hideSubTitleImgViewWithAnimation" i="i" item="_scrollView.subviews[i];" item.hidden="YES;" kbottommenuitemw="kBottomMenuItemW" mark="mark" metadatatool="MetaDataTool" nsnotificationcenter="NSNotificationCenter" nsstring="NSString" pragma="pragma" return="return" self="self" sharedmetadatatool="sharedMetaDataTool" subtitleimgview="SubTitleImgView" subtitleimgviewdelegate="" subtitleimgviewgetcurrentbtntitle="subTitleImgViewGetCurrentBtnTitle" void="void"/>

子类:DistrictPopMenuItem

//
//  DistrictPopMenuItem.h
//  帅哥_团购
//
//  Created by beyond on 14-8-16.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  如海淀区

#import "PopMenuItem.h"
@class District;
@interface DistrictPopMenuItem : PopMenuItem

// 数据源  一个PopMenuItem对应一个商区,如海淀区
@property (nonatomic, strong) District *district;
@end



//
//  DistrictPopMenuItem.m
//  帅哥_团购
//
//  Created by beyond on 14-8-16.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  如海淀区

#import "DistrictPopMenuItem.h"
#import "District.h"
@implementation DistrictPopMenuItem

- (void)setDistrict:(District *)district
{
    _district = district;

    [self setTitle:district.name forState:UIControlStateNormal];
}

// 父类的方法,供子类实现
// 数据源,子标题数组,所有子标题的名字组成的数组,  本接口,专门交给子类实现
// 比如 美食 下面有多少个subCategory
// 比如 海淀区 下面有多少个place
- (NSArray *)subTitlesArr
{
    return _district.places;
}

@end

子类:OrderPopMenu

//
//  OrderPopMenu.h
//  帅哥_团购
//
//  Created by beyond on 14-8-16.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//

#import "PopMenu.h"

@interface OrderPopMenu : PopMenu

@end



//
//  OrderPopMenu.m
//  帅哥_团购
//
//  Created by beyond on 14-8-16.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//

#import "OrderPopMenu.h"
#import "OrderPopMenuItem.h"
#import "Order.h"
#import "MetaDataTool.h"
@implementation OrderPopMenu

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // 1.往UIScrollView添加内容
        NSArray *orders = [MetaDataTool sharedMetaDataTool].AllOrdersArr;
        int count = orders.count;

        for (int i = 0; i

子类:OrderPopMenuItem

//
//  OrderPopMenuItem.h
//  帅哥_团购
//
//  Created by beyond on 14-8-16.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//

#import "PopMenuItem.h"
@class Order;
@interface OrderPopMenuItem : PopMenuItem


@property (nonatomic, strong) Order *order;
@end



//
//  OrderPopMenuItem.m
//  帅哥_团购
//
//  Created by beyond on 14-8-16.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//

#import "OrderPopMenuItem.h"
#import "Order.h"
@implementation OrderPopMenuItem


- (void)setOrder:(Order *)order
{
    _order = order;

    [self setTitle:order.name forState:UIControlStateNormal];
}
@end

最重要的一个工具类

//
//  MetaDataTool.h
//  帅哥_团购
//
//  Created by beyond on 14-8-14.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  元数据管理类
// 1.城市数据
// 2.下属分区数据
// 3.分类数据

#import 
@class Order;
@class City;
@interface MetaDataTool : NSObject
singleton_interface(MetaDataTool)




// readonly只可读,NSArray,不允许外部随便增删改
// 所有的城市分组数组,数组中的元素是section对象
@property (nonatomic, strong, readonly) NSMutableArray *allSectionsArr;

// 所有城市字典,Key是城市名,Value是城市对象
@property (nonatomic, strong, readonly) NSMutableDictionary *allCitiesDict;

// 当前选中的城市, 当点击了控制器下方的tableView的某一行时,会设置当前城市,拦截setter操作,更新最近访问的城市数组
@property (nonatomic, strong) City *currentCity; // 当前选中的城市






// 所有的分类对象组成的数组,一个分类对象包括分类名,图标,所有子分类名组成的数组
@property (nonatomic, strong, readonly) NSArray *allCategoriesArr;

// 所有的排序对象组成的数组
@property (nonatomic, strong, readonly) NSArray *AllOrdersArr;


@property (nonatomic, strong) NSString *currentCategoryName; // 当前选中的类别的名字
@property (nonatomic, strong) NSString *currentDistrictName; // 当前选中的区域名字
@property (nonatomic, strong) Order *currentOrder; // 当前选中的排序对象


// 通过按钮上面的名字如(价格最高),到MyOrder对象数组中,遍历返回MyOder对象
- (Order *)orderWithName:(NSString *)name;



@end




//
//  MetaDataTool.m
//  帅哥_团购
//
//  Created by beyond on 14-8-14.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  元数据管理类
// 1.城市数据
// 2.下属分区数据
// 3.分类数据

#import "MetaDataTool.h"
// 一个分组模型
#import "Section.h"
#import "City.h"

// 一个分类对象模型
#import "MyCategory.h"
#import "Order.h"
// 沙盒里面放的是所有曾经访问过的城市名字
#define kFilePath [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:@"visitedCityNamesArr.data"]
@interface MetaDataTool ()
{
    // 数组,存储曾经访问过城市的名称
    NSMutableArray *_visitedCityNamesArr;
    // 访问过的组section
    Section *_visitedSection; // 最近访问的城市组数组
}

@end

@implementation MetaDataTool
singleton_implementation(MetaDataTool)



- (id)init
{
    if (self = [super init]) {
        // 初始化项目中的所有元数据

        // 1.初始化城市数据

        [self loadCitiesData];

        // 2.初始化分类数据
        [self loadCategoryData];

        // 3.初始化排序对象数据
        [self loadOrderData];
    }
    return self;
}

// 1.初始化城市数据
- (void)loadCitiesData
{
    // 所有城市对象组成的字典,Key是城市名,Value是城市对象
    _allCitiesDict = [NSMutableDictionary dictionary];
    // 临时变量,存放所有的section
    NSMutableArray *tempSectionsArr = [NSMutableArray array];

    // 1.创建一个热门城市分组
    Section *hotSection = [[Section alloc] init];
    // 组名是 热门
    hotSection.name = @"热门";
    // 分组的成员cities,初始化
    hotSection.cities = [NSMutableArray array];
    // 为了将热门这一组加在分组数组的最前面,准备了一个临时的section数组
    [tempSectionsArr addObject:hotSection];

    // 2.添加A-Z分组,到临时section数组后面
    // 加载plist数据
    NSArray *sectionsArr = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Cities.plist" ofType:nil]];
    for (NSDictionary *dict in sectionsArr) {
        // 创建城市分组对象模型
        Section *section = [[Section alloc] init];
        // 调用分类方法,将字典转成模型
        [section setValuesWithDict:dict];
        // 将所有的section对象,加到临时的section对象数组的后面
        [tempSectionsArr addObject:section];

        // 遍历每一组的所有城市,找出热门的加到hotSection里面
        for (City *city in section.cities) {
            if (city.hot) {
                // 如果是热门城市
                [hotSection.cities addObject:city];
            }
            // 并且将所有的城市对象,以城市名作为键,存入字典中
            [_allCitiesDict setObject:city forKey:city.name];
        }
    }

    // 3.从沙盒中读取之前访问过的城市名称
    _visitedCityNamesArr = [NSKeyedUnarchiver unarchiveObjectWithFile:kFilePath];
    // 如果是首次使用,则沙盒中返回的是空数组,需要懒加载,创建一个数组
    if (_visitedCityNamesArr == nil) {
        _visitedCityNamesArr = [NSMutableArray array];
    }

    // 4.创建并添加一个section, 最近访问城市组(section)
    _visitedSection = [[Section alloc] init];
    _visitedSection.name = @"最近访问";
    _visitedSection.cities = [NSMutableArray array];

    // 5.遍历沙盒中取出来的城市名组成的数组,转成一个个城市对象
    for (NSString *name in _visitedCityNamesArr) {
        // 根据城市名,从对象字典中取出城市对象,并添加到最近访问城市组(section)中的城市对象数组
        City *city = _allCitiesDict[name];
        [_visitedSection.cities addObject:city];
    }
    // 6.如果最近访问城市组(section)中的城市对象数组中有城市,那么就可以将最近访问组插入到sections最前面
    if (_visitedSection.cities.count) {
        [tempSectionsArr insertObject:_visitedSection atIndex:0];
    }

    // 将所有的section组成的数组赋值给成员变量供调用者访问
    _allSectionsArr = tempSectionsArr;
}
// 当点击了控制器下方的tableView的某一行时,会设置当前城市,拦截setter操作,更新最近访问的城市数组
- (void)setCurrentCity:(City *)currentCity
{
    _currentCity = currentCity;

    // 修改当前选中的区域
//    _currentDistrict = kAllDistrict;

    // 1.先从最近访问的城市名数组中,移除该的城市名
    [_visitedCityNamesArr removeObject:currentCity.name];

    // 2.再将新的城市名插入到数组的最前面(最近访问的在最前)
    [_visitedCityNamesArr insertObject:currentCity.name atIndex:0];

    // 3.同时,要将新的城市对象,放到_visitedSection的城市对象数组的最前面
    [_visitedSection.cities removeObject:currentCity];
    [_visitedSection.cities insertObject:currentCity atIndex:0];

    // 4.归档最近访问的城市名组成的数组,以便下次再解档
    [NSKeyedArchiver archiveRootObject:_visitedCityNamesArr toFile:kFilePath];

    // 5.每一次点击,拦截setter当前城市之后,都要发出通知,做什么用???
    [[NSNotificationCenter defaultCenter] postNotificationName:kCityChangeNote object:nil];

    // 6.当用点击了某一行,来到了这个setCurrentCity方法时,肯定是要在最前面,添加“最近访问组”了
    // 如果 allSectionsArr 已经有了 【最近访问组】,则不用再添加了
    if (![_allSectionsArr containsObject:_visitedSection]) {
        [_allSectionsArr insertObject:_visitedSection atIndex:0];
    }
}

// 3.初始化排序对象数组
- (void)loadOrderData
{
    NSArray *array = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Orders.plist" ofType:nil]];
    int count = array.count;
    NSMutableArray *temp = [NSMutableArray array];
    for (int i = 0; i

最终效果图: vcD4KPHA+PGJyPgo8L3A+CjxwPjxicj4KPC9wPgo8cD6497/YvP652M+1zbwxOjwvcD4KPHA+PGltZyBzcmM9"...

iOSʹÓÃpushÒþ²Ø×ÓÒ³Ãæµ×²¿bottom TabBar

ÒÔÏÂÁ½ÖÖÇé¿öÊÇÎÒÔÚ¿ª·¢¹ý³ÌÖÐÓöµ½µÄ£¬Ò»ÖÖÊÇ´úÂëʹÓÃpushViewController£¬ÁíÒ»ÖÖÊÇstoryboardÖ±½ÓʹÓÃpush¡£Ö®Ç°Ò²²éÔÄÁ˺ܶà¹ØÓÚÒþ²Øµ×²¿tabbarµÄ×ÊÁÏ£¬µ«ÊÇҪôʹÓÃÆðÀ´Âé·³£¬ÒªÃ´¾ÍÊÇźºÏ¶È¸ß´úÂë²»¹æ·¶£¨ÕâÀïÓеã´úÂë½àñ±£¬µ±Ç°ÀàÏà¹ØµÄÊÂÎñÓ¦¸ÃдÔÚ±¾ÀàÖУ©¡£
1¡¢Ê¹ÓÃpushViewController
ÈçA->B;AÊÇÁбíÒ³£¬´øÓÐtabbar£»BÊÇÄÚÈÝÒ³£¬²»ÐèÒªtabbar£»

ÔÚAµÄʼþÖдò¿ªB£¬ÈçÏ´úÂë

-(void)showVideo:(EJAlbumModel *)model bySId:(NSString *)sid{
NSLog(@"%@",@"Ö´ÐÐίÍÐ");
EJClassVideoViewController *videoController=[[EJClassVideoViewController alloc] init];
videoController.model=model;
videoController.semesterClassId=sid;
self.navigationItem.backBarButtonItem=[[UIBarButtonItem alloc] initWithTitle:@"·µ»Ø" style:UIBarButtonItemStyleBordered target:nil action:nil];// ÐÞ¸Äϼ¶Ò³ÃæµÄ·µ»Ø°´Å¥£¬´Ë´¦ÎÒÊǺÜÏëдµ½videoControllerÖУ¬µ«ÊÇbackBarButtonItemµÄ»úÖƾö¶¨±ØÐëдÔÚAÖУ»
[self.navigationController pushViewController:videoController animated:YES];
}

ÔÚBµÄ¼ÓÔØViewÊÓͼʼþinitWithNibNameÖУ¬¼ÓÈë self.hidesBottomBarWhenPushed=YES;¼´¿ÉʵÏÖ´ò¿ªBÒþ²Øtabbar£¬·µ»ØAÖØÐÂÏÖʵtabbar£»ºÜ¼òµ¥°É

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.hidesBottomBarWhenPushed=YES;
}
return self;
}

2¡¢Ê¹ÓÃstoryboard
ÔÚstoryboardÖн¨Á¢AºÍB£¬²¢Ê¹ÓÃctrl£«Á´½ÓÖÁB,¼´segueµÄ´ò¿ª·½Ê½£»ÈçÏÂͼËùʾ£º

图片 17

< †·Ÿ"" target="_blank" class="keylink">vcD4KPHA+tMu0pta70OjSqtTav8nK07uvytPNvNbQ0N64xEK1xNK7uPbK9NDUvLS/yaOov8nPp7rctuC8vMr1zsTVwra8w7vM4bW91eK146OsysfS8s6qztLDu9PQ1dK1vcLwo6mjrMjnz8LNvKOs0aHW0ELK0828o6yyorm00aFIaWRlIEJvdHRvbSBCYXIgb24gUHVzaDs8L3A+CjxwPjxpbWcgc3JjPQ=="" alt="">

TabBar ÒÔÏÂÁ½ÖÖÇé¿öÊÇÎÒÔÚ¿ª·¢¹ý³ÌÖÐÓöµ½µÄ£¬Ò»ÖÖÊÇ´úÂëʹÓÃpushViewController£¬Á...

本文由葡京网投哪个正规发布于首页,转载请注明出处:iOS_21团购_顶部菜单和弹出菜单联动,iOS_31_cocos2d环境搭建

关键词:

上一篇:让系统更有保障,Windows服务端口大全

下一篇:命令的使用及RUNAS自动输入密码的方法,网络渗透与深度防御