Based on MVVM, used to quickly set up the page settings, the framework of personal information page (attached: imitation WeChat iOS client discovery page, personal page, set the page Demo)

Write a little wheel

When writing UITableView, we often encounter is completely dependent on the network request, need to customize the dynamic cell needs (such as micro-blog post list). But at the same time, most of the app inside there is also a set of pages, personal pages and other static form based pages.

And these pages are more common:

  1. In most cases, you have all the data before you enter the page.
  2. Cell style single, custom cell appears relatively small probability (almost all of the height of 44 cell).
  3. Majority grouping.

Because I really want to write something out of an open source (can also expose their shortcomings, at the same time) is limited by the level, so I intend to write such a relatively simple framework and universal: a custom more suitable for use in personal pages and settings page UITableView.

In the real writing, read a few similar articles, pick out the three feel better:

  1. Clean Table View Code
  2. How to write a UITableView
  3. Using MVVM to design the rapid development of personal center, set up modules

After the summary, using last week 3 days free time writing this framework for its practicability, I modeled on the WeChat client discovery page, personal page settings page and write a Demo, see the effect of map:

Based on MVVM, used to quickly set up the page settings, the framework of personal information page (attached: imitation WeChat iOS client discovery page, personal page, set the page Demo)
found | | personal information personal page page page | settings page

Resources used by the project are: GitHub:zhengwenming/WeChat
Demo address: GitHub: knightsj/SJStaticTableView

In order to reflect the customization of the framework, I also added two pages inside, the entrance in the settings page:

Based on MVVM, used to quickly set up the page settings, the framework of personal information page (attached: imitation WeChat iOS client discovery page, personal page, set the page Demo)
packet | with customized set of custom

Do not tangle with the specific meaning of group customization and the same group, in the back of the time I would like to specify the details. Now just let everyone see the effect.

After a general understanding of the function, start with a detailed introduction to the framework. The reason for this presentation is not how many people want to use, but to express my own ideas. If you feel bad, please criticize.

Before the official explanation, first introduce the basic directory:

  1. Technical points used.
  2. Function description.
  3. Usage method。
  4. Customization introduction.

1 technical points


The framework as a whole is relatively simple, mainly based on Apple’s UITableView components, in order to decouple and separation of responsibility, the main use of the following technical points:

  • MVVM: using the MVVM architecture, each line of “pure” data is handed over to a single ViewModel, which holds the data for each cell (row height, cell type, text width, picture height, etc.). And each section also corresponds to a ViewModel that holds the current section configuration data (title, header and footer height, etc.).
  • Light UIViewController: separate UITableViewDataSource and UIViewController, let alone a class to achieve the functions of UITableViewDataSource.
  • Block: use block to call the cell rendering method.
  • Classification: the use of classification to define each different cell rendering method.

Know the main technical points, to give you a detailed description of the framework of the function.

2 function introduction


This framework can be used to quickly set up the page, the personal information page can be static form page, the user only need to give the tableView DataSource element is an array of viewModel.

Although the layout of this type of page is still relatively simple, but there will still be several different situations (cell layout type), I am more common cell layout to do a package, the user can directly use.

When I define the type of these cell, roughly divided into two categories:

  1. The first is the style of the cell system, in most cases, the cell height is 44 cell; in the left there will be a picture of a label, or there is only one (but only rarely in the picture); the right of cell generally have a right arrow, and sometimes the arrow left may also have label, image, also can have two.
  2. The second category is the custom of the cell, it is not necessarily the height of 44, and the layout and style of the system is not the same as the cell, the user needs to add their own.

Based on these two categories, and then subdivided into several cases, can be viewed directly from the following figure:

Since it is the type of cell, then the type of enumeration needs to be defined in the cell viewModel inside:

Typedef NS_ENUM (NSInteger, SJStaticCellType) {/ / system style of various types of cell, has a good package, can be directly used for SJStaticCellTypeSystemLogout, cell SJStaticCellTypeSystemAccessoryNone / / / / log, right without any control SJStaticCellTypeSystemAccessorySwitch, / / is on the right side of the switch SJStaticCellTypeSystemAccessoryDisclosureIndicator, / / is on the right side of triangular arrow (arrow left there can be a image or a label, or two who are, according to the incoming parameters) need to use custom type cell / / SJStaticCellTypeMeAvatar / / add their own personal page, "I cell"};

To a figure intuitive experience:

Based on MVVM, used to quickly set up the page settings, the framework of personal information page (attached: imitation WeChat iOS client discovery page, personal page, set the page Demo)
supports cell type

Here are three things to say:

  1. Which in addition to a custom cell, other types of cell do not need to own layout, has been packaged well, only the incoming type and the corresponding data in cell ViewModel (text, pictures).
  2. Because the two controls (on the left side of the picture and text) is the existence of at least one and about the fixed order (always in the picture on the left), so the framework by developers need to display incoming left pictures and text, you can own the cell layout. Therefore, the main type of judgment on the right side of the cell.
  3. It is worth mentioning that, in “the right is an arrow” five types of sub branches actually belong to a type, only the incoming text and pictures, text and picture display order parameters (when this parameter only in the presence of pictures and text can effectively decide the layout).

After understanding the functionality of the framework, let’s take a look at how to use this framework:

3 use method


Start with the text to explain:

  1. Copy the SJStaticTableViewComponent folder to the project.
  2. The ViewController of the page to be developed inherits SJStaticTableViewController.
  3. In the new ViewController createDataSource method, the viewModel array to the controller dataSource attribute.
  4. According to different types of cell, call different cell rendering method.
  5. If you need to accept cell clicks, you need to implement the didSelectViewModel method.

May feel more abstract, I set the page to specify:

Take a look at the layout of the settings page:

Based on MVVM, used to quickly set up the page settings, the framework of personal information page (attached: imitation WeChat iOS client discovery page, personal page, set the page Demo)
settings page

Then we look at the ViewController code set:

- (void) viewDidLoad {[super viewDidLoad]; self.navigationItem.title = @ "Settings";} - (void) createDataSource [[SJStaticTableViewDataSource alloc] initWithViewModelsArray:[Factory settingPageData] {self.dataSource = configureBlock:^ (SJStaticTableViewCell *cell, SJStaticTableviewCellViewModel *viewModel) {switch (viewModel.staticCellType) {case} SJStaticCellTypeSystemAccessoryDisclosureIndicator: {[cell configureAccessoryDisclosureIndicatorCellWithViewModel:viewModel]; break; case SJStaticCellTypeSystemAccessorySwitch: {[cell configureAccessorySwitchCellWithViewModel:viewModel];} Break; case SJStaticCellTypeSystemLogout: {[cell configureLogoutTableViewCellWithViewModel:viewModel];} case {[cell break; SJStaticCellTypeSystemAccessoryNone: configureAccessoryNoneCellWithViewModel:viewModel]; break default: break;};}}];} - (void) didSelectViewModel: (SJStaticTableviewCellViewModel * viewModel) atIndexPath: (NSIndexPath * indexPath) {switch (viewModel.identifier) {case {6: NSLog (@ sign); [self showAlertWithMessage:@ "really want to quit? "Break case 8:";}; {NSLog (@ "clean cache");} case {break; 9: NSLog (@ "jump to the custom cell display page - block"); SJCustomCellsViewController *vc = [[SJCustomCellsViewController alloc] init]; [self.navigationController pushViewController:vc animated:YES]; break case {NSLog}; 10: (@ "jump to the custom cell display page - the same group"); SJCustomCellsOneSectionViewController *vc = [[SJCustomCellsOneSectionViewController alloc] init]; [self.navigationController pushViewController:vc animated:YES];} break default:; Break;}}

See here, you may have these questions:

  1. Where is the UITableViewDataSource method?
  2. How is the viewModel array set?
  3. How is the drawing method of cell distinguished?
  4. Where is the UITableViewDelegate method?

I will answer one by one, after reading the following answers, you can almost completely grasp the idea of the framework:

Where is the problem 1:UITableViewDataSource method?

I encapsulate a class of SJStaticTableViewDataSource specifically as a data source that requires the controller to give it an array of viewModel.

Take a look at its implementation file:

//SJStaticTableViewDataSource.m - (NSInteger) numberOfSectionsInTableView: (UITableView * tableView) {return self.viewModelsArray.count;} - (NSInteger) tableView: (UITableView *) tableView numberOfRowsInSection: (NSInteger section) {SJStaticTableviewSectionViewModel *vm = self.viewModelsArray[section]; return vm.cellViewModelsArray.count;} - (UITableViewCell *) tableView: (* UITableView) tableView cellForRowAtIndexPath: (NSIndexPath * indexPath) {/ / get section ViewModel SJStaticTableviewSectionViewModel *sectionViewModel = self.viewModelsArray[indexPath.section]; / / viewModel SJStaticTableviewCellViewModel *cellViewModel for cell = sectionViewModel.cellViewModelsArray[indexPath.row]; SJStaticTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellViewModel.cellID]; if (cell! = [[SJStaticTableViewCell) {cell} alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellViewModel.cellID]; self.cellConfigureBlock (cell, cellViewModel); return cell;} - (NSString *) tableView: (* UITableView) tableView titleForHeaderInSection: (NSInteger) section{SJStaticTableviewSectionViewModel *vm = self.viewModelsArray[section]; return vm.sectionHeaderTitle;} - (NSString * tableView: * (UITableView) tableView titleForFooterInSection: section (NSInteger)) {SJStaticTableviewSectionViewModel *vm = self.viewModelsArray[section]; return vm.sectionFooterTitle;}

Table cell and section are set up corresponding to the viewModel, for the packaging of its corresponding data:

Cell viewModel (roughly look, there is a detailed description of the back):

Typedef NS_ENUM (NSInteger, SJStaticCellType) {/ / system style of various types of cell, has a good package, can be directly used for SJStaticCellTypeSystemLogout, cell / log (packaged) SJStaticCellTypeSystemAccessoryNone / right without any control SJStaticCellTypeSystemAccessorySwitch, / / is on the right side of the switch SJStaticCellTypeSystemAccessoryDisclosureIndicator, / / is on the right side of triangular arrow (arrow left can have a image or a a label, or all two, according to the incoming parameters) need to use custom type cell / / SJStaticCellTypeMeAvatar / / add their own personal page, "I cell typedef"}; void (^SwitchValueChagedBlock (BOOL) IsOn; block @interface) SJStaticTableviewCellViewModel calls //switch switch: NSObject @property (nonatomic, assign) SJStaticCellType staticCellType; / / @property type (nonatomic, copy) NSString *cellID; //cell reuser identifier @property (nonatomic, assign) NSInteger identifier; / / cell / / for each difference, click on the default cell system =============== left =============== (nonatomic / / @property UIImage *leftImage, strong); / / on the left side of the image, according to the needs of the incoming @ property (nonatomic, assign) CGSize leftImageSize; / / left image the size of existing default settings (nonatomic @property, Co Py NSString *leftTitle //cell); the main title, according to the needs of the incoming @property (nonatomic, strong) UIColor *leftLabelTextColor cell label; / / the current group left in the color of the text @property (nonatomic, strong) UIFont *leftLabelTextFont; / / the font @property cell label in the left side of the current group (nonatomic, assign) CGFloat leftImageAndLabelGap; / / image and left the distance of label, there =============== system default default / cell right =============== / / @property (nonatomic, copy) NSString * indicatorLeftTitle; / / text right arrow on the left side, according to the needs of the incoming @property (nonatomic, strong) UIColor *indicatorLeftLabelTextColor; / / right The color of the text, there are default settings, you can also customize the @property (nonatomic, strong) UIFont *indicatorLeftLabelTextFont; / / on the right side of the text font, there are default settings, you can also customize the @property (nonatomic, strong) UIImage * indicatorLeftImage; / / the right arrow on the left side of the image, according to the needs of the incoming @property (nonatomic, assign) CGSize indicatorLeftImageSize; / / right a left image size, there are default settings, you can also customize the @property (nonatomic, assign, readonly) BOOL hasIndicatorImageAndLabel; / / right on the left side of the text and pointed whether image exist at the same time, through the internal calculation of @property (nonatomic, assign) only CGFloat indicatorLeftImageAndLabelGap; / / on the right side of the left. Side image and label distance, there is a default value of @property (nonatomic, assign) BOOL isImageFirst; / / right on the left side of the text and pointed image existing at the same time, whether the image is next to the arrow, the default is YES @property (nonatomic, copy) SwitchValueChagedBlock switchValueDidChangeBlock; / / call when the switch switch of the block / =============== length data =============== / / @property (nonatomic, assign) CGFloat cellHeight; //cell height, the default is 44, you can set the @property (nonatomic, assign) CGSize leftTitleLabelSize; / / left default Label size, incoming text after internal calculation @property (nonatomic, assign) CGSize indicatorLeftLabelSize; / / right Label size / / =============== custom cell data here =============== / / @property (nonatomic, strong) UIImage *avatarImage; @property (nonatomic, strong) UIImage *codeImage @property (nonatomic, copy); NSString *userName; @property (nonatomic, copy) NSString *userID;

Section viewModel (roughly look, there is a detailed description of the back):

@interface SJStaticTableviewSectionViewModel: NSObject @property (nonatomic, copy) NSString *sectionHeaderTitle; / / the section title @property NSString *sectionFooterTitle (nonatomic, copy); / / the title of section @property (nonatomic, strong) NSArray *cellViewModelsArray; / / the data source of section @property (nonatomic, assign) CGFloat sectionHeaderHeight; @property //header (nonatomic, height assign CGFloat sectionFooterHeight; @property) //footer height (nonatomic, assign) CGSize leftImageSize; / / cell left image the size of the current group of @property (nonatomic, strong) UIColor *leftLabelTextColor cell label; / / the current group left in the color of the text (@property nonatomic, strong UIFont *leftLabelTextFont); / / cell label in the current group left the font @property (nonatomic, assign) CGFloat leftImageAndLabelGap; / / the group left image and label distance, there is a default value of @property (nonatomic, strong) UIColor * indicatorLeftLabelTextColor; / / cell label on the right side of the current group of text color @property (nonatomic, strong) UIFont *indicatorLeftLabelTextFont the current group of cell; / / label right in the font @property (nonatomic, assign) CGSize indicatorLeftImageSize; / / the group cell on the right size of image @property (nonatomic, assign) CGFloat indicatorLeftImageAndLabelGap; / / cell image and label on the right side of the current group of distance are the default - (instancetype) initWithCellViewModelsArray: (NSArray * cellViewModelsArray);

You may think that the property is too much, but the meaning of the existence of these attributes is for the customization of cell services, in the latter will be explained.

Now that I have a good package of data sources, cell viewModel, section viewModel, we look at the first two questions:

Question 2:viewModel array is how to set up?

Let’s take a look at the settings of the viewModel array for the page:

+ (NSArray *) settingPageData section 0 SJStaticTableviewCellViewModel ========== {/ / *vm0 = [[SJStaticTableviewCellViewModel alloc] init]; vm0.leftTitle = @ "account and security"; vm0.identifier = 0; vm0.indicatorLeftTitle = @ "protection"; vm0.indicatorLeftImage [UIImage imageNamed:@ = "ProfileLockOn"]; vm0.isImageFirst = NO; SJStaticTableviewSectionViewModel = *section0 [[SJStaticTableviewSectionViewModel alloc] initWithCellViewModelsArray:@[vm0]]; / / section 1 SJStaticTableviewCellViewModel ========== *vm1 alloc] init] = [[SJStaticTableviewCellViewModel; vm1.leftTitle = @ "new message"; vm1.identifier = 1; / / *vm7 = [[SJStaticTablev SJStaticTableviewCellViewModel switch added IewCellViewModel alloc] init]; vm7.leftTitle = @ night mode; vm7.switchValueDidChangeBlock = ^ (BOOL isON) {NSString *message = isON? @ @ "open night mode": "off night mode"; NSLog (@ "% @", message);}; vm7.staticCellType = SJStaticCellTypeSystemAccessorySwitch; vm7.identifier = 7; SJStaticTableviewCellViewModel = *vm8 [[SJStaticTableviewCellViewModel alloc] init]; vm8.leftTitle = @ "clean the cache"; vm8.indicatorLeftTitle = @ "12.3M"; vm8.identifier = 8; SJStaticTableviewCellViewModel = *vm2 [[SJStaticTableviewCellViewModel alloc] init]; vm2.leftTitle = @ "privacy"; vm2.identifier = 2; SJStaticTableviewCellViewModel = *vm3 [[SJStaticTableviewCellViewModel alloc] init]; Vm3.leftTitle = @ "generic"; vm3.identifier = 3; SJStaticTableviewSectionViewModel = *section1 [[SJStaticTableviewSectionViewModel alloc] initWithCellViewModelsArray:@[vm1, vm7, vm8, vm2, vm3]]; / / section 2 SJStaticTableviewCellViewModel *vm4 ========== = [[SJStaticTableviewCellViewModel alloc] init]; vm4.leftTitle = @ "help and feedback"; vm4.identifier = 4; SJStaticTableviewCellViewModel = *vm5 [[SJStaticTableviewCellViewModel alloc] init]; vm5.leftTitle = @ "about WeChat"; vm5.identifier = 5; SJStaticTableviewSectionViewModel = *section2 [[SJStaticTableviewSectionViewModel alloc] initWithCellViewModelsArray:@[vm4, vm5]] section 4 SJStaticTableviewCellViewModel ==========; / / *vm9 = [[S JStaticTableviewCellViewModel alloc] init]; vm9.leftTitle = @ "customized display page - cell group; vm9.identifier = 9; SJStaticTableviewCellViewModel = *vm10 [[SJStaticTableviewCellViewModel alloc] init]; vm10.leftTitle = @" custom cell display page - the same group; vm10.identifier = 10; SJStaticTableviewSectionViewModel = *section4 [[SJStaticTableviewSectionViewModel alloc] initWithCellViewModelsArray:@[vm9, vm10]] section 3 SJStaticTableviewCellViewModel *vm6; / / ========== = "SJStaticTableviewCellViewModel alloc] init]; vm6.staticCellType = SJStaticCellTypeSystemLogout; vm6.cellID = @" logout "; vm6.identifier = 6; SJStaticTableviewSectionViewModel = [[SJStaticTableviewSectionViewM *section3 Odel alloc] initWithCellViewModelsArray:@[vm6]]; return @[section0, Section1, section2, section4, section3];}

As we can see, the dataSource array is a two-dimensional array:

  • The first dimension is the section array, the element is each section corresponding to the viewModel:SJStaticTableviewSectionViewModel.
  • The second is the cell array, the element is each cell corresponding to the viewModel:SJStaticTableviewCellViewModel.

There are several SJStaticTableviewCellViewModel attributes that need to be emphasized:

  1. IsImageFirst: because there is a image and a label on the left side of the cell on the right side of the first group of the page, you need to set the order of the two. Because the default next to the arrow is the picture, so we need to reset it to NO, the role is to make label next to the arrow.
  2. Identifier: this property is an integer, it is used to mark each cell, for users to click on the cell to judge. I don’t associate with cell users click index, because sometimes because of demand we may change the order of the cell or delete a cell, so cell dependent index is not easy to make a mistake.
  3. CellID: this property is used for cell reuse. Because there are always individual cell layout is different: here there is a log out of cell, so we need cell from other open (cellID can not be set, a default value is used to mark the most commonly used cell type).

Obviously, the Factory class belongs to Model, it will be pure data to the dataSource two viewModel. This class is my own definition, the reader in the use of this framework can be defined according to the needs of their own.

Now that we know how to set the data source, let’s look at the three question:

How is the problem 3:cell drawing method distinguished?

All students will be found in the cellForRow: method in dataSource, I used the block method to draw cell.

Take a look at the definition of block:

Typedef void (^SJStaticCellConfigureBlock) (SJStaticTableViewCell *cell, SJStaticTableviewCellViewModel * viewModel);

The block callback in the controller, by judging the type of cell to draw different cell.

So how do different types of cell differentiate?
– I use the classification.

There is a classification, there must be a classified category: SJStaticTableViewCell

Look at the header file:

/ / all cell is the class classification of @interface SJStaticTableViewCell: UITableViewCell @property (nonatomic, strong) SJStaticTableviewCellViewModel *viewModel; / / =============== system cell style all controls =============== / / / / left part @ property (nonatomic, strong) UIImageView *leftImageView ImageView @property; / / left (nonatomic, strong) UILabel *leftTitleLabel; / / Label / / left the right part of the @property (nonatomic, strong) UIImageView *indicatorArrow; / / the arrow on the right @property (nonatomic, strong) UIImageView *indicatorLeftImageView; / / on the right side of the arrow on the left side of the ImageView @property UILabel *indicatorLeftLabel (nonatomic, strong); / / on the right side of the left arrow Label @property (nonatomic, strong) UISwitch *indicatorSwitch; / / @property switch on the right side of the arrow on the left side of the (nonatomic, strong) UILabel *logoutLabel; / / label / / =============== log user defined inside the cell control. ======= / / //MeViewController inside the picture cell @property (nonatomic, strong) UIImageView *avatarImageView @property (nonatomic, strong; UIImageView) *codeImageView; @property (nonatomic, strong) UIImageView * avatarIndicatorImageView; @property (nonatomic, strong) UILabel *userNameLabel (nonatomic, strong); @property UILabel *userIdLabel; / / unified layout, cell left part (title / picture + title), all system calls the cell style of the party Method - (void) layoutLeftPartSubViewsWithViewModel: (SJStaticTableviewCellViewModel *) viewModel; @end

Here I define all of the controls and a method for controlling the left side of the layout cell. Because almost all of the left side of the classification is almost the same, so extract it out.

So how many categories are there? (refer to the above cellViewModel header file enumeration type)

On the right / / cut the first cell (the most common) @interface SJStaticTableViewCell (AccessoryDisclosureIndicator) - (void) configureAccessoryDisclosureIndicatorCellWithViewModel: (SJStaticTableviewCellViewModel * viewModel); @end
There is no control cell @interface / SJStaticTableViewCell (AccessoryNone) - (void) configureAccessoryNoneCellWithViewModel: (SJStaticTableviewCellViewModel * viewModel); @end
The right side is the switch cell @interface / SJStaticTableViewCell (AccessorySwitch) - (void) configureAccessorySwitchCellWithViewModel: (SJStaticTableviewCellViewModel * viewModel); @end
Cell @interface SJStaticTableViewCell / log (Logout) - (void) configureLogoutTableViewCellWithViewModel: (SJStaticTableviewCellViewModel * viewModel); @end
/ / a custom cell (the first row in the personal page) @interface SJStaticTableViewCell (MeAvatar) - (void) configureMeAvatarTableViewCellWithViewModel: (SJStaticTableviewCellViewModel * viewModel); @end

When using this framework, if you do not meet the current needs of the situation, you can add their own classification.

Where is the problem 4:UITableViewDelegate method?

When it comes to UITableViewDelegate proxy methods, we are most familiar with the didSelectRowAtIndexPath.

But when I was writing this framework, I defined a proxy inherited from UITableViewDelegate: SJStaticTableViewDelegate, and added it to a proxy method:

@protocol SJStaticTableViewDelegate < UITableViewDelegate> @optional (void) didSelectViewModel: (SJStaticTableviewCellViewModel *) viewModel atIndexPath: (NSIndexPath *) indexPath; @end

This method returns the cell that corresponds to the current viewModel, weakening the role of indexPath.

Why did you do that?

Think about the original click cell proxy method: didSelectRowAtIndexPath. We click on this method, get the corresponding indexPath cell, and then through the indexPath, you can find the corresponding model in the data source (viewModel or model).

Therefore, I defined this method directly returned to the cell corresponding to the click of the viewModel, that is, to help users save a step. Of course, if you want to use the system can also use the original didSelectRowAtIndexPath: method.

Take a look at how this new proxy method is implemented:

//SJStaticTableView.m - (void) tableView: (UITableView * tableView) didSelectRowAtIndexPath: (NSIndexPath * indexPath) {[tableView deselectRowAtIndexPath:indexPath animated:YES]; if ((self.sjDelegate) & & [self.sjDelegate respondsToSelector:@selector (didSelectViewModel:atIndexPath:)] *cellViewModel) {SJStaticTableviewCellViewModel = [self.sjDataSource tableView:tableView cellViewModelAtIndexPath:indexPath]; [self.sjDelegate didSelectViewModel:cellViewModel atIndexPath:indexPath];}else if ((self.sjDelegate) & [self.sjDelegate respondsToSelector:@selector (tableView:didSelectRowAtIndexPath:; & tableView:tableView didSelectRowAtIndexPath:indexPath]])) {[self.sjDelegate}};

Now the reader should have a general understanding of the implementation of this framework, and now I would like to talk about the framework of customization.

4 customization


This framework has a configuration file: SJConst.h, which defines the framework of all the default data and the default configuration, such as cell lable on the left side of the left label and the font, color; image distance; right label font and color, the right picture of the default size etc.. Look at the code:

#ifndef SJConst_h #define SJConst_h //distance #define SJScreenWidth [UIScreen mainScreen].bounds.size.width #define SJScreenHeight [UIScreen mainScreen].bounds.size.height #define SJTopGap as bottom gap #define 8 //same SJLeftGap 12 //same as right gap define SJLeftMiddleGap //in left # 10 part: the gap between image and label #define SJRightMiddleGap right part: the gap 6 //in between image and label #define SJImgWidth width and height #define 30 //default SJTitleWidthLimit 180 //limt width of left and right labels //image #define SJIndicatorArrow @ //font #define "arrow" SJLeftTitleTextFont [UIFont systemFontOfSize:15] #define SJLogoutButtonFont [UIFont systemFontOfSize:16] #define SJIndicatorLeftTitleTextFont [UIFont systemFontOfSize:13] //color #define SJColorWithRGB (R, G, B, A) [UIColor colorWithRed:R/255.0 green:G/255.0 blue:B/255.0 alpha:A] #define SJLeftTitleTextColor [UIColor blackColor] #define SJIndicatorLeftTitleTextColor SJColorWithRGB (136136136,1) #endif SJConst_h / * * /

The default configuration defined here is used when cellViewModel and sectionViewModel are initialized:

ViewModel cell:

//SJStaticTableviewCellViewModel.m (instancetype init) {self = [super init]; if (self) {_cellHeight = 44; _cellID = @ "defaultCell"; _staticCellType = SJStaticCellTypeSystemAccessoryDisclosureIndicator; / / default is cell _isImageFirst triangular arrow = YES; / / is the default configuration of _leftLabelTextFont = SJLeftTitleTextFont; _leftLabelTextColor = SJLeftTitleTextColor; _leftImageSize = CGSizeMake (SJImgWidth, SJImgWidth); _leftImageAndLabelGap = SJLeftMiddleGap; _indicatorLeftLabelTextFont = SJIndicatorLeftTitleTextFont; _indicatorLeftLabelTextColor = SJIndicatorLeftTitleTextColor; _indicatorLeftImageSize = CGSizeMake (SJImgWidth, SJ ImgWidth); _indicatorLeftImageAndLabelGap = SJRightMiddleGap;} return self;}

ViewModel section:

- (instancetype) initWithCellViewModelsArray: (NSArray * cellViewModelsArray) {self = [super init]; if (self) {_sectionHeaderHeight = 10; _sectionFooterHeight = 10; _leftLabelTextFont = SJLeftTitleTextFont; _leftLabelTextColor = SJLeftTitleTextColor; _leftImageSize = CGSizeMake (SJImgWidth, SJImgWidth); _leftImageAndLabelGap = SJLeftMiddleGap; _indicatorLeftLabelTextFont = SJIndicatorLeftTitleTextFont; _indicatorLeftLabelTextColor = SJIndicatorLeftTitleTextColor; _indicatorLeftImageSize = CGSizeMake (SJImgWidth SJImgWidth); _indicatorLeftImageAndLabelGap = SJRightMiddleGap; _cellViewModelsArray = cellViewModelsArray;} return self; }

Obviously, there is only one set of default configurations, but there may be a setup page and a personal page in a app. The style of these two pages may not be the same, so the default configuration can only give one page, another page needs to be configured, so there is a custom function.

Let’s take a look at the diagram showing the effect of customization:

Based on MVVM, used to quickly set up the page settings, the framework of personal information page (attached: imitation WeChat iOS client discovery page, personal page, set the page Demo)
packet | with customized set of custom

Refer to this effect, we look at how the two pages of the data source is set:

Group page:

+ (NSArray * customCellsPageData) {/ / *vm1 = [[SJStaticTableviewCellViewModel alloc] SJStaticTableviewCellViewModel default configuration init]; vm1.leftImage [UIImage imageNamed:@ = "MoreGame"]; vm1.leftTitle = @ "all the default configuration for control"; vm1.indicatorLeftImage imageNamed:@ [UIImage = "wzry"]; vm1.indicatorLeftTitle = @ "king of glory!"; SJStaticTableviewSectionViewModel *section1 = [[SJStaticTableviewSectionViewModel alloc] initWithCellViewModelsArray:@[vm1]]; SJStaticTableviewCellViewModel *vm2 = [[SJStaticTableviewCellViewModel alloc] init]; vm2.leftImage [UIImage imageNamed:@ = "MoreGame"]; vm2.leftTitle = @ "left picture smaller"; vm2.indicatorLeftImage [UIImage imageNamed:@ = "wzry"]; vm2.ind IcatorLeftTitle = @ "king of glory!"; SJStaticTableviewSectionViewModel *section2 = [[SJStaticTableviewSectionViewModel alloc] initWithCellViewModelsArray:@[vm2]]; section2.leftImageSize = CGSizeMake (20, 20); SJStaticTableviewCellViewModel *vm3 = [[SJStaticTableviewCellViewModel alloc] init]; vm3.leftImage [UIImage imageNamed:@ = "MoreGame"]; vm3.leftTitle = @ "font smaller red"; vm3.indicatorLeftImage [UIImage imageNamed:@ = "wzry"]; vm3.indicatorLeftTitle = @ "the king of glory!"; SJStaticTableviewSectionViewModel *section3 = [[SJStaticTableviewSectionViewModel alloc] initWithCellViewModelsArray:@[vm3]]; section3.leftLabelTextFont [UIFont = systemFontOfSize:8]; section3.leftLabelTextColor = [UIColor redC Olor]; SJStaticTableviewCellViewModel *vm4 = [[SJStaticTableviewCellViewModel alloc] init]; vm4.leftImage [UIImage imageNamed:@ = "MoreGame"]; vm4.leftTitle = @ "left two control distance"; vm4.indicatorLeftImage [UIImage imageNamed:@ = "wzry"]; vm4.indicatorLeftTitle = @ "king of glory!"; SJStaticTableviewSectionViewModel *section4 = [[SJStaticTableviewSectionViewModel alloc] initWithCellViewModelsArray:@[vm4]]; section4.leftImageAndLabelGap = 20; SJStaticTableviewCellViewModel = [[SJStaticTableviewCellViewModel *vm5 alloc] init]; vm5.leftImage [UIImage imageNamed:@ = "MoreGame"]; vm5.leftTitle = @ "right images smaller"; vm5.indicatorLeftImage [UIImage imageNamed:@ = "wzry"]; vm5.indicatorL EftTitle = @ "king of glory!"; SJStaticTableviewSectionViewModel *section5 = [[SJStaticTableviewSectionViewModel alloc] initWithCellViewModelsArray:@[vm5]]; section5.indicatorLeftImageSize = CGSizeMake (15, 15); SJStaticTableviewCellViewModel *vm6= [[SJStaticTableviewCellViewModel alloc] init]; vm6.leftImage [UIImage imageNamed:@ = "MoreGame"]; vm6.leftTitle = @ "right fonts big blue"; vm6.indicatorLeftImage [UIImage imageNamed:@ = "wzry"]; vm6.indicatorLeftTitle = @ "the king of glory!"; SJStaticTableviewSectionViewModel *section6 = [[SJStaticTableviewSectionViewModel alloc] section6.indicatorLeftLabelTextFont = [UIFont initWithCellViewModelsArray:@[vm6]]; systemFontOfSize:18]; section6.indicatorLeftLab ElTextColor = [UIColor blueColor]; SJStaticTableviewCellViewModel *vm7= [[SJStaticTableviewCellViewModel alloc] init]; vm7.leftImage [UIImage imageNamed:@ = "MoreGame"]; vm7.leftTitle = @ "on the right side of the two control distance"; vm7.indicatorLeftImage [UIImage imageNamed:@ = "wzry"]; vm7.indicatorLeftTitle = @ "king of glory!"; SJStaticTableviewSectionViewModel *section7 = [[SJStaticTableviewSectionViewModel alloc] initWithCellViewModelsArray:@[vm7]]; section7.indicatorLeftImageAndLabelGap = 18; return @[section1 section2, Section3, section4, section5, section6, section7];}

As we can see, the custom code works on section’s viewModel.

Group page:

+ (NSArray * customCellsOneSectionPageData) {/ / *vm1 = [[SJStaticTableviewCellViewModel alloc] SJStaticTableviewCellViewModel default configuration init]; vm1.leftImage [UIImage imageNamed:@ = "MoreGame"]; vm1.leftTitle = @ "all the default configuration for control"; vm1.indicatorLeftImage imageNamed:@ [UIImage = "wzry"]; vm1.indicatorLeftTitle = @ "king of glory!"; SJStaticTableviewCellViewModel *vm2 = [[SJStaticTableviewCellViewModel alloc] init]; vm2.leftImage [UIImage imageNamed:@ = "MoreGame"]; vm2.leftTitle = @ "left picture smaller"; vm2.indicatorLeftImage [UIImage imageNamed:@ = "wzry"]; vm2.indicatorLeftTitle = @ "king of glory!"; vm2.leftImageSize = CGSizeMake (20, 20); SJStaticTableviewCellViewModel *vm 3 = [[SJStaticTableviewCellViewModel alloc] init]; vm3.leftImage [UIImage imageNamed:@ = "MoreGame"]; vm3.leftTitle = @ "font smaller red"; vm3.indicatorLeftImage [UIImage imageNamed:@ = "wzry"]; vm3.indicatorLeftTitle = @ "Wang Zherong Yao!"; vm3.leftLabelTextFont [UIFont = systemFontOfSize:8]; vm3.leftLabelTextColor = [UIColor redColor]; SJStaticTableviewCellViewModel *vm4 = [[SJStaticTableviewCellViewModel alloc] init]; vm4.leftImage = [UIImage imageNamed:@ "MoreGame"]; vm4.leftTitle = @ "left two control distance"; vm4.indicatorLeftImage [UIImage imageNamed:@ = "wzry"]; vm4.indicatorLeftTitle = @ "king of glory!"; vm4.leftImageAndLabelGap = 20; SJStaticTableviewCellViewModel = [[SJ *vm5 StaticTableviewCellViewModel alloc] init]; vm5.leftImage [UIImage imageNamed:@ = "MoreGame"]; vm5.leftTitle = @ "right images smaller"; vm5.indicatorLeftImage [UIImage imageNamed:@ = "wzry"]; vm5.indicatorLeftTitle = @ "king of glory!"; vm5.indicatorLeftImageSize = CGSizeMake (15, 15); SJStaticTableviewCellViewModel *vm6= [[SJStaticTableviewCellViewModel alloc] init]; vm6.leftImage [UIImage imageNamed:@ = "MoreGame"]; vm6.leftTitle = @ "right fonts big blue"; vm6.indicatorLeftImage [UIImage imageNamed:@ = "wzry"]; vm6.indicatorLeftTitle = @ "king of glory!"; vm6.indicatorLeftLabelTextFont [UIFont = systemFontOfSize:18]; vm6.indicatorLeftLabelTextColor = [UIColor blueColor]; SJStaticTableviewCe LlViewModel *vm7= [[SJStaticTableviewCellViewModel alloc] init]; vm7.leftImage [UIImage imageNamed:@ = "MoreGame"]; vm7.leftTitle = @ "on the right side of the two control distance"; vm7.indicatorLeftImage [UIImage imageNamed:@ = "wzry"]; vm7.indicatorLeftTitle = @ "king of glory!"; vm7.indicatorLeftImageAndLabelGap = 18; SJStaticTableviewSectionViewModel = *section1 [[SJStaticTableviewSectionViewModel alloc] initWithCellViewModelsArray:@[vm1, vm2, vm3, vm4, vm5 vm6, return, vm7]]; @[section1];}

In order to facilitate comparison, the same group of pages are customized and grouped. As we can see, custom code works on cell’s viewModel.

Why do you want to have the same group and group presentation?

The purpose of the same group and group presentation is to show the two kinds of customization of the framework.

  • The grouping page shows the section level of customization: the cell configuration task is assigned to the section layer of viewModel. Once set, all the section inside the cell can maintain this configuration.
  • The same page shows the cell level of customization: cell configuration tasks to the cell layer of viewModel. Once set, only the current cell has this configuration and does not affect other cell.

In fact, in order to save only the section layer in the viewModel configuration (if for each cell to set the same configuration is too elegant), because from the design perspective, relatively rare inside a section cell style inconsistencies (I think does not meet the design): for example, in a section it is unlikely to two cell inside the picture is not the same size, or font size is not the same.

Or look at the section class custom code:

To set up the group / / all cell left label font - (void) setLeftLabelTextFont: (UIFont * leftLabelTextFont) {if (_leftLabelTextFont! = leftLabelTextFont) {if ([self font1:_leftLabelTextFont hasSameFontSizeOfFont2:! LeftLabelTextFont]) {_leftLabelTextFont = leftLabelTextFont; / / if the new width is greater than the original width, need to re set, there is no need to [_cellViewModelsArray enumerateObjectsUsingBlock:^ (SJStaticTableviewCellViewModel * viewModel, NSUInteger * _Nonnull IDX, BOOL stop) {viewModel.leftLabelTextFont = _leftLabelTextFont; CGSize = size [self sizeForTitle:viewModel.leftTitle withFont:_leftLabelTextFont] if (size.width; > viewModel.leftTitleLabelSize.width) {viewModel.leftTitleLabelSize = size;}}}} / /}]; to set up the group of all cell label on the left side of the color - (void) setLeftLabelTextColor: (UIColor * leftLabelTextColor) {if ([self! Color1:_leftLabelTextColor hasTheSameRGBAOfColor2:leftLabelTextColor]) {_leftLabelTextColor = leftLabelTextColor; [_cellViewModelsArray makeObjectsPerformSelector:@selector withObject:_leftLabelTextColor] (setLeftLabelTextColor:);}} / / re the setting up of the group of all cell inside the left picture size - (void) setLeftImageSize: (CGSize leftImageSize) {SJStaticTableviewCellViewModel *viewMoel = _cellViewModelsArray.firstObject; CGFloat cellHeight = viewMoel.cellHeight; if ((! CGSizeEqualToSize (_leftImageSize, leftImageSize) & (leftImageSize.height); & < cellHeight)) {_leftImageSize = leftImageSize; [_cellViewModelsArray enumerateObjectsUsingBlock:^ (SJStaticTableviewCellViewModel *viewModel, NSUInteger IDX, BOOL * _Nonnull stop) {viewMoel.leftImageSize = _leftImageSize;}]}};

Because each section hold it all inside the cell viewModel, so in the set method, if found in the configuration and the current configuration is not the same, you need to update all the attributes corresponding to the viewModel of the cell.

Since section ViewModel can do this, why should there be a cell layer configuration?

– just to improve the degree of freedom of the configuration, in case of a sudden need to need a cell unique? (you should know I said do you mean God ^ ^)

Cell of the viewModel attribute of the set method and the realization of the section, it is not on the code.

Well, here to talk about the same, although the amount of code is not much, but it is clear that it takes time to think.

I hope that if you feel bad, you can give your valuable advice

This article has been synchronized to the personal blog: Portal


This article has been printed on the copyright, for reprint please visit the copyright print. Forty-eight million four hundred and twenty-two thousand nine hundred and twenty-eight

Obtain authorization