彩票项目(一) - 总体架构

一. 开发准备

1. 理清项目的总体架构–每个页面所用的控制器类型
2. 层级关系–找出每个层级是否有关
3. 计划采取搭建框架的方式(纯代码或者storyboard)
—3.1 当项目的总体页面小于或者等于四个的时候,选用storyboard.反之选用纯代码

二. 纯代码搭建(结构清晰)

1. App展示图:
第一个控制器的展示图
2. 根据功能模块,我们需要先创建文件夹–创建5个文件夹
3. 每个功能模块里面的子文件夹都是需要根据MVC的思想来创建
文件夹展示图
4. 设置APP启动界面
5. 设置APP应用图标
6. 设置类的前缀–在每次创建类的时候会直接在起始位置加上公司的名称的首字母,注意要大写.

三. 子控制器的添加部分

1. 将Min删除

将图片标注的地方删除

2. 创建窗口和根控制器
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    //创建窗口
    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];

    //设置根控制器

    XFTabBarController *tabBarController = [[XFTabBarController alloc] init];

    self.window.rootViewController = tabBarController;

    //显示窗口

    [self.window makeKeyAndVisible];

    return YES;
}
3. 自定义UITabBarController控制器
— 为什么要自定义的原因:由于我们需要往UITabBarController里面添加子控制器,那么这样就需要UITabBarController控制器自己管理,如果都写在AppDelegate里面不便于管理,而且过于累赘.自定义UITabBarController之后就让属于UITabBarController的东西让它自己管理.
4. 创建需要添加的子控制器
#pragma mark - 创建需要添加的子控制器

- (void)setUpAllChildViewController
{

    //购彩大厅
    XFHallViewController *hall = [[XFHallViewController alloc] init];
    hall.view.backgroundColor = [UIColor greenColor];
    [self setUpOneChildViewController:hall image:[UIImage imageNamed:@"TabBar_LotteryHall_new"] selImage:[UIImage imageNamed:@"TabBar_LotteryHall_selected_new"] title:@"购彩大厅"];

    //竞技场
    XFAreanViewController *arean = [[XFAreanViewController alloc] init];

    arean.view.backgroundColor = [UIColor redColor];

    [self setUpOneChildViewController:arean image:[UIImage imageNamed:@"TabBar_Arena_new"] selImage:[UIImage imageNamed:@"TabBar_Arena_selected_new"] title:@"竞技场"];

    //发现
    XFDiscoverViewController *discover = [[XFDiscoverViewController alloc] init];
    discover.view.backgroundColor = [UIColor yellowColor];
    [self setUpOneChildViewController:discover image:[UIImage imageNamed:@"TabBar_Discovery_new"] selImage:[UIImage imageNamed:@"TabBar_Discovery_selected_new"] title:@"发现"];


    //开奖信息
    XFHistoryViewController *history = [[XFHistoryViewController alloc] init];
    history.view.backgroundColor = [UIColor blueColor];
    [self setUpOneChildViewController:history image:[UIImage imageNamed:@"TabBar_History_new"] selImage:[UIImage imageNamed:@"TabBar_History_selected_new"] title:@"开奖信息"];

    //我的彩票

    XFMyLotterViewController *lotter = [[XFMyLotterViewController alloc] init];
    lotter.view.backgroundColor = [UIColor purpleColor];
    [self setUpOneChildViewController:lotter image:[UIImage imageNamed:@"TabBar_MyLottery_new"] selImage:[UIImage imageNamed:@"TabBar_MyLottery_selected_new"] title:@"我的彩票"];



}
5. 由于我们采用的是主流框架的搭建方式,那么我们需要在UITabBarController控制器里面添加一个导航控制器,同时给控制器的底部添加按钮的图片和标题
#pragma mark - 用于添加创建子控件时候需要的参数

- (void)setUpOneChildViewController:(UIViewController *)vc image:(UIImage *)image selImage:(UIImage *)selImage title:(NSString *)title
{
    //设置tabBar中5个按钮的标题
    vc.title = title;
    //平常的图片
    vc.tabBarItem.image = image;
    //用户按下去的样式
    vc.tabBarItem.selectedImage = selImage;

    //tabBarItem本身就是一个模型,这里我们将每个控制器对应的tabBar存入可变数组中
    [self.arrayItem addObject:vc.tabBarItem];

    //创建导航控制器
    //判断:如果导航控制器是竞技场这种类型,就让他用自己自定义的导航控制器
    if ([vc isKindOfClass:[XFAreanViewController class]]) {
        XFAreanNavigationController *areanNav = [[XFAreanNavigationController alloc] initWithRootViewController:vc];

        //将导航控制器添加到UItabBarViewController控制器中
        [self addChildViewController:areanNav];
    }else{

        //否则就用XFNavigationController这个控制器
        XFNavigationController *nav = [[XFNavigationController alloc] initWithRootViewController:vc];

        //将导航控制器添加到UItabBarViewController控制器中
        [self addChildViewController:nav];
    }

}
6. 我们采用抽取方法的形式将子控制器的创建和标题的添加些分别写在两个方法中

四. 控制器底部按钮创建于添加部分

1. 程序一运行我们会发现,系统自带的tabBar并不能满足我们的需求
— 原因:运行后我们发现,系统自带的控制器,在tabBar部分按钮显示的图片突出了tabBar的范围,并不能满足要求.(tabBar的高度是44)
2. 创建两个装模型的数组
第一段代码是在UITabBarController控制器中
//创建一个数组用来装入tabBarItem的模型
@property (nonatomic, strong) NSMutableArray *arrayItem;
第二段代码是在自定义的tabBar中
//创建数组
@property (nonatomic, strong) NSArray *arrayItem;
3. 创建和添加控制器底部按钮
运用get和set方法达到创建底部按钮和添加底部按钮的操作
创建:
#pragma mark - 在里面创建tabBar下面的按钮
//重写arrayItemset方法-->在里面创建UIButton
- (void)setArrayItem:(NSArray *)arrayItem
{
    _arrayItem = arrayItem;

    for (int i = 0; i < arrayItem.count; i++) {
        //创建按钮
        UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];

        btn.tag = i;
        //根据传入的模型角标取出模型
        UITabBarItem *item = arrayItem[i];
        //设置按钮的背景图片
        [btn setBackgroundImage:item.image forState:UIControlStateNormal];
        [btn setBackgroundImage:item.selectedImage forState:UIControlStateSelected];

        //将创建出来的按钮添加到自定义的tabBar中
        [self addSubview:btn];

        //监听按钮的点击
        //UIControlEventTouchDown:由于是事件的点击,所以用这个
        [btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchDown];
        //让程序已加载完,显示页面的时候,默认是在第0个按钮
        if (i == 0) {
            [self btnClick:btn];
        }
    }

}
添加(布局):

#pragma mark - 布局子控件

- (void)layoutSubviews
{
    [super layoutSubviews];
    //重tabBar中取出每个子控件,告诉编译器是整数
    int count = (int)self.subviews.count;
    //计算每个子控件的位置
    CGFloat x = 0;
    CGFloat y = 0;
    //每个按钮的宽度
    CGFloat btnW = self.bounds.size.width / count;
    //每个按钮的高度
    CGFloat btnH = self.bounds.size.height
    for (int i = 0; i < count; i++) {
        //是第几个按钮,就计算出对应的宽度
        x = i * btnW;
        //根据角标一次取出每个按钮
        UIButton *btn = self.subviews[i];
        btn.frame = CGRectMake(x, y, btnW, btnH);
    }   
}

五. 按钮的业务逻辑

总体思路采用的方法:代理
/*由于我们希望XFTabBarController控制器能知道用户点击的是哪个按钮,然后让控制器切换到对应的界面
 问题:但是怎么知道用户点击的是哪个按钮呢?
 实现方法:代理
 具体做法:在自定义的XFTabBar中设置代理属性,并且设置协议方法,通过协议中的方法将用户点击的是哪个按钮通过方法传递给控制器,然后控制器再切换到相应的界面
 代理人:XFTabBarController,让它实现协议的相应的方法,然后就能知道用户点击的是哪个按钮,做出相应的界面切换
 */
1. 监听底部按钮的点击事件
在创建底部按钮的时候我往里面加了一个监听按钮的方法
//监听按钮的点击
        //UIControlEventTouchDown:由于是事件的点击,所以用这个
        [btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchDown];
实现监听中的方法,同时我们在里面设置按钮选中的状态
#pragma mark - 实现监听方法

- (void)btnClick:(UIButton *)btn
{
    //让上一个按钮取消选中状态
    self.preSelecBtn.selected = NO;

    //让当前的按钮选中
    btn.selected = YES;

    //让当前点击的按钮成为上一个选中的按钮
    self.preSelecBtn = btn;

    //调用代理
    //判断代理是否实现对应的代理方法
    if ([self.delegate respondsToSelector:@selector(tabBar:selectBtnIndex:)]) {
        //调用代理方法
        [self.delegate tabBar:self selectBtnIndex:btn.tag];

    }

}
2. 取消系统自带的按钮选中的高亮状态,用自己设置的按钮点击后的亮度
思路:新建一个类,继承UIButton,然后写入下面这段代码
//不用实现这个方法
- (void)setHighlighted:(BOOL)highlighted
{

}
3. 通过点击底部按钮,切换控制器
在自定义的tabBar中写入协议,并且设置代理
@class XFTabBar;
@protocol XFTabBarDelegate<NSObject>

//协议的方法;selectBtnIndex传入相应的点击的角标
- (void)tabBar:(XFTabBar *)tabBar selectBtnIndex:(NSInteger)index;

@end

@interface XFTabBar : UIView

//创建数组
@property (nonatomic, strong) NSArray *arrayItem;

//设置代理
@property (nonatomic, weak) id<XFTabBarDelegate>delegate;
设置XFTabBarController控制器为代理
//设置代理
    tabBar.delegate = self;
4. 在按钮监听的方法中做出判断
 //调用代理
    //判断代理是否实现对应的代理方法
    if ([self.delegate respondsToSelector:@selector(tabBar:selectBtnIndex:)]) {
        //调用代理方法
        [self.delegate tabBar:self selectBtnIndex:btn.tag];

    }
5. 让XFTabBarController控制器实现代理方法
#pragma mark - 实现代理方法
- (void)tabBar:(XFTabBar *)tabBar selectBtnIndex:(NSInteger)index
{
    //设置寻找第几个控制器
    self.selectedIndex = index;

}

六. 导航条的处理

原因:由于在App中看到的每个界面的导航条的样式都不一样,设置了图片,那么系统自带的导航条行业是无法满足我们的需求,那么我们自定义两种类型的导航控制器,通过设置里面导航条的样式来达到需求
1. 创建两种类型的导航控制器:一种是竞技场用的导航控制器和其它页面所用的导航控制器

创建两种导航控制器

2. 两种导航控制器中的方法都是一样的(就只是将自己传入的图片修改)
//当当前类或者它的子类第一次使用的时候调用.
+ (void)initialize
{
    //获取指定类下面的导航条
    UINavigationBar *bar = [UINavigationBar appearanceWhenContainedInInstancesOfClasses:@[[XFNavigationController class]]];

    //设置背景图片
    [bar setBackgroundImage:[UIImage imageNamed:@"NavBar64"] forBarMetrics:UIBarMetricsDefault];

    //设置导航条上的字体(用字典来包)
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    //字体颜色
    dict[NSForegroundColorAttributeName] = [UIColor whiteColor];
    //字体大小
    dict[NSFontAttributeName] = [UIFont boldSystemFontOfSize:20];

    //将设置好的属性添加到导航条上
    [bar setTitleTextAttributes:dict];
}
特别说明:对上面的代码部分,只要将绿色部分图片修改为个对应的图片样式就可以
3. 选中各自的导航控制器的判断方法
    //创建导航控制器
    //判断:如果导航控制器是竞技场这种类型,就让他用自己自定义的导航控制器
    if ([vc isKindOfClass:[XFAreanViewController class]]) {
        XFAreanNavigationController *areanNav = [[XFAreanNavigationController alloc] initWithRootViewController:vc];

        //将导航控制器添加到UItabBarViewController控制器中
        [self addChildViewController:areanNav];
    }else{

        //否则就用XFNavigationController这个控制器
        XFNavigationController *nav = [[XFNavigationController alloc] initWithRootViewController:vc];

        //将导航控制器添加到UItabBarViewController控制器中
        [self addChildViewController:nav];
    }

七. 导航控制器顶部的活动按钮

说明活动按钮的功能:当点击活动按钮的时候,会弹出一张灰色的遮盖,将整个屏幕盖住;然后在遮盖的上面会出现一张图片(两者是同时出现的).当点击图片上右上角的x是会使得图片缩小到某个部位,然后遮盖也移除.
1. 自定义一个继承UIView的类,用来创建遮盖

创建遮盖类

类中的方法:
//对遮盖的布局
+ (void)show
{
    //创建自定义的遮盖
    XFCoverView *coverView = [[XFCoverView alloc] init];
    //设置beij
    coverView.backgroundColor = [UIColor blackColor];
    //设置透明度
    coverView.alpha = 0.6;

    //设置尺寸
    coverView.frame = [UIScreen mainScreen].bounds;
    //获取APP
    [[UIApplication sharedApplication].keyWindow addSubview:coverView];
}
2. 设置并且监听购彩大厅控制器顶部的左侧按钮
//设置购彩大厅左侧的活动按钮
    self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageWithOriImageName:@"CS50_activity_image"] style:UIBarButtonItemStylePlain target:self action:@selector(activity)];
3. 实现监听方法
#pragma mark - 实现监听方法

- (void)activity
{
    [XFCoverView show];
    //活动按钮被点击后调用图片出现的方法
    XFPopView *popView = [XFPopView showInPoint:self.view.center];
    //设置代理
    popView.delegate = self;  
}
4. 移除图片和遮盖
采用思路:代理
/*
 对于购彩大厅左上角的活动按钮处理
问题:如何知道用户点击了图片上面的关闭按钮?
 由于用户点击了图片上的关闭按钮,但是购彩大厅的控制器并不知道用户点击了,那么我们采用代理的方法,通过签订协议的方法来告诉控制器,让控制器成为代理.当用户点击了,我们就让控制器去实现代理的方法,方法里面具体指明了图片将会缩回去的地方(坐标)

 */
4.1 首先我们实现下面两个方法:
//给定义一个点,图片出现在哪个位置

+ (instancetype)showInPoint:(CGPoint)point;

//给定一个点,图片隐藏到哪个位置

- (void)hiddenInPoint:(CGPoint)point;
代码描述1:给定一个点,显示出图片将要出现的位置,并且返回图片
#pragma mark - 图片出现
+ (instancetype)showInPoint:(CGPoint)point
{
    //由于图片是从Xib中加载的
    XFPopView *popView = [[NSBundle mainBundle] loadNibNamed:@"XFPopView" owner:nil options:nil][0];

    //传入的点,显示到指定的位置
    popView.center = point;

    [[UIApplication sharedApplication].keyWindow addSubview:popView];

    return popView;
}
代码描述2:外界给定一个点,知道图片将要隐藏的位置
#pragma mark - 图片隐藏
- (void)hiddenInPoint:(CGPoint)point
{
    //图片隐藏有一个动画效果
    [UIView animateWithDuration:0.7 animations:^{

        //图片要隐藏的地方
        self.center = point;
        //隐藏后图片的大小
        self.transform = CGAffineTransformMakeScale(0.00001, 0.00001);
    } completion:^(BOOL finished) {

       //先遍历所有在窗口上的view
        for (UIView *view in [UIApplication sharedApplication].keyWindow.subviews ) {

            //如果view的类型是XFCoverView就移除
            if ([view isKindOfClass:[XFCoverView class]]) {

                [view removeFromSuperview];
            }
            //如果不是就将自己移除
            [self removeFromSuperview];
        }   
    }];

}
4.2 协议定义与代理设置
让自定义的图片成为拟定协议方:

@class XFPopView;

@protocol XFPopViewDelegate <NSObject>

//协议方法
- (void)popView:(XFPopView *)popView ;

@end

@interface XFPopView : UIView

//设置代理
@property (nonatomic, weak) id <XFPopViewDelegate>delegate;

@end
设置代理:在购彩大厅的监听活动按钮的方法中设置代理:
//设置代理
    popView.delegate = self;
4.3 监听图片上的退出按钮
图片采用Xib的方法创建,理由是因为图片的格式是固定不变的.
代码描述:我们在下面图片移除的按钮中设置判断代理实现的方法
#pragma mark - 图片移除按钮的监听
- (IBAction)btnCloseClick:(UIButton *)sender
{
    //判断代理是否实现了代理方法
    if ([self.delegate respondsToSelector:@selector(popView:)]) {

        //如果实现了就调用协议方法
        [self.delegate popView:self];
    }

}
4.4 代理实现协议的方法
#pragma mark - 实现代理方法

- (void)popView:(XFPopView *)popView
{
    [popView hiddenInPoint:CGPointMake(20, 40)];
}

八. 结束语

最后部分有一点瑕疵,这里我先买个关子,先听听你们的理解,明天再奉上代码优化部分(提醒优化部位:最后的点击图片退出部分).
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值