3d轮播图 swift

2017-05-20 15:54:16 zhaofahseng 阅读数 1300



立方体旋转这里用的是UICollectionView 去实现,重写UICollectionViewLayout的布局,再加入3D设置代码,当视图返回了三个以上的cell时,便可实现无缝连接的旋转立体视觉感,这里建议三个到六个之间,当返回的cell数越多,会越接近圆形! 下面贴代码:


-.第一步建立一个新的文件继承至UICollectionViewLayout 文件名为CircleLayout

.h文件为:

#import <UIKit/UIKit.h>


@interface 3DcleLayout :UICollectionViewLayout

@property(nonatomic,assign) CGSize itemSize;//cell的尺寸


- (instancetype)initWithItemSize:(CGSize)itemSize;//重写cell尺寸方法

@end


.m文件实现

#import "3DcleLayout.h"


@implementation CircleLayout


/**

 重写尺寸初始化方法


 @param itemSize cell尺寸

 @return返回对象

 */

- (instancetype)initWithItemSize:(CGSize)itemSize

{

    if (self = [superinit]) {

        _itemSize = itemSize;

    }

    returnself;

}



/**

 返回尺寸大小


 @return 返回尺寸大小

 */

-(CGSize)collectionViewContentSize

{

    float width =self.collectionView.frame.size.width *([self.collectionViewnumberOfItemsInSection:0 ]+2);

    float height=self.collectionView.frame.size.height;

    CGSize  size =CGSizeMake(width, height);

    return size;

}



- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds

{

    returnYES;

}


//这里是关键,这设置3d效果

#pragma mark - UICollectionViewLayout

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath

{

    //3D代码

    UICollectionViewLayoutAttributes* attributes = [UICollectionViewLayoutAttributeslayoutAttributesForCellWithIndexPath:indexPath];

    UICollectionView *collection =self.collectionView;

    float width = collection.frame.size.width;

    float height = collection.frame.size.height;

    float x = collection.contentOffset.x;

    CGFloat arc =M_PI * 2.0f;

    NSInteger numberOfVisibleItems = [self.collectionViewnumberOfItemsInSection:0];


    attributes.center =CGPointMake(x+width * 0.5,height * 0.5);

//  attributes.size = CGSizeMake(width * 0.5, height - 40);

    attributes.size =_itemSize;

    

    CATransform3D transform =CATransform3DIdentity;

    transform.m34 = -1.0f/700.0f;


    CGFloat radius = attributes.size.width/2/tanf(arc/2.0f/numberOfVisibleItems);

    CGFloat angle = (indexPath.row-x/width+1)/ numberOfVisibleItems * arc;

    transform = CATransform3DRotate(transform, angle,0.0f, 1.0f,0.0f);

    transform = CATransform3DTranslate(transform,0.f, 0.0f, radius);

    attributes.transform3D = transform ;


    return attributes;

}

-(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect

{

    NSArray *arr = [superlayoutAttributesForElementsInRect:rect];

    if ([arrcount] >0) {

        return arr;

    }

    NSMutableArray* attributes = [NSMutableArrayarray];

    for (NSInteger i=0 ; i < [self.collectionViewnumberOfItemsInSection:0 ]; i++) {

        NSIndexPath* indexPath = [NSIndexPathindexPathForItem:i inSection:0];

        [attributes addObject:[selflayoutAttributesForItemAtIndexPath:indexPath]];

    }

    return attributes;

}



@end



第二步:第一步已经封装好了3D效果,接下来只要去初始化UICollectionView的时候调用它即可,方法是在一个UIviewController,或者UIView上初始化一个UICollectionView,例如:

 //控制上下左右边距

    self.collectionView = [[UICollectionViewalloc]

               initWithFrame:rect

        collectionViewLayout:[[CircleLayoutalloc]

                                 initWithItemSize:CGSizeMake(

                                                      rect.size.width *0.55,

                                                      rect.size.height -placeBank)]];


placeBank是控制3d轮播图距离上下边距的大小,rect是collectionView的frame.


到这里以后只需要在实现对应的代理方法,返回3个以上cell即可实现,cell可自行自定义,也可使用定时器做成自动旋转效果





2018-04-24 15:34:59 qq_30932479 阅读数 636

整天逛淘宝,偶尔有一天看到其中的展示页有个看起来很炫的效果,闲来无事就试着写一个出来,先来看效果:

简单记一下思路,这里我选择使用UICollectionView控件,先根据其复用和滚动的特性做出无限轮播的效果,关键代码:

//数据源数组
    let totalCount = 100
    var models: [String] = [String]() {
        didSet {
            //判断元素个数
            if models.count < 2 {
                collectionView.isScrollEnabled = false
            }
            //网上的找来的一个办法添加100组数据源对应的索引数组indexArr
            for _ in 0..<totalCount {
                for j in 0..<models.count {
                    indexArr.append(j)
                }
            }
            //开始就滚动到第50组数据源
            collectionView.scrollToItem(at: IndexPath(item: totalCount/2 * models.count, section: 0), at: .centeredHorizontally, animated: false)
        }
    }

滚动停止时走的方法里做处理:

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        //找到滚动停止的点对应的collectionView的indexPath
        let point =  self.convert(collectionView.center, to: collectionView)
        let index = collectionView.indexPathForItem(at: point)
        let indexpath = (index?.row ?? 0) % models.count
        
        collectionView.scrollToItem(at: IndexPath(item: totalCount/2 * models.count + indexpath, section: 0), at: .centeredHorizontally, animated: false)
    }
以上是滚动的处理,接下来就是item的渐变效果处理,看到这种情况就想到要写一个UICollectionViewFlowLayout
类供collectionView使用,UICollectionViewFlowLayout是管理item怎么展示用的,首先重写展示视图内的layoutAttributes方法,在此方法中找到attribute对应的item及其属性,和collectionView的偏移量和中心点,进行一系列的计算:

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        
        //集合视图的宽高(这里默认宽高相等)
        let itemHeight = self.collectionView?.frame.height ?? 0
        //可是视图内的attributes数组
        let array = super.layoutAttributesForElements(in: rect)
        //item透明度开始变化时的item的中心点x
        let centerX = self.collectionView!.contentOffset.x + itemHeight/2
        print(self.collectionView?.contentOffset.x ?? 0)
        
        for attributes in array! {
            //开始变化时的item的中心点x 与 实际中心点相比较
            let value = attributes.center.x - centerX
            let delta = abs(value)
            //设置缩放比例,此处4*itemHeight可根据缩放效果进行修改
            let scale = 1 - delta/(4*itemHeight)
    
            //设置缩放比例
            attributes.transform = CGAffineTransform.init(scaleX: scale, y: scale)
            //层次关系,设置此属性使item依次上下排列
            attributes.zIndex = Int(1 - abs(delta))
            
            //value<=0表示向左移动,最前面的item停止一段距离
            if value <= 0{
                //实际中心点与开始变化时的item的中心点小于等于设定的边界值
                if delta >= 0 && delta <= itemHeight
                {
                    //item的中心点固定不变
                    attributes.center.x = centerX
                    //根据推进值,改变item的透明度,此处的delta>10是想让item有一个达到目标区域时有一个停顿效果而不是直接进入改变透明度的阶段
                    attributes.alpha = (delta > 10) ? (1 - delta/(itemHeight/4)) : 1
                    //设置缩放比例,停顿阶段不进行缩放
                    attributes.transform = CGAffineTransform.init(scaleX: 1, y: 1)
                } else {
                    //移动大于边界值,就是从停顿阶段到透明度改变,此处是下一个item上来,当前item透明度变为0
                    attributes.alpha = 0
                }
            }
        }
        return array
    }

解决最后一个小问题,拖动iitem开始滚动,滚动结束时让它自动滚动到网格区域,而不是停在当前或许不适当的地方,重写UICollectionViewFlowLayout另一个方法:

override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
        
        let targetRect = CGRect(x: proposedContentOffset.x, y: 0.0, width: self.collectionView!.bounds.size.width, height: self.collectionView!.bounds.size.height)
        
        //目标区域中包含的cell
        let attrArray = super.layoutAttributesForElements(in: targetRect) as! [UICollectionViewLayoutAttributes]
        //collectionView落在屏幕重点的x坐标
        let horizontalCenterX = proposedContentOffset.x + (self.collectionView?.frame.height ?? 0)/2
        var offsetAdjustment = CGFloat(MAXFLOAT)
        for layoutAttributes in attrArray {
            
            let itemHorizontalCenterX = layoutAttributes.center.x
            //找出离中心店最近的
            if (abs(itemHorizontalCenterX-horizontalCenterX) < abs(offsetAdjustment)) {
                offsetAdjustment = itemHorizontalCenterX - horizontalCenterX
            }
        }
        
        //返回collectionView最终停留的位置
        return CGPoint(x: proposedContentOffset.x + offsetAdjustment, y: proposedContentOffset.y)
        
    }
//当collectionView的显示范围发生改变的时候,是否重新布局
    override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
        return true
    }

最后一个方法不写看不到渐变的效果。

源码地址:点击打开链接

2018-07-24 14:16:40 u010960265 阅读数 23694

效果:
这里写图片描述

参考UITableView的UITableViewDataSource和UITableViewDelegate两个方法实现;支持五险轮播,可以加载本地图片,也可以加载网络图片,可以根据自己的需求自定义
Demo地址

UITableViewDelegate

/**
 *  当前显示cell的Size(中间页显示大小)
 *
 *  @param flowView <#flowView description#>
 *
 *  @return <#return value description#>
 */
- (CGSize)sizeForPageInFlowView:(HQFlowView *)flowView;

/**
 *  滚动到了某一列
 *
 *  @param pageNumber <#pageNumber description#>
 *  @param flowView   <#flowView description#>
 */
- (void)didScrollToPage:(NSInteger)pageNumber inFlowView:(HQFlowView *)flowView;

/**
 *  点击了第几个cell
 *
 *  @param subView 点击的控件
 *  @param subIndex    点击控件的index
 *
 *  @return <#return value description#>
 */
- (void)didSelectCell:(HQIndexBannerSubview *)subView withSubViewIndex:(NSInteger)subIndex;

UITableViewDataSource

/**
 *  返回显示View的个数
 *
 *  @param flowView <#flowView description#>
 *
 *  @return <#return value description#>
 */
- (NSInteger)numberOfPagesInFlowView:(HQFlowView *)flowView;

/**
 *  给某一列设置属性
 *
 *  @param flowView <#flowView description#>
 *  @param index    <#index description#>
 *
 *  @return <#return value description#>
 */
- (HQIndexBannerSubview *)flowView:(HQFlowView *)flowView cellForPageAtIndex:(NSInteger)index;
2016-06-16 14:45:00 weixin_33872660 阅读数 90

前言:在这篇文章你可以学到,一些基本的Swift语法, 基本UI控件闭包等.

实际的效果,比gif图的效果好很多.


卡片切换.gif
首先需要导入ZLSwipeableView

pod 'ZLSwipeableView', '~> 0.0.8'

下面是代码
// 1. 签协议
class ViewController: UIViewController, ZLSwipeableViewDelegate, ZLSwipeableViewDataSource {
// 2, 随便定义一个标题数组
let titles = [
    "Teame",
    "Sea",
    "Em",
    "Nes",
    "Pver",
    "Beole",
    "Amst",
    "Wisria",
    "Whalt",
    "Midue",
    "Suwer",
    "Orage",
    ]
 var index = 0
 var xtSwipeableView: ZLSwipeableView?
在viewDidLoad
        xtSwipeableView = ZLSwipeableView.init()
        xtSwipeableView!.frame = CGRectMake(55, 110, self.view.frame.size.width - 110, self.view.frame.size.height - 220)
        xtSwipeableView!.delegate = self
        xtSwipeableView!.dataSource = self
        xtSwipeableView!.translatesAutoresizingMaskIntoConstraints = false
        self.view.addSubview(xtSwipeableView!)
        self.setButton()
创建 ⬆️,⬇️,⬅️,btn
func setButton()
    {
        var items = ["上", "下", "左", "右"]
        for i in 0...3{
            let btn = UIButton.init(type: UIButtonType.Custom)
            self.view.addSubview(btn)
            btn.frame = CGRectMake(50 + 60 * (CGFloat)(i), self.view.frame.size.height - 90, 50, 50)
            btn.setTitle(items[i], forState: UIControlState.Normal)
            btn.addTarget(self, action: "handle:", forControlEvents: UIControlEvents.TouchUpInside)
            btn.tag = i
        }
    }
btn点击方法
func handle(btn: UIButton)
    {
        let tagType = btn.tag
        switch tagType{
        case 0:
            xtSwipeableView!.swipeTopViewToUp()
        case 1:
            xtSwipeableView!.swipeTopViewToDown()
        case 2:
            xtSwipeableView!.swipeTopViewToLeft()
        case 3:
            xtSwipeableView!.swipeTopViewToRight()
        default:
            print("....")
        }
    }
loadViews
override func viewDidLayoutSubviews() {
        xtSwipeableView!.loadViewsIfNeeded()
    }
ZLSwipeableViewDataSource
func nextViewForSwipeableView(swipeableView: ZLSwipeableView!) -> UIView! {
        if self.index >= self.titles.count {
            self.index = 0
        }
        let view = CardView.init(frame: swipeableView.bounds)
        view.backgroundColor = UIColor.purpleColor()
        view.textLabel?.text = self.titles[index]
        // 闭包回调
        view .initWithClosure(addressThatTakesAClosure)
        self.index++
        return view
    }
func addressThatTakesAClosure(string:String) ->Void{
        // do you something
        print("\(string)")
    }
CardView类的实现(在这你可以定义你所需要的)
class CardView: UIView {
        typealias sendValueClosure = (string:String)->Void
        /// 声明一个Closure(闭包)
        var myClosure:sendValueClosure?
        /// 下面这个方法需要传入上个界面的someFunctionThatTakesAClosure函数指针
        func initWithClosure(closure:sendValueClosure?){
            myClosure = closure
        }
        ///
        var imagesView: UIImageView?
        var textLabel : UILabel?
        var btn: UIButton?
        ///
        override init(frame: CGRect) {
            super.init(frame: frame)
            self.setView(frame)
        }
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        /// setView
        func setView(frame: CGRect){
            // Shadow
            self.layer.shadowColor = UIColor.lightGrayColor().CGColor
            self.layer.shadowOpacity = 0.33
            self.layer.shadowOffset = CGSizeMake(0, 1.5)
            self.layer.shadowRadius = 4.0
            self.layer.shouldRasterize = true
            self.layer.rasterizationScale = UIScreen.mainScreen().scale

            // Corner Radius
            self.layer.cornerRadius = 10.0

            // Custom view
            imagesView = UIImageView.init(frame: CGRectMake(5, 5, self.frame.size.width - 10, self.frame.size.height / 2))
            imagesView!.backgroundColor = UIColor.whiteColor()
            self.addSubview(imagesView!)


            textLabel = UILabel.init(frame: CGRectMake(20, imagesView!.frame.size.height + 10, 120, 20))
            textLabel!.backgroundColor = UIColor.lightGrayColor()
            self.addSubview(textLabel!)

            btn = UIButton.init(type: UIButtonType.Custom)
            btn?.setTitle("BUTTON", forState: UIControlState.Normal)
            btn?.frame = CGRectMake(20, (textLabel?.frame.origin.y)! + 20 + 10, 100, 50)
            self.addSubview(btn!)
            btn?.addTarget(self, action: "btnClick", forControlEvents: UIControlEvents.TouchUpInside)

        }
        /// 这里实现了btn点击方法的回调, 回到控制器(VC),可实现跳转
        func btnClick()
        {
            if myClosure != nil{
                self.myClosure!(string: "hello World")
            }
        }
    }

总结: 希望看到这篇文章对读者有一定Swift语言的帮助, 且完成卡片切换效果需求. 喜欢请点赞. 稍候会把项目传到github.今天有点晚了.睡了 呼呼. -.-


demo参考(Objective-C & Swift) :
https://github.com/Zhangjingwang1993/XSmomoStyle
觉得还可以请点个赞, 我要申请微博加V. 点个赞吧客官 -.-
个人技术博客站欢迎您



文/夏天然后(简书作者)
原文链接:http://www.jianshu.com/p/734962c9bbed
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
2016-09-26 09:28:41 mo_xiao_mo 阅读数 5263
图片的无限循环轮播功能常常用在广告或者新闻展示上面,本文演示如何实现一个 iOS 系统下的图片轮播组件。

1,组件功能介绍
(1)每隔一段时间,轮播器就会自动滚动到下一张图片。如果当前是最后一张图片的话,则又滚动回第一张图片。这样无限循环下去。
(2)在组件下方位置有页控制器(小圆点),显示图片数量和当前的位置。
(3)除了自动轮播,我们还可以通过手动滑动组件来显示上一张,下一张图片。手动控制滚动的时候自动轮播功能停止,手动滚动结束后自动轮播功能又自动启用。
(4)点击图片我们可以获取到当前图片的位置索引,便于我们后续操作。这里直接将索引值显示出来。

2,组件效果图
     原文:Swift - 图片循环轮播组件的实现(附样例)      原文:Swift - 图片循环轮播组件的实现(附样例)

3,组件实现原理
(1)我们在一个 scrollerView 中横向放置三个并排的 imageView。管多少张图片都是交替使用这三个 imageView 来显示。
(2)每次图片滚动结束的时候,计算当前显示的图片索引值。并重置三个 imageView 里的图片和位置。
(3)由于图片可以通过网络加载,这里我用了一个第三方的图片库:ImageHelper。可以自动帮我们实现图片缓存,避免重复加载。(关于 ImageHelper,可以参考我之前写过的这篇文章:Swift - 图片处理库AFImageHelper详解
(4)在图片未加载出来的时候,其位置上会先显示一张加载提示图片。这里我同样借助 ImageHelper,将一段提示文字转成 Image,用来作为加载完毕前的提示。
原文:Swift - 图片循环轮播组件的实现(附样例)

4,组件代码
整个组件只有一个 swift 文件(SliderGalleryController.swift),里面包含一个组件实现类:SliderGalleryController。以及相关协议:SliderGalleryControllerDelegate
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
import UIKit
 
//图片轮播组件代理协议
protocol SliderGalleryControllerDelegate{
    //获取数据源
    func galleryDataSource()->[String]
    //获取内部scrollerView的宽高尺寸
    func galleryScrollerViewSize()->CGSize
}
 
//图片轮播组件控制器
class SliderGalleryControllerUIViewController,UIScrollViewDelegate{
    //代理对象
    var delegate : SliderGalleryControllerDelegate!
     
    //屏幕宽度
    let kScreenWidth = UIScreen.main.bounds.size.width
     
    //当前展示的图片索引
    var currentIndex : Int = 0
     
    //数据源
    var dataSource : [String]?
     
    //用于轮播的左中右三个image(不管几张图片都是这三个imageView交替使用)
    var leftImageView , middleImageView , rightImageView : UIImageView?
     
    //放置imageView的滚动视图
    var scrollerView : UIScrollView?
     
    //scrollView的宽和高
    var scrollerViewWidth : CGFloat?
    var scrollerViewHeight : CGFloat?
     
    //页控制器(小圆点)
    var pageControl : UIPageControl?
     
    //加载指示符(用来当iamgeView还没将图片显示出来时,显示的图片)
    var placeholderImage:UIImage!
     
    //自动滚动计时器
    var autoScrollTimer:Timer?
     
    override func viewDidLoad() {
        super.viewDidLoad()
 
        //获取并设置scrollerView尺寸
        let size : CGSize self.delegate.galleryScrollerViewSize()
        self.scrollerViewWidth = size.width
        self.scrollerViewHeight = size.height
 
        //获取数据
        self.dataSource =  self.delegate.galleryDataSource()
        //设置scrollerView
        self.configureScrollerView()
        //设置加载指示图片
        self.configurePlaceholder()
        //设置imageView
        self.configureImageView()
        //设置页控制器
        self.configurePageController()
        //设置自动滚动计时器
        self.configureAutoScrollTimer()
         
        self.view.backgroundColor = UIColor.black
    }
     
    //设置scrollerView
    func configureScrollerView(){
        self.scrollerView = UIScrollView(frame: CGRect(x: 0,y: 0,
                width: self.scrollerViewWidth!, height: self.scrollerViewHeight!))
        self.scrollerView?.backgroundColor = UIColor.red
        self.scrollerView?.delegate = self
        self.scrollerView?.contentSize = CGSize(width: self.scrollerViewWidth! * 3,
                                                height: self.scrollerViewHeight!)
        //滚动视图内容区域向左偏移一个view的宽度
        self.scrollerView?.contentOffset = CGPoint(x: self.scrollerViewWidth!, y: 0)
        self.scrollerView?.isPagingEnabled = true
        self.scrollerView?.bounces = false
        self.view.addSubview(self.scrollerView!)
         
    }
     
    //设置加载指示图片
    func configurePlaceholder(){
        //这里我使用ImageHelper将文字转换成图片,作为加载指示符
        let font = UIFont.systemFont(ofSize: 17.0, weight: UIFontWeightMedium)
        let size = CGSize(width: self.scrollerViewWidth!, height: self.scrollerViewHeight!)
        placeholderImage = UIImage(text: "图片加载中...", font:font,
                                   color:UIColor.white, size:size)!
    }
     
    //设置imageView
    func configureImageView(){
        self.leftImageView = UIImageView(frame: CGRect(x: 0, y: 0,
                    width: self.scrollerViewWidth!, height: self.scrollerViewHeight!))
        self.middleImageView = UIImageView(frame: CGRect(x: self.scrollerViewWidth!, y: 0,
                    width: self.scrollerViewWidth!, height: self.scrollerViewHeight! ));
        self.rightImageView = UIImageView(frame: CGRect(x: 2*self.scrollerViewWidth!, y: 0,
                    width: self.scrollerViewWidth!, height: self.scrollerViewHeight!));
        self.scrollerView?.showsHorizontalScrollIndicator = false
         
        //设置初始时左中右三个imageView的图片(分别时数据源中最后一张,第一张,第二张图片)
        if(self.dataSource?.count != 0){
            resetImageViewSource()
        }
         
        self.scrollerView?.addSubview(self.leftImageView!)
        self.scrollerView?.addSubview(self.middleImageView!)
        self.scrollerView?.addSubview(self.rightImageView!)
    }
     
    //设置页控制器
    func configurePageController() {
        self.pageControl = UIPageControl(frame: CGRect(x: kScreenWidth/2-60,
                        y: self.scrollerViewHeight! - 20, width: 120, height: 20))
        self.pageControl?.numberOfPages = (self.dataSource?.count)!
        self.pageControl?.isUserInteractionEnabled = false
        self.view.addSubview(self.pageControl!)
    }
     
    //设置自动滚动计时器
    func configureAutoScrollTimer() {
        //设置一个定时器,每三秒钟滚动一次
        autoScrollTimer = Timer.scheduledTimer(timeInterval: 3, target: self,
                    selector: #selector(SliderGalleryController.letItScroll),
                    userInfo: nil, repeats: true)
    }
     
    //计时器时间一到,滚动一张图片
    func letItScroll(){
        let offset = CGPoint(x: 2*scrollerViewWidth!, y: 0)
        self.scrollerView?.setContentOffset(offset, animated: true)
    }
     
    //每当滚动后重新设置各个imageView的图片
    func resetImageViewSource() {
        //当前显示的是第一张图片
        if self.currentIndex == 0 {
            self.leftImageView?.imageFromURL(self.dataSource!.last!,
                                             placeholder: placeholderImage)
            self.middleImageView?.imageFromURL(self.dataSource!.first!,
                                               placeholder: placeholderImage)
            let rightImageIndex = (self.dataSource?.count)!>1 ? 1 : 0 //保护
            self.rightImageView?.imageFromURL(self.dataSource![rightImageIndex],
                                              placeholder: placeholderImage)
        }
        //当前显示的是最好一张图片
        else if self.currentIndex == (self.dataSource?.count)! - 1 {
            self.leftImageView?.imageFromURL(self.dataSource![self.currentIndex-1],
                                             placeholder: placeholderImage)
            self.middleImageView?.imageFromURL(self.dataSource!.last!,
                                               placeholder: placeholderImage)
            self.rightImageView?.imageFromURL(self.dataSource!.first!,
                                              placeholder: placeholderImage)
        }
        //其他情况
        else{
            self.leftImageView?.imageFromURL(self.dataSource![self.currentIndex-1],
                                             placeholder: placeholderImage)
            self.middleImageView?.imageFromURL(self.dataSource![self.currentIndex],
                                               placeholder: placeholderImage)
            self.rightImageView?.imageFromURL(self.dataSource![self.currentIndex+1],
                                              placeholder: placeholderImage)
        }
    }
     
    //scrollView滚动完毕后触发
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        //获取当前偏移量
        let offset = scrollView.contentOffset.x
         
        if(self.dataSource?.count != 0){
             
            //如果向左滑动(显示下一张)
            if(offset >= self.scrollerViewWidth!*2){
                //还原偏移量
                scrollView.contentOffset = CGPoint(x: self.scrollerViewWidth!, y: 0)
                //视图索引+1
                self.currentIndex = self.currentIndex + 1
                 
                if self.currentIndex == self.dataSource?.count {
                    self.currentIndex = 0
                }
            }
         
            //如果向右滑动(显示上一张)
            if(offset <= 0){
                //还原偏移量
                scrollView.contentOffset = CGPoint(x: self.scrollerViewWidth!, y: 0)
                //视图索引-1
                self.currentIndex = self.currentIndex - 1
                 
                if self.currentIndex == -1 {
                    self.currentIndex = (self.dataSource?.count)! - 1
                }
            }
             
            //重新设置各个imageView的图片
            resetImageViewSource()
            //设置页控制器当前页码
            self.pageControl?.currentPage = self.currentIndex
        }
    }
     
    //手动拖拽滚动开始
    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        //使自动滚动计时器失效(防止用户手动移动图片的时候这边也在自动滚动)
        autoScrollTimer?.invalidate()
    }
     
    //手动拖拽滚动结束
    func scrollViewDidEndDragging(_ scrollView: UIScrollView,
                                  willDecelerate decelerate: Bool) {
        //重新启动自动滚动计时器
        configureAutoScrollTimer()
         
    }
     
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

5,使用样例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import UIKit
 
class ViewControllerUIViewControllerSliderGalleryControllerDelegate {
     
    //获取屏幕宽度
    let screenWidth =  UIScreen.main.bounds.size.width
     
    //图片轮播组件
    var sliderGallery : SliderGalleryController!
     
     
    override func viewDidLoad() {
        super.viewDidLoad()
         
        //初始化图片轮播组件
        sliderGallery = SliderGalleryController()
        sliderGallery.delegate = self
        sliderGallery.view.frame = CGRect(x: 10, y: 40, width: screenWidth-20,
                                          height: (screenWidth-20)/4*3);
         
        //将图片轮播组件添加到当前视图
        self.addChildViewController(sliderGallery)
        self.view.addSubview(sliderGallery.view)
         
        //添加组件的点击事件
        let tap = UITapGestureRecognizer(target: self,
                        action: #selector(ViewController.handleTapAction(_:)))
        sliderGallery.view.addGestureRecognizer(tap)
    }
     
    //图片轮播组件协议方法:获取内部scrollView尺寸
    func galleryScrollerViewSize() -> CGSize {
        return CGSize(width: screenWidth-20, height: (screenWidth-20)/4*3)
    }
     
    //图片轮播组件协议方法:获取数据集合
    func galleryDataSource() -> [String] {
                "http://tupian.enterdesk.com/2012/1015/zyz/03/5.jpg",
    }
 
    //点击事件响应
    func handleTapAction(_ tap:UITapGestureRecognizer)->Void{
        //获取图片索引值
        let index = sliderGallery.currentIndex
        //弹出索引信息
        let alertController = UIAlertController(title: "您点击的图片索引是:",
                                                message: "\(index)", preferredStyle: .alert)
        let cancelAction = UIAlertAction(title: "确定", style: .cancel, handler: nil)
        alertController.addAction(cancelAction)
        self.present(alertController, animated: true, completion: nil)
    }
     
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}
源码下载hangge_1314.zip
原文出自:www.hangge.com  转载请保留原文链接:http://www.hangge.com/blog/cache/detail_1314.html