swift/制作一个简单易行的tableHeaderview+_navigationbar渐变效果(二)

随即上一篇swift/制作一个简短的tableheaderview+_navigationbar渐变效果(一)继续完成没有做完的任务

编码

上一篇已经完结了对于UINavigationBar的壮大,仅仅只用了24行代码变达成想要的效用。接下来编写tableheaderview的功效部分。

ParallaxHeaderView模糊.gif

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

即便只是好像于一个图形下拉加大的效果,但请允许我动用Parallax来命名。

示例图给出三种效率,一种有模糊效果一种无模糊效果。先来落实率先种无模糊效果的。

对象分析

要求:

1:tableHeaderView需要有张图片(废话)
2:图片能够依据滚动的不同而显得不同等的样式(大小、显示范围)

在分析方法以前先弄精晓两点

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:设计构造方法

创立一个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))
        }
    }

运作效果图就不贴了。

混淆效果

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

越是优化

代码还有许多不足,比如我还得在scrollViewDidScroll中添加大量乘除导航栏透明度的代码。那种总括是通用的,因为老是期待在第一个cell滑动到导航栏下,导航栏就不透明了。完整代码在GitHub[ParallaxHeaderView][id]

总结

尽管重新造轮子不是一种好的习惯,在正规项目支付中也会严重拖缓项目开发进度。可是对于初学者,可以说是一种科学的学习方法。作品中如若出现什么错误或者好的指出欢迎我们提议,我们一同展开学习。要上课了就不啰嗦了。

末尾依旧依附GitHub[ParallaxHeaderView][id]