Бесконечная анимация не прерывается кнопкой «Домой»

У меня есть несколько объектов подкласса uiview внутри основного представления контроллера представления, которые я бесконечно анимирую, вызывая в классе следующий метод:

- (void)hover:(NSNumber *)upDown {
    int sense = [upDown intValue];
    [UIView animateWithDuration:0.8 delay:0.1 options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowUserInteraction
                     animations:^{                        
                         CGRect frame = self.frame;
                         frame.origin.y += (sense==1?1:-1) * 5;
                         self.frame = frame;
                     }
                     completion:^(BOOL finished){ 
                         [self hover:[NSNumber numberWithInt:(sense==1?0:1)]];
                     }];             
}

Он отлично работает, за исключением того, что на устройстве при нажатии кнопки «Домой» приложение наполовину зависает (приложение в конечном итоге переходит в фоновый режим при многократном нажатии кнопки «Домой» в течение достаточно долгого времени), и любое взаимодействие с другими кнопками перестает работать. В любом другом случае он работает нормально, т. е. пока я не нажимаю кнопку «Домой», я могу перемещаться по контроллерам, нажимать кнопки и т. Д. И на симуляторе.

Есть идеи?

ОБНОВЛЕНИЕ: виновата тень, которую я применяю к анимируемым представлениям.

self.layer.shadowColor = [UIColor blackColor].CGColor;
self.layer.shadowOpacity = 1.0;
self.layer.shadowRadius = 5.0;

Кажется, это вызывает какие-то накладные расходы, которые влияют только на то, что приложение не может перейти в фоновое состояние ???

Кто-нибудь сталкивался с этим?

ОБНОВЛЕНИЕ: В конце концов я решил избавиться от этого кода и нарисовать тень с помощью Quartz в методе drawRect:. Я подозреваю, что проблема может быть связана со снимком, который iPhone делает перед переходом в фоновый режим, и тенью, примененной к слою за пределами границ, но это всего лишь предположение.


person Lero    schedule 21.04.2012    source источник
comment
Похоже, вы могли бы просто использовать UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse, так как вы все равно просто зацикливаете анимацию. Есть ли причина, по которой вы этого не делаете?   -  person Hampus Nilsson    schedule 21.04.2012
comment
Я перемещаю вид на 5 пикселей вверх и вниз попеременно, так что это не просто зацикливание. Мне нужно, чтобы объекты плавно возвращались в исходное положение. Я проверю вариант автореверса, но по моему обновлению проблема в тени.   -  person Lero    schedule 22.04.2012
comment
Если вы решили свою проблему, можете ли вы опубликовать ее как ответ и принять ее для нас? :-)   -  person    schedule 22.04.2012


Ответы (3)


В основном проблема связана с этим способом получения округлой формы и тени:

[self.layer setCornerRadius:radius];

self.layer.shadowColor = [UIColor blackColor].CGColor;
self.layer.shadowOpacity = 0.2;
self.layer.shadowRadius = 5;
self.layer.shadowOffset = CGSizeMake(0, 10);

Тень выходит за рамки изображения, и процесс перехода iPhone в фоновое состояние, похоже, не нравится этому при анимации.

Как я упоминал в обновлении, я избавился от этого и использовал Quartz, чтобы нарисовать как форму, так и тень внутри кадра. Есть много постов о том, как это сделать, но все равно вот:

-(void)drawRect:(CGRect)rect
{
   const CGFloat *cComps = CGColorGetComponents([UIColor blackColor]).CGColor;
   CGContextRef context = UIGraphicsGetCurrentContext();

   CGFloat center = rect.size.width / 2.0;
   CGFloat radius = center;

   CGContextBeginPath(context);
   CGContextSetShadowWithColor(context, CGSizeMake(0, 10), 4, [UIColor colorWithWhite:0     alpha:0.1].CGColor);
   CGContextAddArc(context, center, center, radius, 0, 2*M_PI, 1);
   CGContextSetRGBFillColor(context, cComps[0], cComps[1], cComps[2], 1.0);
   CGContextFillPath(context);
}

ПРИМЕЧАНИЕ. Я установил высоту представления на +15 пикселей, чтобы разместить тень внизу.

Надеюсь, это поможет кому-то. Это, конечно, сводило меня с ума на пару дней...

person Lero    schedule 23.04.2012

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

Все мои затененные слои были относительно статичны и не анимировались постоянно, так что YMMV.

Ваш стандартный код добавления тени:

layer.shadowColor = [UIColor blackColor].CGColor;
layer.shadowOffset = CGSizeMake(0, 1);
layer.shadowOpacity = 0.5;
layer.shadowRadius = 1.0;

Вот что вам нужно добавить:

layer.rasterizationScale = [[UIScreen mainScreen] scale];
layer.shouldRasterize = YES;
person ralphshao    schedule 06.06.2012

Моя первая мысль заключается в том, что вы должны реализовать BOOL в вашем файле .h (давайте назовем его stopGoing). Затем сделайте следующее:

- (void)hover:(NSNumber *)upDown {
    if(!stopGoing){
        int sense = [upDown intValue];
        [UIView animateWithDuration:0.8 delay:0.1 options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowUserInteraction
                     animations:^{                        
                         CGRect frame = self.frame;
                         frame.origin.y += (sense==1?1:-1) * 5;
                         self.frame = frame;
                     }
                     completion:^(BOOL finished){ 
                         [self hover:[NSNumber numberWithInt:(sense==1?0:1)]];
                     }];
    }  else {
        // do something else
    }           
}

Затем в вашем IBAction, который вы связали с кнопкой, просто сделайте следующее:

-(IBAction)myButton:(id)sender{
    stopGoing = YES;
}

Это должно эффективно остановить цикл, не будучи слишком агрессивным.

person AMayes    schedule 21.04.2012
comment
под кнопкой домой я имел в виду кнопку на устройстве, а не кнопку в приложении. Навигация и взаимодействие внутри приложения работают нормально. Насколько я вижу, какой бы ни была проблема, applicationWillResignActive в делегате или viewWillDisappear в контроллере не вызываются - person Lero; 21.04.2012
comment
Это потому, что у вас есть бесконечный цикл, из которого вы никогда не выйдете. Вы можете реализовать NSTimer, который будет продолжать цикл бесконечно, но станет недействительным, когда представление исчезнет. Если вы не знаете, как это сделать, я опубликую еще один ответ с методом. - person AMayes; 21.04.2012
comment
Я попробую, но я думаю, что таймер может привести к тому, что анимация будет дергаться, поскольку функция должна вызываться снова точно после завершения предыдущего вызова. - person Lero; 21.04.2012
comment
Единственное, что я могу придумать, это изменить значение BOOL в viewWillDisappear или сделать его одноэлементным и изменить его в applicationWillResignActive: - person AMayes; 21.04.2012
comment
К сожалению, таймер этого не сделал. Та же проблема! Дело в том, что ни один из этих методов не вызывается. Как будто анимацию нельзя прервать кнопкой домой! Я буду продолжать пробовать разные вещи и опубликую решение, если попаду в него... - person Lero; 21.04.2012