动画后的iOS旋转手势

Posted

技术标签:

【中文标题】动画后的iOS旋转手势【英文标题】:iOS Rotation Gesture after animation 【发布时间】:2015-09-29 22:19:19 【问题描述】:

第一个问题,放轻松!

创建一个简单的 ios 应用程序。我有一个视图,其中包含一个旋转拨盘(一个 UIImageView)(通过旋转手势旋转)和一个 UIButton,当按下它时使用 UIView animateWithDuration 将按钮移动到 3 个位置之一。

我的问题.. 旋转转盘很好,移动按钮很好,但是.. 当我移动按钮,然后旋转转盘时,按钮的位置“重置”到原来的框架。

如何停止影响按钮位置/按钮移动的旋转。

ViewController.h

#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>

@interface ViewController : UIViewController <UIGestureRecognizerDelegate>

IBOutlet UIImageView *lock;
IBOutlet UILabel *number;
IBOutlet UILabel *displayNumber1;
IBOutlet UILabel *displayNumber2;
IBOutlet UILabel *displayNumber3;

IBOutlet UIButton *slider;

AVAudioPlayer *theAudio;



@property (retain, nonatomic) IBOutlet UIImageView *lock;
@property (retain, nonatomic) IBOutlet UILabel *number;
@property (retain, nonatomic) IBOutlet UILabel *displayNumber1;
@property (retain, nonatomic) IBOutlet UILabel *displayNumber2;
@property (retain, nonatomic) IBOutlet UILabel *displayNumber3;

@property (retain, nonatomic) IBOutlet UIButton *slider;

@property (retain, nonatomic) AVAudioPlayer *theAudio;

-(IBAction)moveSlider:(id)sender;

@end

ViewController.m

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

#define RADIANS_TO_DEGREES(radians) ((radians) * (180.0 / M_PI))

@synthesize lock, number, slider, displayNumber1, displayNumber2, displayNumber3, theAudio;

CGFloat _lastRotation;
int lastNumber;
NSTimer *clickTimer;

int _whichNumberSelected;

int _currentDirection;
CGFloat _changeDirectionMatch;

float no1Left = 61;
float no2Left = 151;
float no3Left = 238;

NSString *lastText1;

CGRect newFrameSet;

- (BOOL)prefersStatusBarHidden 
    return YES;




- (void)viewDidLoad 
    [super viewDidLoad];

    lock.userInteractionEnabled = YES;


    UIRotationGestureRecognizer *rotationGestureRecognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(handleRotationWithGestureRecognizer:)];
    rotationGestureRecognizer.delegate = self;
    [lock addGestureRecognizer:rotationGestureRecognizer];

    _lastRotation = 0;

    lastNumber = 0;


    NSString *path = [[NSBundle mainBundle] pathForResource:@"click" ofType:@"wav"];
    NSURL *fileURL = [[NSURL alloc] initFileURLWithPath: path];
    theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:NULL];
    theAudio.volume = 1.0;
    [theAudio prepareToPlay];

    _currentDirection = 0;
    _changeDirectionMatch = 0;
    _whichNumberSelected = 1;

    lastText1 = ([NSString stringWithFormat:@"0"]);





-(IBAction)moveSlider:(id)sender 

    [UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^
        CGRect newFrame = slider.frame;
        switch (_whichNumberSelected) 
            case 1:
                newFrame.origin.x= no2Left;
                _whichNumberSelected = 2;
                break;
            case 2:
                newFrame.origin.x= no3Left;
                _whichNumberSelected = 3;
                break;
            case 3:
                newFrame.origin.x= no2Left;
                _whichNumberSelected = 4;
                break;
            case 4:
                newFrame.origin.x= no1Left;
                _whichNumberSelected = 1;
                break;

            default:
                break;
        
        slider.frame = newFrame;
        newFrameSet = newFrame;
     completion:nil];





-(void)handleRotationWithGestureRecognizer:(UIRotationGestureRecognizer *)rotationGestureRecognizer



    CGFloat newRot = RADIANS_TO_DEGREES(rotationGestureRecognizer.rotation) / 3.6;
    lock.transform = CGAffineTransformRotate(lock.transform, rotationGestureRecognizer.rotation);
    CGFloat c = _lastRotation - newRot;
    _lastRotation = c;

    if(c < 0)
        c = c + 100;
        _lastRotation = c;
    
    if(c >= 100)
        c = c-100;
        _lastRotation = c;
    



    if(c >= 99.5)
        displayNumber1.text = @"0";
     else 
        displayNumber1.text = ([NSString stringWithFormat:@"%.f", c]);
    

    if([displayNumber1.text isEqualToString:lastText1])
     else 
        [theAudio play];
    



    lastText1 = displayNumber1.text;

    rotationGestureRecognizer.rotation = 0.0;








- (void)didReceiveMemoryWarning 
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.


@end

【问题讨论】:

【参考方案1】:

欢迎来到 Stack Overflow。

我的猜测是您的视图控制器已激活 AutoLayout。如果是这种情况,您需要更改动画代码,以便通过操作按钮上的一个或多个约束而不是更改其框架来为按钮设置动画。

问题在于,当您直接更改框架时,有时会触发表单的重新布局,并且约束会将其重新定位。即使您没有显式添加约束,系统也会这样做。

旋转动画应该没问题,因为它改变的是视图变换的旋转,而不是它的位置,而且我知道旋转没有任何约束。

使用约束进行动画处理的方法是将约束附加到 IB 中的按钮,然后从约束拖动到视图控制器的标题以创建约束的出口。 (例如,前导和上边缘约束。)

然后在您的动画中更改约束上的常量并调用 layoutIfNeeded。

另一种方法是关闭视图控制器的自动布局,使用旧式“支柱和弹簧”布局,然后您的帧动画将照常工作。

【讨论】:

关闭自动布局 - 现在完美运行!!正如你所说,我代码中的旋转手势在使用自动布局时似乎触发了某种“重置约束”。 关闭自动布局并不是一个理想的解决方案。 Apple 正在积极转向自动布局,甚至可能在未来某个时候弃用旧式的调整遮罩(“支柱和弹簧”布局)的方式。同时,除非您使用自动布局,否则某些功能将无法使用。你肯定无法支持 iOS 9 中提供的分屏多任务窗口大小调整,除非你使用自动布局和大小类,例如。

以上是关于动画后的iOS旋转手势的主要内容,如果未能解决你的问题,请参考以下文章

手势与动画效果

ios uiimageview点击手势在动画期间不起作用

iOS 动画块手势识别器

使用手势在 iOS 中移动/动画化 UI 元素

iOS火焰动画效果图文混排框架StackView效果偏好设置底部手势等源码

iOS核心动画之图片旋转、脉冲动画、水波纹动画