iOS開發高級分享 - iOS的可摺疊表視圖

導言

我曾經開發過一個iphone應用程序,它顯示了大量的輸入,這些輸入分爲不一樣的類別,在`UITableView`...若要更改其中一個輸入的值,用戶按下表視圖中的對應行,並在出現的單獨屏幕中更改該值。表視圖爲每一個類別有一個節,每一個節包含每一個輸入的表格單元格(行)。編程

問題是輸入的數量變得很是很是大,因此它沒有給用戶一個很是好的概述。從桌面滾動到底部甚至很乏味。數組

咱們決定用戶應該可以經過簡單地按下節的標題來摺疊和展開表中的部分(類別)。咱們要求實現這一目標的代碼應該是可重用的,而且要求對現有代碼進行儘量少的更改。緩存

另外,若是你想一塊兒進階,不妨添加一下交流羣[1012951431](),選擇加入一塊兒交流,一塊兒學習。期待你的加入!(進羣獲取本文源碼多線程

下面的屏幕截圖顯示了表視圖及其可摺疊部分的外觀:app

最高達到IOS 6                                       iOS 7+

         

實施

我認爲實現上述目標的最佳方法是建立 UITableView 類,命名爲 CollapsableTableView ...這確保了代碼是可重用的。若是操做正確,則不須要對 UITableView- 他們會像一個普通的人同樣處理桌子上的風景`UITableView`...惟一必要的更改是更改 UITableView 在西布文件到這個新的子類。,以確保客戶端能夠像普通用戶同樣使用表視圖。UITableView ,咱們必須嘗試容許徹底經過 UITableView 類,包括 UITableViewDelegate ,以及 UITableViewDataSource 協議。iphone

可摺疊表視圖必須以某種方式跟蹤哪些區段被摺疊(收縮)以及哪些部分被展開。可能最明顯的方法是維護一組已展開的節的索引,或者一個布爾數組,其中每一個索引的值指示對應的節是否展開。可是,若是咱們假設表視圖的客戶端能夠添加和刪除節(在咱們的場景中是這樣的),那麼節的索引將不會保持固定,所以處理索引充其量也是很麻煩的。所以,咱們必須爲節找到不一樣的標識符。爲此,咱們可使用章節的標題文本。固然,這假定節的標題文本惟一地標識該節,而且其標題文本保持不變,但考慮到必須堅持使用 UITableView 同窗們,這多是咱們能作的最好的了。這還假設客戶端實現了 tableView:titleForHeaderInSection: 的選擇器 UITableViewDelegate 全部表格單元格的協議。在咱們的項目中,狀況就是這樣。在使用代碼節中,咱們將解釋咱們的類是如何支持實現 tableView:viewForHeaderInSection: 選擇器。ide

爲了更容易地管理頭視圖,咱們建立了一個 UIViewController 類,命名爲 CollapsableTableViewHeaderViewController ...對於這門課,有兩個西布一號西布用於平面佈局的表,而用於具備分組佈局的表。此類包含視圖中可操做的全部標籤的`IB`出口。它存儲一個布爾值,指示區段是否摺疊。此視圖控制器類還確保它的視圖在用戶點擊它時通知咱們,以便 CollapsableTableView 才能採起必要的行動。佈局

下面是.h.的檔案 CollapsableTableViewHeaderViewController學習

#import <UIKit/UIKit.h>
#import "TapDelegate.h"
#import "CollapsableTableViewTapRecognizer.h"

@interface CollapsableTableViewHeaderViewController : UIViewController 
{
IBOutlet UILabel *collapsedIndicatorLabel,*titleLabel,*detailLabel;

CollapsableTableViewTapRecognizer* tapRecognizer;

BOOL viewWasSet;
id<TapDelegate> tapDelegate;

NSString* fullTitle;
BOOL isCollapsed;
}

@property (nonatomic, retain) NSString* fullTitle;
@property (nonatomic, readonly) UILabel* titleLabel;
@property (nonatomic, retain) NSString* titleText;
@property (nonatomic, readonly) UILabel* detailLabel;
@property (nonatomic, retain) NSString* detailText;
@property (nonatomic, assign) id<TapDelegate> tapDelegate;
@property (nonatomic, assign) BOOL isCollapsed;

@end

 collapsedIndicatorLabel 是否顯示「-」或「+」的小標籤,取決於區段是否摺疊。當 isCollapsed 的文本被更改。 collapsedIndicatorLabel 則相應地設置爲「-」或「+」。 titleLabel 是包含標題和 detailLabel 顯示標題右側的可選詳細文本。優化

下面是`TapDelegate`議定書:

#import <UIKit/UIKit.h>

@protocol TapDelegate

- (void) view:(UIView*) view tappedWithIdentifier:(NSString*) identifier;

@end

這個 view:tappedWithIdentifier: 當頭視圖被點擊時調用選擇器 CollapsableTableView 實現 TapDelegate 協議,使其可以摺疊或展開相應的報頭以響應此協議。調用選擇器時,將使用 view 參數的標頭的標題字符串。 identifier 參數,以便`CollapsableTableView`能夠進行查找,以肯定標題當前是否已摺疊,以及其當前節索引是什麼。

在該項目的第一個已發佈的實現中,該選擇器由 CollapsableTableViewHeaderViewController 對應的標題視圖。由於在該版本中, CollapsableTableView 存儲(並所以保留) CollapsableTableViewHeaderViewControllers 其全部章節。可是,爲了提升實現的內存效率--特別是對於具備多個節的表 --CollapsableTableView 因此它再也不這樣作了。所以,結果是 CollapsableTableViewHeaderViewController 在頭視圖出如今表中後不久,就會從內存中釋放報頭視圖(報頭)。UIView 只要它在表中可見,它仍然保留在內存中)。這意味着當頭視圖被點擊時,可能沒有。 CollapsableTableViewHeaderViewController 調用 TapDelegate 選擇器。

在咱們尋找這個問題的解決方案以前,讓咱們看看頭視圖的點擊是如何在 CollapsableTableViewHeaderViewController.m. 

- (void) setView:(UIView*) newView
{
if (viewWasSet)
{
[self.view removeGestureRecognizer:tapRecognizer];
[tapRecognizer release];
}
[super setView:newView];
tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self 
action:@selector(headerTapped)];
[self.view addGestureRecognizer:tapRecognizer];
viewWasSet = YES;
}

- (void) headerTapped
{
[tapDelegate viewTapped:self.view ofViewController:self];
}

因此咱們推翻了 setView: 方法 UIViewController 類以添加 UITapGestureRecognizerUIView 分配給 CollapsableTableViewHeaderViewController ...這,這個 UITapGestureRecognizer 的方法被配置爲調用 CollapsableTableViewHeaderViewController 每當頭視圖被點擊時。在新代碼中,此技術再也不起做用,由於 CollapsableTableViewHeaderViewController 將常常在用戶點擊頭時被解除分配。

這個問題的惟一解決方案多是最明顯的,就是配置 UITapGestureRecognizer 若要調用對象中的選擇器,當用戶單擊標頭視圖時,該對象將不會被釋放。該對象的一些選擇以下:

  •  CollapsableTableView
  •  UIView
  •  UITapGestureRecognizer

第二個選擇將不起做用,由於咱們沒法控制 UIView 傳遞到 setView: 方法來自(也就是說,咱們不能使用子類)。 UIView 爲了給它添加一個額外的方法,也許咱們能夠將傳入的內容包裝起來。 UIView 類的子類中的 UIView 咱們本身的,但咱們不要去那裏!)向 CollapsableTableView 是一個選項,儘管添加沒有參數的方法是不行的,由於 CollapsableTableView 不知道哪一個標題已被點擊。然而,在文件中 UITapGestureRecognizer ,咱們看到替代選擇器類型是一個選擇器,它接受 UITapGestureRecognizer 對象做爲參數。可是,咱們必須把 UITapGestureRecognizer 以添加存儲標題字符串的屬性。因此若是咱們必須把 UITapGestureRecognizer,使用第三個選項並配置 UITapGestureRecognizer 調用其內部的選擇器。這是在實現中採起的方法:咱們使用 UITapGestureRecognizer ,咱們稱之爲 CollapsableTableViewTapRecognizer ,定義以下:

#import <Foundation/Foundation.h>
#import "TapDelegate.h"

@interface CollapsableTableViewTapRecognizer : UITapGestureRecognizer
{
id<TapDelegate> tapDelegate;

NSString* fullTitle;
UIView* tappedView;
}

@property (nonatomic, assign) id<TapDelegate> tapDelegate;
@property (nonatomic, retain) NSString* fullTitle;
@property (nonatomic, assign) UIView* tappedView;

- (id) initWithTitle:(NSString*) theFullTitle andTappedView:(UIView*) 
theTappedView andTapDelegate:(id<TapDelegate>) theTapDelegate;

@end 

initWithTitle:andTappedView:andTapDelegate: 方法,CollapsableTableViewTapRecognizer 對象配置爲調用私有方法。headerTapped 當景物被點擊的時候。

- (void) headerTapped
{
[tapDelegate view:tappedView tappedWithIdentifier:fullTitle];
} 

讓咱們回到 CollapsableTableView 如今。當它從客戶端得到一個節的標題時,它須要可以進行一次查找,以查看標頭是否摺疊,以及標頭的節索引是什麼。爲此,咱們保持兩個獨立的 NSMutableDictionary 對象:將標題標題映射爲指示標頭是否摺疊的布爾值的對象,以及將標題標題映射爲整數(給定標頭節索引的整數)的對象。咱們還可使用一個字典在指定的索引上查找該節的標題(固然,每當客戶端從表中添加或刪除一個節時,就必須更新該字典)。

那麼,如何 CollapsableTableView 其實是塌陷和擴張部分?那麼,摺疊的部分只會有0行,因此即便客戶端將返回該節的正常行數, CollapsableTableView 將返回摺疊節的行數爲0,或由客戶端返回的擴展節的行數。這代表 CollapsableTableView 須要攔截對 tableView:numberOfRowsInSection: 方法。它還必須返回 CollapsableTableViewHeaderViewController 對於每一個部分,所以它還必須攔截對 tableView:viewForHeaderInSection: 方法。因此爲了 CollapsableTableView 爲了可以響應這兩個選擇器,它必須實現 UITableViewDelegateUITableViewDataSource 協議,並在運行時將其委託和數據源屬性設置爲.自己!可是,必須將對這些協議的選擇器的許多調用轉發給客戶端,所以 CollapsableTableView 存儲真實委託和數據源的引用,以便爲這些狀況提供參考。

- (void) setDelegate:(id <UITableViewDelegate>) newDelegate
{
[super setDelegate:self];
realDelegate = newDelegate;
}

- (void) setDataSource:(id <UITableViewDataSource>) newDataSource
{
[super setDataSource:self];
realDataSource = newDataSource;
}

的接口文件CollapsableTableView:

#import <Foundation/Foundation.h>
#import "TapDelegate.h"

#define COLLAPSED_INDICATOR_LABEL_TAG 36
#define BUSY_INDICATOR_TAG 37
@interface CollapsableTableView : 
UITableView <UITableViewDelegate,UITableViewDataSource,TapDelegate>
{
id<UITableViewDelegate> realDelegate;
id<UITableViewDataSource> realDataSource;
id<CollapsableTableViewDelegate> collapsableTableViewDelegate;

...
}

@property (nonatomic,assign) id<CollapsableTableViewDelegate> collapsableTableViewDelegate;
@property (nonatomic,retain) NSString* collapsedIndicator;
@property (nonatomic,retain) NSString* expandedIndicator;
@property (nonatomic,assign) BOOL showBusyIndicator;
@property (nonatomic,assign) BOOL sectionsInitiallyCollapsed;
@property (nonatomic,readonly) NSDictionary* headerTitleToIsCollapsedMap;

- (void) setIsCollapsed:(BOOL) isCollapsed forHeaderWithTitle:(NSString*) headerTitle;
- (void) setIsCollapsed:(BOOL) isCollapsed forHeaderWithTitle:(NSString*) 
headerTitle andView:(UIView*) headerView;
- (void) setIsCollapsed:(BOOL) isCollapsed forHeaderWithTitle:(NSString*) 
headerTitle withRowAnimation:(UITableViewRowAnimation) rowAnimation;
- (void) setIsCollapsed:(BOOL) isCollapsed forHeaderWithTitle:(NSString*) 
headerTitle andView:(UIView*) headerView 
withRowAnimation:(UITableViewRowAnimation) rowAnimation;

@end 

執行 CollapsableTableView 從討論到這一點,基本上都是這樣。下面的段落簡要解釋了該類的公共屬性和方法的用途。

這個 collapsableTableViewDelegate 屬性能夠設置爲實現 CollapsableTableViewDelegate 屬性,以便每當某個區段摺疊或展開時,以及當該對象完成摺疊或展開時,都會通知該對象。

默認摺疊和展開指示符(默認值分別爲「+」和「-」)可使用 collapsedIndicatorexpandedIndicator 財產。
這個 showBusyIndicator 屬性的默認值爲YES,若是設置,則會致使活動指示符視圖( SPINTER )(位於標頭視圖中的子視圖中具備由BUSY_INDICATOR_TAG)當摺疊或展開頁眉視圖的部分花費的時間超過0.5秒時,要在標題視圖上動畫。
這個 sectionsInitiallyCollapsed 屬性的默認值爲NO,並控制新的部分是否會首先被摺疊或不折疊。

這個 headerTitleToIsCollapsedMap 物業供應 NSDictionary 將標題的標題字符串映射到 NSNumber 對象,該對象包含指示標頭是否摺疊的布爾值。

這個 setIsCollapsed:forHeaderWithTitle: ...方法將用於以編程方式摺疊或展開區段。若是客戶端具備對 UIView 對於相應的標頭,它能夠調用包含 andView: 用那個`UIView`做爲參數。若是調用了另外兩個方法中的任何一個,則必須從新加載相應的部分(和頭視圖),而且動畫有時會比... andView: 使用方法。

使用「守則」

須要添加到 Xcode 項目以便使用 CollapsableTableView 類中的 CollapsableTableView 文件夾中的壓縮文件(下載源代碼).

另外,若是你想一塊兒進階,不妨添加一下交流羣[1012951431](),選擇加入一塊兒交流,一塊兒學習。期待你的加入!(進羣獲取本文源碼

 CollapsableTableView 徹底能夠像普通的 UITableView ,只要客戶端實現 tableView:titleForHeaderInSection: 選擇器(相對於 tableView:viewForHeaderInSection: )用於全部表單元格。惟一必要的更改是更改 UITableView 在西布到 CollapsableTableView ...要作到這一點,請打開西布文件,選擇 UITableView ,打開身份檢查器並鍵入「 CollapsableTableView 「」類「字段旁邊。

執行 CollapsableTableView 也容許使用 tableView:viewForHeaderInSection: ,但在這裏,它沒法訪問標頭的標題字符串,它一般用做標頭的標識符。相反,它使用字符串「標記%i」,其中%i是tag返回的視圖的屬性(若是tag爲0,但區段索引不是0,此數字默認爲 CollapsableTableView )。這意味着,若是客戶端返回某些單元格的視圖(而不是頭文本字符串),而且若是它能夠添加和刪除部分,則必須分配惟一的tag對應於每一個區段的視圖的編號。

若是客戶端返回某些單元格的視圖,則這些視圖能夠包含一個標籤,該標籤指示是否摺疊了標頭。簡單地設置tag屬性設置爲 COLLAPSED_INDICATOR_LABEL_TAG 中定義的 CollapsableTableView.h ...這個 CollapsableTableView 而後,每當區段摺疊或展開時,該標籤的文本將設置爲「+」或「-」(除非 collapsedIndicator或expandedIndicator 屬性已設置爲不一樣的字符串)。

的客戶端。CollapsableTableView 可能不知道它不適用於常規的 UITableView 但若是它知道 UITableViewCollapsableTableView ,它能夠將對象強制轉換爲後一種類型,並使用headerTitleToIsCollapsedMap屬性以肯定哪些區段已摺疊,而setIsCollapsed:forHeaderWithTitle: 方法以編程方式摺疊或展開區段。

正如在實施部分,CollapsableTableView 還容許將細節文本顯示在標題的右側。若要使用此功能,請在 tableView:titleForHeaderInSection: ,返回表單的字符串「Header Text\Details Text」。

 歷史

  •  2011/08/13
    •  初始版本
  •  2011/10/29
    •  在上一個版本中,在IOS 5中,標題的高度都是0。這個tableView:heightForHeaderInSection:選擇器如今找到適當的標題視圖,並直接詢問它的高度,這解決了問題。
    •  增長了對多行標頭的支持。若是numberOfLines屬性設置爲0,而且標頭的文本不適合一行,標籤將按須要將文本拆分紅多行,標頭視圖控制器將設置標籤和標頭視圖的高度,以便全部行都適合(這在setTitleText:選擇器CollapsableTableViewHeaderViewController.m)。能夠經過設置標籤的numberOfLines屬性設置爲最大行數。
    •  1 st.osama指出setIsCollapsed:forHeaderWithTitle:在顯式從新加載相應標頭的整個部分以後,選擇器纔有效果。這個已經修好了。
    •  當最後一節被摺疊並展開時,表視圖最多向下滾動到該節的第五行,這樣用戶就能夠看到出現了一些行。
  •  2011/11/05
    •  修正了iOS 4中出現的錯誤,致使純文本表格視圖的標題消失。
  •  2011/11/27
    •  CollapsableTableView被更改,使其再也不存儲全部的CollapsableTableViewHeaderViewController各部分的對象。此更改的目的是提升實現的內存效率,特別是對於有許多節的表。這是一個至關戲劇性的變化,但文章的相關部分已經更新。
    •  這個getHeaderTitleToIsCollapsedMap方法CollapsableTableView被只讀屬性替換。headerTitleToIsCollapsedMap.
    •  自定義頭視圖如今能夠包含一個具備魔力的標籤。tag值爲36(按常量定義)COLLAPSED_INDICATOR_LABEL_TAG在……裏面CollapsableTableView.h)當相應的標題摺疊或展開時,其文本將被更新爲「+」或「-」。
  •  2012/01/26
    •  根據阿拉斯加22的請求,除了initWithCoder:方法,CollapsableTableView如今也重寫了init, initWithFrame:,和initWithFrame:style:方法來執行必要的初始化。這是由於CollapsableTableView也能夠以編程方式構造,而不是由西布.
  •  2012/02/12
    •  正如magikcm在註釋中所建議的那樣,我已經實現了對展開節時行插入的優化。我是經過實施「不誠實的代理數據源」策略來作到這一點的。這個職位.
  •  2012/08/10
    •  之前,當表視圖須要知道標頭視圖的高度時,可摺疊表視圖實際上將建立該標頭,以肯定並返回其高度。當表視圖須要從新計算其總高度時,這會形成很大的延遲,由於在此過程當中會查詢全部標頭的高度。例如,當擴展或摺疊一個區段時,就會發生這種狀況。這一延誤在許多款次中尤其明顯。

可摺疊表視圖如今緩存全部標頭視圖的高度。這實際上消除了在摺疊或擴展區段時發生的過分延遲。

    • 美學改進:擴展部分的標題視圖的摺疊/擴展指示符如今顯示較長的破折號字符,而不是常規的短破折號字符。
  •  2012/11/14
    • 當區段爲空時,未顯示其摺疊/展開指示符。
    • 已摺疊和展開的指示符如今能夠經過collapsedIndicator和expandedIndicator.的性質CollapsableTableView.
  •  2012/12/23
    •  若是客戶端同時爲標題提供視圖和標題(經過實現tableView:viewForHeaderInSection:和tableView:titleForHeaderInSection:),則當爲該節返回的視圖未被選中時,視圖是首選的。nil.頁腳的處理方式相似。這種行爲與UITableView已實現。
    •  增長了對節頁腳的支持。
    •  修正了當最後一個部分不包含任何行而且被點擊時發生的崩潰。
    •  當區段摺疊或展開所需時間超過0.5秒時,活動指示符將出如今標頭視圖中。(嗚嗚!使用多線程進行用戶界面編程是很棘手的!)
    •  能夠經過設置showBusyIndicator屬性(默認爲打開)。若要在自定義標頭視圖中啓用此行爲,請添加UIActivityIndicatorView值爲BUSY_INDICATOR_TAG(定義爲CollapsableTableView.h如37).
    •  A CollapsableTableViewDelegate能夠分配給CollapsableTableView,這樣,每當某個區段開始摺疊或展開時,或當它完成摺疊或展開時,均可以通知委託。
    •  新財產sectionsInitiallyCollapsed的CollapsableTableView若是新區段最初是否摺疊,則控制。默認值是NO.
  •  2013/01/18
    •  修正了在scrollToRowAtIndexPath:…,或selectRowAtIndexPath:…,或deselectRowAtIndexPath:…在摺疊部分中的一行被調用。
    •  修正了上面提到的方法,以便在使用動畫=調用它們時YES,效果將是即時的(同步的)。
    •  修正了在摺疊和擴展部分時偶爾發生的崩潰。
    •  實現了刪除-行優化。因爲這一點,具備大量行的摺疊部分如今應該更快了。
    •  CollapsableTableView已與存儲板中的靜態單元格兼容。
  •  2013/02/10
    •  修正了雙擊大截面的頭部時發生的崩潰.
  • 2013/09/08
    •  修正了使用自定義標頭視圖時在IOS 6.1旋轉時發生的崩潰。
    •  啓用即時編程行-選擇或在區段展開上滾動行。
  •  2013/09/23
    • 修正了在將行添加到空部分後未顯示摺疊/展開指示符的錯誤。
  •  2013/10/26
    • 在iOS 7或更高版本上運行時,可摺疊表視圖如今使用單獨的XIB文件做爲表各節的頭和頁腳,以適應IOS 7的新外觀。

翻譯地址:https://www.codeproject.com/Articles/240435/Collapsable-Table-View-for-iOS

相關文章
相關標籤/搜索