iOS開發:一個無限滾動自動播放圖片的Demo(Swift語言編碼)


很久以前就想寫這么一個無限滾動的Demo了,最近學習了下Swift,手中沒有可以用來練手的Demo,所以才將它實現了。


Github地址(由於使用了UIView+AutoLayout第三方進行布局,所以Github判斷主要語言是OC):https://github.com/wzpziyi1/DisplayingImage

使用UICollectionView來實現的,不同於UIScrollView實現的一點是,就是不需要再手動實現緩存池功能,因為UICollectionView中的cell本就是循環利用的,我只是需要處理好無限滾動以及定時器的移除與添加即可。

這里需要注意下,MJExtension框架,並不能完美支持Swift,我在編寫的過程中,利用它解析一個plist文件,並未成功,然后自己寫了個KVC解析的,希望MJ老師盡快將它升級為Swift版本吧。

示例圖片:

 

在編寫過程中,遇到的問題還是比較多的,是因為我不是那么熟悉Swift導致的,個人覺得Swift現在最不好的一點,就是還沒有一個統一的規范。我是從OC轉Swift的,所以代碼中基本是使用OC的那一套規范,但是從其他語言轉過來的,可能就會有很大差異了。

    1. 這是一個從plist里面讀取數據,並將之存儲到數組里面的代碼:
      class ZYNew: NSObject {
          var icon: String!
          var title: String!
          
          init(dict: Dictionary<String, String>) {
              super.init()
              self.setValuesForKeysWithDictionary(dict)
          }
          
          class func getNews() -> Array<ZYNew>
          {
              let path = NSBundle.mainBundle().pathForResource("newses.plist", ofType: nil)
              let originArray: NSArray? = NSArray(contentsOfFile: path!)
              var news = Array<ZYNew>()
              originArray?.enumerateObjectsUsingBlock({ (obj: AnyObject, index: Int, stop: UnsafeMutablePointer<ObjCBool>) -> Void in
                  let tmp = ZYNew(dict: obj as! Dictionary<String, String>)
                  news.append(tmp)
              })
              return news
          }
      }
      

      這里有個極為坑的地方,Swift中的Array類型竟然沒有contentsOfFile方法,也就是說,使用Array是不能從一個文件路徑中讀取一個plist,然后將之轉化為數組的。好吧,沒有那就算了,反正也是可以使用NSArray,那么我用NSArray轉化就好,然后就掉進坑里了。
      在Swift里面,OC中的NSArray\NSDictionary等里面裝的對象它是全部將之認為是anyObject類型的,這就意味着,你在將NSArray強制轉化為Array<ZYNew>的時候,是錯誤的。比如說,在上面的代碼,我就使用如下代碼強制轉化過:

               let originArray: NSArray? = NSArray(contentsOfFile: path!)
               let news: Array<ZYNew> = originArray as! [ZYNew]
      這樣轉,在這里是錯誤的,因為anyObject的真正類型是字典,然后我修改成上面的代碼了。

    2. 自定義UICollectionViewCell的代碼:
      import UIKit
      
      class ZYNewCell: UICollectionViewCell {
          
          //Mark:- 存儲屬性
          var new: ZYNew? {
              didSet{
      //            print(new?.icon)
                  self.imageView.image = UIImage(named: (new?.icon)!)
                  self.titleLabel.text = new?.title
              }
          }
          //MARK:- 計算屬性
          
          
          //MARK:- UI屬性
          private weak var imageView: UIImageView!
          private weak var titleLabel: UILabel!
          
          
          
          override init(frame: CGRect) {
              super.init(frame: frame)
              self.commitInit()
          }
          
          required init?(coder aDecoder: NSCoder) {
              super.init(coder: aDecoder)
              self.commitInit()
          }
          
          private func commitInit()
          {
              let imageView = UIImageView()
              imageView.contentMode = UIViewContentMode.ScaleAspectFill
              imageView.clipsToBounds = true
              self.addSubview(imageView)
              self.imageView = imageView
              
              let titleLabel = UILabel()
              titleLabel.textAlignment = NSTextAlignment.Center
              titleLabel.textColor = UIColor.whiteColor()
              self.addSubview(titleLabel)
              self.titleLabel = titleLabel
          }
          
          override func layoutSubviews() {
              super.layoutSubviews()
              
              self.imageView.autoPinEdgesToSuperviewEdgesWithInsets(UIEdgeInsetsZero)
              self.titleLabel.autoPinEdgesToSuperviewEdgesWithInsets(UIEdgeInsetsZero, excludingEdge: ALEdge.Bottom)
              self.titleLabel.autoSetDimension(ALDimension.Height, toSize: 30)
          }
      }
      

      這里倒是編寫得很順利,由於OC的編碼習慣,我喜歡將類的屬性進行分層,這樣方便我后期開發中快速查找問題所在,代碼看過去也是一目了然。

      Swift中的屬性有兩種:
              存儲屬性:它有willSet和didSet方法
              計算屬性:它有set和get方法
      感覺就是對應OC中的getter和setter方法,可以進行重寫。

    3. 主要代碼ZYImageDisplayingView:
      import UIKit
      
      class ZYImageDisplayingView: UIView, UICollectionViewDelegate, UICollectionViewDataSource {
          
          //MARK:- 常量
          private let identifier = "ZYNewCell"
          
          //MARK:- 存儲屬性
          override var frame: CGRect{
              didSet{
                  if (self.collectionView != nil) {
                      self.collectionView?.removeFromSuperview()
                  }
                  
                  if (frame.width == 0.0 && frame.height == 0.0 && frame.origin.x == 0.0 && frame.origin.y == 0.0) {
                      return
                  }
                  
                  let layout = UICollectionViewFlowLayout()
                  layout.itemSize = frame.size
                  layout.scrollDirection = UICollectionViewScrollDirection.Horizontal
                  layout.minimumLineSpacing = 0
                  let collectionView = UICollectionView(frame: CGRectMake(0, 0, frame.width, frame.height), collectionViewLayout: layout)
                  collectionView.registerClass(ZYNewCell.self, forCellWithReuseIdentifier: identifier)
                  collectionView.showsHorizontalScrollIndicator = false
                  self.addSubview(collectionView)
                  self.collectionView = collectionView
                  
                  self.collectionView!.delegate = self
                  self.collectionView!.dataSource = self
                  self.collectionView!.backgroundColor = UIColor.whiteColor()
                  self.collectionView!.pagingEnabled = true
                  
                  self.collectionView!.scrollToItemAtIndexPath(NSIndexPath(forItem: 0, inSection: ZYImageGroups / 2), atScrollPosition: UICollectionViewScrollPosition.None, animated: false)
                  
                  self.bringSubviewToFront(pageControl)
                  self.addTimer()
              }
          }
          
          var news = ZYNew.getNews()
          
          var timer: NSTimer?
          
          //MARK:- 計算屬性
          
          
          //MARK:- UI控件
          weak var collectionView: UICollectionView?
          weak var pageControl: UIPageControl!
          
          //MARK:- 初始化方法
          override init(frame: CGRect) {
              super.init(frame: frame)
              self.commitInit()
          }
          
          required init?(coder aDecoder: NSCoder) {
              super.init(coder: aDecoder)
              self.commitInit()
              
          }
          
          private func commitInit(){
              self.backgroundColor = UIColor.yellowColor()
              var pageControl = UIPageControl()
              pageControl.numberOfPages = self.news.count
              pageControl.pageIndicatorTintColor = UIColor.redColor()
              pageControl.currentPageIndicatorTintColor = UIColor.whiteColor()
              self.addSubview(pageControl)
              self.pageControl = pageControl
              
              
          }
          
          //MARK:- UICollectionViewDataSource
          func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
              return ZYImageGroups
          }
          
          func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
              return self.news.count
          }
      
          func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
              
              var cell:ZYNewCell? = collectionView.dequeueReusableCellWithReuseIdentifier(self.identifier, forIndexPath: indexPath) as? ZYNewCell
              if (cell == nil) {
                  cell = ZYNewCell()
              }
      //        print(self.news[indexPath.row])
              cell?.new = self.news[indexPath.row]
              return cell!
          }
          
          
          //MARK:- UIScrollViewDelegate
          func scrollViewWillBeginDragging(scrollView: UIScrollView) {
              self.removeTimer()
          }
          
          //當scrollView減速完畢時調用,最好是在這個時候添加定時器
          func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
              self.addTimer()
          }
          
          func scrollViewDidScroll(scrollView: UIScrollView) {
              let size = scrollView.contentOffset
      //        print(size)
              self.pageControl.currentPage = Int(size.x / (self.collectionView?.frame.width)! + 0.5) % self.news.count
          }
          
          //MARK:- 定時器處理
          func addTimer()
          {
              self.removeTimer()
              self.timer = NSTimer(timeInterval: 2, target: self, selector: Selector("updateTimer"), userInfo: nil, repeats: true)
              NSRunLoop.mainRunLoop().addTimer(self.timer!, forMode: NSRunLoopCommonModes)
          }
          
          func removeTimer()
          {
              self.timer?.invalidate()
              self.timer = nil
          }
          
          func updateTimer()
          {
              let currentIndexPath = self.resetIndexPath()
              
              var section = currentIndexPath.section
              var row = currentIndexPath.row + 1
              
              
              if (row == self.news.count) {
                  row = 0
                  section++
              }
              self.collectionView?.scrollToItemAtIndexPath(NSIndexPath(forItem: row, inSection: section), atScrollPosition: UICollectionViewScrollPosition.None, animated: true)
          }
          
          func resetIndexPath() -> NSIndexPath
          {
              let currentIndexPath = self.collectionView?.indexPathsForVisibleItems().first
              
              self.collectionView?.scrollToItemAtIndexPath(NSIndexPath(forItem: (currentIndexPath?.row)!, inSection: ZYImageGroups / 2), atScrollPosition: UICollectionViewScrollPosition.None, animated: false)
              return NSIndexPath(forItem: (currentIndexPath?.row)!, inSection: ZYImageGroups / 2)
          }
          
          override func layoutSubviews() {
              super.layoutSubviews()
              self.pageControl.autoPinEdgeToSuperviewEdge(ALEdge.Bottom, withInset: 8)
              self.pageControl.autoPinEdgeToSuperviewEdge(ALEdge.Right, withInset: 20)
              self.pageControl.autoSetDimensionsToSize(CGSizeMake(100, 20))
          }
      }
      

       這部分代碼更多的是邏輯處理吧。plist里面只有5個具體的model,我是假設collectionViewCell有100組(也就是section等於100),每一組有5行(也就是row等於5),每一次要滾動到下一個cell的時候,我會先讓它滾動到sectio等於50的地方,然后row不變,在開始滾動到下一張,也就是row+1,如果row超過plist中model的個數,那么相應的,section++,row清零。

      這里值得說的一點的是,我是重寫了父類的frame屬性,當ZYImageDisplayingView的frame發生改變的時候,就會觸發這個屬性的didSet方法,我在這個方法里面初始化了UICollectionView,並做了相應的設置。個人認為這里寫的不是很好,我不應該在這個方法里面初始化UICollectionView,這要有這樣幾點考慮:
              如果我是用autoLayout來布局這個控件,是不會觸發frame的didSet方法的。
              如果我需要更改ZYImageDisplayingView的位置,那么為了避免重復創建UICollectionView,
              我必須先把以前創建的UICollectionView移除,再
              創建新的collectionView。

      其他的,OC中的[ZYImageDisplayingView class]對應Swift中的ZYImageDisplayingView.self
      OC中的#pragma mark 對應Swift中的 //MARK:-

    4. ViewController里面的代碼:
      import UIKit
      
      class ViewController: UIViewController {
      
          weak var displayingView: ZYImageDisplayingView!
          override func viewDidLoad() {
              super.viewDidLoad()
              // Do any additional setup after loading the view, typically from a nib.
              
              self.view.backgroundColor = UIColor.whiteColor()
              
              let displayingView = ZYImageDisplayingView()
              self.view.addSubview(displayingView)
              self.displayingView = displayingView
              self.displayingView.frame = CGRectMake(50, 100, 300, 130)
      //        self.displayingView.autoPinEdgeToSuperviewEdge(ALEdge.Left, withInset: 50)
      //        self.displayingView.autoPinEdgeToSuperviewEdge(ALEdge.Top, withInset: 100)
      //        self.displayingView.autoSetDimensionsToSize(CGSizeMake(300, 130))
          }
          
      }
      

      這里需要注意的是,不要使用autoLayout對displayingView進行布局,否則會導致collectionView的frame為CGRectZero。

      當然,這是我的Swift還不怎么熟練所導致的,后續會進行一定的更改。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM