iOS那些“垃圾”的轮播

KarSVO 7年前
   <p>轮播视图通常也叫Banner,90%以上App都会用到的一个控件,网上有很多开源代码,但是至今我觉得比较好的一个是 <a href="/misc/goto?guid=4958968187571867351" rel="nofollow,noindex">SDCycleScrollView</a> ,因为他解决了我接下来要吐槽的两个问题。</p>    <p>通常实现定时自动滚动Banner的思路大体有三种</p>    <pre>  <code class="language-objectivec">1.  3个`UIImageView`    2.  N+2个`UIImageView`思路    3.  N * section(个人不推荐,因为这将代码写死了,当有个无聊的人真的滚动到最后一个section时,程序就会crash了)</code></pre>    <p>前两种思路又分为用 UIScrollView 和 UICollectionView 实现, 个人没有用过第一种思路,都是第二种,本文也是基于第二种思路 ,这两种思路的中心思想其实都是运用了 <strong>视觉误差</strong> 。</p>    <h2>快速滑动时卡顿</h2>    <p>先来看看那些“垃圾”Banner</p>    <p>卡顿问题一(3个 UIImageView 思路)</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/4fe0493861ccfdc087bd73d767d01ced.gif"></p>    <p style="text-align:center">Aiqiyi.gif</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/523f5288f625d94e250799414eee9e37.gif"></p>    <p style="text-align:center">Youku.gif</p>    <p>通过卡顿频率,我猜想这两个项目的Banner思路应该一样,用的三个 UIImageView 。</p>    <p>不知道动图你是否看的卡顿的问题,如果你手机上恰好装了这两个App,可以自己试一下,很简单,只要快速滑动就可以了。</p>    <p>但是这两个的PageControl还是处理得很好的,能实时滚动到相应的位置。</p>    <p>卡顿问题二((N+2)个 UIImageView 思路)</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/0bb27630ae3fb4f2b6b752aabcf16363.gif"></p>    <p style="text-align:center">Tianmao.gif</p>    <p>这个问题不好看出,因为他的卡顿频率比较低,刚好是一组轮播视图的周期。必须在第N+1张时才会复现。想看得清楚的小伙伴,如果自己项目Banner是这个思路可以测试一下自己项目的。</p>    <p>再看看这个PageControl的位置,在你快速滑动时,它是不动的,我猜想他控制PageControl的位置应该是在这个方法里做的</p>    <pre>  <code class="language-objectivec">func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { }</code></pre>    <h2>卡顿原因</h2>    <p>就是这个两个方法其中一个里计算cell位置的判断条件不对</p>    <pre>  <code class="language-objectivec">func scrollViewDidScroll(_ scrollView: UIScrollView) { }    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { }</code></pre>    <h2>Tab切换卡中间,不能复位</h2>    <p>由于这个问题比较难复现,我就用自己的Demo测试的</p>    <p>UICollectionView实现,会自动修复</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/2748d90e9f5ddf5b3058532acb77c48f.gif"></p>    <p style="text-align:center">Test.gif</p>    <p>UIScrollView实现,需手动修复</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/393a61c36da8aed1314d74612cc9bf81.gif"></p>    <p style="text-align:center">HalfScreen.gif</p>    <p>动图中应该可以清楚的看到滚动视图滚动的坐标不对。</p>    <h2>原因</h2>    <p>这个具体原因我也不知道,这是所有轮播都会发生的问题,我猜想是跟内部的RunLoop应该有关。</p>    <p>还有的Banner是pageControl和cell联动不及时,比如 <strong>咸鱼</strong></p>    <p>因为是在这里处理控制pageControl的位置的</p>    <pre>  <code class="language-objectivec">func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { }</code></pre>    <p>简书Banner的pageControl向左手动拖动时又太灵敏。</p>    <pre>  <code class="language-objectivec">func scrollViewDidScroll(_ scrollView: UIScrollView) {          let page = scrollView.contentOffset.x / scrollView.frame.width          if page <= 0.0 {              // 向右拉              collectionView?.scrollToItem(at: IndexPath(item: urlStrs.count - 2, section: 0), at: .centeredHorizontally, animated: false)              pageControl?.currentPage = urlStrs.count - 3          } else if page >= CGFloat(urlStrs.count - 1) {              // 向左              pageControl?.currentPage = 0              collectionView?.scrollToItem(at: IndexPath(item: 1, section: 0), at: .centeredHorizontally, animated: false)          } else {              let value = page.truncatingRemainder(dividingBy: 1) < 0.5              if value { // cell过半才改变pageControl(简书的Banner应该没有这个判断)                  pageControl?.currentPage = Int(page) - 1              }          }      }</code></pre>    <p> </p>    <p> </p>    <p>来自:http://www.jianshu.com/p/97037c126d7c</p>    <p> </p>