一.界面搭建 1.項目需求 主界面能左右滾動,還能上下滾動,點擊按鈕跳轉界面 2.分析界面 點擊按鈕跳轉界面可以自定義UITabBarCotroller來實現 左右滾動,可以利用scrollView來實現 或 UICollectionView 上下滾動,用tableView可以實現 3.選擇實現方案 ...
一.界面搭建 1.項目需求 主界面能左右滾動,還能上下滾動,點擊按鈕跳轉界面 2.分析界面 點擊按鈕跳轉界面可以自定義UITabBarCotroller來實現 左右滾動,可以利用scrollView來實現 或 UICollectionView 上下滾動,用tableView可以實現 3.選擇實現方案 方案一: UITabBarCotroller + scrollView + tableView + titleView(TabBar條) UIScrollView弊端:沒有做離屏渲染優化 使用scrollView,沒有顯示的tableView也會渲染,渲染比較耗記憶體,創建很多對象 離屏渲染:如果一個界面,沒有顯示到屏幕上,不會渲染,如果在屏幕上,就會渲染 方案二: UITabBarCotroller + UICollectionView + tableView + scrollView(TabBar條) 能擴展標題 UICollectionView好處:優化離屏渲染,並不是少創建UITableView tableView添加UICollectionView的cell裡面 4.界面搭建實現步驟 4.1 先創建一個UIViewContriller 4.2 創建UICollectionView添加到UIViewContriller的View上面 創建UICollectionView,要先設置佈局參數,而且還要設置滾動方向為水平滾動,cell的大小就為屏幕的大小 4.3 添加一個scrollView(TabBar條)到控制器的View上面 scrollView的y值要從64開始,因為上面還有一個導航條 4.4 添加子控制器(添加給UIViewContriller) 按鈕的內容由對應的子控制器決定,創建子控制器的時候,要確定按鈕的內容 4.5 添加標題按鈕(添加到scrollView上面) 給按鈕綁定tag,點擊按鈕的時候,就移除之前按鈕對應的控制器,添加當前按鈕對應的控制器,並記錄當前選中的按鈕 註意: 如果A控制器的View添加到B控制器的View上,那麼A控制器一定要成為B控制器的子控制器 5.展示cell 5.1 設置cell的尺寸等於屏幕的尺寸,設置水平滾動運行報錯,垂直滾動不報錯,為什麼? 報錯: bug:the item height must be less than the height of the UICollectionView minus the section insets top and bottom values 分析: 原因:cell高度 必須 要小於等於 colllectionView高度 - (top + bottom) iOS7之後,導航控制器會給它裡面一個的UIScrollView頂部添加額外滾動區域 解決方案:取消系統自動添加的滾動區域 5.2 左右滾動的時候,cell之間有間距,怎麼解決 取消cell的行間距和列間距 layout.minimumInteritemSpacing = 0; layout.minimumLineSpacing = 0; 5.3 點擊按鈕切換界面的時候,發現cell為nill,為什麼? 點擊按鈕切換界面不會去調用UICollectionView數據源方法,只有屏幕滾動的時候才會調用數據源方法 解決方法:在點擊按鈕的方法裡面,改變collectionView的偏移量,讓他偏移到指定的位置 5.4 切換界面,發現還是不調用數據源方法? 因為之前添加控制器的view我們寫在 點擊按鈕的方法裡面了 點擊按鈕雖然會滾動cell,但會有延遲,不能及時去調用數據源方法, 怎麼解決? 我們把添加控制器view的代碼寫在創建cell之後就可以了,這樣保證有cell我們再去添加控制器的view 把添加控制器view的代碼寫在數據源方法裡面 5.5 滾動cell有時候會顯示兩個界面,我們想只顯示一個界面,怎麼辦? 開啟UIScrollView的分頁功能就解決了 UICollectionView繼承UIScrollView,所以UIScrollView的所有屬性和方法都能用 5.6 滾動到最後一頁,發現還能往後滾,只不過會彈回來,怎麼解決? 關閉彈簧效果 5.7 發現tableView上面和下麵被擋住了(導航條和TabBar條擋住了) 給tableView上邊和下邊添加一個內邊距 5.8 預設選中第0個按鈕 6.添加下劃線(標題指示器) 6.1用什麼控制項來作為下劃線 用View就可以了 6.2下劃線添加到哪裡? 下劃線是用來指示按鈕被選中的,和按鈕相關,添加到按鈕裡面可以嗎? 不可以,要求下劃線只有一個,按鈕有多個,不符合需求 可以添加到按鈕所在的父控制項裡面(標題欄scrollView) 6.3在哪裡添加? 下劃線和按鈕還有scrollView有關係,那麼應該在設置標題欄和按鈕的時候添加 按鈕需要添加多個,下劃線只需要添加一次, 預設選中第一個按鈕方法只會調用一次,可以寫在這裡面 6.4下劃線的frame怎麼設置? 下劃線的centerX始終和被選中的按鈕的centerX相同 下劃線高度根據需要我們自己設定 高度確定,y值也就確定了 = 父控制項高度 - 自己高度 下劃線寬度等於按鈕文字的高度 underLineV.xt_width = btn.titleLabel.xt_width; 6.5設置了下劃線,運行不顯示,為什麼? 一個控制項沒有顯示一般有三個原因: 6.5.1沒有frame 6.5.2被擋住 6.5.3被隱藏 我們通過小麵包查看,找不到下劃線控制項,排除被擋住和被隱藏的可能 6.6列印下劃線frame,發現寬度為0,為什麼? 我們是在viewDidLoad方法裡面添加按鈕,雖然給按鈕設置了frame,但是按鈕裡面的子控制項還沒有尺寸,在viewDidLayoutSubviews方法裡面才有尺寸 我們要手動計算btn.titleLabel的寬度 6.7怎麼計算btn.titleLabel的寬度 NSDictionary *nameAttr = @{NSFontAttributeName : [UIFont systemFontOfSize:15]}; [btn.titleLabel.text sizeWithAttributes:nameAttr]; 過期的方法 [btn.titleLabel.text sizeWithFont:[UIFont systemFontOfSize:15]]; 計算一段文字高度:constrainedToSize文字的寬度和最大高度 [btn.titleLabel.text sizeWithFont:[UIFont systemFontOfSize:15] constrainedToSize:CGSizeMake(355, MAXFLOAT)]; 7.監聽collectionView滾動完成 7.1 怎麼監聽? 設置代理UICollectionView繼承UIScrollView,所以UIScrollView代理方法都能用 -(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView 7.2 滾動完成要讓對應的標題按鈕成為選中狀態,怎麼實現? 首先要拿到按鈕 根據控制器就能找到對應的按鈕 7.3怎麼拿到當前的控制器? 偏移量 / 每個view的寬度 = 當前所在的頁數(取整) 頁數也就對應著是第幾個控制器 7.4按鈕怎麼拿到? 首先想到從按鈕父控制項scrollView的Subviews中去取,但我們有可能會取到下劃線控制項,不可行 我們需要定義一個數組,來保存所有的按鈕,從數組中就能拿到想要的按鈕 註意:數組一定要懶載入(初始化),而且用的時候要用點語法(調用set方法) 7.5拿到按鈕,調用按鈕選中狀態方法,讓按鈕成為選中狀態 7.6滾動完成,怎麼讓下劃線(指示器)也跟著移動? 滾動完成,會調用按鈕選中狀態的方法,在這個方法設置下劃線的centerX始終等於當前按鈕的centerX就可以了 8.封裝精華框架(類似與百思不得姐的主流界面) 8.1為什麼要抽取一個框架? 這樣的主流界面很多app都需要,封裝起來方便復用 8.2怎麼封裝? 封裝的前提:復用性 擴展性 抽取一個基類,把框架特有的方法和實現封裝到基類(例如:設置標題欄和標題按鈕,collectionView等) 我們用的時候只要繼承自這個基類,添加我們所需要的控制器就可以了 8.3封裝的簡單方法 如果實在不會,就把子類代碼全部拷貝到基類 一些固定的,能確定死的就保留在基類裡面 一些不確定的東西(例如:有多少個子控制器)放到子類實現, 能讓使用者去擴展 8.4繼承基類去實現主流界面的搭建,發現標題欄不能顯示,為什麼? 標題欄的標題按鈕是根據對應子控制來設置的 而我們調用完父類(基類)的viewDidLoad之後才添加自控制器,也就是說先設置按鈕,在添加自控制器 顯然,標題欄按鈕是設置不成功的 註意:重寫父類的方法,一定要調用super方法 8.5怎麼設置標題欄,才能正常顯示? 我們只需要在添加完子控制器再設置標題欄就可以了 只需要把設置標題欄的按鈕寫在viewWillAppear裡面就行了(模仿UITabBarController的實現原理) 8.6設置標題欄出現一個bug,再次來到同一個界面,標題欄又被重新設置一次,怎麼解決? 只需要讓標題欄只載入一次就可以了 8.7設置標題欄,為什麼不能使用一次代碼? static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ <#code to be executed once#> }); 一次代碼是在整個工程中只會被調用一次,如果在這個工程中有兩個界面復用這個框架,那麼第二次復用這個框架的控制器設置不了標題欄 這樣框架就存在漏洞 8.8怎麼只讓代碼執行一次,還能夠復用? 在基類中定義一個BOOL類型的屬性,記錄該方法有沒有被執行 - (void)viewWillAppear:(BOOL)animated
{ [super viewWillAppear:animated]; if (_isInitial == NO) {
// 添加標題按鈕
[self setupAllTitleButton];
_isInitial = YES; } }