【问题标题】:UIPageViewController Swipe DelayUIPageViewController 滑动延迟
【发布时间】:2015-01-24 00:36:59
【问题描述】:

我的 iOS 应用正在使用大约 18 页的 UIPageViewcontroller。每个页面都有一个 UITableView 和 4 个动态单元格。每个单元格有大约 10 张不同的图像。

问题是每次我滑动 UIPageViewcontroller 以转到下一个/上一个页面时,都会有半秒的延迟,这让用户体验非常糟糕。

似乎在滑动后要显示的下一页的 UITableView 正在加载其所有重数据单元格,这导致了此延迟。

我已阅读可以使此加载异步,但我不知道如何执行此操作。

你们中有人知道如何避免这种延迟,以便顺利过渡到页面吗?

这是 UITableView 的一些代码:

#pragma mark - Table view data source

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    // Return the number of rows in the section.
    return 4;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if ([cellsStatus[indexPath.row] integerValue] == CLOSED_CELL)
        return [GrintScoreTrackPlayerDynamicCell getHeightForCell];
    else
        return [GrintScoreTrackPlayerDynamicCell getFullHeightForCell];
}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    if ([mainController respondsToSelector:@selector(tableViewDidScroll:)] &&
        [mainController isKindOfClass:[GrintScoreTrackViewController class]])
    {
        [mainController tableViewDidScroll:scrollView];
    }
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier;
    GrintScoreTrackPlayerDynamicCell *cell, *cellOwner;

    // Cell ID
    CellIdentifier = @"GrintScoreTrackPlayerDynamicCell-ID";

    // Creating the cell
    cell = (GrintScoreTrackPlayerDynamicCell*)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    // Creating the cell owner
    cellOwner = [[GrintScoreTrackPlayerDynamicCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];

    // Getting cell from Nib, if possible.
    if (cell == nil)
    {
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"GrintScoreTrackPlayerDynamicCell" owner:cellOwner options:nil];
        cell = [nib objectAtIndex:0];
    }

    // Filling cell with the corresponding user info
    [cell fillCellWithContent];

    // Changing appearance based on the new status
    [self setStatusOfCell:cell withStatus:[cellsStatus[indexPath.row] integerValue]];

    // Setting action for cell's "collapseButton" button
    [cell.collapseButton addTarget:self action:@selector(changeCellStatus:) forControlEvents:UIControlEventTouchUpInside];

    // Setting action for cell's "editScoresButton" button
    [cell.editScoresButton addTarget:self action:@selector(editScoresButtonWasPressed:) forControlEvents:UIControlEventTouchUpInside];

    // Setting action for cell's "pickerEnterButton" button
    [cell.pickerEnterButton addTarget:self action:@selector(pickerEnterButtonWasPressed:) forControlEvents:UIControlEventTouchUpInside];

    // Setting cell selection style
    cell.selectionStyle = UITableViewCellSelectionStyleNone;
    cell.layoutMargins = UIEdgeInsetsZero;

    // Setting picker view delegate and data source.
    [cell.pickerView setDelegate:self];
    [cell.pickerView setDataSource:self];

    return cell;
}

还有一些来自 GrintScoreTrackPlayerDynamicCell 单元格的代码:

- (void) fillCellWithContent
{
    // Doing some processing fixes
    [self postProcessCellContent];
}

- (void) postProcessCellContent
{
    CGSize textSize;
    CGFloat scoreLabelTextWidth, newHazzardLabelXValue, newPuttsLabelXValue, offset;

    // Setting an offset for the hazzard and putts label. This offset represents the distance between the score label text and the hazzard and putts labels.
    offset = 1;

    // Getting the width of the text that's inside the Score Label.
    textSize = [[self.scoreLabel text] sizeWithAttributes:@{NSFontAttributeName:[self.scoreLabel font]}];
    scoreLabelTextWidth = textSize.width;

    // Getting new x position value for the Hazzards Label.
    newHazzardLabelXValue = self.scoreLabel.frame.origin.x +
                            (self.scoreLabel.frame.size.width - scoreLabelTextWidth) * 0.5 -
                            self.hazardsLabel.frame.size.width - offset;

    // Setting the new x position value for the Hazzards label
    [GrintUtils moveView:self.hazardsLabel inX:newHazzardLabelXValue andY:self.hazardsLabel.frame.origin.y];

    // Getting new x position value for the Putts Label.
    newPuttsLabelXValue = self.scoreLabel.frame.origin.x +
                         (self.scoreLabel.frame.size.width - scoreLabelTextWidth) * 0.5 +
                          scoreLabelTextWidth + offset;

    // Setting the new x position value for the Putts label
    [GrintUtils moveView:self.puttsLabel inX:newPuttsLabelXValue andY:self.puttsLabel.frame.origin.y];
}

这是一些关于我的 UIPageViewController 的代码,其中页面预加载在 pageContent 数组中:

#pragma mark - UIPageViewController Data Course

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
    // Getting the previous of the next controller
    int index;
    index = currentPageBeingDisplayed - 1;
    if (index < 0)
        index = [pageContent count] - 1;

    return pageContent[index];
}

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
    // Getting the index of the next controller
    int index;
    index = currentPageBeingDisplayed + 1;
    index = index % [pageContent count];

    return pageContent[index];
}

Instruments Tool Counter 的屏幕截图专注于延迟:

单元格的最后 2 张图片(它有 2 个状态):

【问题讨论】:

  • 您需要展示您的fillCellWithContent 方法。您应该做的另一件事是在pageViewController 中预加载“下一个”视图控制器 - 这样它可能会在显示之前加载所有数据。同样在cellForRowAtIndexPath 中获取数据并不理想——您应该预先获取viewDidLoad 或类似中的数据
  • 使用仪器!它会准确地告诉你“延迟”用在了哪里。
  • 嗨@Paulw11,我刚刚编辑了代码以添加fillCellWithContent 方法...另一方面,我已经将UIPageViewController 的所有页面预加载到数组中。所以我只创建一次。我也刚刚添加了一些关于它的代码......我还没有从服务器获取任何数据。一切都是本地的。
  • @jmukel 你在开玩笑吗?你在没有任何帮助的情况下做得很好!出色的侦探工作。做得好。 - 那么,为了清楚起见,这些图像是如何进入细胞的?我没有看到任何这样做的代码;你是说它发生是因为图像在单元格定义的 .xib 中?
  • @jmoukel 这已经足够我提出建议的信息了 - 请参阅下面的答案。可能行不通,但我认为会的! :)

标签: ios objective-c xcode uitableview uipageviewcontroller


【解决方案1】:

这将是一个疯狂的猜测 - 我还没有尝试过。但是根据您如此出色的推断以及您在 cmets 中所说的内容,我认为这就是图像进入细胞的方式:它们位于定义细胞的 .xib.

因此,对于表格的每一行,都加载了 .xib,并且所有图像都必须从 .xib 中重新加载。这就是我们认为会拖慢您速度的原因。

所以这里有一个建议:不要那样做。相反,只需在单元格中有空的图像视图,然后用 cellForRowAtIndexPath: 中的图像填充它们。

为什么会有帮助?因为如果您通过调用imageNamed: 获取图像,则图像会被系统缓存。因此,每张图片都会被提取一次,之后会被永久缓存。

还有一个建议 - 确保图像,即与它们将显示的大小相同。从大图像开始并在小图像视图中显示它是非常浪费时间的,因为每次都必须计算要显示的图像版本。

【讨论】:

  • 非常感谢马特的建议! ....但是,我犯了一个错误。我告诉你的那些 20 或更多的图像只是我四舍五入的带有彩色背景的 UIView。每个单元格中只有 3 张图像。我已经调整了它们的大小,使它们更小,现在我将它们加载到 cellForRowAtIndexPath: 方法中(而不是 .xib 文件)。但是问题依然存在,过渡仍然滞后……那么,您不认为这种延迟是因为正在渲染那 20 个或更多 UIView 吗?我添加了一张单元格的图片(在最初的帖子中),这样你就可以看到它有多少视图。谢谢!
  • 通过操作 CALayer 进行舍入肯定会加重渲染树的压力。同样,您只需要进行实验。取出“四舍五入”代码,看看会发生什么。
  • 是的,我确实尝试过删除舍入,但问题仍然存在......此外,每个单元格也有自己的 UIPickerView(我在帖子中添加了另一张图片)。但是删除 UIPickerView 后,延迟问题仍然存在。
  • 好的,但你继续移动球门柱。你说你通过改变一些东西来解决滞后问题。嗯,就是这样。那是什么?
  • 很高兴你解决了一些问题!您可以回答自己的问题(并且在 48 小时内您可以接受自己的回答)。这是一种很好的形式,它可以帮助其他人。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多