ZZFLEX is an iOS agile development framework developed based on UIKit/Foundation. It contains a chain API extension for common controls and a command list controller. It uses a “modular” design concept and aims to greatly reduce the difficulty and workload of UI development and maintenance.
How to use
1, direct import (experience DEMO) :
Making: github.com/tbl00c/ZZFL…
2. CocoaPods mode:
pod 'ZZFLEX'
Function module
I. Expansion of Foundation
There are NSMutableAttributedString and NSMutableParagraphStyle chain API, using method is as follows:
/// Create style NSMutableParagraphStyle *style = NSMutableParagraphStyle.zz_create.lineSpacing(5).paragraphSpacing(20).alignment(NSTextAlignmentCenter).lineBreakMode(NSL ineBreakByWordWrapping).object; Zz_setup.headindent (20).tailindent (20); / / / to create rich text NSMutableAttributedString * attrStr = NSMutableAttributedString zz_create (@ "rich text string"). The backgroundColor ([UIColor redColor]).font([UIFont systemFontOfSize:32]).foregroundColor([UIColor redColor]).object; /// Edit rich text (concatenating pictures, strings, rich text, etc.) attrstr.zz_setup.paragraphstyle (style).appendString(@" concatenating string ").appenDimage ([UIImage ImageNamed :@" name of image to concatenate.png "], CGRectMake(0, 0, 20, 20)); Zz_setup. fontWithRange([UIFont boldSystemFontOfSize:12], NSMakeRange(0, 10)).foregroundColorWithRange([UIColor blueColor], NSMakeRange(0, 10));Copy the code
2. UIKit common control extension
2.1 View control chain API expansion:
UIView+ZZFLEX extends the chain API for common UIKit controls. After introducing it, we can directly addButton, addLabel, addImageView, etc. The link API enables you to set the properties of the control, arrange the layout of the navigation and handle events coherently and quickly.
Take adding a button to a view as an example:
UIButton *button = self.view.addButton(1).title(@"Hello").titlehl (@"world") TitleFont ([UIFont systemFontOfSize:12]).titlecolor ([UIColor blackColor]).titlecolorhl ([UIColor blackColor]) redColor]).titleColorDisabled([UIColor grayColor]) .backgroundColor([UIColor whiteColor]).backgroundColorHL([UIColor CornerRadius (5.0f).shadow(CGSizeZero, 5.0f, [UIColor grayColor], EventTouchDown (^ (UIButton *sender) {NSLog(@"touch down"); }) .eventTouchUpInside(^ (UIButton *sender) { NSLog(@"touch inside"); }) // set constraint (navigation). ^ (UIButton *sender, MASConstraintMaker *make) {make.clip.top.mas_equalto (0); make.size.mas_equalTo(CGSizeMake(80, 30)); }) .view;Copy the code
As you can see, the chained API is very concise and efficient, greatly reducing the number of lines of code while improving the readability of the code. It makes the code logic of the same control centralized, which is called “control modularization”.
UIView+ZZFLEX is implemented using the objective-C generic *** to set control properties in any order, regardless of inheritance.
To edit a property of a control, write:
button.zz_setup.title(@"hello").titleFont([UIFont boldSystemFontOfSize:32]);
Copy the code
If you want to create a separate control, do not add it to the view:
UIButton *button = UIButton.zz_create(2).title(@"world").titleFont([UIFont boldSystemFontOfSize:32]).view;
Copy the code
Currently, UIView+ZZFLEX has added the chain API:
UIView
, UIImageView
, UILabel
, UIControl
, UITextField
, UIButton
, UISwitch
, UIScrollView
, UITextView
, UITableView
, UICollectionView
2.2 API expansion of secant line and rounded corner chain
/* addSeparatorz type: support top, bottom, left, right, centerX, centerY, a view can run multiple addSeparatorz beginAt: start position offset, default 0 endAt: end position offset, default 0; You can also set the length property instead of offset: With type offset, Separator(ZZSeparatorPositionTop).color([UIColor) grayColor]).beginAt(15).endAt(-15).offset(-10); self.view.removeSeparator(ZZSeparatorPositionTop); /* Set rounded cornor: Supports topLeft, topRight, bottomLeft, bottomRight, top, bottom, left, right, all, Support logic or * / self. View. SetCornor (ZZCornerPositionLeft | ZZCornerPositionTop). The radius (5.0 f), color ([UIColor grayColor]).borderWidth(1); self.view.removeCornor();Copy the code
Imperative list controller · ZZFLEXAngel
ZZFLEXAngel is a list page controller that supports both UITableView and UICollectionView, greatly reducing the difficulty of implementing and maintaining complex list interfaces.
3.1 Initializing Angel
Its initialization principle is to point the dataSource and delegate of tableView/collectionView(collectively called hostView) to Angel, and Angel will weakly reference hostView. The code is as follows:
// tableView
UITableView *tableView = self.view.addTableView(0).view;
ZZFLEXAngel *angel = [[ZZFLEXAngel alloc] initWithHostView:tableView];
// collectionView
UICollectionView *collectionView = self.view.addCollectionView(1).view;
ZZFLEXAngel *angel2 = [[ZZFLEXAngel alloc] initWithHostView:collectionView];
Copy the code
3.2 Page Container Layer (hostView)
With her, we usually have little to no concern for and implementation of hostView’s various proxy methods. Her design makes the construction of the list page like a jigsaw puzzle, just need to add the required modules one by one, we want to draw the interface, the code is as follows
- (void)reloadListUI {// Clear all data self.clear(); // Add section 1 {// Section identifies NSInteger sectionTag = 1; /* * Add section * sectionInsets: Section margin * minimumLineSpacing: Row Spacing * minimumInteritemSpacing: */ self.angel.addSection(sectionTag).sectionInsets(UIEdgeInsetsMake(15, 15, 15, 15)).minimumLineSpacing(15).minimumInteritemSpacing(15); Self.angel.setheader ([UICollectionReusableView class]).toSection(sectionTag); /* * Add cell * withDataModel: Cell data model * selectedAction: cell click event * eventAction: EventType is the eventType, model is the event data * viewTag: Cell identification, easy debugging, */ self.angel.addCell([UICollectionViewCell Class]).toSection(sectionTag).withDatamodel (@"hello") .selectedAction(^ (id model) {NSLog(@"cell click event "); }). EventAction (^ id(NSInteger eventType, id model) {NSLog(@"cell internal event, type: %ld, model: %@", eventType, model); return nil; }) .viewTag(10001); /* * Add cell to section * withDataModelArray: cell model array, the number of cells is determined by the number of elements in the array * delegate: AddCells ([UICollectionViewCell Class]).toSection(sectionTag).withDatamodelArray (@[@"1", @"2", @"3"]).selectedAction(^ (id model) {NSLog(@"cell click event, data model: %@", model); }).delegate(self); } // Refresh data [self.angel reloadView]; }Copy the code
In ZZFLEXAngel, instead of using sectionIndex/indexPath to locate sections/cells, we use more unique sectionTag/viewTag instead (if necessary). Because the former is inherently a very indeterminable data, it changes as the interface changes, and many crashes related to tableView/collectionView are also related to this.
P.S. ZZFLEXAngel simply manipulates and organizes the list data source; interface updates call the reload method of the list.
3.3 elements layer
Unlike before, all added to the cell, the header and footer need extra implementation of ZZFLEXAngel a deal – ZZFlexibleLayoutViewProtocol used to interact with Angel:
/** * All views/cells with ZZFLEXAngel or ZZFLEX ViewController must implement this protocol ** The rest can be on-demand choose to implement * / @ protocol ZZFlexibleLayoutViewProtocol < NSObject > @ optional; /** * Get the size of the cell/view, and the viewHeightByDataModel option Added to ZZFlexibleLayoutViewController or ZZFLEXAngel, such as implementation only call once, the size will be cached in the ViewModel. * Others: To update the view size, call the update method manually. 0 to -1 indicates the scale, such as sie.width =-0.5, indicating that the width of the view is 50% of the list width */ + (CGSize)viewSizeByDataModel:(id)dataModel; /** * Get the height of the cell/view, and select ** from the viewSizeByDataModel. Added to the ZZFlexibleLayoutViewController or ZZFLEXAngel, such as implementation calls only once, height will be cached in the ViewModel. * Others: To update the height of the view, call the Update method manually. This method can also be used for CollectionView. The default width is -1, i.e. the list width */ + (CGFloat)viewHeightByDataModel:(id)dataModel; /** * Set cell/view data source ** call timing: cellForRowAtIndexPath or cellForItemAtIndexPath Return */ - (void)setViewDataModel:(id)dataModel; /** * Set the delegate object of the cell/view ** call time: CellForRowAtIndexPath or cellForItemAtIndexPath, as the implementation calls */ - (void)setViewDelegate:(id)delegate; /** * Set cell/view actionBlock ** call timing: CellForRowAtIndexPath or cellForItemAtIndexPath, */ - (void)setViewEventAction:(id (^)(NSInteger actionType, id data))eventAction; /** * The current view's indexPath, the number of elements in the section (currently only called by cell) ** When to call: cellForRowAtIndexPath or cellForItemAtIndexPath IndexPath can be used for UI differentiation Settings, etc. It is not recommended that cells hold indexPath. Because may often become * / - (void) onViewPositionUpdatedWithIndexPath: (NSIndexPath *) indexPath sectionItemCount (NSInteger) count; @endCopy the code
Cell/View implements this protocol for two purposes and benefits:
1. The framework layer can process the interaction between collectionView and cell/header/footer uniformly;
2, convenient for overall performance optimization, such as caching view/header/footter calculation method data.
3.4 inheritance ZZFLEXAngel
If the API provided by ZZFLEXAngel is not enough to use or the container layer logic is complex, you can inherit ZZFLEXAngel to implement your own Angel, and you can directly reconstruct/implement the proxy method of hostView in the subclass. If there is super, remember to call super, otherwise the chain API may fail.
3.5 Other list control apis
- (void)reloadListUI {// Clear all data self.clear(); // advanced usage {NSInteger sectionTag = 2; self.angel.addSection(sectionTag); /* * Add cell * configAction to section: Cell manually configure methods (section method, call time cellForRowAtIndexPath or cellForItemAtIndexPath) * viewSize: AddCell ([UICollectionViewCell Class]).toSection(sectionTag).configAction(^) (UICollectionViewCell *cell, id model){NSLog(@" custom config method "); [cell setBackgrounColor:[UIColor redColor]]; }) .viewSize(CGSizeMake(100, 100)); } self.sectionForTag(1).sectionInsets(UIEdgeInsetsMake(10, 0, 0, UIEdgeInsetsMake(10, 0, 0, UIEdgeInsetsMake(10, 0, 0) 0)).minimumInteritemSpacing(10); InsertCell ([UICollectionViewCell Class]).toSection(1).beforecell (10001); self.angel.insertCell([UICollectionViewCell class]).toSection(1).afterCell(10001); self.angel.insertCells([UICollectionViewCell class]).toSection(1).toIndex(0).withDataModelArray(@[@"1", @"2"]); / / remove the cell self. Angel. DeleteCell. ByViewTag (10001); self.angel.deleteCell.byDataModel(@"1"); / / update the cell, often used to trigger cell height to recalculate (the default height calculation only once, after using a cache) self. Angel. The updateCell. ByViewTag (10001); // Section operation, items means cell+header+footer self.angel.sectionFortag (1).clearCells(); self.angel.sectionForTag(1).clearItems(); NSMutableArray *data = self.sectionForTag(1).dataModelArray; NSInteget sectionIndex = self.angel.sectionForTag(1).index; NSArray *sectionDataModelArry = self.angel.sectionForTag(sectionType).dataModelArray; } // Refresh data [self.angel reloadView]; }Copy the code
3.6 Other Applications
- Cell template library: ZZFLEXAngel modularizes cells so that some common cells can be extracted as common templates.
- Dynamic page: Deliver the page configuration file together with the service cell template.
ZZFLEXAngel currently supports the following functions:
add | insert | To obtain | Batch add | Bulk insert | Batch to obtain | The editor | delete | Empty data | Update the height | |
---|---|---|---|---|---|---|---|---|---|---|
section | ✔ ️ | ✔ ️ | ✔ ️ | ✔ ️ | ✔ ️ | ✔ ️ | ✔ ️ | |||
cell | ✔ ️ | ✔ ️ | ✔ ️ | ✔ ️ | ✔ ️ | ✔ ️ | ✔ ️ | ✔ ️ | ||
header/footer | ✔ ️ | ✔ ️ | ✔ ️ | ✔ ️ |
Four, ZZFLEXTableViewController and ZZFLEXCollectionViewController
ZZFLEXTableViewViewController level based on the UITableView and ZZFLEXAngel VC implementation;
ZZFLEXCollectionViewController level based on UICollectionView and ZZFLEXAngel VC implementation;
Direct inheritance is used to quickly build list pages.
Methods in the tableView proxy or collectionView proxy can be directly refactored in vc subclasses, remember to call super (if present), otherwise the chain API may fail.
Fifth, ZZFLEXRequestQueue
Some complex pages may have multiple asynchronous data requests (NET, DB, etc.). However, when asynchronous requests are made at the same time, the return order of the results is uncertain, which leads to the uncertainty of the UI display order, which is not desirable in many cases.
The core idea of ZZFLEXRequestQueue is to “encapsulate the process of a data request as an object”, which ensures that the DISPLAY UI is loaded in queue order in this business scenario.
As shown in the Demo.
Automatic code generation
ZZUIHelpler already supports automatic generation of ZZFLEX code
See github.com/tbl00c/ZZUI…