Как реализовать UIScrollView с 1 000 + подпредставления?

Я борюсь с записью части приложения, которое должно вести себя как собственное фото приложение iPhone. Посмотревший iPhone sdk книга разработки приложений от Orielly, который дал пример кода для реализации этого так называемого щелкающего страницей. Код там сначала создал все подпредставления, и затем скройтесь/раскройте их. В установленный срок только 3 подпредставления являются видимым отдыхом, скрыты. После большого усилия я получил его работающий с приложением, которое в то время имело только приблизительно 15 страниц.

Как только я добавил 300 страниц, стало ясно, что существует производительность/проблемы памяти с тем подходом предварительного выделения такого количества подпредставлений. Затем я думал, может быть для моего случая, я должен просто выделить 3 подпредставления, и вместо скрываются/раскрывают их. Может быть я должен просто удалить/добавить подпредставления во времени выполнения. Но не может выяснить, может ли UIScrollView динамично обновить содержание. Например, в запуске существует 3 кадра при различных x-смещениях (0, 320, 640) с экрана, как понято под UIScrollView. После того как пользователь перемещается в 3-ю страницу, как я удостоверяюсь, что могу добавить 4-ю страницу и удалить 1-ю страницу, и все же UIScrollView не запутывается?

Надежда там является стандартным решением этого вида проблемы... кто-то может вести?

12
задан Adrian Kosmaczewski 2 February 2011 в 21:36
поделиться

3 ответа

UISCROLLVIEW - это просто подкласс UIView, поэтому можно добавить и удалить подпрослушие во время выполнения. Предполагая, что у вас есть фиксированные фотографии ширины (320PX), а также есть 300, то ваш главный вид будет 300 * 320 Pixels широко. При создании прокрутки просмотра инициализируйте кадр, чтобы быть так широко.

Таким образом, кадр просмотра просмотра будет иметь размеры (0, 0) до (96000, 480). Всякий раз, когда вы добавляете подсыднее, вам придется изменить его кадр, поэтому он подходит в правильном положении на своем родительском представлении.

Итак, скажем, мы добавляем 4 Фото на вид прокрутки. Это кадр будет из (960, 480) до (1280, 480). Это легко рассчитать, если вы можете как-то связать индекс с каждой картинкой. Затем используйте это, чтобы рассчитать кадр изображения, где индексы начинаются с 0:

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

на

Bottom-Right -- (320 * index, 480)

, удаление первого изображения / субвезонного типа должно быть легко. Держите массив из 3 подпроектов, в настоящее время на экране. Всякий раз, когда вы добавляете новый подсчет на экран, также добавьте его в конец этого массива, а затем удалите первый подзвучай в этом массиве с экрана.

7
ответ дан 2 December 2019 в 05:27
поделиться

После того, что было сказано, вы можете показать тысячу элементов, используя только ограниченное количество ресурсов (и да , это действительно немного шаблона избалливания). Вот какой-то код, который может помочь вам сделать то, что вы хотите.

Класс intitledviewController просто содержит UISCROLL и устанавливает себя в качестве делегата. У нас есть NSARRAY с экземплярами NSString внутри в качестве модели данных (в нем может быть потенциально тысячи Nsstrings), и мы хотим показать каждому в UILabel, используя горизонтальную прокрутку. Когда пользователь прокручивает, мы смещаем UILabels, чтобы поставить один слева, другой справа, чтобы все было готово к следующему событию прокрутки.

Вот интерфейс, скорее простой:

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

    NSArray *_objects;

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

@end

и вот реализация для этого класса:

@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

Надеюсь, это поможет!

15
ответ дан 2 December 2019 в 05:27
поделиться

Большое спасибо Адриану за его очень простой и мощный пример кода. С этим кодом была только одна проблема: когда пользователь делал "двойную прокрутку" (т.е. когда он не ждал остановки анимации и снова и снова прокручивал прокрутку).

В этом случае обновление позиции трех подпредставлений эффективно только тогда, когда вызывается метод scrollViewDidEndDecelerating, и в результате возникает задержка перед появлением подпредставлений на экране.

Этого можно легко избежать, добавив несколько строк кода:

в интерфейс, просто добавьте это:

int refPage, currentPage;

в реализацию, инициализируйте refPage и currentPage в методе "viewDidLoad" следующим образом:

refpage = 0; 
curentPage = 0;

в реализации, просто добавьте метод scrollViewDidScroll, например:

- (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];
        }
    }

et voilà!

Теперь подвиды правильно заменяются в правильных положениях, даже если пользователь никогда не останавливает анимацию и если никогда не вызывается метод scrollViewDidEndDecelerating!

6
ответ дан 2 December 2019 в 05:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: