Приложение iOS для iPad: делегаты не вызываются для ViewController с двумя UIScrollViews и UIPageControl (функции делегирования для пейджинга НЕ ВЫЗЫВАЮТСЯ)

Для моего приложения для iPad у меня есть основной ViewController, который содержит два UIScrollview и UIPageControl. Проблема в том, что делегаты для пейджинга не вызываются. Вот макет:

введите здесь описание изображения

При выборе кнопки в нижнем thumbScrollView необходимо обновить изображение в mainScrollView (это работает). Пролистывание thumbScrollView или выбор точки на странице. Control должен «пролистывать» thumbScrollView, чтобы отобразить следующий предыдущий набор кнопок. Пролистывание не работает, потому что функции делегата просто не вызываются.

Я объявляю прокрутки и управление страницами следующим образом в своем VC

@property (strong, nonatomic) IBOutlet UIScrollView *mainScrollView;
@property (strong, nonatomic) IBOutlet UIScrollView *thumbScrollView;
@property (strong, nonatomic) IBOutlet UIPageControl *pageControl;

ViewController реализует UIScrollViewDelegate.

@interface MyViewController : UIViewController<UIScrollViewDelegate>

И я реализую следующие функции делегата UIScrollViewDelegate в файле .m моего VC.

- (void)scrollViewDidScroll:(UIScrollView *)sender;
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView;
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;

Представление появляется, но когда я прокручиваю кнопки, я не вижу вызываемых выше функций делегата.

Я не нашел решения для этого в StackOverflow, хотя я учел рекомендации из других связанных сообщений для других аспектов этого (например, логика, позволяющая различать, какой вид прокрутки инициировал действие и т. д.)

ДОБАВЛЕНИЕ ПОДРОБНОГО КОДА ЗДЕСЬ (по просьбе @HeWas)

Это заголовочный файл для контроллера основного представления, который управляет двумя видами прокрутки и управлением страницами (СООТВЕТСТВУЮЩИЕ ВЫДЕРЖКИ - СКАЖИТЕ МНЕ, ЕСЛИ ВАМ НУЖНО БОЛЬШЕ)

// ImageBrowseViewController.h
// (NOTE - In Interface Builder I have added a tag attribute of 0 to mainScrollView
//  and 1 to thumbScrollView, to enable me to distinguish which scrollView the delegate 
//  needs to respond to)



#define TAG_MAIN_SCROLLVIEW 0
#define TAG_THUMB_SCROLLVIEW 1

@interface ImageBrowseViewController : UIViewController<UIScrollViewDelegate>
{
    UIButton* currentlySelectedButton;
    UIScrollView *mainScrollView;
    UIScrollView *thumbScrollView;
    UIPageControl* pageControl;
    BOOL pageControlBeingUsed;

}

@property (strong, nonatomic) IBOutlet UIScrollView *mainScrollView;
    // … connected as outlet in IB to mainScrollView
@property (strong, nonatomic) IBOutlet UIScrollView * thumbScrollView;
    // … connected as outlet in IB to thumbScrollView
@property (strong, nonatomic) IBOutlet UIPageControl *pageControl;
    // … connected as outlet in IB to pageControl


…
-(IBAction)changePage; //Touch up Inside IBAction connected to pageControl


…
@end

Это файл реализации для контроллера основного представления, который управляет двумя видами прокрутки и управлением страницами (СООТВЕТСТВУЮЩИЕ ВЫДЕРЖКИ - СКАЖИТЕ МНЕ, ЕСЛИ ВАМ НУЖНО БОЛЬШЕ)

//
//  ImageBrowseViewController.m
//

    …
@synthesize mainScrollView;
@synthesize thumbScrollView;
@synthesize pageControl;


// UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)sender {

    if ( [sender tag] == TAG_THUMB_SCROLLVIEW ) {
        // This is the thumbScrollview
        // Update the page when more than 50% of the previous/next page is visible

        CGFloat pageWidth = self.thumbScrollView.frame.size.width;
        int page = 
            floor((self.thumbScrollView.contentOffset.x - pageWidth / 2) / pageWidth) 
            + 1;
        self.pageControl.currentPage = page;

    }
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
    pageControlBeingUsed = NO;
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    pageControlBeingUsed = NO;
}

- (IBAction)changePage {
    // Update the scroll view to the appropriate page
    CGRect frame;
    //frame.origin.x = self.scrollView.frame.size.width * self.pageControl.currentPage;
    frame.origin.x = self.thumbScrollView.frame.size.width * self.pageControl.currentPage;

    frame.origin.y = 0;
    frame.size = self.thumbScrollView.frame.size;
    [self.thumbScrollView scrollRectToVisible:frame animated:YES];

    // Keep track of when scrolls happen in response to the page control
    // value changing. If we don't do this, a noticeable "flashing" occurs
    // as the the scroll delegate will temporarily switch back the page
    // number.
    pageControlBeingUsed = YES;
}

person CoolDocMan    schedule 09.01.2013    source источник
comment
Первый очевидный вопрос, который нужно задать - вы настроили делегатов в ваших scrollViews? Либо в коде, либо в интерфейсном конструкторе?   -  person foundry    schedule 10.01.2013
comment
Да, я установил все три в Interface Builder. Таким образом, mainScrollView, thumbScrollView и pageControl связаны в IB с приведенными выше объявлениями в файле .h VC.   -  person CoolDocMan    schedule 10.01.2013
comment
Это закодировано/работает на симуляторе iOS 5.1 iPad.   -  person CoolDocMan    schedule 10.01.2013
comment
Я также закодировал функцию changePage, которую я установил как IBAction «touchupinside» для PageControl. Это вызывается, когда я вручную выбираю точку в элементе управления страницей, но функции делегата scrollViewDidScroll и т. д. не вызываются независимо от того, какие действия я выполняю в thumbScrollView.   -  person CoolDocMan    schedule 10.01.2013
comment
@HeWas - посмотрите мои комментарии, относящиеся к вашему вопросу (благодарю вас за помощь в этом)   -  person CoolDocMan    schedule 10.01.2013
comment
Можете ли вы показать свои фактические реализации этих методов делегата   -  person foundry    schedule 10.01.2013
comment
@HeWas - я добавил фактические реализации методов делегата, а также IBAction, подключенный к элементу управления страницей.   -  person CoolDocMan    schedule 10.01.2013
comment
Это опечатка... @synthesize floorplanThumbScrollView;   -  person foundry    schedule 10.01.2013


Ответы (1)


В вашем коде все выглядит на 100% (кроме этой опечатки: @synthesize floorplanThumbScrollView;, но это не ваша проблема).

Я уверен, что ответ заключается в том, что вы неправильно подключили прокрутку DELEGATES в IB.

Это подсказка:

«Да, я установил все три в Interface Builder. Таким образом, mainScrollView, thumbScrollView и pageControl связаны в IB с приведенными выше объявлениями в файле .h VC».

Вам нужно 2 соединения между вашим ViewController и вашими scrollViews.

(1) перетащите, удерживая нажатой клавишу CTRL, ОТ viewController В scrollView, подключитесь к свойству IBOutlet.
Это то, что вы сделали.

(2) перетащите, удерживая нажатой клавишу CTRL, ОТ scrollView В viewController, подключитесь к delegate.
Я не думаю, что вы это сделали.

Объяснение шага 2

UIScrollView имеет встроенное свойство, называемое «делегатом». ScrollView использует это свойство для отправки сообщений своему делегату. Вы устанавливаете этот делегат в построителе интерфейса (шаг 2) или можете сделать это в коде. Например, в вашем viewController вы можете сделать это:

    [myScrollView setDelegate:self];

который установил бы viewController в качестве делегата для myScrollView. Если вы сделаете это, связавшись в Interface Builder, вам не нужен этот код (и IB его не создает).

В любом случае, что это на самом деле делает, это устанавливает iVar делегата scrollView в указатель на viewController. Самое замечательное в использовании таких делегатов заключается в том, что делегатор (UIScrollView) не должен ничего знать о делегате (в данном случае о вашем UIViewController). Это позволяет нам повторно использовать UIScrollView до тех пор, пока мы соблюдаем его протокол делегата.

Всякий раз, когда scrollView необходимо уведомить своего делегата, внутри он отправляет такое сообщение.

    [self.delegate scrollViewDidScroll:self];

(вы этого не видите, это в реализации scrollView).

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

Чтобы выяснить, какие методы требуются, прочтите Справочник по классу UIScrollView, который говорит вам следующее:

Класс UIScrollView может иметь делегата, который должен использовать протокол UIScrollViewDelegate. Для работы масштабирования и панорамирования делегат должен реализовать как viewForZoomingInScrollView:, так и scrollViewDidEndZooming:withView:atScale:; кроме того, максимальный (maximumZoomScale) и минимальный (minimumZoomScale) масштабы масштабирования должны быть разными.

Все остальное в протоколе необязательно.

Этот шаблон делегата можно легко реализовать самостоятельно для повторного использования собственных объектов, и он является одним из наиболее распространенных способов передачи сообщений между несвязанными объектами в Objective-C.

person foundry    schedule 10.01.2013
comment
это было прекрасно! Я сделал именно так, и это сработало отлично! Большое спасибо! :-) Теперь, в волнении, увидев, как это работает, я не хочу упустить эту возможность обучения! Можете ли вы напомнить, что делает этот отсутствующий шаг (т.е. шаг 2)? Это определенно устранило проблему, но я не заметил никаких изменений в коде ImageBrowseViewController.h. Каково обоснование этого шага (шаг 2)? - person CoolDocMan; 10.01.2013
comment
@CoolDocMan, см. развернутый ответ - person foundry; 10.01.2013
comment
ага теперь понял! Да, как вы утверждаете, шаг, который я пропустил, был ... [myScrollView setDelegate:self] Спасибо за такое четкое объяснение и за то, что научили меня тому, как это работает, а также за предоставление удобной альтернативы - использовать IB для установки прокрутки делегировать! - person CoolDocMan; 11.01.2013