iOS开发高级分享 – iOS的可折叠表视图
导言
我曾经开发过一个iphone应用程序,它显示了大量的输入,这些输入分为不同的类别,在UITableView…若要更改其中一个输入的值,客户按下表视图中的对应行,并在出现的单独屏幕中更改该值。表视图为每个类别有一个节,每个节包含每个输入的表格单元格(行)。
问题是输入的数量变得非常非常大,所以它没有给客户一个非常好的概述。从桌面滚动究竟部甚至很乏味。
我们决定客户应该能够通过简单地按下节的标题来折叠和开展表中的部分(类别)。我们要求实现这一目标的代码应该是可重用的,并且要求对现有代码进行尽可能少的更改。
另外,假如你想一起进阶,不妨增加一下交流群1012951431,选择加入一起交流,一起学习。期待你的加入!(进群获取本文源码)
下面的屏幕截图显示了表视图及其可折叠部分的外观:
最高达到IOS 6

iOS 7+

实施
我认为实现上述目标的最佳方法是创立UITableView类,命名为CollapsableTableView…这确保了代码是可重用的。假如操作正确,则不需要对UITableView-他们会像一个普通的人一样解决桌子上的风景UITableView…唯一必要的更改是更改UITableView在西布文件到这个新的子类。,以确保用户端可以像普通客户一样使用表视图。UITableView,我们必需尝试允许完全通过UITableView类,包括UITableViewDelegate,以及UITableViewDataSource协议。
可折叠表视图必需以某种方式跟踪哪些区段被折叠(收缩)以及哪些部分被开展。可能最显著的方法是维护一组已开展的节的索引,或者者一个布尔数组,其中每个索引的值指示对应的节能否开展。但是,假如我们假设表视图的用户端可以增加和删除节(在我们的场景中是这样的),那么节的索引将不会保持固定,因而解决索引充其量也是很麻烦的。因而,我们必需为节找到不同的标识符。为此,我们可以使用章节的标题文本。当然,这假定节的标题文本唯一地标识该节,并且其标题文本保持不变,但考虑到必需坚持使用UITableView同学们,这可能是我们能做的最好的了。这还假设用户端实现了tableView:titleForHeaderInSection:的选择器UITableViewDelegate所有表格单元格的协议。在我们的项目中,情况就是这样。在使用代码节中,我们将解释我们的类是如何支持实现tableView:viewForHeaderInSection:选择器。
为了更容易地管理头视图,我们创立了一个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;@endcollapsedIndicatorLabel能否显示“-”或者“+”的小标签,取决于区段能否折叠。当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类以增加UITapGestureRecognizer到UIView分配给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为了能够响应这两个选择器,它必需实现UITableViewDelegate而UITableViewDataSource协议,并在运行时将其委托和数据源属性设置为.本身!但是,必需将对这些协议的选择器的许多调用转发给用户端,因而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属性,以便每当某个区段折叠或者开展时,以及当该对象完成折叠或者开展时,都会通知该对象。
默认折叠和开展指示符(默认值分别为“+”和“-”)可以使用collapsedIndicator和expandedIndicator财产。
这个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但假如它知道UITableView是CollapsableTableView,它可以将对象强制转换为后一种类型,并使用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已实现。
- 假如用户端同时为标题提供视图和标题(通过实现tableView:viewForHeaderInSection:和tableView:titleForHeaderInSection:),则当为该节返回的视图未被选中时,视图是首选的。nil.
- 添加了对节页脚的支持。
- 修正了当最后一个部分不包含任何行并且被点击时发生的崩溃。
- 当区段折叠或者开展所需时间超过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
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » iOS开发高级分享 – iOS的可折叠表视图