zoukankan      html  css  js  c++  java
  • 有弹性,可伸展的UICollectionView 头部视图

    本文翻译自:Stretchy UICollectionView headers

    滚动视图的反弹效果可能是iOS中最具特色的效果之一。虽然最初只是华而不实,但随着时间的推移,实际上它已经发挥了一些功能用途,像下拉刷新。另一个很好地应用滚动视图的反弹效果的,就是我最近看到的弹性头部视图。

    这个效果非常好,当你向下拉动滚动视图时,可以在顶部和底部查看更多的图片内容。你可能已经在Twitter的iOS应用和Airbnb清单中看到类似的效果了。这种效果很容易实现,今天我将向您展示如何去做。

    让我们开始吧。首先,创建一个[UICollectionViewFlowLayout][3]的子类。

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

    如果你曾经摆弄自定义过UICollectionView的布局,那么你可能已经意识到它们非常强大的。这是我们的实现:

    #import "StretchyHeaderCollectionViewLayout.h"
    
    @implementation StretchyHeaderCollectionViewLayout
    
    - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {
        // This will schedule calls to layoutAttributesForElementsInRect: as the 
        // collectionView is scrolling. 
        return YES;
    }
    
    - (UICollectionViewScrollDirection)scrollDirection {
        // This subclass only supports vertical scrolling.
        return UICollectionViewScrollDirectionVertical;
    }
    
    - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
    
        UICollectionView *collectionView = [self collectionView];
        UIEdgeInsets insets = [collectionView contentInset];
        CGPoint offset = [collectionView contentOffset];
        CGFloat minY = -insets.top;
    
        // First get the superclass attributes.
        NSArray *attributes = [super layoutAttributesForElementsInRect:rect];
    
        // Check if we've pulled below past the lowest position
        if (offset.y < minY) {  
    
            // Figure out how much we've pulled down 
            CGFloat deltaY = fabsf(offset.y - minY);
    
            for (UICollectionViewLayoutAttributes *attrs in attributes) {
    
                // Locate the header attributes
                NSString *kind = [attrs representedElementKind];
                if (kind == UICollectionElementKindSectionHeader) {
    
                    // Adjust the header's height and y based on how much the user
                    // has pulled down.
                    CGSize headerSize = [self headerReferenceSize];
                    CGRect headerRect = [attrs frame];
                    headerRect.size.height = MAX(minY, headerSize.height + deltaY);
                    headerRect.origin.y = headerRect.origin.y - deltaY;
                    [attrs setFrame:headerRect];
                    break;
                }
            }
        }
        return attributes;
    }
    
    @end
    

    这个自定义的布局会检查我们是否下拉到最低的偏移量,这意味着我们将开始拉伸头部视图。如果真的是,我们找到这个头部元素,根据拉伸的值来增加它的高度和y轴上的偏移量。

    接下来,在你配置你的集合视图的地方,添加下面的代码:

    // Create a new instance of our stretchy layout and set the 
    // default size for our header (for when it's not stretched)
    StretchyHeaderCollectionViewLayout *stretchyLayout;
    stretchyLayout = [[StretchyHeaderCollectionViewLayout alloc] init];
    [stretchyLayout setHeaderReferenceSize:CGSizeMake(320.0, 160.0)];
    
    // Set our custom layout
    [collectionView setCollectionViewLayout:stretchyLayout];
    // and tell our collection view to always bounce.
    [collectionView setAlwaysBounceVertical:YES];
    
    // Then register a class to use for the header.
    [collectionView registerClass:[UICollectionReusableView class]
    

    forSupplementaryViewOfKind:UICollectionElementKindSectionHeader
    withReuseIdentifier:@"ident"];

    最后一件需要做的事情就是创建我们的头部视图,而且应该是UICollectionReusableView的子类。我们可以添加一个UIImageView作为它的子视图,然后使用autoresizing来让它大小合适:

    - (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView 
           viewForSupplementaryElementOfKind:(NSString *)kind 
                                 atIndexPath:(NSIndexPath *)indexPath {
        // You can make header an ivar so we only ever create one
        if (!header) {
    
            header = [collectionView dequeueReusableSupplementaryViewOfKind:kind
                                                    withReuseIdentifier:@"ident"
                                                           forIndexPath:indexPath];
            CGRect bounds;
            bounds = [header bounds];
    
            UIImageView *imageView;
            imageView = [[UIImageView alloc] initWithFrame:bounds];
            [imageView setImage:[UIImage imageNamed:@"header-background"]];
    
            // Make sure the contentMode is set to scale proportionally
            [imageView setContentMode:UIViewContentModeScaleAspectFill];
            // Clip the parts of the image that are not in frame
            [imageView setClipsToBounds:YES];
            // Set the autoresizingMask to always be the same height as the header
            [imageView setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
            // Add the image to our header
            [header addSubview:imageView];
        }
        return header;
    }
    

    这个autoresizingMask 会保持图片的高度与头部视图的一致。这个contentMode和clipsToBounds属性将居中图片以及裁切多余的内容。

    你可以在Github上找到完整的代码。

  • 相关阅读:
    微信小程序promise解决onload异步
    小程序中使用 Less (VScode)
    Vue中使用less
    小程序获取 图片宽高
    ssh 登录出现Are you sure you want to continue connecting (yes/no)?解决方法
    SQL SERVER 收缩日志
    SQL SERVER-日期时间
    oracle判断查询结果是否为空
    修改Tomcat默认JDK版本
    Microsoft SQL Server Management Studio ------- 附加数据库 对于 服务器“xxx&amp;amp;quot;失败(错误码5120)
  • 原文地址:https://www.cnblogs.com/YungMing/p/4342368.html
Copyright © 2011-2022 走看看