“This is my 35th day of participating in the First Challenge 2022. For more details: First Challenge 2022.”

The introduction

In iOS development, a common way to do tabular data presentation is to use UITableView.

I UITableViewCell introduction

1.1 Cell Structure

Each row of a UITableView is a UITableView cell

  1. Cell initialization: Initialize each row via datasource’s tableView: cellForRowAtIndexPath: method
  2. UITableViewCell has a default ContentView inside it:

ContentView is the parent view of what the UITableViewCell displays, and can display secondary views (secondary views are used to display an action icon); By default, contentView has 3 subviews (textLabel, detailTextLabel, UIImageView). Used to determine which subviews of the contentView to use and the position of the view within the contentView. 4. Cell structure

1.2 Principles of Cell Reuse

  1. Reuse principle

When scrolling through the list, some cells are moved out of the window, and UITableView puts cells outside the window into a pool of objects waiting to be reused. When the UITableView asks the datasource to return a cell, the datasource first checks to see if there are any unused cells in the object pool. If there are any, the datasource configures the cell with the new data and returns it to the UITableView. To avoid creating new objects. When initializing the cell, pass in a specific “string identifier” (usually using the class name of the cell) to assign a value to the reuseIdentifier attribute of the cell. When UITableView asks its datasource to return a cell, it uses the reuseIdentifier attribute to find the corresponding type of cell object in the object word. Otherwise use the reuseIdentifier property to instantiate a cell object.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 1. Define a cell identifier
      static NSString *ID = @"mjcell";
     
    // 2. Remove the cell from the cache pool
      UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
     
    // 3. If no cell exists in the cache pool
      if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
    }
     
    // 4. Set cell properties...
    return cell;
}
Copy the code
  1. Cells refer to concepts in a loop

II Use xiB to encapsulate a View step

  1. New A XIB file that describes the internal structure of a View
  2. New A custom view class (inherited from the class of the xiB root object). The class name is usually the same as the XIB file name
  3. Connect the control in xiB to the.m file of the custom view class (before connecting, specify the class of the root object as the newly created control -> Specify the reusable identifier in the XI B properties panel
  4. Provide a class method that returns a custom view class that has been created (masking the loading from the XIB)

5. Provide a model property to pass model data, override setter methods for model property (display model data on corresponding child controls)

III delegate

The parent control (view controller) listens for the child control’s events and tells it to work when something happens to the child control.

If a strong reference is used, it creates a loop of strong references -> the son can only weakly reference the father.

@property (nonatomic.weak) id<HSGroupBuyingFooterViewDelegate> delegate;// In oc, only if there is no strong use, will be immediately released; Once a custom view is called a view controller, and the custom view is the child of the view controller, and the view controller is the proxy of the custom view, then if the proxy is a strong reference, it will cause a loop of strong references, "you have me, I have you". -- Stay in memory forever
Copy the code

3.1 Usage situations of delegate

  1. Object A wants to notify object B of something happening inside, and object A wants to pass data to object B
  2. What is going on inside object A that object B wants to listen for
  3. Object A wants to call some methods of object B from within its own methods, and object A cannot have coupling dependencies on object B

3.2 Steps to use a delegate

  1. Figure out who’s delegate to whom
  2. Define the proxy protocol (protocol name naming convention: control class name +Delegate)
  3. Define proxy methods:

* Proxy methods are generally defined as optional * proxy method names begin with space names; Proxy methods take at least one argument, which is used to pass control capabilities 4. Set proxy objects (proxy objects comply with the protocol and implement protocol methods) 5. Call delegate’s protocol methods at the appropriate moment to inform the delegate of what is happening (determine if the proxy implements the delegate method before calling).

IV Customizes cells through code

  1. New a class that inherits from UITableViewCell
  2. Overrides initWithStyle: reuseIndentifier: method (a one-time assignment of attributes to child controls)

Some properties only need to be set once, such as font, fixed image 3. Add child controls to contentView to display 4. Data model and frame model data model is used to store text and picture data. Frame model Stores data model, frames of all child controls, and height of cell 5. Cell has a frame model 6. Override setter method of frame model (set child control display number frame); The frame object is instantiated using the lazy loading method, which overrides the getter method

//
 
// HSStatusCell.h
 
 
 
 
#import <UIKit/UIKit.h>
 
#import "HSStatus.h"
 
@interface HSStatusCell : UITableViewCell
 
// The real data of the custom view comes from the model, that is, the model is used to assemble the display content of the custom view
 
@property (nonatomic.strong) HSStatus *status;// The model corresponding to the view is the interface provided by the view to the outside world
 
/** Setting the view content through the data model eliminates the need for the view controller to know the details of the view */
 
+ (instancetype) tableVieCellwWithStatus:(HSStatus *) status tableView:(UITableView *)tableView;// Use the class method to get the custom view, with parameters for the view's data assembly
 
//
 
+ (instancetype) tableVieCellwWittableView:(UITableView *)tableView;// Use the class method to get the custom view
 
@end
 
Copy the code
  • Set the location
- (void)setStatus:(HSStatus *)status{
 
    _status = status;
 
    [self settingData];
 
        // Set the location
 
    [self settingFrame];
 
}
 
 
 
 
- (void) settingData{
 
    // Set the location
 
    [self.textView  setText:self.status.text];
 
    [self.nameView setText:self.status.name];
 
    [self.iconView setImage:self.status.iconImage];
 
    if (self.status.picture.length > 0) {[self.pictureView setImage:self.status.pictureImage];
 
        [self.pictureView setHidden:NO];
 
    }else{[self.pictureView setImage:nil];// Clear the image information when there is no image - when the cell is reused, the optional view is processed
 
        [self.pictureView setHidden:YES];
 
 
 
 
    }
 
    if (self.status.vip) {
 
        [self.vipView setImage:self.status.vipImage];
 
        [self.vipView setHidden:NO];// Display the VIP view
 
        [self.nameView setTextColor:[UIColor redColor]];
 
    }else{[self.vipView setImage:nil];// Empty the VIP identifier when it is not a VIP - Special treatment for optional views when cells are reused
 
        [self.vipView setHidden:YES];
 
        [self.nameView setTextColor:[UIColorblackColor]]; }}/** Sets the location information */
 
- (void) settingFrame{
 
    // Define the spacing
 
    CGFloat padding =10;
 
    CGFloat iconX = padding;
 
    CGFloat iconY = padding;
 
    CGFloat iconWidth = 30;
 
    CGFloat iconHeiht = 30;
 
    [self.iconView setFrame:CGRectMake(iconX, iconY, iconWidth, iconHeiht)];
 
    // Set the nickname, whose size is determined by the length of the text
 
    /** 1. The boundingRectWithSize method calculates the area occupied by the given text. Calculate the accurate height of the multiline need incoming NSStringDrawingUsesLineFragmentOrigin 3, the attributes specified font properties; The first header file in the UIKit framework, nsAttributedString.h */
 
    NSDictionary *nameDict = @{NSFontAttributeName:KnameFont};
 
    CGRect nameFrame = [self.status.name boundingRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:nameDict context:nil];// Return a CGRect with x,y, both 0
 
    nameFrame.origin.x = CGRectGetMaxX(self.iconView.frame)+padding;
 
    nameFrame.origin.y = padding+(CGRectGetHeight(self.iconView.frame)-CGRectGetHeight(nameFrame))*0.5;
 
     
 
    [self.nameView setFrame:nameFrame];
 
     
 
    // Set the frame of the VIP id
 
    [self.vipView setFrame:CGRectMake(CGRectGetMaxX(self.nameView.frame)+padding, CGRectGetHeight(self.nameView.frame), 14.14)];
 
    // Set the frame for the text content
 
 
 
 
    NSDictionary *textDict = @{NSFontAttributeName:KtextFont};
 
    CGRect textFrame = [self.status.text boundingRectWithSize:CGSizeMake(300, MAXFLOAT) options: NSStringDrawingUsesLineFragmentOrigin attributes:textDict context:nil];
 
    textFrame.origin.x = padding;
 
    textFrame.origin.y = CGRectGetMaxY(self.iconView.frame)+padding ;
 
    [self.textView setFrame:textFrame];
 
    // Set the picture frame
 
    [self.pictureView setFrame:CGRectMake(padding,CGRectGetMaxY(self.textView.frame)+padding, 100.100)];
 
      
 
}
Copy the code
  • Calculate the line height
#pragmaThe Mark-TableView delegate method
 
#if 1
 
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
 
    /** When this method is executed, the cell has not yet been instantiated; After instantiating the cell, set the model property status of the cell object to calculate the solution: obtain the model - "determine the row height */
 
    // Get the line height - before cell instantiation
 
    HSStatus *statuse = self.stautses[indexPath.row];
 
    // Start counting row heights
 
// CGFloat height = padding+iconView.frame.height+padding+textView.frame.height+pictureView.frame.height+padidng;
 
    CGFloat iconViewHeight = 30;
 
    CGFloat pictureViewHeight = 100;
 
    CGFloat padding = 10;
 
    CGFloat textViewHeight = [statuse.text boundingRectWithSize:CGSizeMake(300, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:16]} context:nil].size.height;
 
    CGFloat height =iconViewHeight+textViewHeight+((statuse.picture.length >0 ? pictureViewHeight+padding: 0))+padding*2;
 
    return height;
 
}
 
#endif
Copy the code

see also

🍅 Contact author: iOS Reverse (public number: iosrev)


🍅 Author profile: CSDN blog expert certification 🏆 international Top 50, Huawei Cloud enjoy expert certification 🏆, iOS reverse public number master


🍅 Resume template, technical assistance. Pay attention to me, all for you.