Использование UIDynamicAnimator из UIKit Dynamics при создании таблиц на основе UICollectionView

от автора

Как известно в последней версии SDK (фреймворк UIKit Dynamics) разработчики могут определять динамическое поведение для UIView объектов, а также других объектов, принимающих протокол UIDynamicItem.

В данной статье я хочу поделиться опытом использования таких объектов.

Целью было сделать анимацию, аналогичную той, что используется в приложении Messages на iOS 7:

image

После поисков и изучения документации решено было использовать UIDynamicAnimator в связке с UICollectionView.

Для этого необходимо было создать класс-наследник UICollectionViewFlowLayout:

#import <UIKit/UIKit.h>  @interface DVCollectionViewFlowLayout : UICollectionViewFlowLayout  @end 

добавить свойство с типом 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; }  

Динамическое поведение становится активным, когда мы его добавляем к объекту, который является экземпляром UIDynamicAnimator. Аниматор определяет контекст, в котором динамическое поведение выполняется.

После этого мы должны переопределить в нём нижеперечисленные функции:

 #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; }  

Объект UIAttachmentBehavior определяет связь между динамическим элементом item класса UICollectionViewLayoutAttributes и точкой item.center (центром этого элемента). Когда один элемент или точка перемещается, присоединенный элемент также перемещается. C помощью свойств damping и frequency мы можем указать как изменится поведение с течением времени.

Исходный код

Полезные ссылки про анимации в iOS 7:

ссылка на оригинал статьи http://habrahabr.ru/post/198890/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *