热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

iOS开发:一个无限滚动自动播放图片的Demo(Swift语言编码)

很久以前就想写这么一个无限滚动的Demo了,最近学习了下Swift,手中没有可以用来练手的Demo,所以才将它实现了。Github地址(由于使用了UIView+AutoLayout

很久以前就想写这么一个无限滚动的Demo了,最近学习了下Swift,手中没有可以用来练手的Demo,所以才将它实现了。


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

使用UICollectionView来实现的,不同于UIScrollView实现的一点是,就是不需要再手动实现缓存池功能,因为UICollectionView中的cell本就是循环利用的,我只是需要处理好无限滚动以及定时器的移除与添加即可。

这里需要注意下,MJExtension框架,并不能完美支持Swift,我在编写的过程中,利用它解析一个plist文件,并未成功,然后自己写了个KVC解析的,希望MJ老师尽快将它升级为Swift版本吧。

示例图片:

iOS开发:一个无限滚动自动播放图片的Demo(Swift语言编码)

 

iOS开发:一个无限滚动自动播放图片的Demo(Swift语言编码)

在编写过程中,遇到的问题还是比较多的,是因为我不是那么熟悉Swift导致的,个人觉得Swift现在最不好的一点,就是还没有一个统一的规范。我是从OC转Swift的,所以代码中基本是使用OC的那一套规范,但是从其他语言转过来的,可能就会有很大差异了。

    1. 这是一个从plist里面读取数据,并将之存储到数组里面的代码:
      class ZYNew: NSObject {
          var icon: String!
          var title: String!
          
          init(dict: Dictionary) {
              super.init()
              self.setValuesForKeysWithDictionary(dict)
          }
          
          class func getNews() -> Array
          {
              let path = NSBundle.mainBundle().pathForResource("newses.plist", ofType: nil)
              let originArray: NSArray? = NSArray(contentsOfFile: path!)
              var news = Array()
              originArray?.enumerateObjectsUsingBlock({ (obj: AnyObject, index: Int, stop: UnsafeMutablePointer) -> Void in
                  let tmp = ZYNew(dict: obj as! Dictionary)
                  news.append(tmp)
              })
              return news
          }
      }
      

      这里有个极为坑的地方,Swift中的Array类型竟然没有contentsOfFile方法,也就是说,使用Array是不能从一个文件路径中读取一个plist,然后将之转化为数组的。好吧,没有那就算了,反正也是可以使用NSArray,那么我用NSArray转化就好,然后就掉进坑里了。
      在Swift里面,OC中的NSArray\NSDictionary等里面装的对象它是全部将之认为是anyObject类型的,这就意味着,你在将NSArray强制转化为Array的时候,是错误的。比如说,在上面的代码,我就使用如下代码强制转化过:

               let originArray: NSArray? = NSArray(contentsOfFile: path!)
               let news: Array = 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还不怎么熟练所导致的,后续会进行一定的更改。

 


推荐阅读
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Webpack5内置处理图片资源的配置方法
    本文介绍了在Webpack5中处理图片资源的配置方法。在Webpack4中,我们需要使用file-loader和url-loader来处理图片资源,但是在Webpack5中,这两个Loader的功能已经被内置到Webpack中,我们只需要简单配置即可实现图片资源的处理。本文还介绍了一些常用的配置方法,如匹配不同类型的图片文件、设置输出路径等。通过本文的学习,读者可以快速掌握Webpack5处理图片资源的方法。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • 带添加按钮的GridView,item的删除事件
    先上图片效果;gridView无数据时显示添加按钮,有数据时,第一格显示添加按钮,后面显示数据:布局文件:addr_manage.xml<?xmlve ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 本文介绍了在Vue项目中如何结合Element UI解决连续上传多张图片及图片编辑的问题。作者强调了在编码前要明确需求和所需要的结果,并详细描述了自己的代码实现过程。 ... [详细]
  • 在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板
    本文介绍了在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板的方法和步骤,包括将ResourceDictionary添加到页面中以及在ResourceDictionary中实现模板的构建。通过本文的阅读,读者可以了解到在Xamarin XAML语言中构建控件模板的具体操作步骤和语法形式。 ... [详细]
  • Sleuth+zipkin链路追踪SpringCloud微服务的解决方案
    在庞大的微服务群中,随着业务扩展,微服务个数增多,系统调用链路复杂化。Sleuth+zipkin是解决SpringCloud微服务定位和追踪的方案。通过TraceId将不同服务调用的日志串联起来,实现请求链路跟踪。通过Feign调用和Request传递TraceId,将整个调用链路的服务日志归组合并,提供定位和追踪的功能。 ... [详细]
author-avatar
hh呢喃_845
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有