IOS实现碎片化动画详解

2020-01-15 17:30:45于海丽
进行封装,以此来降低入侵性,实现低耦合的要求:


#define LXDMAXDURATION 1.2
#define LXDMINDURATION .2
#define LXDMULTIPLED .25

@interface UIView (LXDFadeAnimation)

/*!
 * @brief 视图是否隐藏
 */
@property (nonatomic, assign, readonly) BOOL isFade;
/*!
 * @brief 是否处在动画中
 */
@property (nonatomic, assign, readonly) BOOL isFading;
/*!
 * @brief 垂直方块个数。默认为3
 */
@property (nonatomic, assign) NSInteger verticalCount;
/*!
 * @brief 水平方块个数。默认为18
 */
@property (nonatomic, assign) NSInteger horizontalCount;
/*!
 * @brief 方块动画之间的间隔0.2~1.2。默认0.7
 */
@property (nonatomic, assign) NSTimeInterval intervalDuration;
/*!
 * @brief 每个方块隐藏的动画时间0.05~0.3,最多为动画时长的25%。默认为0.175
 */
@property (nonatomic, assign) NSTimeInterval fadeAnimationDuration;

- (void)configurateWithVerticalCount: (NSInteger)verticalCount horizontalCount: (NSInteger)horizontalCount interval: (NSTimeInterval)interval duration: (NSTimeInterval)duration;

- (void)reverseWithComplete: (void(^)(void))complete;
- (void)animateFadeWithComplete: (void(^)(void))complete;
- (void)reverseWithoutAnimate;

@end

在iOS中,在category中声明的所有属性编译器都不会自动绑定gettersetter方法,这意味着我们需要重写这两种方法,而且还不能使用下划线+变量名的方式直接访问变量。因此我们需要导入objc/runtime.h文件使用动态时提供的objc_associateObject机制来为视图动态增加属性:


- (BOOL)isFade
{
  return [objc_getAssociatedObject(self, kIsFadeKey) boolValue];
}  
// other getAssociatedObject method

- (void)setIsFade: (BOOL)isFade
{
  objc_setAssociatedObject(self, kIsFadeKey, @(isFade), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
// other setAssociatedObject method

有了碎片化隐藏视图的动画,同样需要一个还原的动画效果:


NSInteger fadeCount = self.verticalCount * self.horizontalCount;
for (NSInteger idx = fadeCount - 1; idx >= 0; idx--) {
  UIView * subview = [self.maskView viewWithTag: [self subViewTag: idx]];
  [UIView animateWithDuration: self.fadeAnimationDuration delay: self.intervalDuration * (fadeCount - 1 - idx) options: UIViewAnimationOptionCurveLinear animations: ^{
    subview.alpha = 1;
  } completion: nil];
}

现在我们还要考虑一个问题:假设用户点击某张图片的时候就根据视图是否隐藏状态来开始隐藏/显示的动画,当用户多次点击的时候,我们应该判断是否已经处在动画状态,如果是,那么不继续执行动画代码。另外,在动画开始之前,我们需要把标识动画状态的isFading设为YES,但是由于每个方块隐藏都存在一个动画,动画的结束时间应该怎么判断呢?已知fadeView的个数是