Как я могу получить уведомление, когда UIView становится видимым? - PullRequest
21 голосов
/ 16 марта 2010

Есть ли способ получить уведомление, обратный вызов или другие средства для вызова метода всякий раз, когда UIView становится видимым для пользователя, т.е. когда UIScrollview является суперпредставлением некоторых UIViews, и ViewController такого UIView должен получить уведомление, когда его вид теперь виден пользователю?

Мне известно о возможном, но не очень элегантном решении проверить, в какую позицию прокручивается ScrollView (с помощью UIScrollViewDelegate-методов), и вычислить, является ли видимым одно из подпредставлений ...
Но я ищу более универсальный способ сделать это.

Ответы [ 4 ]

8 голосов
/ 19 июня 2013

Мне удалось решить проблему следующим образом:

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

// retrieve an array containing all super views

-(NSArray *)getAllSuperviews
{
    NSMutableArray *superviews = [[NSMutableArray alloc] init];

    if(self.superview == nil) return nil;

    [superviews addObject:self.superview];
    [superviews addObjectsFromArray:[self.superview getAllSuperviews]];

    return superviews;
}

Затем в вашем представлении проверьте, установлено ли свойство окна:

-(void)didMoveToWindow
{
    if(self.window != nil)
        [self observeSuperviewsOnOffsetChange];
    else
        [self removeAsSuperviewObserver];
}

Если он установлен, мы будем наблюдать «contentOffset» каждого суперпредставления при любом изменении. Если окно равно нулю, мы прекратим наблюдать. Вы можете изменить keyPath на любое другое свойство, например «frame», если в ваших суперпредставлениях нет UIScrollView:

-(void)observeSuperviewsOnOffsetChange
{
    NSArray *superviews = [self getAllSuperviews];
    for (UIView *superview in superviews)
    {
        if([superview respondsToSelector:@selector(contentOffset)])
            [superview addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil];
    }
}

-(void)removeAsSuperviewObserver
{
    NSArray *superviews = [self getAllSuperviews];
    for (UIView *superview in superviews)
    {
        @try
        {
            [superview removeObserver:self forKeyPath:@"contentOffset"];
        }
        @catch(id exception) { }
    }
}

Теперь реализуем метод «наблюдаем значение для ключа»:

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if([keyPath isEqualToString:@"contentOffset"])
    {
        [self checkIfFrameIsVisible];
    }
}

Наконец, проверьте, видна ли рамка вида внутри рамки окна:

-(void)checkIfFrameIsVisible
{
    CGRect myFrameToWindow = [self.window convertRect:self.frame fromView:self];
    if(myFrameToWindow.size.width == 0 || myFrameToWindow.size.height == 0) return;
    if(CGRectContainsRect(self.window.frame, myFrameToWindow))
    {
        // We are visible, do stuff now
    }
}
7 голосов
/ 16 марта 2010

Если ваше представление демонстрирует поведение, оно должно быть внутри контроллера представления. На контроллере представления метод viewDidAppear будет вызываться каждый раз, когда появляется представление.

- (void)viewDidAppear:(BOOL)animated
1 голос
/ 22 июля 2010

Я не думаю, что есть универсальный способ сделать это для представлений. Похоже, вы застряли с scrollViewDidEndScrolling и другими методами ScrollViewDelegate. Но я не уверен, почему вы говорите, что это элегантно, они довольно просты.

0 голосов
/ 22 июля 2010
* Свойство слоя вида

должно сообщать нам, является ли это представление видимым или нет

[view.layer visibleRect];

но это не работает для меня.

Таким образом, можно обойти использование свойства contentOffset UiScrollView, чтобы вычислить, является ли конкретное представление видимым или нет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...