如何实现像 Feedly 这样的动画,在 iOS Objective-c 中分类新闻应用

Posted

技术标签:

【中文标题】如何实现像 Feedly 这样的动画,在 iOS Objective-c 中分类新闻应用【英文标题】:How to implement animation like Feedly , insorts news app in iOS objective-c 【发布时间】:2016-11-28 10:57:09 【问题描述】:

我想实现一个类似 insorts 和 feedly 新闻应用的动画。 我找到了快速版本 是通过uicollectionview布局定制实现的。

这是链接

Depth Page transform on ios 我将 swift 转换为目标 c,但没有达到相同的效果。

这是我的代码

导入“DepthLayout.h”

@interface DepthLayout() 
    CGFloat contentWidth;
    CGFloat contentHeight;
    CGFloat yOffset;
    CGFloat maxAlpha;
    CGFloat minAlpha;
    CGFloat widthOffset;
    CGFloat heightOffset;
    NSMutableArray * cache;

@end

@implementation DepthLayout
#pragma mark - Lifecycle

- (id)init

    self = [super init];
    if (self) 
        [self setup];
    

    return self;


- (id)initWithCoder:(NSCoder *)aDecoder

    self = [super init];
    if (self) 
        [self setup];
    

    return self;


- (void)setup


    yOffset=0;
    maxAlpha=1;
    minAlpha=0;
    widthOffset=35;
    heightOffset=35;
    cache=[[NSMutableArray alloc]init];


-(CGFloat)itemWidth
    return CGRectGetWidth(self.collectionView.bounds);


-(CGFloat)itemHeight
    return CGRectGetHeight(self.collectionView.bounds);


-(CGFloat)collectionViewHeight
    return CGRectGetHeight(self.collectionView.bounds);


-(NSInteger)numberOfItems
    return [self.collectionView numberOfItemsInSection:0];


-(CGFloat)dragOffset
    return CGRectGetHeight(self.collectionView.bounds);


-(NSInteger)currentItemIndex
    return MAX(0,(NSInteger)(self.collectionView.contentOffset.y/[self collectionViewHeight]));


-(CGFloat)nextItemBecomeCurrentPercentage
    return (self.collectionView.contentOffset.y/[self collectionViewHeight])-(CGFloat)[self currentItemIndex];


#pragma mark - Layout

- (void)prepareLayout
    [cache removeAllObjects];
    yOffset=0;
    for(NSInteger item=0;item<[self numberOfItems];item++)
       NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
        UICollectionViewLayoutAttributes *attribute =
        [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
        if ((indexPath.item == [self currentItemIndex ]+1) && (indexPath.item < [self numberOfItems]))
            attribute.alpha = minAlpha + MAX((maxAlpha-minAlpha) * [self nextItemBecomeCurrentPercentage], 0);
            CGFloat width = [self itemWidth] - widthOffset + (widthOffset * [self nextItemBecomeCurrentPercentage]);
            CGFloat height = [self itemWidth] - heightOffset + (heightOffset * [self nextItemBecomeCurrentPercentage]);
            CGFloat deltaWidth =  width/[self itemWidth];
            CGFloat deltaHeight = height/[self itemHeight ];
            attribute.frame = CGRectMake(0, yOffset, [self itemWidth],[self itemHeight]);
            attribute.transform = CGAffineTransformMakeScale(deltaWidth, deltaHeight);
            CGPoint center=self.collectionView.center;
            center.y=self.collectionView.center.y+self.collectionView.contentOffset.y;
            center.x=self.collectionView.center.x+self.collectionView.contentOffset.x;
            attribute.center = center;
            yOffset += [self collectionViewHeight];

        else
            attribute.frame = CGRectMake(0, yOffset, [self itemWidth],[self itemHeight]);
            CGPoint center=self.collectionView.center;
            center.y=self.collectionView.center.y+yOffset;
            center.x=self.collectionView.center.x;
            yOffset += [self collectionViewHeight];
        
        [cache addObject:attribute];
    



-(CGSize)collectionViewContentSize
    contentWidth = CGRectGetWidth(self.collectionView.bounds);
    contentHeight = (CGFloat)[self numberOfItems] * CGRectGetHeight(self.collectionView.bounds);
    return CGSizeMake(contentWidth, contentHeight);

-(NSMutableArray *)layoutAttributesForElementsInRect:(CGRect)rect


    NSMutableArray* layoutAttributes = [[NSMutableArray alloc]init];
    for (UICollectionViewLayoutAttributes * attribute in cache)
        if(CGRectIntersectsRect(attribute.frame, rect))
            [layoutAttributes addObject:attribute];
        
    
    return layoutAttributes;

-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
    return YES;

-(CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
    NSInteger itemIndex = round(proposedContentOffset.y / ([self dragOffset]));
    CGFloat yOffsetTemp = itemIndex * CGRectGetHeight(self.collectionView.bounds);
    return CGPointMake( 0,  yOffsetTemp);


-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath*)indexPath 

    UICollectionViewLayoutAttributes *attr=[UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    return attr;

@end

有什么问题?

【问题讨论】:

【参考方案1】:

无需将 swift 转换为目标 c。

我在我的 Objective C 项目中直接使用 Swift 文件 满足我的要求。

我从这里使用了 UltravisualLayout:Depth Page transform on iOS

感谢 swift 和 Objective C 之间的桥接;

【讨论】:

以上是关于如何实现像 Feedly 这样的动画,在 iOS Objective-c 中分类新闻应用的主要内容,如果未能解决你的问题,请参考以下文章

如何在 iOS 11 中像点击状态栏一样调用缓慢滚动到顶部的动画?

ios中的圆轮动画实现

如何在 iOS 中高效地使用图像制作动画

这样做动画交互,一点都不费力!

尝试重新创建像 Stripe 这样的抖动动画

如何通过许多子视图保持 iOS 动画流畅