美文网首页ios学习M_iOSiOS开发骚操作
iOS主流个人主页随滚动可缩放头图

iOS主流个人主页随滚动可缩放头图

作者: 开源者联盟 | 来源:发表于2015-12-18 11:56 被阅读1154次

效果图

  • 向上滚动图片变窄


    zoomHeaderImageView.gif
  • 向上滚动图片不变


    zoomHeaderImageViewNoNarrow.gif

源码地址在我的github

前言

目前主流APP的个人主页都会在顶部展示一个头图,图片可以由用户自定义设置,不仅彰显了用户的个性,也增加了页面的丰富性;并且头图也可以随着页面的滚动有一种缩放的效果,大大的提高了用户的交互性,让用户爱不释手!如果你正在负责这方面的需求,我觉得你应该尝试下这个效果。

实现原理

核心原理很简单,就是UIViewcontentMode属性。针对UIImageView有常用的三种mode:UIViewContentModeScaleToFill
UIViewContentModeScaleAspectFitUIViewContentModeScaleAspectFill,用三个图片展示它们的区别吧。

  • UIViewContentModeScaleToFill 这个就比较暴力了,按着UIImageView的尺寸将图片不按着原图比例填满,所以出现了比较丑的压扁效果。
    UIViewContentModeScaleToFill.png
  • UIViewContentModeScaleToFill将图片进行等比例缩放,直到宽或者高和UIImageView的一样。所以高度先合适,宽度只能留白了。
    UIViewContentModeScaleAspectFit.png
  • UIViewContentModeScaleAspectFill将图片进行等比例缩放,直到填满整个UIImageView,这个效果正是我们想要的。
    UIViewContentModeScaleAspectFill.png

综上所述,我们将UIImageView.contentMode设置为UIViewContentModeScaleAspectFill,然后随着滚动的offsetY去更新UIImageView的y和height就行了。

代码展示

我们开发的时候,对于视图的布局一般有三种方式:

  • 直接设置视图的frame,不进行约束;

  • 使用代码约束,常用的masonry;

  • 使用xib约束;
    选择不同的布局方式,在实现效果的细节上也是不一样的,所以我针对这三种方式进行分别展示。当你的项目选择一种适合的布局方式,然后选择效果的实现方式即可。

  • 直接设置视图的frame,不进行约束

初始化视图
- (void)initUINoConstraint
{
    UIImageView *headerImageView = [[UIImageView alloc] initWithFrame:self.bounds];
    headerImageView.clipsToBounds = YES;
    headerImageView.contentMode = UIViewContentModeScaleAspectFill;
    headerImageView.image = [UIImage imageNamed:@"lufei.jpg"];
    [self addSubview:headerImageView];
    self.headerImageView = headerImageView;
    self.originalHeaderImageViewFrame = self.bounds;
}
根据offsetY更新布局
- (void)updateHeaderImageViewFrameWithOffsetY:(CGFloat)offsetY
{
//防止height小于0
            if (self.originalHeaderImageViewFrame.size.height - offsetY < 0) {
                return;
            }
            //如果不使用约束的话,图片的y值要上移offsetY,同时height也要增加offsetY
            CGFloat x = self.originalHeaderImageViewFrame.origin.x;
            CGFloat y = self.originalHeaderImageViewFrame.origin.y + offsetY;
            CGFloat width = self.originalHeaderImageViewFrame.size.width;
            CGFloat height = self.originalHeaderImageViewFrame.size.height - offsetY;
            self.headerImageView.frame = CGRectMake(x, y, width, height);
}
  • 使用代码约束,常用的masonry
初始化视图
- (void)initUICodeConstraint
{
    UIImageView *headerImageView = [[UIImageView alloc] init];
    headerImageView.clipsToBounds = YES;
    headerImageView.contentMode = UIViewContentModeScaleAspectFill;
    headerImageView.image = [UIImage imageNamed:@"lufei.jpg"];
    [self addSubview:headerImageView];
    self.headerImageView = headerImageView;
    //约束设置为:跟父视图左、下、右贴紧,再约束高度,所以更新高度约束的时候会向上增加,xib约束同理
    [headerImageView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.right.and.bottom.equalTo(self).offset(0);
        self.codeConstraintHeight = make.height.equalTo(@(self.bounds.size.height));
    }];
    self.originalHeaderImageViewHeight = self.bounds.size.height;
}
根据offsetY更新布局
- (void)updateHeaderImageViewFrameWithOffsetY:(CGFloat)offsetY
{
//防止height小于0
            if (self.originalHeaderImageViewHeight -offsetY < 0) {
                return;
            }
            //第一种方式:获取到这个约束,直接对约束值修改
            //self.codeConstraintHeight.equalTo(@(self.originalHeaderImageViewHeight -offsetY));
            //第二种方式:直接使用masonry提供的更新约束方法,其实原理是一样的
            [self.headerImageView mas_updateConstraints:^(MASConstraintMaker *make) {
                make.height.equalTo(@(self.originalHeaderImageViewHeight -offsetY));
            }];
}
  • 使用xib约束
//需要将xib中的高度约束用拉线拉出来
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *layoutHeightOfHeaderImageView;
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {
        self.isNeedNarrow = YES;
        [self initUIXibConstraint];
    }
    return self;
}
根据offsetY更新布局
- (void)updateHeaderImageViewFrameWithOffsetY:(CGFloat)offsetY
{
//防止height小于0
            if (self.originalHeaderImageViewHeight -offsetY < 0) {
                return;
            }
            self.layoutHeightOfHeaderImageView.constant = self.originalHeaderImageViewHeight - offsetY;
}
  • 向上滚动图片是否变窄的实现
//用于实现向上滚动的时候,图片不变窄
- (void)updateHeaderImageViewFrameWithOffsetY:(CGFloat)offsetY
{
    if (!self.isNeedNarrow && offsetY > 0) {
        return;
    }
}

外部使用

    //没有约束
//    ZoomHeaderView *headerView = [[ZoomHeaderView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 300) type:ZoomHeaderViewTypeNoConstraint];
    //代码约束
//    ZoomHeaderView *headerView = [[ZoomHeaderView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 300) type:ZoomHeaderViewTypeCodeConstraint];
    //xib约束
    ZoomHeaderView *headerView = [[[NSBundle mainBundle] loadNibNamed:@"ZoomHeaderView" owner:nil options:nil] lastObject];
    //可以对比看效果
//    headerView.isNeedNarrow = NO;
    tableView.tableHeaderView = headerView;
    self.headerView = headerView;
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    CGFloat offsetY = scrollView.contentOffset.y;
    [self.headerView updateHeaderImageViewFrameWithOffsetY:offsetY];
}

总结

总得来说,代码还是比较简单的,可以快捷实现滚动缩放的效果,只是要注意一些细节设置,欢迎大家去我的github,下载源码进行查看。如何我的描述中有什么纰漏或者错误的地方,麻烦各位大神多多指正!

相关文章

网友评论

  • rookiesss::blush: 大佬,能做个下拉轮播放大的不?
    开源者联盟:@rookiesss 应该是你内部代码错误,推荐找一个靠谱的三方库轮播图试试
    rookiesss:@暴走的鑫鑫 我用SDWebImage来做的,不自动轮播的时候正常的,打开自动轮动下拉图片一直抖动变大,不知道是不是NSTimer的影响。
    开源者联盟:你把UIImageView换成你的轮播图视图就可以了,缩放原理是一样的
  • 弹钢琴的安徒生:博主见谅。并不是说你的方法不好。我只是说我的做法。并且我只是个初学者
  • 弹钢琴的安徒生:我也做过这个效果 你这个做的有点麻烦 uitableview继承自uiscrollview。你上面放个uiimageview 设置好frame 实现scrollviewdidscrollview这个方法 计算偏移值。
    开源者联盟:@弹钢琴的安徒生 这个方案是我目前能想到比较好的思路了,不知兄台能否分享下您的实现方案,留下github地址借看一下?

本文标题:iOS主流个人主页随滚动可缩放头图

本文链接:https://www.haomeiwen.com/subject/otsphttx.html