UITableView Division Expansion and CollectionOverview
Today, we teach you to use the section of UITableView to realize the effect of starting and collecting like QQ. In fact, the implementation is very simple, but still write an article to everyone to talk about ideas and the source code for the Novice reference.
Simple, but different people come to realize maybe there will be different ways of implementation, the simplicity of the same OH. In fact, and AppStore in the category of the effect of the page is quite similar, but people that is not the animation effect, but more beautiful animation!
Article content
After reading this article, you will learn:
- How to use the section of UITableView to realize the effect of unfolding and collecting
- How to re-use UITableView header view
- How to better solve cell multiplexing problems by using models that correspond to UI structure one by one
The words are not as good as a GIF, see the following effect:
Image Assumption
When you see this, what do you think? How to achieve it? Is there a ready-made one? Does the animation meet the needs? Is scalability enough?
If you are familiar with UITableView, then you should be able to easily think of the UITableView section, after the expansion is UITableView multiple cells.
Of course, if you do not use the UITableView section to implement, then you need to solve the problem of reuse, instead of trouble. Therefore, this article teaches you how to use UITableView to achieve.
Building a model
The hierarchy of the UI is the same as the structure of the model, which is most streamlined. First, we define the partitioning model, where each partition model represents a zone, and there can be many cells under the zone:
Partitioning model@interfaceHybsectionmodel:NSObject@property (Nonatomic,CopyNSString *sectiontitle;//is an expanded @property (nonatomic, Span class= "Hljs-keyword" >assign) bool isexpanded; There can be a number of cell-corresponding models nonatomic, strong) nsmutablearray *cellmodels; @end //each cell corresponds to one such model@ Interface hybcellmodel: nsobject@ Property (nonatomic, copy) NSString *title; @end
It's very easy to use it when you build a hierarchical relationship between the model and the UI.
Custom Uitableviewheaderfooterview
We need to customize the uitableviewheaderfooterview here, so we need to subclass it. In fact, with the UITableViewCell of the sub-class is the same, there are similar properties, use is the same.
Maybe a lot of friends haven't seen anyone use this stuff. Yes, in project development, I have not seen anyone else using it, all directly customizing a uiview. This is not a no-no, but it cannot be linked to uitableview reuse.
We customize the Hybheaderview, then the registration multiplexing Headerfooterview can be reused:
[self.tableView registerClass:[HYBHeaderView class] forHeaderFooterViewReuseIdentifier:kHeaderIdentifier];
First, we first subclass the Uitableviewheaderfooterview, we need to pass Hybsectionmodel object come over, represent a partition header, through model rewrite setter method, automatic configuration data. Since we've added a simple animation to the expansion and unwinding, the external callback is required and we give a callback closure:
@class hybsectionmodel; typedef void (^hybheaderviewexpandcallback) (bool isexpanded); @interface hybheaderview: uitableviewheaderfooterview @property ( Nonatomic, strong) Hybsectionmodel *model; @property (nonatomic, copy) Hybheaderviewexpandcallback Expandcallback; @end
Someone might ask, why Hybsectionmodel use @class to declare, instead of directly introducing header files? In fact, in project development, I usually use @class in the header file declaration, and in the implementation file is really introduced, this can avoid the loop contains the problem of compiling errors.
Our implementation of the file content is relatively small, we have to rewrite the Setmodel method to configure the data. In my project development, almost all of this configuration data is used, unless a cell is shared in multiple places. If a cell is shared by multiple places, and the model has the same, and some are different, this requires a specific write API to differentiate. We are adding rotation animations through tranform, which is very simple to implement:
#import"HYBHeaderView.h"#import"HYBSectionModel.h"@interfaceHybheaderview ()@property (Nonatomic,Strong)Uiimageview *arrowimageview;@property (Nonatomic,Strong)UILabel *titlelabel;@end@implementationhybheaderview-(Instancetype) Initwithreuseidentifier: (NSString *) Reuseidentifier {if (Self = [Super Initwithreuseidentifier:reuseidentifier]) {CGFloat w = [UIScreen Mainscreen]. Bounds. Size. width;Self. Arrowimageview = [[Uiimageview Alloc] initwithimage:[UIImage imagenamed:@ "expanded"];Self. Arrowimageview. frame =CGRectMake (10, (44-8)/2,15,8); [Self. Contentview Addsubview:Self. Arrowimageview];UIButton *button = [UIButton Buttonwithtype:Uibuttontypecustom]; [Button AddTarget:Self action:@selector (Onexpand:) forControlEvents:UIControlEventTouchUpInside]; [Self. Contentview Addsubview:button]; button. frame =CGRectMake (0,0, W,44);Self. Titlelabel = [[UILabel Alloc] initWithFrame:CGRectMake (35,0,200,44)];Self. Titlelabel. TextColor = [Uicolor Whitecolor];Self. Titlelabel. backgroundcolor = [Uicolor Clearcolor]; [Self. Contentview Addsubview:Self. Titlelabel];Self. Contentview. backgroundcolor = [Uicolor Purplecolor];UIView *line = [[UIView Alloc] initWithFrame:CGRectMake (0,44-0.5, W,0.5)]; Line. backgroundcolor = [Uicolor Lightgraycolor]; [Self. Contentview Addsubview:line]; }ReturnSelf;} - (void) Setmodel: (Hybsectionmodel *) Model {if (_model! = model) {_model = model;}if (model. isexpanded) {Self. Arrowimageview. Transform =cgaffinetransformidentity; }else {Self. Arrowimageview. Transform =Cgaffinetransformmakerotation (M_PI); }Self. Titlelabel. Text = Model. Sectiontitle;} - (void) Onexpand: (UIButton *) Sender {Self. Model. isexpanded =!Self. Model. isexpanded; [UIView animatewithduration:0.25 animations:^{if (self.model.isExpanded) { Span class= "Hljs-keyword" >self.arrowimageview.transform = cgaffinetransformidentity;} else {self.arrowImageView< Span class= "hljs-variable" >.transform = cgaffinetransformmakerotation (M_PI);}]; if (self.expandCallback) { Span class= "Hljs-keyword" >self.expandcallback (self.model.isexpanded); }} @end
When we configure the data, we will also display the direction of the picture according to the isexpanded status, otherwise it will be returned to the original state after reuse.
Create a UITableView and configure the data source
First, we create the UITableView and register the cell, Headerview:
Self.tableview = [[UITableView Alloc]initWithFrame:Self.view.bounds]; [self.view addsubview: Self.tableview]; self.tableview.delegate = self; Self.tableView.dataSource = self;[ self.tableview registerclass:[ UITableViewCell class] Forcellreuseidentifier:kcellidentfier]; [self.tableview registerclass:[ Hybheaderview class] Forheaderfooterviewreuseidentifier:kheaderidentifier];
Then, initialize the data source:
- (Nsmutablearray *) Sectiondatasources {if (_sectiondatasources = =Nil) {_sectiondatasources = [[Nsmutablearray alloc] init];for (Nsuinteger i =0; I <20; ++i) {Hybsectionmodel *sectionmodel = [[Hybsectionmodel alloc] init]; Sectionmodel. isexpanded =no; Sectionmodel.sectiontitle = [ nsstring stringwithformat:@ "section:%ld", I]; nsmutablearray *itemarray = [[nsmutablearray alloc] init]; for (nsuinteger j = 0; J < 10; ++J) {Hybcellmodel *cellmodel = [[Hybcellmodel alloc] init]; Cellmodel.title = [nsstring stringwithformat:@ "marker: Section=%ld, row=%ld", I, j]; [ItemArray Addobject:cellmodel]; } sectionmodel.cellmodels = ItemArray; [_sectiondatasources Addobject:sectionmodel]; }} return _sectiondatasources;}
Tip: in development, I will use the rewrite getter method to create, including the UI is the same, for do not need to display immediately, the use of lazy loading.
Implement the Proxy method of UITableView
For us, the partition is the number of elements of the corresponding data source array, and the number of rows per section needs to be judged to be expanded or closed. When the expansion state is, it is the number of elements of the cellmodels array, otherwise it is 0.
We need to use Dequeuereusableheaderfooterviewwithidentifier:kheaderidentifier to get the Headerview for reuse:
#pragma mark-uitableviewdatasource-(Nsinteger) Numberofsectionsintableview: (UITableView *) TableView {ReturnSelf. sectiondatasources. Count;} - (Nsinteger) TableView: (UITableView *) TableView numberofrowsinsection: (Nsinteger) Section {Hybsectionmodel *sectionmodel =Self. Sectiondatasources[section];Return Sectionmodel. isexpanded? Sectionmodel. cellmodels. Count:0;} - (UITableViewCell *) TableView: (UITableView *) TableView Cellforrowatindexpath: (Nsindexpath *) Indexpath {UITableViewCell *cell = [TableView dequeuereusablecellwithidentifier:kcellidentfier Forindexpath:indexpath]; Hybsectionmodel *sectionmodel =Self. Sectiondatasources[indexpath. section]; Hybcellmodel *cellmodel = Sectionmodel. Cellmodels[indexpath. row]; Cell. Textlabel. Text = Cellmodel. title;return cell;} - (UIView *) TableView: (UITableView *) TableView viewforheaderinsection: (Nsinteger) Section {hybheaderview *view = [TableView dequeuereusableheaderfooterviewwithidentifier:kheaderidentifier ]; Hybsectionmodel *sectionmodel =Self. Sectiondatasources[section]; View. model = Sectionmodel; View.expandcallback = ^ (bool isexpanded) {[TableView Reloadsections:[nsindexset indexsetwithindex:section] WithRowAnimation:uitableviewrowanimationfade"; }; return view;} #pragma mark-uitableviewdelegate-(CGFloat) TableView :(uitableview *) TableView Heightforrowatindexpath: ( Nsindexpath *) Indexpath {return 44;} -(cgfloat) TableView: (uitableview *) TableView Heightforheaderinsection: (nsinteger) section {return 44;}
Tip: in the optimization of TableView, one of them is multiplexing cell, multiplexing header/footer view.
Tip: This article was reproduced in Http://www.jianshu.com/p/fc45624603f6
Uitable View's Unfolding