Iphone 如何使用1000+;子视图?

Iphone 如何使用1000+;子视图?,iphone,objective-c,performance,uiscrollview,Iphone,Objective C,Performance,Uiscrollview,我正在努力编写一个应用程序的一部分,它的行为应该与本机iphone照片应用程序类似。查看Oriely的iphone sdk应用程序开发书,书中给出了实现这种所谓页面翻转的示例代码。那里的代码首先创建所有子视图,然后隐藏/取消隐藏它们。在给定时间内,只有3个子视图可见,其余子视图隐藏。经过很多努力,我得到了它的应用程序,在那个时候只有约15页工作 当我添加了300页后,很明显,预分配这么多子视图的方法存在性能/内存问题。然后我想,对于我的情况,我应该只分配3个子视图,而不是隐藏/取消隐藏它们。也许

我正在努力编写一个应用程序的一部分,它的行为应该与本机iphone照片应用程序类似。查看Oriely的iphone sdk应用程序开发书,书中给出了实现这种所谓页面翻转的示例代码。那里的代码首先创建所有子视图,然后隐藏/取消隐藏它们。在给定时间内,只有3个子视图可见,其余子视图隐藏。经过很多努力,我得到了它的应用程序,在那个时候只有约15页工作

当我添加了300页后,很明显,预分配这么多子视图的方法存在性能/内存问题。然后我想,对于我的情况,我应该只分配3个子视图,而不是隐藏/取消隐藏它们。也许我应该在运行时删除/添加子视图。但无法确定UIScrollView是否可以动态更新内容。例如,如UIScrollView所理解的,在开始时,屏幕上有3个不同x偏移(0320640)的帧。一旦用户移动到第3页,我如何确保我能够添加第4页和删除第1页,而UIScrollView不会感到困惑


希望能有一个标准的解决方案来解决这类问题……有人可以指导吗?

UIScrollView只是UIView的一个子类,因此可以在运行时添加和删除子视图。假设你有固定宽度的照片(320px)并且有300张,那么你的主视图将是300*320像素宽。创建滚动视图时,将帧初始化为该宽度

因此,滚动视图的框架的尺寸为(0,0)到(96000480)。无论何时添加子视图,都必须更改其框架,使其适合其父视图中的正确位置

比如说,我们正在将第四张照片添加到滚动视图中。它的帧从(960480)到(1280480)。这很容易计算,如果你能以某种方式将索引与每张图片关联起来。然后使用此值计算图片的帧,其中索引从0开始:

Top-Left -- (320 * (index - 1), 0)


删除第一个图片/子视图应该很容易。保持屏幕上当前有3个子视图的数组。无论何时向屏幕添加新的子视图,也要将其添加到此数组的末尾,然后将此数组中的第一个子视图也从屏幕中删除。

按照前面所说的,您可以使用有限的资源显示数千个元素(是的,这确实有点像飞锤模式)。这里有一些代码可以帮助你做你想做的事情

UntitledViewController类只包含一个UIScroll,并将自身设置为其委托。我们有一个NSArray,其中包含NSString实例作为数据模型(其中可能有数千个NSString),我们希望使用水平滚动在UILabel中显示每个实例。当用户滚动时,我们移动UILabel,将一个放在左侧,另一个放在右侧,以便为下一个滚动事件做好准备

以下是界面,非常简单:

@interface UntitledViewController : UIViewController <UIScrollViewDelegate>
{
@private
    UIScrollView *_scrollView;

    NSArray *_objects;

    UILabel *_detailLabel1;
    UILabel *_detailLabel2;
    UILabel *_detailLabel3;
}

@end
@interface UntitledViewController:UIViewController
{
@私人的
UIScrollView*\u滚动视图;
NSArray*_对象;
UILabel*_详细标签1;
UILabel*\u详细标签2;
UILabel*_详细标签3;
}
@结束
下面是该类的实现:

@interface UntitledViewController ()
- (void)replaceHiddenLabels;
- (void)displayLabelsAroundIndex:(NSInteger)index;
@end

@implementation UntitledViewController

- (void)dealloc 
{
    [_objects release];
    [_scrollView release];
    [_detailLabel1 release];
    [_detailLabel2 release];
    [_detailLabel3 release];
    [super dealloc];
}

- (void)viewDidLoad 
{
    [super viewDidLoad];

    _objects = [[NSArray alloc] initWithObjects:@"first", @"second", @"third", 
                @"fourth", @"fifth", @"sixth", @"seventh", @"eight", @"ninth", @"tenth", nil];

    _scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 460.0)];
    _scrollView.contentSize = CGSizeMake(320.0 * [_objects count], 460.0);
    _scrollView.showsVerticalScrollIndicator = NO;
    _scrollView.showsHorizontalScrollIndicator = YES;
    _scrollView.alwaysBounceHorizontal = YES;
    _scrollView.alwaysBounceVertical = NO;
    _scrollView.pagingEnabled = YES;
    _scrollView.delegate = self;

    _detailLabel1 = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 460.0)];
    _detailLabel1.textAlignment = UITextAlignmentCenter;
    _detailLabel1.font = [UIFont boldSystemFontOfSize:30.0];
    _detailLabel2 = [[UILabel alloc] initWithFrame:CGRectMake(320.0, 0.0, 320.0, 460.0)];
    _detailLabel2.textAlignment = UITextAlignmentCenter;
    _detailLabel2.font = [UIFont boldSystemFontOfSize:30.0];
    _detailLabel3 = [[UILabel alloc] initWithFrame:CGRectMake(640.0, 0.0, 320.0, 460.0)];
    _detailLabel3.textAlignment = UITextAlignmentCenter;
    _detailLabel3.font = [UIFont boldSystemFontOfSize:30.0];

    // We are going to show all the contents of the _objects array
    // using only these three UILabel instances, making them jump 
    // right and left, replacing them as required:
    [_scrollView addSubview:_detailLabel1];
    [_scrollView addSubview:_detailLabel2];
    [_scrollView addSubview:_detailLabel3];

    [self.view addSubview:_scrollView];
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    [_scrollView flashScrollIndicators];
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self displayLabelsAroundIndex:0];
}

- (void)didReceiveMemoryWarning 
{
    // Here you could release the data source, but make sure
    // you rebuild it in a lazy-loading way as soon as you need it again...
    [super didReceiveMemoryWarning];
}

#pragma mark -
#pragma mark UIScrollViewDelegate methods

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    // Do some initialization here, before the scroll view starts moving!
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    [self replaceHiddenLabels];
}

- (void)displayLabelsAroundIndex:(NSInteger)index
{
    NSInteger count = [_objects count];
    if (index >= 0 && index < count)
    {
        NSString *text = [_objects objectAtIndex:index];
        _detailLabel1.frame = CGRectMake(320.0 * index, 0.0, 320.0, 460.0);
        _detailLabel1.text = text;
        [_scrollView scrollRectToVisible:CGRectMake(320.0 * index, 0.0, 320.0, 460.0) animated:NO];

        if (index < (count - 1))
        {
            text = [_objects objectAtIndex:(index + 1)];
            _detailLabel2.frame = CGRectMake(320.0 * (index + 1), 0.0, 320.0, 460.0);
            _detailLabel2.text = text;
        }

        if (index > 0)
        {
            text = [_objects objectAtIndex:(index - 1)];
            _detailLabel3.frame = CGRectMake(320.0 * (index - 1), 0.0, 320.0, 460.0);
            _detailLabel3.text = text;
        }
    }
}

- (void)replaceHiddenLabels
{
    static const double pageWidth = 320.0;
    NSInteger currentIndex = ((_scrollView.contentOffset.x - pageWidth) / pageWidth) + 1;

    UILabel *currentLabel = nil;
    UILabel *previousLabel = nil;
    UILabel *nextLabel = nil;

    if (CGRectContainsPoint(_detailLabel1.frame, _scrollView.contentOffset))
    {
        currentLabel = _detailLabel1;
        previousLabel = _detailLabel2;
        nextLabel = _detailLabel3;
    }
    else if (CGRectContainsPoint(_detailLabel2.frame, _scrollView.contentOffset))
    {
        currentLabel = _detailLabel2;
        previousLabel = _detailLabel1;
        nextLabel = _detailLabel3;
    }
    else
    {
        currentLabel = _detailLabel3;
        previousLabel = _detailLabel1;
        nextLabel = _detailLabel2;
    }

    currentLabel.frame = CGRectMake(320.0 * currentIndex, 0.0, 320.0, 460.0);
    currentLabel.text = [_objects objectAtIndex:currentIndex];

    // Now move the other ones around
    // and set them ready for the next scroll
    if (currentIndex < [_objects count] - 1)
    {
        nextLabel.frame = CGRectMake(320.0 * (currentIndex + 1), 0.0, 320.0, 460.0);
        nextLabel.text = [_objects objectAtIndex:(currentIndex + 1)];
    }

    if (currentIndex >= 1)
    {
        previousLabel.frame = CGRectMake(320.0 * (currentIndex - 1), 0.0, 320.0, 460.0);
        previousLabel.text = [_objects objectAtIndex:(currentIndex - 1)];
    }
}

@end
@interface UntitledViewController()
-(无效)替换隐藏标签;
-(void)displaylabaroundex:(NSInteger)索引;
@结束
@实现无标签的IEWController
-(无效)解除锁定
{
[_物体释放];
[_scrollView发布];
[_detailLabel1发布];
[_detailLabel2发布];
[_detailLabel3发布];
[super dealoc];
}
-(无效)viewDidLoad
{
[超级视图下载];
_objects=[[NSArray alloc]initWithObjects:@“第一”,“第二”,“第三”,
@“第四”、“第五”、“第六”、“第七”、“第八”、“第九”、“第十”、“无”;
_scrollView=[[UIScrollView alloc]initWithFrame:CGRectMake(0.0,0.0320.0460.0)];
_scrollView.contentSize=CGSizeMake(320.0*[\u对象计数],460.0);
_scrollView.showsVerticalScrollIndicator=否;
_scrollView.showsHorizontalScrollIndicator=是;
_scrollView.alwaysBounceHorizontal=是;
_scrollView.alwaysBounceVertical=否;
_scrollView.PaginEnabled=是;
_scrollView.delegate=self;
_detailLabel1=[[UILabel alloc]initWithFrame:CGRectMake(0.0,0.0320.0460.0)];
_detailLabel1.textAlignment=UITextAlignmentCenter;
_detailLabel1.font=[UIFont boldSystemFontOfSize:30.0];
_detailLabel2=[[UILabel alloc]initWithFrame:CGRectMake(320.0,0.0,320.0,460.0)];
_detailLabel2.textAlignment=UITextAlignmentCenter;
_detailLabel2.font=[UIFont boldSystemFontOfSize:30.0];
_detailLabel3=[[UILabel alloc]initWithFrame:CGRectMake(640.0,0.0320.0460.0)];
_detailLabel3.textAlignment=UITextAlignmentCenter;
_detailLabel3.font=[UIFont boldSystemFontOfSize:30.0];
//我们将显示_objects数组的所有内容
//仅使用这三个UILabel实例,使它们跳转
//左右两侧,根据需要更换:
[_scrollviewaddsubview:_detailLabel1];
[_scrollviewaddsubview:_detailLabel2];
[_scrollviewaddsubview:_detailLabel3];
[self.view addSubview:_scrollView];
}
-(无效)视图显示:(BOOL)动画
{
[超级视图显示:动画];
[_ScrollViewFlashScrollIndicators];
}
-(无效)视图将显示:(BOOL)动画
{
[超级视图将显示:动画];
[自显示标签aroundex:0];
}
-(无效)未收到记忆警告
{
//在这里,您可以释放数据源,但请确保
//一旦您再次需要它,您就以延迟加载的方式重新构建它。。。
[超级记忆警告];
}
#布拉格标记-
#pragma标记UIScrollViewDelegate方法
-(无效)scrollView将开始刷新:(UIScrollView*)scrollView
{
//在滚动视图开始移动之前,在此执行一些初始化!
}
-(无效)ScrollViewDiEndDecelling:(UI)
@interface UntitledViewController ()
- (void)replaceHiddenLabels;
- (void)displayLabelsAroundIndex:(NSInteger)index;
@end

@implementation UntitledViewController

- (void)dealloc 
{
    [_objects release];
    [_scrollView release];
    [_detailLabel1 release];
    [_detailLabel2 release];
    [_detailLabel3 release];
    [super dealloc];
}

- (void)viewDidLoad 
{
    [super viewDidLoad];

    _objects = [[NSArray alloc] initWithObjects:@"first", @"second", @"third", 
                @"fourth", @"fifth", @"sixth", @"seventh", @"eight", @"ninth", @"tenth", nil];

    _scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 460.0)];
    _scrollView.contentSize = CGSizeMake(320.0 * [_objects count], 460.0);
    _scrollView.showsVerticalScrollIndicator = NO;
    _scrollView.showsHorizontalScrollIndicator = YES;
    _scrollView.alwaysBounceHorizontal = YES;
    _scrollView.alwaysBounceVertical = NO;
    _scrollView.pagingEnabled = YES;
    _scrollView.delegate = self;

    _detailLabel1 = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 460.0)];
    _detailLabel1.textAlignment = UITextAlignmentCenter;
    _detailLabel1.font = [UIFont boldSystemFontOfSize:30.0];
    _detailLabel2 = [[UILabel alloc] initWithFrame:CGRectMake(320.0, 0.0, 320.0, 460.0)];
    _detailLabel2.textAlignment = UITextAlignmentCenter;
    _detailLabel2.font = [UIFont boldSystemFontOfSize:30.0];
    _detailLabel3 = [[UILabel alloc] initWithFrame:CGRectMake(640.0, 0.0, 320.0, 460.0)];
    _detailLabel3.textAlignment = UITextAlignmentCenter;
    _detailLabel3.font = [UIFont boldSystemFontOfSize:30.0];

    // We are going to show all the contents of the _objects array
    // using only these three UILabel instances, making them jump 
    // right and left, replacing them as required:
    [_scrollView addSubview:_detailLabel1];
    [_scrollView addSubview:_detailLabel2];
    [_scrollView addSubview:_detailLabel3];

    [self.view addSubview:_scrollView];
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    [_scrollView flashScrollIndicators];
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self displayLabelsAroundIndex:0];
}

- (void)didReceiveMemoryWarning 
{
    // Here you could release the data source, but make sure
    // you rebuild it in a lazy-loading way as soon as you need it again...
    [super didReceiveMemoryWarning];
}

#pragma mark -
#pragma mark UIScrollViewDelegate methods

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    // Do some initialization here, before the scroll view starts moving!
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    [self replaceHiddenLabels];
}

- (void)displayLabelsAroundIndex:(NSInteger)index
{
    NSInteger count = [_objects count];
    if (index >= 0 && index < count)
    {
        NSString *text = [_objects objectAtIndex:index];
        _detailLabel1.frame = CGRectMake(320.0 * index, 0.0, 320.0, 460.0);
        _detailLabel1.text = text;
        [_scrollView scrollRectToVisible:CGRectMake(320.0 * index, 0.0, 320.0, 460.0) animated:NO];

        if (index < (count - 1))
        {
            text = [_objects objectAtIndex:(index + 1)];
            _detailLabel2.frame = CGRectMake(320.0 * (index + 1), 0.0, 320.0, 460.0);
            _detailLabel2.text = text;
        }

        if (index > 0)
        {
            text = [_objects objectAtIndex:(index - 1)];
            _detailLabel3.frame = CGRectMake(320.0 * (index - 1), 0.0, 320.0, 460.0);
            _detailLabel3.text = text;
        }
    }
}

- (void)replaceHiddenLabels
{
    static const double pageWidth = 320.0;
    NSInteger currentIndex = ((_scrollView.contentOffset.x - pageWidth) / pageWidth) + 1;

    UILabel *currentLabel = nil;
    UILabel *previousLabel = nil;
    UILabel *nextLabel = nil;

    if (CGRectContainsPoint(_detailLabel1.frame, _scrollView.contentOffset))
    {
        currentLabel = _detailLabel1;
        previousLabel = _detailLabel2;
        nextLabel = _detailLabel3;
    }
    else if (CGRectContainsPoint(_detailLabel2.frame, _scrollView.contentOffset))
    {
        currentLabel = _detailLabel2;
        previousLabel = _detailLabel1;
        nextLabel = _detailLabel3;
    }
    else
    {
        currentLabel = _detailLabel3;
        previousLabel = _detailLabel1;
        nextLabel = _detailLabel2;
    }

    currentLabel.frame = CGRectMake(320.0 * currentIndex, 0.0, 320.0, 460.0);
    currentLabel.text = [_objects objectAtIndex:currentIndex];

    // Now move the other ones around
    // and set them ready for the next scroll
    if (currentIndex < [_objects count] - 1)
    {
        nextLabel.frame = CGRectMake(320.0 * (currentIndex + 1), 0.0, 320.0, 460.0);
        nextLabel.text = [_objects objectAtIndex:(currentIndex + 1)];
    }

    if (currentIndex >= 1)
    {
        previousLabel.frame = CGRectMake(320.0 * (currentIndex - 1), 0.0, 320.0, 460.0);
        previousLabel.text = [_objects objectAtIndex:(currentIndex - 1)];
    }
}

@end
int refPage, currentPage;
refpage = 0; 
curentPage = 0;
- (void)scrollViewDidScroll:(UIScrollView *)sender{
    int currentPosition = floor(_scrollView.contentOffset.x);
    currentPage = MAX(0,floor(currentPosition / 340)); 
//340 is the width of the scrollview...
    if(currentPage != refPage)  { 
        refPage = currentPage;
        [self replaceHiddenLabels];
        }
    }