Проблемы с производительностью с помощью DrawRect и NSTimer

98
6

Я пытаюсь создать анимацию игрового автомата, в которой вращаются барабаны. для этого я использую drawRect для рисования изображений в пользовательском классе, который наследуется от UIView. Я использую nstimer для обновления положения изображений и вызова [self setNeedsDisplay] для обновления чертежа. В симуляторе это выглядит очень хорошо, однако, на устройстве, он очень лаги. Мне было интересно, что я делаю что-то не так с моим методом рисования или есть какие-то лучшие решения.


- (void)drawRect:(CGRect)rect
{
[image1 drawInRect:CGRectMake(0, image1Position, 98, 80)];
[image2 drawInRect:CGRectMake(0, image2Position, 98, 80)];
[image3 drawInRect:CGRectMake(0, image3Position, 98, 80)];
}

- (void)spin
{
// move each position down by 10 px
image1Position -= MOVEMENT;
image2Position -= MOVEMENT;
image3Position -= MOVEMENT;
// if any of the position <= -60 reset to 180
if(image1Position < -50)
{
image1Position = 180;
}
if(image2Position < -50)
{
image2Position = 180;
}
if(image3Position < -50)
{
image3Position = 180;
}
[self setNeedsDisplay];
}

-(void)beginSpinAnimation
{
timer = [NSTimer scheduledTimerWithTimeInterval:SCROLL_TIME target:self selector:@selector(spin) userInfo:self repeats:YES];
}


Моя попытка CoreAnimation с UIScrollView:


- (void) spinToNextReel
{
int y = self.contentOffset.y + 80;

// if the current >= last element reset to first position (-30)
if(y >= (80 *(elementCount+1) - 30))
{
y = -30;
}

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDelegate:self];
[UIView setAnimationDuration:SCROLL_TIME];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];

self.contentOffset = CGPointMake(0, y);

[UIView commitAnimations];

if (!isSpinning && targetY == y)
{
NSLog(@"target is %d, y is %d", targetY, y);

if(timer)
{
[timer invalidate];
timer = nil;
}
[self playSound];
}
}

спросил(а) 2021-01-25T14:04:22+03:00 4 месяца, 3 недели назад
1
Решение
99

Я бы сказал, исследование CoreAnimation. Это сделано для того, чтобы делать то, что вы хотите сделать здесь. Это будет намного быстрее, чем то, что вы здесь делаете.

Что касается того, что он медленный, вызов drawInRect не самый быстрый в мире. Что такое SCROLL_TIME?

ответил(а) 2021-01-25T14:04:22+03:00 4 месяца, 3 недели назад
62

Вы хотите использовать CoreAnimation, это будет намного проще и эффективнее. Сказав это, если вы настаиваете на попытке вручную активировать этот способ, вы делаете пару вещей неправильно:

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


    Не используйте NSTimer, используйте CADisplayLink. Это привяжет ваш рисунок к исходной частоте обновления системы и синхронизирует его с любым другим чертежом, который происходит.


    Я знаю, что я это уже сказал, но изучаю и использую CoreAnimation, вы будете намного счастливее.


ответил(а) 2021-01-25T14:04:22+03:00 4 месяца, 3 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема