Swift21/90Days - 動態變化的 UITableView 頭部

Swift90Days - 動態變化的 UITableView 頭部

今天公司的有一個需求是實現動態的 UITableView 頭部,基本需求是:git

  • 默認狀態顯示一個 headerView 展現頭像。
  • 上推時 headerView 縮小高度,圖像逐漸模糊。
  • 下拉時 headerView 的圖像相應下移,方便展現全景。

下面先看看開源項目 ParallaxTableViewHeader 的實現方式,和本身的作個對比。github

Blur

它的虛化效果是經過 UIImage+ImageEffects 這個 category 實現的。app

具體內容就不深究了,對於圖像處理這塊的類庫不太熟悉。code

在 headerView 中能夠這樣使用獲取一張虛化的圖片:事件

- (void)refreshBlurViewForNewImage
{
    UIImage *screenShot = [self screenShotOfView:self];
    screenShot = [screenShot applyBlurWithRadius:5 tintColor:[UIColor colorWithWhite:0.6 alpha:0.2] saturationDeltaFactor:1.0 maskImage:nil];
    self.bluredImageView.image = screenShot;
}

Header

源碼中提供了兩種工廠方法進行初始化:圖片

+ (id)parallaxHeaderViewWithImage:(UIImage *)image forSize:(CGSize)headerSize;
+ (id)parallaxHeaderViewWithSubView:(UIView *)subView;

第一種方法是經過 image 進行初始化,會調用默認的 init 方法,第二種是自定義 subView 的方法。ip

咱們只用看下默認的 init 方法:get

- (void)initialSetupForDefaultHeader
{
    // 初始化一個 scrollView 做爲容器
    UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:self.bounds];
    self.imageScrollView = scrollView;

    // 初始化默認大小的圖片,用於顯示
    UIImageView *imageView = [[UIImageView alloc] initWithFrame:scrollView.bounds];
    // 設置其拉伸模式爲:上下左右間距不變,拉伸高度和寬度。
    imageView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
    // 設置圖片填充模式:儘可能填充,適當裁剪
    imageView.contentMode = UIViewContentModeScaleAspectFill;
    imageView.image = self.headerImage;
    self.imageView = imageView;
    [self.imageScrollView addSubview:imageView];

    // 設置顯示的標籤文字
    CGRect labelRect = self.imageScrollView.bounds;
    labelRect.origin.x = labelRect.origin.y = kLabelPaddingDist;
    labelRect.size.width = labelRect.size.width - 2 * kLabelPaddingDist;
    labelRect.size.height = labelRect.size.height - 2 * kLabelPaddingDist;
    UILabel *headerLabel = [[UILabel alloc] initWithFrame:labelRect];
    headerLabel.textAlignment = NSTextAlignmentCenter;
    headerLabel.numberOfLines = 0;
    headerLabel.lineBreakMode = NSLineBreakByWordWrapping;
    headerLabel.autoresizingMask = imageView.autoresizingMask;
    headerLabel.textColor = [UIColor whiteColor];
    headerLabel.font = [UIFont fontWithName:@"AvenirNextCondensed-Regular" size:23];
    self.headerTitleLabel = headerLabel;
    [self.imageScrollView addSubview:self.headerTitleLabel];

    // 設置虛化的圖片,默認 alpha 爲0,即徹底透明
    self.bluredImageView = [[UIImageView alloc] initWithFrame:self.imageView.frame];
    self.bluredImageView.autoresizingMask = self.imageView.autoresizingMask;
    self.bluredImageView.alpha = 0.0f;
    [self.imageScrollView addSubview:self.bluredImageView];
    [self addSubview:self.imageScrollView];
}

大概瞭解了整個 view 的結構,不太清楚爲何要經過截屏的方式獲取圖片。源碼

經過實現 UISCrollViewDelegate 中的 scrollViewDidScroll 方法來監聽 UITableView 的滑動事件。it

若是當前 UITableView 滑動了,則會調用 headerView 的 layoutHeaderViewForScrollViewOffset 方法:

- (void)layoutHeaderViewForScrollViewOffset:(CGPoint)offset
{
    CGRect frame = self.imageScrollView.frame;

    // 若是是上推
    if (offset.y > 0)
    {
        frame.origin.y = offset.y *kParallaxDeltaFactor;
        self.imageScrollView.frame = frame;

        // 設置虛化圖層的 alpha 值。乘2是爲了增大虛化梯度
        self.bluredImageView.alpha = 2 * (offset.y / kDefaultHeaderFrame.size.height) ;

        // 裁切 subview
        self.clipsToBounds = YES;
    }
    // 若是是下拉
    else
    {
        CGFloat delta = 0.0f;
        CGRect rect = kDefaultHeaderFrame;
        delta = fabs(offset.y);
        // 爲了保持 header 的 top 對齊須要設置 y 座標
        rect.origin.y -= delta;
        rect.size.height += delta;
        self.imageScrollView.frame = rect;
        self.clipsToBounds = NO;

        // 設置 label 的 alpha 值
        self.headerTitleLabel.alpha = 1 - delta / kMaxTitleAlphaOffset;
    }
}

上推的時候主要工做是虛化圖片,下拉的時候主要工做是設置圖片高度和座標。這個和我本身寫的基本思路相同。

大概就是這樣,引用中放了另外一個相似的項目供你們參考。這個項目與 Swift 無關,不過實現的思路能夠借鑑。


References

相關文章
相關標籤/搜索