Swift之collectionView实现瀑布流

我们在用collectionView的时候难免会觉得整齐的框框放在那有些单调,大脸猫给大家分享一个小demo,用collectionView实现瀑布流。效果如下:
swift-collectionView实现瀑布流.gif
首先,自定义一个流水布局WaterCollectionViewLayout,继承UICollectionViewLayout,代码如下:(更新至swift3.0)
import UIKit

class WaterCollectionViewLayout: UICollectionViewLayout {

//来控制cell的大小
var setSize:()->(Array<UIImage>) = {_ in return []}
var queueNum: Int = 2 //列数,默认为两列
var hs: Array<CGFloat>!
private var totalNum: Int!
private var layoutAttributes: Array<UICollectionViewLayoutAttributes>!
override func prepare() {
    super.prepare()
    hs = []
    for _ in 0..<queueNum {
        hs.append(5)
    }
    totalNum = collectionView?.numberOfItems(inSection: 0)
    layoutAttributes = []
    var indexpath: NSIndexPath!
    for index in 0..<totalNum {
        indexpath = NSIndexPath(row: index, section: 0)
        let attributes = layoutAttributesForItem(at: indexpath as IndexPath)
        layoutAttributes.append(attributes!)
    }
}
private let gap:CGFloat = 5//间隔,缝隙大小
private var width:CGFloat!
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
    width = (collectionView!.bounds.size.width-gap*(CGFloat(queueNum)-1))/CGFloat(queueNum)
    let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
    let sizes = setSize()
    attributes.size = CGSize(width: width, height: sizes[indexPath.row].size.height*width/sizes[indexPath.row].size.width)
    var nub:CGFloat = 0
    var h:CGFloat = 0
    (nub,h) = minH(hhs: hs)
    attributes.center = CGPoint(x:(nub+0.5)*(gap+width), y:h+(width/attributes.size.width*attributes.size.height+gap)/2)
    hs[Int(nub)] = h+width/attributes.size.width*attributes.size.height+gap
    return attributes
}

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    return layoutAttributes
}

//    override func collectionViewContentSize() -> CGSize {
//        return CGSize(width: (collectionView?.bounds.width)!, height: maxH(hhs: hs))
//    }
//swift3.0废弃了上面这个方法,所以我们改成重写collectionViewContentSize属性
override var collectionViewContentSize: CGSize {
    get {
        return CGSize(width: (collectionView?.bounds.width)!, height: maxH(hhs: hs))
    }
    set {
        self.collectionViewContentSize = newValue
    }
}

private func minH(hhs:Array<CGFloat>)->(CGFloat,CGFloat){
    var num = 0
    var min = hhs[0]
    for i in 1..<hhs.count{
        if min>hhs[i] {
            min = hhs[i]
            num = i
        }
    }
    return (CGFloat(num),min)
}
func maxH(hhs:Array<CGFloat>)->CGFloat{
    var max = hhs[0]
    for i in 1..<hhs.count{
        if max<hhs[i] {
            max = hhs[i]
        }
    }
    return max
} 
}
再来自定义一个button--WaterButton来实现点击cell得到大图
import UIKit

class WaterButton: UIButton {

var wImage:UIImage!{
    didSet{
        wImageView.image = wImage
    }
}
private var wImageView:UIImageView!
override init(frame: CGRect) {
    super.init(frame: frame)
    wImageView = UIImageView(frame:bounds)
    addSubview(wImageView)
}

override func layoutSubviews() {
    super.layoutSubviews()
    wImageView.frame = bounds
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}
}
最后就是我们的ViewController的实现了:
import UIKit

class ViewController: UIViewController {

var width: CGFloat!
var images: Array<UIImage>!
var collectionView:UICollectionView!
var maskView: UIView!
var cellRect: CGRect!
var changeRect: CGRect!
//MARK: --life cycle
override func viewDidLoad() {
    super.viewDidLoad()
    waterfallCollectionView()
}
private func waterfallCollectionView() {
    width = (view.bounds.size.width - 20)/3
    let layout = WaterCollectionViewLayout()
    images = []
    for i in 1..<16 {
        let image = UIImage(named: String.init(format: "%.2d.png", i))
        images.append(image!)
    }
    layout.setSize = {_ in
        return self.images
    }
    collectionView = UICollectionView(frame: self.view.bounds, collectionViewLayout: layout)
    collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "newCell")
    collectionView.backgroundColor = UIColor.white
    collectionView.alwaysBounceVertical = true
    
    collectionView.delegate = self
    collectionView.dataSource = self
    view.addSubview(collectionView)
    
}

func showPic(btn:UIButton){
    UIView.animate(withDuration: 1, animations: {
        btn.frame = self.cellRect
    }) { (finish) in
        btn.removeFromSuperview()
        self.maskView.removeFromSuperview()
        self.maskView = nil
        self.cellRect = nil
    }
}
}

extension ViewController: UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout {
//MARK: --UICollectionViewDelegate
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return images.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "newCell", for: indexPath as IndexPath)
    let imageView = UIImageView(frame: cell.bounds)
    imageView.image = images[indexPath.row]
    let bgView = UIView(frame:cell.bounds)
    bgView.addSubview(imageView)
    cell.backgroundView = bgView
    
    return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    let cell = collectionView.cellForItem(at: indexPath)
    maskView = UIView.init(frame: view.bounds)
    maskView.backgroundColor = UIColor.black
    maskView.alpha = 0.5
    view.addSubview(maskView)
    
    //cell在veiw的位置
    cellRect = cell!.convert(cell!.bounds, to: view)
    let btn = WaterButton.init(frame: cellRect)
    let img = images[indexPath.row]
    btn.wImage = img
    btn.addTarget(self, action: #selector(showPic(btn:)), for: UIControlEvents.touchUpInside)
    view.addSubview(btn)
    //图片长宽的比例与屏幕长宽的比例的对比
    var changeH:CGFloat
    var changeW:CGFloat
    if img.size.width/img.size.height >= view.frame.size.width/view.frame.size.height{
        //对比图片实际宽与屏幕宽
        if img.size.width>view.frame.size.width {
            changeH = img.size.height*view.frame.size.width/img.size.width
            changeRect = CGRect(x: 0, y: (view.frame.size.height-changeH)/2, width:view.frame.size.width, height: changeH)
        }else{
            changeRect = CGRect(x: (view.frame.size.width-img.size.width)/2, y: (view.frame.size.height-img.size.height)/2, width: img.size.width,height: img.size.height)
        }
    }else{
        if img.size.height>view.frame.size.height {
            changeW = img.size.width*view.frame.size.height/img.size.height
            changeRect = CGRect(x: (view.frame.size.width-changeW)/2, y: 0, width: changeW, height: view.frame.size.height)
        }else{
            changeRect = CGRect(x: (view.frame.size.width-img.size.width)/2, y: (view.frame.size.height-img.size.height)/2, width: img.size.width,height: img.size.height)
        }
    }
    
    UIView.animate(withDuration: 1, animations: {
        btn.frame = self.changeRect
    })
    
}
}

当然,瀑布流也可以通过tableView来实现,具体的设计思路就不在这里详细说明了,大家可以参考://www.greatytc.com/p/78830bdb04a9iOS瀑布流基本实现 很棒的一篇文章哦。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,755评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,369评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,799评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,910评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,096评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,159评论 3 411
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,917评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,360评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,673评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,814评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,509评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,156评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,123评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,641评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,728评论 2 351

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,066评论 4 62
  • Swift版本点击这里欢迎加入QQ群交流: 594119878最新更新日期:18-09-17 About A cu...
    ylgwhyh阅读 25,340评论 7 249
  • 门洞里透漏出一位身着练功服的大爷, 大爷没练功,大爷在远望, 大爷外面是大明湖, 点缀了一圈儿荷花, "夏雨荷"的...
    布布老师吕布凡阅读 1,011评论 0 1
  • 记忆差的的好处是对一些美好的事物,仿佛初次遇见一样,可以享受多次。—— 尼 采 你老了么?想知道如何判断老没老? ...
    Coffee6点5阅读 528评论 0 1
  • 一、语 法 解 释 (小句)と思います表示说话人的思考内容时,在句子后面加“と思います”。“~と思います”前的小句...
    MJ_喵酱阅读 1,372评论 0 0