Using UIDynamicAnimator from UIKit Dynamics when creating tables based on UICollectionView

As you know in the latest version of the SDK (UIKit Dynamics framework), developers can define dynamic behavior for UIView objects, as well as other objects that accept the UIDynamicItem protocol.

In this article I want to share the experience of using such objects.

The goal was to make an animation similar to that used in the Messages application on iOS 7:

image

After searching and studying the documentation, it was decided to use the UIDynamicAnimator in conjunction with the UICollectionView .

To do this, it was necessary to create an inheritor class UICollectionViewFlowLayout :

#import 
@interface DVCollectionViewFlowLayout : UICollectionViewFlowLayout
@end


add property with type UIDynamicAnimator


#import "DVCollectionViewFlowLayout.h"
@interface DVCollectionViewFlowLayout()
//объект-аниматор
@property (nonatomic, strong) UIDynamicAnimator *dynamicAnimator;
@end
@implementation DVCollectionViewFlowLayout
@synthesize dynamicAnimator = _dynamicAnimator;
-(id)initr{
    self = [super init];
    if (self){
        _dynamicAnimator = [[UIDynamicAnimator alloc] initWithCollectionViewLayout:self];
    }
    return self;
}


Dynamic behavior becomes active when we add it to an object that is an instance of UIDynamicAnimator. An animator defines the context in which dynamic behavior is executed.

After that, we must redefine the following functions in it:


#import "DVCollectionViewFlowLayout.h"
 // .........
- (void)prepareLayout{
    [super prepareLayout];
    CGSize contentSize = [self collectionViewContentSize];
    NSArray *items = [super layoutAttributesForElementsInRect:CGRectMake(0, 0, contentSize.width, contentSize.height)];
    if (items.count != self.dynamicAnimator.behaviors.count) {
        [self.dynamicAnimator removeAllBehaviors];
        for (UICollectionViewLayoutAttributes *item in items) {
            UIAttachmentBehavior *springBehavior = [[UIAttachmentBehavior alloc] initWithItem:item attachedToAnchor:item.center];
//экспериментальным путём подобранные значения для лучшего восприятия (на глаз)
            springBehavior.length = 0.f;
            springBehavior.damping = 1.f;
            springBehavior.frequency = 6.8f;
            [self.dynamicAnimator addBehavior:springBehavior];
        }
    }
}
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{
    return [self.dynamicAnimator itemsInRect:rect];
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
    return [self.dynamicAnimator layoutAttributesForCellAtIndexPath:indexPath];
}
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds{
    CGFloat scrollDelta = newBounds.origin.y - self.collectionView.bounds.origin.y;
    CGPoint touchLocation = [self.collectionView.panGestureRecognizer locationInView:self.collectionView];
    for (UIAttachmentBehavior *springBehavior in self.dynamicAnimator.behaviors) {
        CGPoint anchorPoint = springBehavior.anchorPoint;
        CGFloat touchDistance = fabsf(touchLocation.y - anchorPoint.y);
       //экспериментальным путём подобранные значения для лучшего восприятия (на глаз)
 CGFloat resistanceFactor = 0.002;
        UICollectionViewLayoutAttributes *attributes = springBehavior.items.firstObject;
        CGPoint center = attributes.center;
        float resistedScroll = scrollDelta * touchDistance * resistanceFactor;
        float simpleScroll = scrollDelta;
        float actualScroll = MIN(abs(simpleScroll), abs(resistedScroll));
        if(simpleScroll < 0){
            actualScroll *= -1;
        }
        center.y += actualScroll;
        attributes.center = center;
        [self.dynamicAnimator updateItemUsingCurrentState:attributes];
    }
    return NO;
}
-(void)dealloc{
        [self.dynamicAnimator removeAllBehaviors];
        self.dynamicAnimator = nil;
}


The UIAttachmentBehavior object defines the relationship between the dynamic item element of the UICollectionViewLayoutAttributes class and the item.center (the center of this element). When one element or point moves, the attached element also moves. Using the damping and frequency properties, we can specify how the behavior will change over time.

Source code

Useful links about animations in iOS 7:



Also popular now: