0

我必须在滚动视图中显示大约 100 页,每个页面包含 8 个图像视图和 8 个标签。图像视图的图像应该延迟加载。我创建的示例延迟加载图像并且分页也很好,但我正在加载所有 100 页,每个页面总共包含 8 个图像视图和 8 个标签。它在模拟器上运行良好,但我没有在设备上测试它,因为我很害怕看到它崩溃,因为我一次加载这么多视图。任何人都可以帮助我或指导我一些可以帮助我重用我的视图以及我可以执行图像视图的延迟加载的示例吗?

4

4 回答 4

4

我会推荐UIPageViewController这是一个很好的教程如何实现它。

所以这个想法是你有一个控制器来显示页面上的所有图像和标签,所以当你转到下一页时,你只需启动另一个控制器并设置图像,你也会从内存中删除前一页。每个页面都由页面控制器的一个实例表示,而 UIPageViewController 负责。如果你不想,你不必做页面卷曲动画。

当然,您可以使用分页计算滚动视图中页面上每个项目的位置并移动项目和加载其他图像UIScrollView,但是如果您有数百页,为什么不使用UIPageViewController呢?

顺便说一句,您甚至不需要教程,您只需Page Based Application从 iOS 模板创建,然后将代码移动Model ControllerDataViewController

于 2012-10-24T19:53:29.907 回答
2

Have a look at the post UIScrollView and lazy loading, describing how to do lazy loading of images in UIScrollView.

This is exactly the kind of step-by-step intro to lazy loading with UIScrollView that you are looking for.

The idea is: you keep, e.g., 3 views in memory: the current, the previous one, and the next one; so you can move to the next one or previous one with no delay. When you move to one new view, you load the previous one and the next one (if necessary). If you plan on having fast scroll as an important feature, you would need to increase the number of views in memory to 5 or 7. The more views you hold in memory, the seamless scrolling will be, but you will pay a price in terms of memory usage.

I would not suggest trying to keep all the views in memory because the device memory will fill up and your app will be killed. In any case, you can try and see if the device can handle all those views in memory at the same time.

One interesting option you might consider is showing an activity indicator while a page is being loaded. This would make scrolling feel more natural, although the view shall be loaded.

Having a look at your files, one thing I noticed is the

for (int i =0; i<loopTimes; i++)

in loadImagesForPage.

You might try to split that method so that it's not executed on a single run (blocking the UI meanwhile). I mean:

for (int i =0; i<loopTimes; i++) {
    [self performSelector:@selector(loadSingleImageForPage:)
               withObject:[NSNumber numberWithInt:i]
               afterDelay:0.0];
}

where loadSingleImageForPage: is a method which encapsulates the current body of the for loop. By doing like this (i.e., using the afterDelay) you load one page and return back to the run loop; then the next one and return back to the run loop; etc. When you return back to the run loop, you give the system a chance to deal with the UI, delegate calls, whatever...

I hope this could make a difference. Otherwise, my suggestion is just trying to comment out portions of your code (i.e., checking whether the app work correctly when displaying only the placeholders without attempting to download the images, etc.).

EDIT (7/9/2013)

Since the link above seems to be dead, here is the code:

1 - Listen for scrollViewDidScroll on your delegate, like this:

-(void)scrollViewDidScroll:(UIScrollView *)myScrollView {
}

2 - Calculate the current page using the known size of your images:

/**
 *  calculate the current page that is shown
 *  you can also use myScrollview.frame.size.height if your image is the exact size of your scrollview
 */
int currentPage = (myScrollView.contentOffset.y / currentImageSize.height);

3 - Look if the image already exists, if not, add it:

// display the image and maybe +/-1 for a smoother scrolling
// but be sure to check if the image already exists, you can do this very easily using tags
if ( [myScrollView viewWithTag:(currentPage +1)] ) {
    return;
}
else {
    // view is missing, create it and set its tag to currentPage+1
}

4 - And don’t forget to clean your memory:

/**
 *  using your paging numbers as tag, you can also clean the UIScrollView
 *  from no longer needed views to get your memory back
 *  remove all image views except -1 and +1 of the currently drawn page
 */
for ( int i = 0; i < currentPages; i++ ) {
    if ( (i < (currentPage-1) || i > (currentPage+1)) && [myScrollView viewWithTag:(i+1)] ) {
        [[myScrollView viewWithTag:(i+1)] removeFromSuperview];
    }
}

5 - And the final combination of all steps:

-(void)scrollViewDidScroll:(UIScrollView *)myScrollView {

    int currentPage = (myScrollView.contentOffset.y / currentImageSize.height);

    if ( [myScrollView viewWithTag:(currentPage +1)] ) {
        return;
    }
    else {
        // view is missing, create it and set its tag to currentPage+1
    }

    for ( int i = 0; i < currentPages; i++ ) {
        if ( (i < (currentPage-1) || i > (currentPage+1)) && [myScrollView viewWithTag:(i+1)] ) {
            [[myScrollView viewWithTag:(i+1)] removeFromSuperview];
         }
    }
}
于 2012-10-24T19:48:14.523 回答
0

或者其他一些人,你可以看看我在VSScroller上的课程

于 2013-06-24T05:12:06.783 回答
0

我写了一个简单的 UIScrollView 子类,它和 UITableView 一样实现了单元格可重用性,项目MMHorizo​​ntalListView在 gitHub 上,还有一个测试项目,所以你可以通过示例看到如何使用它,它也适用于 4.x 等旧 iOS 版本(可能更老了……)

于 2013-08-09T08:30:39.407 回答