关于项目思路的思考

  • 项目结构更加清晰,方便以后调试bug

  • 怎么让项目结构更加清晰,谁的事情谁管理

  • 分析项目架构

    • 方便处理多人开发
    • 让更多的功能复用
    • 让代码的结构更加清晰
  • 自定义类的思路

    • 当系统的某些类不能满足需求的时候,需要给系统的类添加某些功能,但还要保持原有类的功能,采用自定义类,继承系统的类(自定义控件,自定义模型)
    • 让项目的结构更加清晰,谁的事情谁管理,采取自定义类,以后这个类的问题,可以马上定位到这个类做的哪些方法(自定义控制器)
  • 复习程序的运行

    • main -> UIApplicationMain
    • 创建UIApplication对象
    • 创建UIApplication对象的代理
    • 开启主运行循环,保持程序一直运行
    • 加载info.plist文件,判断下是否指定main
  • 关于窗口的建立

    • 创建窗口
    • 创建窗口的根控制器
    • 添加子控制器
    • 让窗口显示
    • 代码实现 (去消info中Main)
// 1.创建窗口
    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];

    // 2.创建窗口的跟控制器
    // 创建tabBarVc
    UITabBarController *tabBarVc  = [[UITabBarController alloc] init];
    // 设置窗口的根控制器
    self.window.rootViewController = tabBarVc;

    // 添加子控制器
    UIViewController *vc = [[UIViewController alloc] init];

    vc.view.backgroundColor = [UIColor redColor];

    [tabBarVc addChildViewController:vc];

  ...

    // 3.让窗口显示
    [self.window makeKeyAndVisible];
  • 搭建主架构(让程序更清晰化)

    • 不同的页面交给不同的控制器管理,并放在不同的文件夹中。
  • 结构清晰化,谁的控件谁管理。

  • 自定义UITabBarController

    • 内部添加子控制器 可以进行自定义方法,来抽取相同代码,简化程序
    • 自定义 子控制器,谁的控件,谁管理,方便管理子控制器- 关于主流框架 (UITabBarController 和 UINavigationController) 主要是上面一个条,下面一个条。
    • 一般是在 UITabBarController上添加UINavigationController 这样的话, 在UINavigationController上push子控制器的话 (这样的话上面的条可以叫给push进去的子控制器进行管理)
  • 注意, 每运行一步,都都要看看所运行的效果,满不满足自己的需求。

    • 此处由于美工的的图片(tabBar的图标图片,大于tabBar的宽度,所以没有显示出想要的效果)【tabBar的宽度44 < 图片高度】
      所以需要自定义tabBar,因为系统的tabBar不满足需求
  • 自定义TabBar,取代原有tabBar,并实现原有tabBar的功能
    • 有多少按钮控件,控件的样式有什么决定。 (对于tabBar,它的样式是有对应控制器决定的,可以这么说,对应控制器,将所设置的样式素材,存放在 tabBarItem 属性中 tabBarItem就是一个模型数据,tabBar从模型数据中读取了素材,再赋值到它对应的位置上)
    • 所以底层实现我认为是这么几步。
      • 从外界读取模型数据,有多少控制器,应该就有多少组模型数据。
      • 提取模型数据,并将其赋值给子控件button上。
      • 给子控件设置位置
      • 点击按钮,跳转到对应的控制器。
      • 当然,还有一些细节需要处理,比如按钮不需要高亮指示,只需要选中和正常两种状态, (所以需要自定义按钮,重写- (void)setHighlighted:(BOOL)highlighted方法,为空即可,让其在高亮时不做任何操作);按钮默认选中第一个;选中一个那么前一个就要取消选中。
      • 具体代码如下。
// 由于不确定什么时候有数据加入,所以采用懒加载方式,进行items的加载,加载完成后才进行按钮的创建以及赋值操作,不需要在视图 一创建的时候,就取创建按钮, 节约功耗
- (void)setItems:(NSArray *)items
{
    _items = items;

    for (UITabBarItem *item in items) {

        // 从items中取出模型数据,并将其赋值给对应按钮
        UIButton *btn = [LXLTabBarButton buttonWithType:UIButtonTypeCustom];


        // 设置内容
        [btn setBackgroundImage:item.image forState:UIControlStateNormal];

        [btn setBackgroundImage:item.selectedImage forState:UIControlStateSelected];

        [btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchDown];

        btn.tag = self.subviews.count;

        if (self.subviews.count == 0) {
            // 为了程序之处,没有子控件的时候,按钮就已经点击。
            [self btnClick:btn];
        }

        [self addSubview:btn];
    }
}
// 进行子控件的布局, 根据子控件的个数,遍历对每个子控件进行布局
- (void)layoutSubviews
{
    [super layoutSubviews];

    int count = (int)self.subviews.count;

    CGFloat btnW = self.bounds.size.width / count;
    CGFloat btnH = self.bounds.size.height;
    CGFloat btnY = 0;
    CGFloat btnX = 0;
    // 布局按钮的位置
    for (int i = 0; i < count; i++) {
        UIButton *btn = self.subviews[i];

        btnX = i * btnW;

        btn.frame = CGRectMake(btnX, btnY, btnW, btnH);
    }

}

// 监听点击事件, 由于是逆向传值,所以需要代理,来完成点击事件处理,并且传入参数(点击的是哪个按钮)tag ,来完成让控制器的跳转
- (void)btnClick:(UIButton *)btn
{
    _selBtn.selected = NO;
    btn.selected = YES;
    _selBtn = btn;

    // 通知代理点击了哪个角标的按钮
    if ([_delegate respondsToSelector:@selector(tabBar:didClickBtn:)]) {
        [_delegate tabBar:self didClickBtn:btn.tag];
    }
}

  • 对于父控件,tabBarController
    • 创建自定义tabBar控件,并将其作为子控件放置在,原系统tabBar之上,盖住系统tabBar。(需要注意的是,要移除系统原有的tabBar,但是系统底部处理的时候并不是马上移除,会在过一段事件才进行移除操作)。
    • 需要将对应的模型数组数据(懒加载),传入,属于顺传
    • 作为代理,完成对应的方法,进行控制器的跳转
    • 具体代码如下
// 取得模型数据,并存放在模型数组中
- (void)setUpOneChildViewController:(UIViewController *)vc image:(UIImage *)image selImage:(UIImage *)selImage
{

    // 设置tabBarButton的图片,tabBarButton的内容由对应的子控制器的tabBarItem
    vc.tabBarItem.image = image;
    vc.tabBarItem.selectedImage = selImage;

    // 保存对应子控制器的UITabBarItem
    [self.items addObject:vc.tabBarItem];

    [self addChildViewController:vc];
}

- (void)setUpTabBar
{
    // 1.移除系统的tabBar,移除系统自带的tabBarButton
    [self.tabBar removeFromSuperview];
    NSLog(@"%@",self.tabBar);

    // 2.添加自己的tabBar
    LXLTabBar *tabBar = [[LXLTabBar alloc] init];

    tabBar.delegate = self;

    // tabBar按钮的个数,由tabBar子控制器个数决定
//    tabBar.count = (int)self.childViewControllers.count;
    // 传对应子控制器的tabBarItem数组
    tabBar.items = self.items;

    tabBar.backgroundColor = [UIColor greenColor];

    tabBar.frame = self.tabBar.frame;

    [self.view addSubview:tabBar];

}

// 遵守协议实现代理方法,进行界面的跳转。
#pragma mark  -LXLTabBarDelgate方法
// 当点击tabBar上的条的时候调用
- (void)tabBar:(XMGTabBar *)tabBar didClickBtn:(NSInteger)index
{
    // 切换界面
    self.selectedIndex = index;
}
  • 对于跳转按钮的添加
    • 我觉得有两种方案
      • 添加到最后一个cell上去
      • 直接添加到collectionView上去。
    • 第一种方案的实现
// 判断是否是最后一个cell,可以根据indexPath进行判断
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{

  ...

    // 给最后一个cell添加一个立即体验按钮
    // 告诉cell是否是最后一个
    // 宏定义数目为4
    [cell setIndexPath:indexPath count:LXLPage];
//    [cell setIndexPath:indexPath count:4]
//    if (indexPath.item == XMGPage - 1) {
//        // 添加立即体验按钮
//
//    }

    return cell;
}
  • cell内部拿到indexPathcount进行判断
// 用来判断下当前cell对象是否是最后一个cell
- (void)setIndexPath:(NSIndexPath *)indexPath count:(int)count
{
    if (indexPath.item == count - 1) {
        // 最后一个cell
        // 添加一个立即体验按钮,首先保存整个cell只有一个体验按钮

        // 显示这个按钮
        self.startBtn.hidden = NO;

    }else{ // 不是最后一个cell

        // 隐藏这个按钮,涉及到循环引用,否则就会被别的cell所引用。
        self.startBtn.hidden = YES;
    }
}

  • 由于cell的按钮是用的时候才进行显示,(所以可以进行懒加载
- (UIButton *)startBtn
{
    if (_startBtn == nil) {
        UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
        _startBtn= btn;

        [btn setBackgroundImage:[UIImage imageNamed:@"guideStart"] forState:UIControlStateNormal];

        // 尺寸可以进行自适应'自己根据图片来安排大小'
        [btn sizeToFit];
        // 位置确定
        btn.center = CGPointMake(self.width * 0.5 , self.height * 0.9);
        [self.contentView addSubview:btn];
    }

    return _startBtn;
}

  • 对于控制器之间的跳转,点击按钮跳转到新控制器。
    • 没有任何联系的控制器跳转,直接跳转即可。 创建到主窗口根控制器显示,代替原有主窗口根控制器
// 点击立即体验按钮的时候调用
- (void)start
{
    // 跳转到主框架界面。界面之间跳转,导航控制器,tabBarVc,modal

    // 不能使用modal原因:新特性界面一直存在,被窗口的根控制器一直强引用

    LXLTabBarController *vc = [[LXLTabBarController alloc] init];

    // 设置窗口的根控制器为主框架控制器
   [UIApplication shareApplication].keyWindow.rootViewController = vc;
}

  • 第二种方法(代码实现)
- (viod)viewDidLoad{
    UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
    [btn setImage:[UIImage imageNamed:@"guideStart"] forState:UIControlStateNormal];
    [btn sizeToFit];
    // 初始化位置直接设置在 最终位置,而且只创建一次,不必思考情况
    btn.center = CGPointMake(self.collectionView.width * (LXLPageCount - 0.5), self.collectionView.height * 0.9);
    [self.collectionView addSubview:btn];
    [btn addTarget:self action:@selector(btnClick) forControlEvents:UIControlEventTouchUpInside];
}
// 跳转控制器
- (void)btnClick
{
     LXLTabBarController *vc =[[LXLTabBarController alloc]init];

    [UIApplication sharedApplication].keyWindow.rootViewController =vc;
}

  • 总结一下,我觉得第二个方法好,因为是控制器进行跳转,我觉得完全是控制器自己的事,交给它完全是可以处理的。如果交给cell的话,还需要额外的设置,以及判断清空。从代码量来看,还是直接设置好一点。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,409评论 25 707
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,016评论 4 62
  • 1、什么是RunLoop?2、开发中如何使用RunLoop?什么应用场景?3、RunLoop和线程有什么关系?4、...
    Mr吴标阅读 1,993评论 2 0
  • 昨晚我做了个梦,梦里我被梦想追杀了,是的你没听错,他的名字是叫梦想。梦境的开始我并不知道他是谁,我只知道有人在追杀...
    草塘不会游泳阅读 345评论 0 0