Multi-line text presentation problem for media/list classes

In the development process of iOS, when we implement the function of text display, we often encounter the situation that the text is too long. If we use UITableView, when the text is displayed in the Cell, if all the text is displayed completely, then the whole screen may display only one Cell. At this point we need to split, multiline text at the end of the part before with “full text/” button, after users click on this button, the Cell across all the display of the text, unfold the launch at the end of the full text, after also need a” folded up “button, after a user clicks on a Cell once again return to the fold of the state.

How to implement

1. Model preparation

For the model that presents the data, we need to add at least three additional attributes in addition to content

支那

@property (nonatomic, assign) CGFloat titleActualH; @property (nonatomic, assign) CGFloat titleMaxH; @property (nonatomic, assign) BOOL isOpen;Copy the code

When the model is initialized, the added property is assigned in the set method of the content property

- (void)setContent:(NSString *)content { _content = content; if ([NSString isEmptyString:content]) { self.titleActualH = 0; self.titleMaxH = 0; } else { NSUInteger numCount = 5; NSString * STR = @" This is a line of text used to calculate the height "; // This line of text can also be one word, but not too long CGFloat W = kscreenwidth-30; / / this is the width of the text display self. TitleActualH = [content boundingRectWithSize: CGSizeMake (W, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:kRegularFont(14)} context:nil].size.height; self.titleMaxH = [str boundingRectWithSize:CGSizeMake(W, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:kRegularFont(14)} context:nil].size.height*numCount; }}Copy the code

2. The Cell assignment

The control used to display the text in the cell is selected UITextView, and then the content is filled with rich text and the response to the click. PS: Here can also use UILabel+UIButton method, but it is too cumbersome to implement, is a very inefficient solution. In cell’s assignment method, the dynamic reality “collapse” button is based on the comparison of the actual height and maximum height of the text (the text is implemented as rich text).

支那

- (void)setupCellData:(LWYMyFavouriteModel *)model { NSString *suffixStr = @""; NSString *contentStr = model.content; // Add suffix button text (fold or expand) NSString *contentStr = model.content; CGFloat H = model.titleActualH; If (model.titleActualH > model.titleMaxh) {if (model.titleActualH > model.titleMaxh) {if (model.isopen) {// The text has been expanded, SuffixStr = @" Pack "; contentStr = [NSString stringWithFormat:@"%@ %@", contentStr, suffixStr]; H = model.titleActualH; } else {// The text has been folded, and the suffix is "expand/full" button // the text needs to be truncated, and the "... "Expand" added to the end of our limited display text NSUInteger numCount = 5; CGFloat W = kscreenwidth-30; // This is the maximum number of rows expected to be displayed when the cell is in the fold state. / / this is the width of the text display nsstrings * tempStr = [self stringByTruncatingString: contentStr suffixStr: @ "... "the font: kRegularFont (14) forWidth:W*numCount]; contentStr = tempStr; SuffixStr = @" expand "; H = model.titleMaxH; } } NSMutableAttributedString *attStr = [[NSMutableAttributedString alloc] initWithString:contentStr attributes:@{NSFontAttributeName:kRegularFont(14)}]; self.contentTextView.linkTextAttributes = @{}; // Add a click event to the rich text suffix if(! [NSString isEmptyString:suffixStr]){ NSRange range3 = [contentStr rangeOfString:suffixStr]; [attStr addAttribute:NSForegroundColorAttributeName value:[UIColor systemBlueColor] range:range3]; //[UIColor colorWithHexString:@"#000000"] NSString *valueString3 = [[NSString stringWithFormat:@"didOpenClose://%@", suffixStr] stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]]; [attStr addAttribute:NSLinkAttributeName value:valueString3 range:range3]; } self.contentTextView.attributedText = attStr; // @param STR // @param STR // @param STR // @param STR // @param STR // @param STR // @param STR // @param STR // @param STR // @param STR // @param STR // @param STR // @param STR // @param STR // @param font /// @param length // @param length - (NSString*)stringByTruncatingString:(NSString *)str suffixStr:(NSString *)suffixStr font:(UIFont *)font forLength:(CGFloat)length { if (! str) return nil; if (str && [str isKindOfClass:[NSString class]]) { for (int i=(int)[str length] - (int)[suffixStr length]; i< [str length]; i = i - (int)[suffixStr length]){ NSString *tempStr = [str substringToIndex:i]; CGSize size = [tempStr sizeWithAttributes:@{NSFontAttributeName:font}]; if(size.width < length){ tempStr = [NSString stringWithFormat:suffixStr, tempStr]; CGSize size1 = [tempStr sizeWithAttributes:@{NSFontAttributeName:font}]; if(size1.width < length){ str = tempStr; break; } } } } return str; }Copy the code

3. Respond to the click event in the UITextView’s agent method

Code in a Cell

支那

- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange { if ([[URL Scheme] isEqualToString:@"didOpenClose"]) {// After clicking "expand" or "enclose", using an agent or block callback, Let the controller holding the tableView refresh the single-line Cell if (self.opencloseBlock) {self.opencloseBlock (); } return NO; } return YES; }Copy the code

Code in the controller (implemented in this case with blocks)

支那

// return the height of the Cell - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { LWYMyFavouriteModel *model = self.dataArray[indexPath.section]; CGFloat otherH = 100; If (model.titleActualH > model.titleMaxH) {if (model.isopen) {return model.titleActualH+otherH; } else { return model.titleMaxH+otherH; } } else { return model.titleActualH+otherH; }} // return Cell - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { LWYMyCollectionCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cellID" forIndexPath:indexPath]; LWYMyFavouriteModel *model = self.dataArray[indexPath.section]; [cell setupCellData:model]; kWeakSelf(self); [cell setOpenCloseBlock:^{NSMutableArray *tempArr = Weakself. DataArray; for (int I = 0; I < weakself.dataArray.count; i++) { LWYMyFavouriteModel *subModel = weakself.dataArray[i]; if (subModel.favouriteId == Model.favouriteid) {// update the data in the data source model.isopen =! Model.isopen; [tempArr replaceObjectAtIndex: I withObject:model]; DataArray = [NSMutableArray arrayWithArray:tempArr]; // Refresh the specified row NSIndexSet * indexSet = [[NSIndexSet alloc]; initWithIndex:i]; [weakself.tableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationAutomatic]; break; }}}]; return cell; }Copy the code

Welcome to pay attention to the public number: programming daxin, together with the exchange of progress!

Summary: This is the core process of expanding and folding multi-line text, how is it simple