關于項目思路的思考

  • 項目結構更加清晰,方便以后調試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閱讀 230,527評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,687評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,640評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,957評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,682評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,011評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,009評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,183評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,714評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,435評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,665評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,148評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,838評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,251評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,588評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,379評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,627評論 2 380

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,765評論 25 708
  • 發現 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,179評論 4 61
  • 1、什么是RunLoop?2、開發中如何使用RunLoop?什么應用場景?3、RunLoop和線程有什么關系?4、...
    Mr吳標閱讀 2,010評論 2 0
  • 昨晚我做了個夢,夢里我被夢想追殺了,是的你沒聽錯,他的名字是叫夢想。夢境的開始我并不知道他是誰,我只知道有人在追殺...
    草塘不會游泳閱讀 368評論 0 0