【问题标题】:UIButton Press/Release Animation Oddly InconsistentUIButton Press/Release 动画奇怪地不一致
【发布时间】:2014-10-09 08:19:47
【问题描述】:

我正在尝试编写一个自定义的UIButton 子类,它将在新闻发布期间“动画化”。

按下时,按钮应“缩小”(朝向其中心)至其原始大小的 90%。 释放后,按钮应“展开”到 105%,再次缩小到 95%,然后恢复到原来的大小。

这是我现在得到的代码:

#pragma mark -
#pragma mark - Touch Handling
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesBegan:touches withEvent:event];
    [self animatePressedDown];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesCancelled:touches withEvent:event];
    [self animateReleased];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesEnded:touches withEvent:event];
    [self animateReleased];
}

- (void)animatePressedDown {
    NSLog(@"button.frame before animatedPressedDown: %@", NSStringFromCGRect(self.frame));
    [self addShadowLayer];
    CATransform3D ninetyPercent = CATransform3DMakeScale(0.90f, 0.90f, 1.00f);
    [UIView animateWithDuration:0.2f
                     animations:^{
                         self.layer.transform = ninetyPercent;
                     }
                     completion:^(BOOL finished) {
                         NSLog(@"button.frame after animatedPressedDown: %@", NSStringFromCGRect(self.frame));
                     }
     ];
}
- (void)animateReleased {
    [self.shadowLayer removeFromSuperlayer];
    CATransform3D oneHundredFivePercent = CATransform3DMakeScale(1.05f, 1.05f, 1.00f);
    CATransform3D ninetyFivePercent     = CATransform3DMakeScale(0.95f, 0.95f, 1.00f);
    [UIView animateWithDuration:0.1f
                     animations:^{
                         self.layer.transform = oneHundredFivePercent;
                     }
                     completion:^(BOOL finished) {
                         NSLog(@"button.frame after animateReleased (Stage 1): %@", NSStringFromCGRect(self.frame));
                         [UIView animateWithDuration:0.1f
                                          animations:^{
                                              self.layer.transform = ninetyFivePercent;
                                          }
                                          completion:^(BOOL finished) {
                                              NSLog(@"button.frame after animateReleased (Stage 2): %@", NSStringFromCGRect(self.frame));
                                              [UIView animateWithDuration:0.1f
                                                               animations:^{
                                                                   self.layer.transform = CATransform3DIdentity;
                                                                   self.layer.frame     = self.frame;
                                                               }
                                                               completion:^(BOOL finished) {
                                                                   NSLog(@"button.frame after animateReleased (Stage 3): %@", NSStringFromCGRect(self.frame));
                                                               }
                                               ];
                                          }
                          ];
                     }
     ];
}

无论如何,上面的代码可以完美运行……有时。在其他时候,按钮动画按预期工作,但在“释放”动画之后,按钮的最后一帧从其原始位置向上和向左“移动”。这就是为什么我有那些NSLog 语句,以准确跟踪动画每个阶段按钮框架的位置。当“转变”发生时,它发生在animatePressedDownanimateReleased 之间。至少,animatePressedDown 中显示的框架是 ALWAYS 我所期望的,但animateReleased 中框架的第一个值经常出错。

我看不出这种疯狂的模式,尽管我的应用程序中的相同按钮在不同应用程序运行之间往往表现得正确或不正确。

我对所有按钮都使用了自动布局,所以我不知道让一个按钮正常工作而另一个按钮改变其位置有什么区别。

【问题讨论】:

    标签: ios objective-c animation uibutton


    【解决方案1】:

    当我回答自己的问题时,我真的很讨厌,但我想通了。

    (我已经为这个问题苦苦挣扎了好几天,但在我问了这个问题之后,它终于点击了。它不总是这样吗?)

    显然,对我来说问题在于(在“移动”的按钮上)我在动画中间更改了按钮的标题。

    一旦我设置了一个基于块的系统,仅在按钮的“弹跳”/“弹出”动画完成后调用标题更改,问题就消失了。

    我仍然不知道为什么会这样工作,因为我设置的标题并没有改变按钮的整体大小,但是按照描述设置按钮解决了我的问题。

    这是来自我的自定义 UIButton 子类的代码,添加了 block 属性:

    @interface MSSButton : UIButton {
    
    }
    @property (copy  , nonatomic) void(^pressedCompletion)(void);
    // Other, non-related stuff...
    @end
    
    @implementation MSSButton
    #pragma mark -
    #pragma mark - Touch Handling
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
        [super touchesBegan:touches withEvent:event];
        [self animatePressedDown];
    }
    - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
        [super touchesCancelled:touches withEvent:event];
        [self animateReleased];
    }
    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
        [super touchesEnded:touches withEvent:event];
        [self animateReleased];
    }
    
    - (void)animatePressedDown {
        [self addShadowLayer];
        CATransform3D ninetyPercent = CATransform3DMakeScale(0.90f, 0.90f, 1.00f);
        [UIView animateWithDuration:0.2f
                         animations:^{
                             self.layer.transform = ninetyPercent;
                         }
         ];
    }
    
    - (void)animateReleased {
        [self.shadowLayer removeFromSuperlayer];
        CATransform3D oneHundredFivePercent = CATransform3DMakeScale(1.05f, 1.05f, 1.00f);
        CATransform3D ninetyFivePercent     = CATransform3DMakeScale(0.95f, 0.95f, 1.00f);
        [UIView animateWithDuration:0.1f
                         animations:^{
                             self.layer.transform = oneHundredFivePercent;
                         }
                         completion:^(BOOL finished) {
                             [UIView animateWithDuration:0.1f
                                              animations:^{
                                                  self.layer.transform = ninetyFivePercent;
                                              }
                                              completion:^(BOOL finished) {
                                                  [UIView animateWithDuration:0.1f
                                                                   animations:^{
                                                                       self.layer.transform = CATransform3DIdentity;
                                                                   }
                                                                   completion:^(BOOL finished) {
                                                                       if (self.pressedCompletion != nil) {
                                                                           self.pressedCompletion();
                                                                           self.pressedCompletion = nil;
                                                                       }
                                                                   }
                                                   ];
                                              }
                              ];
                         }
         ];
    }
    @end
    

    由于我的IBActionanimateReleased 之前触发(由于我的触摸处理方法中列出的方法顺序),我只需在IBAction 中设置pressedCompletion 块,并且标题在末尾更改动画序列。

    【讨论】:

      【解决方案2】:

      一个可能的问题是您在更改transform 属性后尝试使用视图的frame 属性。 UIView 类参考页specifically warns against that

      警告:如果变换属性不是恒等变换,则 此属性的值未定义,因此应忽略。

      具体来说,您正在更改图层的transform,这可能会影响视图的transform,然后访问self.frame。在访问 self.frame 之前,您可能需要确保视图的 transform 设置为 CGAffineTransformIdentity

      【讨论】:

      • 我理解为什么视图的框架应该被忽略,正如文档所说,但你似乎是说我的访问框架(我'我假设我的NSLog 声明)在某种程度上负责。我继续删除了我分配给视图框架的唯一行(在最后一个动画中),结果没有改变。我添加了该行,以查看是否可以防止视图“移动”,并且无论是否包含该行似乎都没有任何作用。所以,我不确定框架问题是否与我的问题有关。
      猜你喜欢
      • 1970-01-01
      • 2023-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-11
      • 2013-11-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多