zoukankan      html  css  js  c++  java
  • [Swift通天遁地]九、拔剑吧-(11)创建强大的Pinterest风格的瀑布流界面

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
    ➤微信公众号:山青咏芝(shanqingyongzhi)
    ➤博客园地址:山青咏芝(https://www.cnblogs.com/strengthen/
    ➤GitHub地址:https://github.com/strengthen/LeetCode
    ➤原文地址:https://www.cnblogs.com/strengthen/p/10357522.html 
    ➤如果链接不是山青咏芝的博客园地址,则可能是爬取作者的文章。
    ➤原文已修改更新!强烈建议点击原文地址阅读!支持作者!支持原创!
    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

    目录:[Swift]通天遁地Swift

    本文将演示如何创建强大的Pinterest风格的瀑布流界面

    Github项目:【demonnico/PinterestSwift】,下载并解压文件。

    【PinterestSwift】文件夹->【CHTCollectionViewWatrfallLayout.swift】文件

    ->按下【Command】,继续选择【Extension.swift】->继续选择【Macro.swift

    ->继续选择【NTHorizontalPagViewCell.swift

    ->继续选择【NTTransition.swift

    ->继续选择【NTTransitionProtocol.swift

    ->继续选择【NTWaterfallViewCell.swift

    将上面选择的文件,拖入到自己的项目中。

    在弹出的文件导入确认窗口中,点击【Finish】完成按钮,确认文件的导入。

    在项目文件夹上点击鼠标右键,弹出右键菜单。

    【New File->【Cocoa Touch->【Next】->

    【Class】:HorizontalPageViewController

    【Subclass of:UICollectionViewController

    【Language】:Swift

    ->Next->【Create】

    点击打开【HorizontalPageViewController.swift】,

    现在开始编写代码,创建一个自定义的集合视图。

     1 import Foundation
     2 import UIKit
     3 
     4 //初始化一个字符串常量,作为集合单元格的复用标识。
     5 let horizontalPageViewCellIdentify = "horizontalPageViewCellIdentify"
     6 
     7 //给当前的类添加两个协议,使用第一个协议中的方法,返回页面切换所需的集合视图,
     8 //使用第二个协议的方法,设置集合视图的单元格的偏移距离。
     9 class HorizontalPageViewController : UICollectionViewController, NTTransitionProtocol ,NTHorizontalPageViewControllerProtocol
    10 {
    11     //添加一个字符串数组属性,作为集合视图每个单元格显示的图片内容。
    12     var imageNameList : Array <NSString> = []
    13     //添加一个属性,作为集合视图单元格的偏移距离。
    14     var pullOffset = CGPoint.zero
    15     
    16     //添加一个初始化方法,用来设置集合视图的布局。
    17     init(collectionViewLayout layout: UICollectionViewLayout!, currentIndexPath indexPath: IndexPath)
    18     {
    19         super.init(collectionViewLayout:layout)
    20         //获得集合视图控制器的集合视图。
    21         let collectionView :UICollectionView = self.collectionView!;
    22         //设置集合视图在页面跳转时自动停止滚动
    23         collectionView.isPagingEnabled = true
    24         //使用第三方类库提供的集合单元格类,注册集合视图的单元格,并设置单元格的复用标识。
    25         collectionView.register(NTHorizontalPageViewCell.self, forCellWithReuseIdentifier: horizontalPageViewCellIdentify)
    26         //通过扩展方法,把一个对象与另外一个对象进行关联。
    27         //这需要使用到运行时函数,包含四个参数:
    28         //源对象、关键字、关联的对象、一个关联策略。
    29         collectionView.setToIndexPath(indexPath)
    30         
    31         //调用集合视图对象的序列刷新方法,该方法可以执行多个插入、删除、重新加载、移动等操作。
    32         collectionView.performBatchUpdates({collectionView.reloadData()}, completion: { finished in
    33             if finished
    34             {
    35                 //调用集合视图对象的滑动到指定项目方法,在垂直方向上,滑动到指定索引的单元格。
    36                 collectionView.scrollToItem(at: indexPath,at:.centeredHorizontally, animated: false)
    37             }});
    38     }
    39     
    40     override func viewDidLoad()
    41     {
    42         super.viewDidLoad()
    43     }
    44     
    45     //添加一个代理方法,用来初始化或复用集合视图中的单元格。
    46     override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
    47     {
    48         //根据复用标识,从集合视图中获取可以复用的单元格。
    49         let collectionCell: NTHorizontalPageViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: horizontalPageViewCellIdentify, for: indexPath) as! NTHorizontalPageViewCell
    50         
    51         //设置集合视图的扩展设置,从而往集合视图中添加一个图像视图。
    52         collectionCell.imageName = self.imageNameList[(indexPath as NSIndexPath).row] as String
    53         //初始化集合视图的扩展属性。
    54         collectionCell.tappedAction = {}
    55         //给集合视图添加一个下拉动作。
    56         collectionCell.pullAction = { offset in
    57             //当接收到下拉事件时,
    58             self.pullOffset = offset
    59             //在导航控制器的堆栈中,返回上一个页面。
    60             self.navigationController!.popViewController(animated: true)
    61         }
    62         //在绘制周期开始前,首先对集合视图进行布局,
    63         collectionCell.setNeedsLayout()
    64         
    65         //最后返回设置好的集合视图单元格。
    66         return collectionCell
    67     }
    68     
    69     //添加一个代理方法,用来设置集合视图的单元格的数据。
    70     override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
    71     {
    72         return imageNameList.count
    73     }
    74     
    75      //添加一个代理方法,用来返回页面切换所需的集合视图
    76     func transitionCollectionView() -> UICollectionView!
    77     {
    78         return collectionView
    79     }
    80     
    81      //添加一个代理方法,设置集合视图的单元格的偏移距离。
    82     func pageViewCellScrollViewContentOffset() -> CGPoint
    83     {
    84         return self.pullOffset
    85     }
    86     
    87     //添加一个必须实现的初始化方法
    88     required init?(coder aDecoder: NSCoder)
    89     {
    90         fatalError("init(coder:) has not been implemented")
    91     }
    92 }

    在左侧的项目导航区,打开视图控制器的代码文件【ViewController.swift】

    现在开始编写代码,将系统默认的视图控制器,修改为另一个集合视图控制器,

    作为瀑布流的载体

      1 import UIKit
      2 
      3 let waterfallViewCellIdentify = "waterfallViewCellIdentify"
      4 
      5 //创建一个遵循导航控制器代理协议的类
      6 class NavigationControllerDelegate: NSObject, UINavigationControllerDelegate
      7 {
      8     //添加一个方法,用来处理导航控制器页面之间的跳转事件,
      9     //并返回页面跳转的动画样式。
     10     func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning?{
     11         
     12         //初始化三个对象,作为导航控制器跳转前的页面。
     13         let fromVCConfromA = (fromVC as? NTTransitionProtocol)
     14         let fromVCConfromB = (fromVC as? NTWaterFallViewControllerProtocol)
     15         let fromVCConfromC = (fromVC as? NTHorizontalPageViewControllerProtocol)
     16         
     17         //初始化三个对象,作为导航控制器跳转后的页面。
     18         let toVCConfromA = (toVC as? NTTransitionProtocol)
     19         let toVCConfromB = (toVC as? NTWaterFallViewControllerProtocol)
     20         let toVCConfromC = (toVC as? NTHorizontalPageViewControllerProtocol)
     21         
     22         //判断当从瀑布流页面,跳转到详情页面,或者从详情页面,返回瀑布流页面时的跳转样式。
     23         if((fromVCConfromA != nil)&&(toVCConfromA != nil)&&(
     24             (fromVCConfromB != nil && toVCConfromC != nil)||(fromVCConfromC != nil && toVCConfromB != nil))){
     25             //初始化一个动画跳转对象
     26             let transition = NTTransition()
     27             //根据导航控制器的页面跳转的类型是否为出栈操作,
     28             //来设置跳转对象的布尔属性。
     29             transition.presenting = operation == .pop
     30             //最后返回设置好的切换对象。
     31             return  transition
     32         }
     33         else
     34         {
     35             return nil
     36         }
     37     }
     38 }
     39 
     40 //修改当前视图控制器的父类,将父类修改为集合视图控制器,
     41 //并遵循瀑布流布局协议、动画切换协议、以及瀑布流视图控制器协议。
     42 class ViewController:UICollectionViewController, CHTCollectionViewDelegateWaterfallLayout, NTTransitionProtocol, NTWaterFallViewControllerProtocol{
     43     
     44     //初始化一个字符串数组,作为集合视图所有图像的名称。
     45     var imageNameList : Array <NSString> = []
     46     //初始化一个导航控制器代理对象。
     47     let delegateHolder = NavigationControllerDelegate()
     48     override func viewDidLoad()
     49     {
     50         super.viewDidLoad()
     51         // Do any additional setup after loading the view, typically from a nib.
     52         //设置当前导航控制器的代理对象。
     53         self.navigationController!.delegate = delegateHolder
     54         
     55         var index = 1
     56         //添加一个循环语句,用来往数组中添加图片的名称。
     57         while(index<14)
     58         {
     59             //根据循环的索引,初始化一个由图片名称组成的字符串数组。
     60             let imageName = NSString(format: "Pic%d.png", index)
     61             //将图片名称添加到数组中。
     62             imageNameList.append(imageName)
     63             index += 1
     64         }
     65         
     66         //获得当前集合视图控制器中的集合视图。
     67         let collection :UICollectionView = collectionView!
     68         //设置集合视图的显示区域与屏幕相同,在此使用了宏定义常量。
     69         collection.frame = screenBounds
     70         //设置集合视图的布局样式
     71         collection.setCollectionViewLayout(CHTCollectionViewWaterfallLayout(), animated: false)
     72         //设置集合视图的背景颜色为黑色
     73         collection.backgroundColor = UIColor.black
     74         //给集合视图注册复用标识符
     75         collection.register(NTWaterfallViewCell.self, forCellWithReuseIdentifier: waterfallViewCellIdentify)
     76         //重新加载集合视图中的数据
     77         collection.reloadData()
     78     }
     79     
     80     //添加一个方法,用来设置单元格的尺寸
     81     func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: IndexPath) -> CGSize
     82     {
     83         //加载数组中的指定名称的图片
     84         let image:UIImage! = UIImage(named: self.imageNameList[(indexPath as NSIndexPath).row] as String)
     85         //单元格的宽度时固定的,在此根据单元格的高度和图片的宽度,获得等比例的图片高度。
     86         let imageHeight = image.size.height*gridWidth/image.size.width
     87         
     88         //返回计算好的图片尺寸
     89         return CGSize( gridWidth, height: imageHeight)
     90     }
     91     
     92     //添加一个代理方法,用来初始化或复用集合视图中的单元格。
     93     override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
     94     {
     95         //根据复用标识,从集合视图中获取可以复用的单元格。
     96         let collectionCell: NTWaterfallViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: waterfallViewCellIdentify, for: indexPath) as! NTWaterfallViewCell
     97         //设置集合视图的扩展方法,从而往集合视图中添加一个图像视图。
     98         collectionCell.imageName = self.imageNameList[(indexPath as NSIndexPath).row] as String
     99         //对单元格在绘制之前进行重新布局。并返回设置好的单元格。
    100         collectionCell.setNeedsLayout()
    101         return collectionCell
    102     }
    103     
    104      //添加一个代理方法,用来设置单元格的数量
    105     override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
    106     {
    107         return imageNameList.count
    108     }
    109     
    110      //添加一个代理方法,用来处理单元格的触摸事件。
    111     override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
    112     {
    113         //初始化一个视图控制器,作为即将显示的细节页面。
    114         let pageViewController =
    115             HorizontalPageViewController(collectionViewLayout: pageViewControllerLayout(), currentIndexPath:indexPath)
    116         //设置控制器的图片名称列表属性
    117         pageViewController.imageNameList = imageNameList
    118         //在集合视图中,跳转到指定位置的单元格
    119         collectionView.setToIndexPath(indexPath)
    120         //在导航控制器的堆栈中,压入新的集合控制器。
    121         navigationController!.pushViewController(pageViewController, animated: true)
    122     }
    123     
    124     //添加一个方法,用来设置集合视图的布局方式
    125     func pageViewControllerLayout () -> UICollectionViewFlowLayout
    126     {
    127         //初始化一个集合视图流布局对象。
    128         let flowLayout = UICollectionViewFlowLayout()
    129         //根据导航栏的显示状态,创建集合视图的尺寸。
    130         let itemSize  = self.navigationController!.isNavigationBarHidden ?
    131             CGSize( screenWidth, height: screenHeight+20) : CGSize( screenWidth, height: screenHeight-navigationHeaderAndStatusbarHeight)
    132         //设置集合视图的单元格的尺寸。
    133         flowLayout.itemSize = itemSize
    134         //设置单元格之间的最小行距
    135         flowLayout.minimumLineSpacing = 0
    136         //设置同一行的单元格之间的最小间距。
    137         flowLayout.minimumInteritemSpacing = 0
    138         //设置布局对象的滚动方向为水平方向。
    139         flowLayout.scrollDirection = .horizontal
    140         
    141         //返回设置好的布局对象
    142         return flowLayout
    143     }
    144     
    145     //添加一个方法,用来返回进行动态切换的集合视图
    146     func transitionCollectionView() -> UICollectionView!
    147     {
    148         return collectionView
    149     }
    150     
    151     func viewWillAppearWithPageIndex(_ pageIndex : NSInteger)
    152     {
    153         
    154     }
    155     
    156     override func didReceiveMemoryWarning() {
    157         super.didReceiveMemoryWarning()
    158         // Dispose of any resources that can be recreated.
    159     }
    160 }

    在项目导航区,打开故事板文件。

    在故事板中添加一个集合视图控制器,首先选择并删除默认的视图控制器。

    选择默认的视图控制器,【Command】+【Delete】删除选择的视图控制器。

    点击控件库图标,打开控件库的列表窗口。双击集合视图控制器,往故事板中插入一个控制器。

    依次点击:【Editor】编辑器->【Embed In】植入->【Navigation Controller】导航控制器

    将集合视图控制器植入导航控制器。植入导航控制器。

    打开检查器设置面板,点击属性检查器图标,进入属性设置面板。

    勾选【Is Initial View Controller】是否初始视图控制器。

    将导航控制器修改为项目的初始控制器。

    选择集合视图控制器,点击身份检查器图标,打开身份设置面板。

    在类名输入框内,输入所绑定的自定义集合视图类。

    【Class】:ViewController

    模拟器启动后,由下往上拖动,可以浏览瀑布流底部的内容。

    在详情页面的顶部往下方拖动,

    通过下拉动作,返回瀑布流页面。

  • 相关阅读:
    spring
    C++容器常用方法简单总结
    【转】shell中各种括号的作用详解()、(())、[]、[[]]、{}
    c++创建对象时一些小细节
    ros建模与仿真(urdf介绍)
    常用vi命令
    Linux零零碎碎的小知识
    Linux目录都是些什么
    关于c/c++指针,指针的指针
    关于c/c++中的二维数组与指针
  • 原文地址:https://www.cnblogs.com/strengthen/p/10357522.html
Copyright © 2011-2022 走看看