接轨形成没有做完的义务

紧接着上一篇swift/制作八个简练的tableheaderview+_navigationbar渐变效果(一)接轨形成没有做完的天职

根本介绍##\

  1. 监测tableView垂直滚动的舒畅(英文名:Jennifer)姿势
  2. 监测scrollView/collectionView横向滚动的不利姿势

编码

上一篇已经做到了对于UINavigationBar的增添,仅仅只用了24行代码变落成想要的效果。接下来编写tableheaderview的效果部分。

ParallaxHeaderView模糊.gif

1.监测tableView垂直滚动的舒畅(英文名:Jennifer)姿势###\

常备我们用KVO或许在scrollViewDidScroll代理方法中监听ScrollView/TableView的contentOffset,比如监听TableView的contentOffset来安装导航栏的发光度恐怕拉伸顶部的图形。

图片 1

JKNavigationController

大规模的架势是在scrollViewDidScroll的代办方法中监听scrollView.contentOffset.y,会发觉有导航栏时scrollView.contentOffset.y早先值大概会等于-64,借使再手动设置tableView.contentInset这些值又会变动,这些时候就需求计算出先河偏移量,然后再算偏移的差值,若是过几天再改下必要……重新总括

**那有没有更称心快意的姿态? **

首先定义二个成员属性,多少个是监测范围的临界值,另2个用来记录scrollView.contentInset.top(重点)

        // 监测范围的临界点,>0代表向上滑动多少距离,<0则是向下滑动多少距离
        @property (nonatomic, assign)CGFloat threshold;
        // 记录scrollView.contentInset.top
        @property (nonatomic, assign)CGFloat marginTop;

        // 这里设值-80,即向下滑动80,-80到0就是咱们重点监测的范围
        self.threshold = -80;

接下来在KVO回调或许scrollViewDidScroll代理方法中增进上面的代码。

2:ParallaxHeaderView(1在上篇%>_<%)

即使如此只是好像于二个图纸下拉推广的听从,但请允许本身使用Parallax来定名。

示例图给出三种功用,一种有模糊效果一种无模糊效果。先来贯彻率先种无模糊效果的。

亟需精通的就是contentInset,多少个值代表tableView的contentView上下左右偏离边界的值,界面有导航栏时,系统会自行将tableView的contentView到顶部的相距设为64,即contentInset.top=64,假如导航栏透明就足以看到有空白区域。没有导航栏或然我们调用self.automaticallyAdjustsScrollViewInsets

NO时,tableView的contentInset.top就会变为0。通过下边的算法,大家就可以不用去刻意统计起初的偏移量,只要设置好临界值就行,newoffsetY
就是大家实际要监测的舞狮。PS:手动设置tableView.contenInset要求在viewDidAppear中开展。

        // 实时监测scrollView.contentInset.top, 系统优化以及手动设置contentInset都会影响contentInset.top。
        if (self.marginTop != self.scrollView.contentInset.top) {
            self.marginTop = self.scrollView.contentInset.top;
        }
        //CGFloat offsetY = [change[@"new"] CGPointValue].y;
        CGFloat offsetY = scrollView.contentOffset.y;

        // newoffsetY 便是我们想监测的偏移offset.y,初始值为0
        // 向下滑动时<0,向上滑动时>0;
        CGFloat newoffsetY = offsetY + self.marginTop;

         if (newoffsetY >= self.threshold && newoffsetY <= 0) {
            CGFloat progress = newoffsetY/self.threshold;
        }

是骡子是马,拉出来溜溜,再看看效果图(图已毁)。

率先个页面(首页),上划变透明

- (void)scrollViewDidScroll:(UIScrollView *)scrollView{

    if (self.marginTop != scrollView.contentInset.top) {
        self.marginTop = scrollView.contentInset.top;
    }

    CGFloat offsetY = scrollView.contentOffset.y;
    CGFloat newoffsetY = offsetY + self.marginTop;

    // 临界值150,向上拖动时变透明
    if (newoffsetY >= 0 && newoffsetY <= 150) {
        [self.navigationController.navigationBar jp_setNavigationBarBackgroundAlpha:1- newoffsetY/150];
    }else if (newoffsetY > 150){
        [self.navigationController.navigationBar jp_setNavigationBarBackgroundAlpha:0];
    }else{
        [self.navigationController.navigationBar jp_setNavigationBarBackgroundAlpha:1];
    }

}

其次个界面仿搜狐晚报的出力,一生X命在他的稿子[仿写新浪晚报

图片 2

出自毕生X命

简短说下小编的笔触

  1. tableView的y坐标为20,然后组头中度44,加起来刚刚就是导航栏的可观。因为组头悬停在tableView的最下面,所以y坐标为20。
  2. 在navigationBar上面添加二个中度为20的view,放在状态栏上边,跟组头一样的颜料。navigationBar透明后view看上去会和组头连接起来。
  3. 在viewDidAppear方法里面总结第贰个组头的frame,取y坐标。(最幸好viewDidAppear方法里面,不然加了tableHeaderView大概会发出偏差)
  4. 然后在scrollViewDidScroll方法完成导航栏的透明以及切换titleView

- (void)viewDidAppear:(BOOL)animated{
    [super viewDidAppear:animated];
    HeaderFrame = [self.tableView rectForHeaderInSection:1];
}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView{

    if (self.marginTop != scrollView.contentInset.top) {
        self.marginTop = scrollView.contentInset.top;
    }

    CGFloat offsetY = scrollView.contentOffset.y;
    CGFloat newoffsetY = offsetY + self.marginTop;



    if (newoffsetY >= 0 && newoffsetY <= 150) {
        [self.navigationController.navigationBar jp_setStatusBarBackgroundViewAlpha:newoffsetY/150];
    }else if (newoffsetY > 150){
        [self.navigationController.navigationBar jp_setStatusBarBackgroundViewAlpha:1];
    }

    if (newoffsetY >= HeaderFrame.origin.y) {
        self.refrshView.hidden = YES;
        [self.navigationController.navigationBar setBackgroundColor:[[UIColor purpleColor] colorWithAlphaComponent:0]];

    }else if (newoffsetY < HeaderFrame.origin.y){
        [self.refrshView resetNavigationItemTitle:@"首页"];
        self.refrshView.hidden = NO;
    }
}

图片 3

JKNavigationController

目的分析

要求:

1:tableHeaderView要求有张图纸(废话)
2:图片可以根据滚动的两样而显得不雷同的样式(大小、展现范围)

在分析方法在此以前先弄驾驭两点

2.监测scrollView/collectionView横向滚动的不利姿势###\

先看功能图,上边的scrollView翻页后才移动方面的导航条,你会怎么落到实处?

图片 4

iamge

率先想到的早晚是得了减速的代办方法:scrollViewDidEndDecelerating,然则滑动过快的时候是不会调用scrollViewDidEndDecelerating代理方法的,如若做过用2个界面+scrollView落成循环滚动体现图片,那么基本上都会遇上这么难题。什么规范的监听翻页?自个儿的化解的思绪如下

  1. 把本来减速后需求处理的代码整合到三个办法中,并且需传入scrollView的contentOffset,来规定当前的page/index。后边简称【方法A】
  2. 任何进程中根本留意多个代理方法,拖动后
    初步减慢–>截至减速–>起首拖动
  3. 例行滑动速度的时候,先调用scrollView威尔BeginDecelerating再调用scrollViewDidEndDecelerating,然后调用方法A
  4. 登时滑动的时候,先调用scrollView威尔BeginDecelerating,再调用scrollViewWillBeginDragging,不会调用scrollView威尔BeginDragging。大家能够加个flag,来判定是或不是减速。没减速再调用方法A

// 开始减速的时候开始self.didEndDecelerating = NO;结束减速就会置为YES,如果滑动很快就还是NO。
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView{   
 self.didEndDecelerating = NO;
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
    self.didEndDecelerating = YES;
   // 调用方法A,传scrollView.contentOffset
}


// 再次拖拽的时候,判断有没有因为滑动太快而没有调用结束减速的方法。
// 如果没有,四舍五入手动确定位置。这样就可以解决滑动过快的问题
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
    if (!self.didEndDecelerating) {
        // 先计算当期的page/index
        CGFloat index = scrollView.contentOffset.x/self.screenWidth;
       //再四舍五入推算本该减速时的scrollView的contentOffset。即:roundf(index)*self.screenWidth]
    }
}

著效能到的1个Demo,相关的类都已经封装好,可以一贯用。

UIImageView的contentMode属性的意义意义
        /**
         UIViewContentModeScaleToFill : 图片拉伸至填充整个UIImageView(图片可能会变形)

         UIViewContentModeScaleAspectFit : 图片拉伸至完全显示在UIImageView里面为止(图片不会变形)

         UIViewContentModeScaleAspectFill : 
         图片拉伸至 图片的宽度等于UIImageView的宽度 或者 图片的高度等于UIImageView的高度 为止

         UIViewContentModeRedraw : 调用了setNeedsDisplay方法时,就会将图片重新渲染

         UIViewContentModeCenter : 居中显示
         UIViewContentModeTop,
         UIViewContentModeBottom,
         UIViewContentModeLeft,
         UIViewContentModeRight,
         UIViewContentModeTopLeft,
         UIViewContentModeTopRight,
         UIViewContentModeBottomLeft,
         UIViewContentModeBottomRight,

         经验规律:
         1.凡是带有Scale单词的,图片都会拉伸
         2.凡是带有Aspect单词的,图片都会保持原来的宽高比,图片不会变形
         */

地点是原先用oc的时候对于UIImageView的contentMode的有些说明,在那利用UIViewContentModeScaleAspectFill那百分之十效举办出现说法验证(因为品种中采用的就是那一个格局)。

金红的层面是UIImageView的大小320X100,而它的image大小是320X320,如若未安装clipsToBounds性子的话,还可以看出整张图片即便UIImageView的分寸不够。(注意:使用UIImageVIew的init?(named
name: String)
主意成立出的imageView大小暗中认同是和image一样大的)

tableView的contentOffset以及contentInset属性(其实是UIScrollView的属性)

网上有诸多诠释的作品,那里就不详细讲解,做个简易解释.

正如上图所示,UITableViewController有导航栏的气象。暗中认同是不会被导航栏遮挡的,那并不是因为tableView的y值是64的案由,而是因为automaticallyAdjustsScrollViewInsets个性的留存,会将tableViewcontentInset。Top安装为64,从而致使未”被屏蔽”(其实TableView依旧被挡住了一片段,只是展现UI的contentView地方偏移了)。那么未来小编想问tableViewcontentOffset值是有个别?答案是-64。contentOffset
是scrollview当前彰显区域顶点相对于frame顶点的偏移量,contentInset
是scrollview中contentView.frame.origin与scrollview.frame.origin的关系

编码落成:

任然一步一步的来

1:设计构造方法

创办3个ParallaxHeaderView.swift并加上

class ParallaxHeaderView: UIView {

    var subView: UIView
    var contentView: UIView = UIView()


    init(subView: UIView, headerViewSize: CGSize) {

        self.subView = subView
        super.init(frame: CGRectMake(0, 0, headerViewSize.width, headerViewSize.height))
        //这里是自动布局的设置,大概意思就是subView与它的superView拥有一样的frame
        subView.autoresizingMask = [.FlexibleLeftMargin, .FlexibleRightMargin, .FlexibleTopMargin, .FlexibleBottomMargin, .FlexibleWidth, .FlexibleHeight]
        self.clipsToBounds = false;  //必须得设置成false

        self.contentView.frame = self.bounds
        self.contentView.addSubview(subView)
        self.contentView.clipsToBounds = true
        self.addSubview(contentView)

    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

接下来成立多少个ParallaxHeaderView并安装为tableHeaderView

             override func viewDidLoad() {
        super.viewDidLoad()

         self.navigationController?.navigationBar.setMyBackgroundColor(UIColor(red: 0/255.0, green: 130/255.0, blue: 210/255.0, alpha: 0))

        let imageView = UIImageView(frame: CGRectMake(0, 0, self.tableView.bounds.width, 100))
        imageView.image = UIImage(named: "ba1ec0437cc8d5367a516ff69b01ea89")
        imageView.contentMode = .ScaleAspectFill

        let heardView = ParallaxHeaderView(subView: imageView, headerViewSize: CGSizeMake(self.tableView.frame.width, 100))
        self.tableView.tableHeaderView = heardView

    }

结果效果是这么的

意识图片压根就没从(0,0)点来得,因为我们一味值是创设了,啥都未曾处理的。那里我们目标很显明,要让图片从(0,0)开始体现一视同仁新安装大小。所以大家转移ParallaxHeaderViewcontentViewframe就好了。还记得前边说的automaticallyAdjustsScrollViewInsets属性让tableViewontentInset。Top活动成为64的吗?那里自行安装的进度系统会电动调用scrollViewDidScroll,于是自身因时制宜,顺便让它也帮作者重新安装contentViewframe

2:滚动计算contentView的frame

先贴代码再解释,在ParallaxHeaderView.swift中添加如下方法

    func layoutHeaderViewWhenScroll(let offset: CGPoint) {

        var delta:CGFloat = 0.0
        var rect = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height)

        delta = offset.y
        rect.origin.y += delta ;
        rect.size.height -= delta;

        self.contentView.frame = rect;

    }

在控制器中继续丰裕

    override func scrollViewDidScroll(scrollView: UIScrollView) {
        let heardView = self.tableView.tableHeaderView as! ParallaxHeaderView
        heardView.layoutHeaderViewWhenScroll(scrollView.contentOffset)
    }

Bingo!在ParallaxHeaderView.swift其间添加的是滑动设置contentViewframe的方法。在scrollViewDidScroll中便是调用。那为啥只修改那八个地点,一开头图片大小也变了吗?没错,在automaticallyAdjustsScrollViewInsets属性为true的意况下,系统在加载的时候便会自动调用scrollViewDidScroll方法。至于layoutHeaderViewWhenScroll个中的测算办法,本身体会体会,很粗略。

3:锁定最大滑动地方。

依据地方这样做是不周到的,因为本人不住的下拉,图片会遍地的变大。而其实须要往往是,下拉到一定的地点便不可以再三再四下拉了。接下来便继续完善。

  • 修改构造方法

    /// 最大的下拉限度(因为是下拉所以总是为负数),超过(小于)这个值,下拉将不会有效果
    var maxOffsetY: CGFloat
   init(subView: UIView, headerViewSize: CGSize, maxOffsetY: CGFloat) {

        ...
        self.maxOffsetY = maxOffsetY < 0 ? maxOffsetY : -maxOffsetY
        ....
   }

添加了壹个最大下拉的y值,别的未修改的位置没有贴出

  • 概念协议

protocol ParallaxHeaderViewDelegate: class {
    func LockScorllView(maxOffsetY: CGFloat)
}
//这个的意思是,对协议进行扩展,任何遵守此协议的UITableViewController都由默认的实现方法
extension ParallaxHeaderViewDelegate where Self : UITableViewController {
    func LockScorllView(maxOffsetY: CGFloat) {
        self.tableView.contentOffset.y = maxOffsetY
    }
}

此间用到swift2.0的新特色了。因为倘使是行使ParallaxHeaderView这一个的类的,笔者接连期望他能锁定最大的岗位,所以肯定都会去已毕LockScorllView其一协议形式,又因为那几个艺术的落到实处是定位的,所以自个儿直接给了它二个暗许的兑现,那样就毫无老是去写重复的情商了。

下一场修改一下layoutHeaderViewWhenScroll方法

    func layoutHeaderViewWhenScroll(let offset: CGPoint) {

        if offset.y < maxOffsetY {
            self.delegate.LockScorllView(maxOffsetY)

        }else {
            var delta:CGFloat = 0.0
            var rect = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height)

            delta = offset.y
            rect.origin.y += delta ;
            rect.size.height -= delta;

            self.contentView.frame = rect;

        }
    }

双重修改构造方法,添加一个参数。

    weak var delegate: ParallaxHeaderViewDelegate!

    init(subView: UIView, headerViewSize: CGSize, maxOffsetY: CGFloat, delegate: ParallaxHeaderViewDelegate) {
    ...
        self.delegate = delegate
    ...

    }

此时再在控制器里周详开头化,并添在scrollViewDidScroll添加上篇博客写的恢弘,就ok了

    override func scrollViewDidScroll(scrollView: UIScrollView) {
        let heardView = self.tableView.tableHeaderView as! ParallaxHeaderView
        heardView.layoutHeaderViewWhenScroll(scrollView.contentOffset)

        let color = UIColor(red: 0/255.0, green: 130/255.0, blue: 210/255.0, alpha: 1)
        let offsetY = scrollView.contentOffset.y
        let prelude: CGFloat = 50

        if offsetY >= -64 {
            let alpha = min(1, (64 + offsetY) / (64 + prelude))
            //NavBar透明度渐变
            self.navigationController?.navigationBar.setMyBackgroundColor(color.colorWithAlphaComponent(alpha))

        } else {
            self.navigationController?.navigationBar.setMyBackgroundColor(color.colorWithAlphaComponent(0))
        }
    }

运转效果图就不贴了。

漏洞12分多效果

因为原理相似,而且时间相比较紧就不写了。最后版代码已经上传到GitHub[ParallaxHeaderView][id]
[id]:
https://github.com/SmallLang/ParallaxHeaderView
“ParallaxHeaderView”

进而优化

代码还有众多供不应求,比如笔者还得在scrollViewDidScroll中添加多量计量导航栏发光度的代码。那种计算是通用的,因为老是期待在第三个cell滑动到导航栏下,导航栏就不透明了。完整代码在GitHub[ParallaxHeaderView][id]

总结

虽说重新造轮子不是一种好的习惯,在标准项目支付中也会严重拖缓项目开发进程。但是对于初学者,可以说是一种科学的求学格局。小说中若是出现哪些错误或者好的提出欢迎我们指出,我们一道开展学习。要上课了就不啰嗦了。

最后如故依附GitHub[ParallaxHeaderView][id]