将tabBarController切换到包含许多单元格的tableView时的Laggy

时间:2015-09-08 06:57:44

标签: ios objective-c uitableview uitabbarcontroller

我的应用基于tabBarController并有2个标签。

当应用程序在选项卡1上启动时,我在后台加载第二个选项卡的数据,因此用户在单击选项卡2时无需等待。

我的问题是:如果我提前加载数据并且有很多数据要显示在属于选项卡2的tableView的单元格中,那么切换到选项卡2会很困难。如果要显示的单元格不多,那么它不是总的来说很迟钝。

我想这是因为生成单元格非常耗时,因此当单元格太多时视图会被阻止。我该如何优化?

1 个答案:

答案 0 :(得分:0)

重要!此代码尚未在XCode中进行测试,但包含来自实际项目的部分内容。

CellView类可以作为Nib创建,甚至可以使用calculateCellHeight中的ServicesHelper.m方法手动创建。在这两种情况下,必须在要调整大小layoutSubviews detailTextLabel代码的位置实施UILabel方法。 CellView标签字体和颜色必须与calculateCellHeight方法中使用的相同。

<强> ServicesHelper.m

#define FontRegular(fontSize) [UIFont fontWithName:@"HelveticaNeue" size:fontSize]

// the height of fixed part of the cell, fixed height UILabel + some padding
#define kFixedPartCellHeight 20
#define kLeftPaddingWidth 20

#define kLandscapeHeightKey @"landscapeKey"
#define kPortraitHeight @"portraitKey"

+ (NSDictionary *) calculateCellHeight: (NSString *) text {

// dynamic height label
UILabel *detailTextLabel = [UILabel new];

UIFont *mainFont = FontRegular(14.0);

// specifying font and colour to be used inside cell is important to get precise frame rect
[detailTextLabel setFont: mainFont];
[detailTextLabel setTextColor:[UIColor blackColor]];

detailTextLabel.lineBreakMode = NSLineBreakByWordWrapping;
detailTextLabel.numberOfLines = 0;

[textLabel setBackgroundColor: [UIColor clearColor]];
[detailTextLabel setBackgroundColor: [UIColor clearColor]];

// get the width of the cell for both orientations
CGRect screenRect = [[UIScreen mainScreen] bounds];

CGFloat landscapeWidth = MAX (screenRect.size.width, screenRect.size.height);
CGFloat portraitWidth = MIN (screenRect.size.width, screenRect.size.height);

// kLeftPaddingWidth - is just a white space left and right to the UILabel inside cell
// we set the UILabel width with maximum possible height, then set text and shrink it using sizeToFit to get the exact size

detailTextLabel.frame = CGRectMake (0, 0 , landscapeWidth - kLeftPaddingWidth * 2, CGFLOAT_MAX);
textLabel.frame = detailTextLabel.frame;

detailTextLabel.text = text;
[detailTextLabel sizeToFit];

CGFloat landscapeHeight = detailTextLabel.frame.size.height + kFixedPartCellHeight;

detailTextLabel.frame = CGRectMake (0, 0 , portraitWidth - kLeftPaddingWidth * 2, CGFLOAT_MAX);
textLabel.frame = detailTextLabel.frame;

detailTextLabel.text = text;
[detailTextLabel sizeToFit];

CGFloat portraitHeight = detailTextLabel.frame.size.height + kFixedPartCellHeight;

return  @{kLandscapeHeightKey: landscapeHeight, kPortraitHeightKey: portraitHeight};
}

<强> TableView.h

@property (nonatomic, strong) NSMutableArray *arrayOfTexts;
@property (nonatomic, strong) NSMutableDictionary *dictOfHeights;

<强> TableView.m

- (void) precalculateHeight {
    if (nil == self.dictOfHeights) self.dictOfHeights = [NSMutableDictionary new];
    CGRect screenRect = [[UIScreen mainScreen] bounds];
    // height of two screens
    CGFloat maxHeight = MAX (screenRect.size.width, screenRect.size.height) * 2;
    CGFloat totalHeight = 0;
    CGFloat portraitHeight;
    CGFloat landscapeHeight;
    NSDictionary *dictHeights;

    for (int i = 0; i < self.arrayOfTexts.count; i++ ) {

      dictHeights = [ServicesHelper calculateCellHeight: arrayOfTexts[i]];
      portraitHeight = [dictHeights[kPortraitHeightKey] floatValue];
      [self.dictOfHeights setValue: dictHeights forKey:@(i)];
      totalHeight += portraitHeight;
      if (totalHeight > maxHeight) break;
    }
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
  if (self.dictOfHeights && self.dictOfHeights[@(indexPath.row)]) {
      return UIDeviceOrientationIsPortrait([UIDevice currentDevice].orientation) ? 
             [self.dictOfHeights[@(indexPath.row)][kPortraitHeightKey] floatValue] : 
             [self.dictOfHeights[@(indexPath.row)][kLandscapeHeightKey] floatValue];
  } else {
    // you decide, call calculateCellHeight for particular row, right from here, or also calculate rows height for the coming set of cells
    // @todo:
  }
  return CGFLOAT_MIN;
}