iOS: UIDynamicAnimator updateItemUsingCurrentState не работает с вращением

Я пытаюсь вручную изменить поворот вида в UIDynamics, но вращение вида всегда сбрасывается после обновления. В документации сказано, что UIDynamicAnimator"s updateItemUsingCurrentState: Метод должен обновлять позицию и поворот элемента, но обновляется только позиция.
Я создал короткий пример, когда квадратный вид падает с экрана, и после касания он должен быть расположен в месте касания и повернут на 45 градусов. Однако вращение не происходит (иногда вращение можно увидеть в течение доли секунды, но после этого оно снова сбрасывается):

#import "ViewController.h"

@interface ViewController ()
{
    UIDynamicAnimator* _animator;
    UIView* _square;
}
@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    _square = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
    _square.backgroundColor = [UIColor grayColor];
    [self.view addSubview:_square];

    _animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
    UIGravityBehavior *gravityBehavior = [[UIGravityBehavior alloc] initWithItems:@[_square]];
    gravityBehavior.magnitude = 0.1;
    [_animator addBehavior:gravityBehavior];
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [[event allTouches] anyObject];
    _square.center = [touch locationInView:self.view];
    NSLog(@"transform before rotation: %@", NSStringFromCGAffineTransform(_square.transform));
    _square.transform = CGAffineTransformMakeRotation(M_PI/4);
    [_animator updateItemUsingCurrentState:_square];
    NSLog(@"transform after rotation: %@", NSStringFromCGAffineTransform(_square.transform));
}
@end

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

Так я что-то не так делаю? Или нельзя явно изменить ротацию вида?

2 ответа

Решение

Основываясь на ответе Бесконечности Джеймса, я нашел решение, которое работает довольно хорошо. Таким образом, чтобы обновить ротацию элемента, вам нужно
1. удалить все поведения, которые влияют на элемент из динамического аниматора
2. обновить ротацию элемента
3. вернуть удаленное поведение аниматору (нет необходимости создавать новое поведение)

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

- (void)rotateItem:(UICollectionViewLayoutAttributes *)item toAngle:(CGFloat)angle
{
    CGPoint center = item.center;
    [self.dynamicAnimator removeBehavior:self.parentBehavior];
    item.transform = CGAffineTransformMakeRotation(angle);
    [self.dynamicAnimator addBehavior:self.parentBehavior];
}

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

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

Код для моего решения:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self.animator removeBehavior:self.gravityBehavior];
    self.gravityBehavior = nil;

    UITouch *touch = touches.anyObject;
    CGPoint touchLocation = [touch locationInView:touch.view];

    self.square.center = touchLocation
    self.square.transform = CGAffineTransformMakeRotation(M_PI/4);

    self.gravityBehavior = [[UIGravityBehavior alloc] initWithItem:self.square];
    self.gravityBehavior.magnitude = 0.1f;

    [self.animator addBehavior:self.gravityBehavior];
}
Другие вопросы по тегам