├── .gitignore
├── LICENSE
├── README.md
├── WRCycleScrollView
├── WRCycleCell.swift
├── WRCycleScrollView.swift
├── WRPageControl.swift
└── WRProxy.swift
├── WRCycleScrollViewDemo
├── Podfile
├── Podfile.lock
├── Pods
│ ├── Kingfisher
│ │ ├── LICENSE
│ │ ├── README.md
│ │ └── Sources
│ │ │ ├── AnimatedImageView.swift
│ │ │ ├── Box.swift
│ │ │ ├── CacheSerializer.swift
│ │ │ ├── Filter.swift
│ │ │ ├── Image.swift
│ │ │ ├── ImageCache.swift
│ │ │ ├── ImageDownloader.swift
│ │ │ ├── ImagePrefetcher.swift
│ │ │ ├── ImageProcessor.swift
│ │ │ ├── ImageTransition.swift
│ │ │ ├── ImageView+Kingfisher.swift
│ │ │ ├── Indicator.swift
│ │ │ ├── Kingfisher.h
│ │ │ ├── Kingfisher.swift
│ │ │ ├── KingfisherManager.swift
│ │ │ ├── KingfisherOptionsInfo.swift
│ │ │ ├── RequestModifier.swift
│ │ │ ├── Resource.swift
│ │ │ ├── String+MD5.swift
│ │ │ ├── ThreadHelper.swift
│ │ │ └── UIButton+Kingfisher.swift
│ ├── Manifest.lock
│ ├── Pods.xcodeproj
│ │ └── project.pbxproj
│ └── Target Support Files
│ │ ├── Kingfisher
│ │ ├── Info.plist
│ │ ├── Kingfisher-dummy.m
│ │ ├── Kingfisher-prefix.pch
│ │ ├── Kingfisher-umbrella.h
│ │ ├── Kingfisher.modulemap
│ │ └── Kingfisher.xcconfig
│ │ └── Pods-WRCycleScrollViewDemo
│ │ ├── Info.plist
│ │ ├── Pods-WRCycleScrollViewDemo-acknowledgements.markdown
│ │ ├── Pods-WRCycleScrollViewDemo-acknowledgements.plist
│ │ ├── Pods-WRCycleScrollViewDemo-dummy.m
│ │ ├── Pods-WRCycleScrollViewDemo-frameworks.sh
│ │ ├── Pods-WRCycleScrollViewDemo-resources.sh
│ │ ├── Pods-WRCycleScrollViewDemo-umbrella.h
│ │ ├── Pods-WRCycleScrollViewDemo.debug.xcconfig
│ │ ├── Pods-WRCycleScrollViewDemo.modulemap
│ │ └── Pods-WRCycleScrollViewDemo.release.xcconfig
├── WRCycleScrollViewDemo.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ └── contents.xcworkspacedata
├── WRCycleScrollViewDemo.xcworkspace
│ └── contents.xcworkspacedata
├── WRCycleScrollViewDemo
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ ├── Contents.json
│ │ │ ├── wr@2x.png
│ │ │ └── wr@3x.png
│ │ ├── Contents.json
│ │ ├── LaunchImage.launchimage
│ │ │ └── Contents.json
│ │ ├── dot
│ │ │ ├── Contents.json
│ │ │ ├── currentDot.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ ├── slider_current_dot.png
│ │ │ │ ├── slider_current_dot@2x.png
│ │ │ │ └── slider_current_dot@3x.png
│ │ │ └── defaultDot.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ ├── slider_default_dot.png
│ │ │ │ ├── slider_default_dot@2x.png
│ │ │ │ └── slider_default_dot@3x.png
│ │ ├── image11.imageset
│ │ │ ├── Contents.json
│ │ │ └── image11.png
│ │ ├── image12.imageset
│ │ │ ├── Contents.json
│ │ │ └── image12.jpg
│ │ ├── image13.imageset
│ │ │ ├── Contents.json
│ │ │ └── image13.png
│ │ ├── image14.imageset
│ │ │ ├── Contents.json
│ │ │ └── image14.jpg
│ │ ├── image15.imageset
│ │ │ ├── Contents.json
│ │ │ └── image15.jpg
│ │ ├── localImg1.imageset
│ │ │ ├── 1.png
│ │ │ └── Contents.json
│ │ ├── localImg10.imageset
│ │ │ ├── Contents.json
│ │ │ └── localImg10.jpg
│ │ ├── localImg2.imageset
│ │ │ ├── 2.png
│ │ │ └── Contents.json
│ │ ├── localImg3.imageset
│ │ │ ├── 3.png
│ │ │ └── Contents.json
│ │ ├── localImg4.imageset
│ │ │ ├── 4.png
│ │ │ └── Contents.json
│ │ ├── localImg5.imageset
│ │ │ ├── 5.png
│ │ │ └── Contents.json
│ │ ├── localImg6.imageset
│ │ │ ├── 6.jpg
│ │ │ └── Contents.json
│ │ ├── localImg7.imageset
│ │ │ ├── Contents.json
│ │ │ └── localImg7.jpg
│ │ ├── localImg8.imageset
│ │ │ ├── Contents.json
│ │ │ └── localImg8.jpg
│ │ ├── localImg9.imageset
│ │ │ ├── Contents.json
│ │ │ └── localImg9.jpg
│ │ └── placeholder
│ │ │ ├── Contents.json
│ │ │ └── placeholder_720x360.imageset
│ │ │ ├── Contents.json
│ │ │ ├── placeholder_720x360@2x.png
│ │ │ └── placeholder_720x360@3x.png
│ ├── Base.lproj
│ │ └── LaunchScreen.storyboard
│ ├── CustomDotController.swift
│ ├── DemoListController.swift
│ ├── Info.plist
│ ├── LocalImgController.swift
│ ├── NoEndlessController.swift
│ ├── NoPageControlController.swift
│ ├── SBController.swift
│ ├── ServerImgController.swift
│ ├── StandaloneDotController.swift
│ ├── StoryBoardController.storyboard
│ ├── WRCycleScrollView
│ │ ├── WRCycleCell.swift
│ │ ├── WRCycleScrollView.swift
│ │ ├── WRPageControl.swift
│ │ └── WRProxy.swift
│ ├── WRNavigationBar
│ │ └── WRNavigationBar.swift
│ └── ZhiHuController.swift
└── WRCycleScrollViewDemoTests
│ ├── Info.plist
│ └── WRCycleScrollViewDemoTests.swift
└── screenshots
├── StoryBoard创建.gif
├── WRCycleScrollView.png
├── demos.png
├── 不无限轮播.gif
├── 不显示pageControl.gif
├── 本地图片轮播.gif
├── 知乎日报.gif
└── 网络图片轮播.gif
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xcuserstate
23 |
24 | ## Obj-C/Swift specific
25 | *.hmap
26 | *.ipa
27 | *.dSYM.zip
28 | *.dSYM
29 |
30 | ## Playgrounds
31 | timeline.xctimeline
32 | playground.xcworkspace
33 |
34 | # Swift Package Manager
35 | #
36 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
37 | # Packages/
38 | .build/
39 |
40 | # CocoaPods
41 | #
42 | # We recommend against adding the Pods directory to your .gitignore. However
43 | # you should judge for yourself, the pros and cons are mentioned at:
44 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
45 | #
46 | # Pods/
47 |
48 | # Carthage
49 | #
50 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
51 | # Carthage/Checkouts
52 |
53 | Carthage/Build
54 |
55 | # fastlane
56 | #
57 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
58 | # screenshots whenever they are needed.
59 | # For more information about the recommended setup visit:
60 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
61 |
62 | fastlane/report.xml
63 | fastlane/Preview.html
64 | fastlane/screenshots
65 | fastlane/test_output
66 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | #####[强烈推荐使用:WRNavigationBar 超简单!!! 一行代码设置状态栏、导航栏按钮、标题、颜色、透明度,移动等](https://github.com/wangrui460/WRNavigationBar)
4 | ------------------------------------------------------------
5 | ## iOS 技术交流
6 | 我创建了一个 微信 iOS 技术交流群,欢迎小伙伴们加入一起交流学习~
7 |
8 | 可以加我微信我拉你进去(备注iOS),我的微信号 wr1204607318
9 |
10 | ## Requirements
11 | - iOS 8+
12 | - Xcode 8+
13 |
14 |
15 | ## Demo
16 | ---
17 | demo列表
18 |
19 | 
20 |
21 | ---
22 | 知乎日报
23 |
24 | 
25 |
26 | ---
27 | 本地图片轮播
28 |
29 | 
30 |
31 | ---
32 | 网络图片轮播
33 |
34 | 
35 |
36 | ---
37 | StoryBoard创建
38 |
39 | 
40 |
41 | ---
42 | 不无限轮播
43 |
44 | 
45 |
46 | ---
47 | 不显示pageControl
48 |
49 | 
50 |
51 |
52 | ## Installation
53 |
54 | > **手动拖入**
55 | > 将 WRCycleScrollView 文件夹拽入项目中即可使用
56 |
57 | ## How To Use
58 |
59 |
60 | var cycleScrollView:WRCycleScrollView?
61 | let height = 520 * kScreenWidth / 1080.0
62 | let frame = CGRect(x: 0, y: 150, width: kScreenWidth, height: height)
63 | // 可加载网络图片或者本地图片
64 | let serverImages = ["http://p.lrlz.com/data/upload/mobile/special/s252/s252_05471521705899113.png", "http://p.lrlz.com/data/upload/mobile/special/s303/s303_05442007678060723.png", "http://p.lrlz.com/data/upload/mobile/special/s303/s303_05442007587372591.png", "http://p.lrlz.com/data/upload/mobile/special/s303/s303_05442007388249407.png", "http://p.lrlz.com/data/upload/mobile/special/s303/s303_05442007470310935.png"]
65 | // 构造方法
66 | cycleScrollView = WRCycleScrollView(frame: frame, type: .SERVER, imgs: serverImages)
67 | view.addSubview(cycleScrollView!)
68 | // 添加代理
69 | cycleScrollView?.delegate = self
70 |
71 |
72 | 代理方法
73 |
74 | extension ServerImgController: WRCycleScrollViewDelegate
75 | {
76 | /// 点击图片事件
77 | func cycleScrollViewDidSelect(at index:Int, cycleScrollView:WRCycleScrollView)
78 | {
79 | print("点击了第\(index+1)个图片")
80 | }
81 |
82 | /// 图片滚动事件
83 | func cycleScrollViewDidScroll(to index:Int, cycleScrollView:WRCycleScrollView)
84 | {
85 | print("滚动到了第\(index+1)个图片")
86 | }
87 | }
88 |
89 |
90 |
91 |
92 | ## License
93 |
94 | WRCycleScrollView is available under the MIT license. See the LICENSE file for more info.
95 |
96 |
--------------------------------------------------------------------------------
/WRCycleScrollView/WRCycleCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WRCycleCell.swift
3 | // WRCycleScrollViewDemo
4 | //
5 | // Created by wangrui on 2017/5/12.
6 | // Copyright © 2017年 wangrui. All rights reserved.
7 | //
8 | // Github地址:https://github.com/wangrui460/WRCycleScrollView
9 |
10 | import UIKit
11 | import Kingfisher
12 |
13 | class WRCycleCell: UICollectionViewCell
14 | {
15 | //=======================================================
16 | // MARK: 对外提供的属性
17 | //=======================================================
18 | var imgSource:ImgSource = ImgSource.LOCAL(name: "placeholder") {
19 | didSet {
20 | switch imgSource {
21 | case let .SERVER(url):
22 | imgView.kf.setImage(with: url)
23 | case let .LOCAL(name):
24 | imgView.image = UIImage(named: name)
25 | }
26 | }
27 | }
28 |
29 | var placeholderImage: UIImage?
30 |
31 | var descText:String? {
32 | didSet {
33 | descLabel.isHidden = (descText == nil) ? true : false
34 | bottomView.isHidden = (descText == nil) ? true : false
35 | descLabel.text = descText
36 | }
37 | }
38 |
39 | override var frame: CGRect {
40 | didSet {
41 | bounds.size = frame.size
42 | }
43 | }
44 |
45 | var imageContentModel:UIViewContentMode = .scaleAspectFill {
46 | didSet {
47 | imgView.contentMode = imageContentModel
48 | }
49 | }
50 |
51 | var descLabelFont: UIFont = UIFont(name: "Helvetica-Bold", size: 18)! {
52 | didSet {
53 | descLabel.font = descLabelFont
54 | }
55 | }
56 | var descLabelTextColor: UIColor = UIColor.white {
57 | didSet {
58 | descLabel.textColor = descLabelTextColor
59 | }
60 | }
61 | var descLabelHeight: CGFloat = 60 {
62 | didSet {
63 | descLabel.frame.size.height = descLabelHeight
64 | }
65 | }
66 | var descLabelTextAlignment:NSTextAlignment = .left {
67 | didSet {
68 | descLabel.textAlignment = descLabelTextAlignment
69 | }
70 | }
71 | var bottomViewBackgroundColor: UIColor = UIColor.black.withAlphaComponent(0.5) {
72 | didSet {
73 | bottomView.backgroundColor = bottomViewBackgroundColor
74 | }
75 | }
76 |
77 | //=======================================================
78 | // MARK: 内部属性
79 | //=======================================================
80 | fileprivate var imgView:UIImageView!
81 | fileprivate var descLabel:UILabel!
82 | fileprivate var bottomView:UIView!
83 |
84 | //=======================================================
85 | // MARK: 构造方法
86 | //=======================================================
87 | override init(frame: CGRect)
88 | {
89 | super.init(frame: frame)
90 | backgroundColor = UIColor.white
91 | setupImgView()
92 | setupDescLabel()
93 | setupBottomView()
94 | }
95 | required init?(coder aDecoder: NSCoder) {
96 | fatalError("init(coder:) has not been implemented")
97 | }
98 | deinit {
99 | print("WRCycleCell deinit")
100 | }
101 |
102 |
103 | //=======================================================
104 | // MARK: 内部方法(layoutSubviews)
105 | //=======================================================
106 | override func layoutSubviews()
107 | {
108 | super.layoutSubviews()
109 | imgView.frame = self.bounds
110 |
111 | if let _ = descText
112 | {
113 | let margin:CGFloat = 16
114 | let labelWidth = imgView.bounds.width - 2 * margin
115 | let labelHeight = descLabelHeight
116 | let labelY = bounds.height - labelHeight
117 | descLabel.frame = CGRect(x: margin, y: labelY, width: labelWidth, height: labelHeight)
118 | bottomView.frame = CGRect(x: 0, y: labelY, width: imgView.bounds.width, height: labelHeight)
119 | bringSubview(toFront: descLabel)
120 | }
121 | }
122 | }
123 |
124 | //=======================================================
125 | // MARK: - 基本控件(图片、描述文字、底部view)
126 | //=======================================================
127 | extension WRCycleCell
128 | {
129 | fileprivate func setupImgView()
130 | {
131 | imgView = UIImageView()
132 | imgView.contentMode = imageContentModel
133 | imgView.clipsToBounds = true
134 | addSubview(imgView)
135 | }
136 |
137 | fileprivate func setupDescLabel()
138 | {
139 | descLabel = UILabel()
140 | descLabel.text = descText
141 | descLabel.numberOfLines = 0
142 | descLabel.font = descLabelFont
143 | descLabel.textColor = descLabelTextColor
144 | descLabel.frame.size.height = descLabelHeight
145 | descLabel.textAlignment = descLabelTextAlignment
146 | addSubview(descLabel)
147 | descLabel.isHidden = true
148 | }
149 |
150 | fileprivate func setupBottomView()
151 | {
152 | bottomView = UIView()
153 | bottomView.backgroundColor = bottomViewBackgroundColor
154 | addSubview(bottomView)
155 | bottomView.isHidden = true
156 | }
157 | }
158 |
159 |
--------------------------------------------------------------------------------
/WRCycleScrollView/WRPageControl.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WRPageControl.swift
3 | // WRCycleScrollViewDemo
4 | //
5 | // Created by itwangrui on 2017/11/14.
6 | // Copyright © 2017年 wangrui. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | private let WRPageControlPointWidth: CGFloat = 7
12 | private let WRPageControlPointHeight: CGFloat = 20
13 |
14 | class WRPageControl: UIPageControl
15 | {
16 | var currentImage: UIImage?
17 | var defaultImage: UIImage?
18 | var pointSpace: CGFloat = 15
19 | var pageSize: CGSize {
20 | get {
21 | if let curImage = currentImage, let defImage = defaultImage {
22 | let pageH = curImage.size.height
23 | let defDotW = defImage.size.width
24 | let curDotW = curImage.size.width
25 | let pageW = CGFloat(numberOfPages - 1) * (pointSpace + defDotW + defDotW) + curDotW
26 | return CGSize(width: pageW, height: pageH)
27 | }
28 | else {
29 | let pageW = CGFloat(numberOfPages - 1) * (pointSpace + WRPageControlPointWidth) + WRPageControlPointWidth
30 | return CGSize(width: pageW, height: WRPageControlPointHeight)
31 | }
32 | }
33 | }
34 |
35 | override var currentPage: Int {
36 | didSet {
37 | updatePageControl()
38 | }
39 | }
40 |
41 | init(frame: CGRect, currentImage: UIImage?, defaultImage: UIImage?)
42 | {
43 | super.init(frame: frame)
44 | self.currentImage = currentImage
45 | self.defaultImage = defaultImage
46 | }
47 | required init?(coder aDecoder: NSCoder) {
48 | fatalError("init(coder:) has not been implemented")
49 | }
50 | }
51 |
52 |
53 | // MARK: - update index
54 | extension WRPageControl
55 | {
56 | func updatePageControl()
57 | {
58 | for index in 0.. CGSize
92 | {
93 | var newSize = CGSize(width: 0, height: 0)
94 | if let curImage = currentImage, let defImage = defaultImage {
95 | if currentIndex == currentPage {
96 | newSize = curImage.size
97 | } else {
98 | newSize = defImage.size
99 | }
100 | } else {
101 | newSize = CGSize(width: WRPageControlPointWidth, height: WRPageControlPointWidth)
102 | }
103 | return newSize
104 | }
105 | }
106 |
107 |
108 |
--------------------------------------------------------------------------------
/WRCycleScrollView/WRProxy.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WRProxy.swift
3 | // WRCycleScrollViewDemo
4 | //
5 | // Created by wangrui on 2017/5/15.
6 | // Copyright © 2017年 wangrui. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | /////////////////////////////////////////////////////////////////////////////
12 | // MARK: 数据 相关
13 | /////////////////////////////////////////////////////////////////////////////
14 |
15 | // 图片资源
16 | enum ImgSource {
17 | case SERVER(url:URL)
18 | case LOCAL(name:String)
19 | }
20 |
21 | // 图片类型
22 | enum ImgType:Int {
23 | case SERVER = 0 // default
24 | case LOCAL = 1
25 | }
26 |
27 | struct Proxy
28 | {
29 | var imgType:ImgType = .SERVER
30 | var imgArray:[ImgSource] = [ImgSource]()
31 |
32 | // 下标法获取imgArray中对应索引的ImgSource eg: proxy[0] == imgArray[0]
33 | subscript (index:Int) -> ImgSource {
34 | get {
35 | return imgArray[index]
36 | }
37 | }
38 |
39 | // 构造方法
40 | init(type:ImgType, array:[String])
41 | {
42 | imgType = type
43 | if imgType == .SERVER
44 | {
45 | imgArray = array.map({ (urlStr) -> ImgSource in
46 | return ImgSource.SERVER(url: URL(string: urlStr)!)
47 | })
48 | }
49 | else
50 | {
51 | imgArray = array.map({ (name) -> ImgSource in
52 | return ImgSource.LOCAL(name: name)
53 | })
54 | }
55 | }
56 | }
57 |
58 |
59 | /////////////////////////////////////////////////////////////////////////////
60 | // MARK: pageControl 相关
61 | /////////////////////////////////////////////////////////////////////////////
62 |
63 | private let WRPageControlMargin: CGFloat = 15
64 | private let WRPageControlPointWidth: CGFloat = 2
65 |
66 | enum PageControlAliment {
67 | case CenterBottom
68 | case RightBottom
69 | case LeftBottom
70 | }
71 |
72 | protocol PageControlAlimentProtocol
73 | {
74 | // Property in protocol must have explicit { get } or { get set } specifier
75 | var pageControlAliment: PageControlAliment { get set }
76 | var pageControlPointSpace: CGFloat { get set }
77 | func relayoutPageControl(pageControl: WRPageControl)
78 | func relayoutPageControl(pageControl: WRPageControl, outerFrame:CGRect)
79 | }
80 |
81 | extension PageControlAlimentProtocol where Self : UIView
82 | { // TODO: 等待优化
83 | func relayoutPageControl(pageControl: WRPageControl)
84 | {
85 | if pageControl.isHidden == false
86 | {
87 | let pageH:CGFloat = 20//pageControl.pageSize.height
88 | let pageY = bounds.height - pageH
89 | let pageW = pageControl.pageSize.width
90 | var pageX:CGFloat = 0
91 |
92 | switch self.pageControlAliment {
93 | case .CenterBottom:
94 | pageX = CGFloat(self.bounds.width / 2) - pageW * 0.5
95 | case .RightBottom:
96 | pageX = bounds.width - pageW - WRPageControlMargin
97 | case .LeftBottom:
98 | pageX = bounds.origin.x + WRPageControlMargin
99 | }
100 | pageControl.frame = CGRect(x:pageX, y:pageY, width:pageW, height:pageH)
101 | }
102 | }
103 | func relayoutPageControl(pageControl: WRPageControl, outerFrame:CGRect)
104 | {
105 | if pageControl.isHidden == false {
106 | pageControl.frame = CGRect(x:outerFrame.origin.x, y:outerFrame.origin.y, width:pageControl.pageSize.width, height:pageControl.pageSize.height)
107 | }
108 | }
109 | }
110 |
111 |
112 | /////////////////////////////////////////////////////////////////////////////
113 | // MARK: 无限轮播 相关
114 | /////////////////////////////////////////////////////////////////////////////
115 |
116 | protocol EndlessScrollProtocol
117 | {
118 | /////////////////////////////////
119 | /// 是否自动滚动
120 | var isAutoScroll: Bool { get set }
121 | /// 自动滚动的时间间隔
122 | var autoScrollInterval: Double { get set }
123 | /// 用于自动滚动的定时器
124 | var timer:Timer? { get set }
125 |
126 | /////////////////////////////////
127 | /// 是否无限轮播
128 | var isEndlessScroll: Bool { get set }
129 | /// 无线轮播中,一组图片最多轮播多少次
130 | var endlessScrollTimes: Int { get }
131 | /// 真实的cell数量
132 | var itemsInSection: Int { get }
133 |
134 | /** 设置定时器,用于自动滚动 */
135 | func setupTimer()
136 |
137 | /** 滚动到第一个cell (在无限轮播中就是中间的那个cell) */
138 | func changeToFirstCycleCell(animated: Bool, collectionView: UICollectionView)
139 | }
140 |
141 | extension EndlessScrollProtocol where Self : UIView
142 | {
143 | func changeCycleCell(collectionView: UICollectionView)
144 | {
145 | guard itemsInSection != 0 else {
146 | return
147 | }
148 |
149 | let flowLayout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
150 | let curItem = Int(collectionView.contentOffset.x / flowLayout.itemSize.width)
151 | if curItem == itemsInSection - 1
152 | {
153 | let animated = (isEndlessScroll == true) ? false : true
154 | changeToFirstCycleCell(animated: animated, collectionView: collectionView)
155 | }
156 | else
157 | {
158 | let indexPath = IndexPath(item: curItem + 1, section: 0)
159 | collectionView.scrollToItem(at: indexPath, at: .init(rawValue: 0), animated: true)
160 | }
161 | }
162 |
163 | func changeToFirstCycleCell(animated: Bool, collectionView: UICollectionView)
164 | {
165 | guard itemsInSection != 0 else {
166 | return
167 | }
168 |
169 | let firstItem = (isEndlessScroll == true) ? (itemsInSection / 2) : 0
170 | let indexPath = IndexPath(item: firstItem, section: 0)
171 | collectionView.scrollToItem(at: indexPath, at: .init(rawValue: 0), animated: animated)
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 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 |
3 | #官方Cocoapods的源
4 | #source 'https://github.com/CocoaPods/Specs.git'
5 |
6 | #本地私有源
7 | #source 'https://git.oschina.net/scx/JLSpecs.git'
8 |
9 | # 本项目地址
10 | #source https://github.com/wangrui460
11 |
12 | # 修改过得第三方库
13 |
14 |
15 | platform :ios, '8.0'
16 | use_frameworks!
17 |
18 | target 'WRCycleScrollViewDemo' do
19 |
20 | #swift
21 | pod 'Kingfisher'
22 |
23 | end
24 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Kingfisher (3.6.2)
3 |
4 | DEPENDENCIES:
5 | - Kingfisher
6 |
7 | SPEC CHECKSUMS:
8 | Kingfisher: 2c94e72c6830622c71d06adf4ea024c37d316830
9 |
10 | PODFILE CHECKSUM: 6daf8f1d76fe64163802c6a83d3d697d2866e5e0
11 |
12 | COCOAPODS: 1.2.1
13 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Kingfisher/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017 Wei Wang
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Kingfisher/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | Kingfisher is a lightweight, pure-Swift library for downloading and caching images from the web. This project is heavily inspired by the popular [SDWebImage](https://github.com/rs/SDWebImage). It provides you a chance to use a pure-Swift alternative in your next app.
19 |
20 | ## Features
21 |
22 | - [x] Asynchronous image downloading and caching.
23 | - [x] `URLSession`-based networking. Basic image processors and filters supplied.
24 | - [x] Multiple-layer cache for both memory and disk.
25 | - [x] Cancelable downloading and processing tasks to improve performance.
26 | - [x] Independent components. Use the downloader or caching system separately as you need.
27 | - [x] Prefetching images and showing them from cache later when necessary.
28 | - [x] Extensions for `UIImageView`, `NSImage` and `UIButton` to directly set an image from a URL.
29 | - [x] Built-in transition animation when setting images.
30 | - [x] Extensible image processing and image format support.
31 |
32 | The simplest use-case is setting an image to an image view with the `UIImageView` extension:
33 |
34 | ```swift
35 | let url = URL(string: "url_of_your_image")
36 | imageView.kf.setImage(with: url)
37 | ```
38 |
39 | Kingfisher will download the image from `url`, send it to both the memory cache and the disk cache, and display it in `imageView`. When you use the same code later, the image will be retrieved from cache and shown immediately.
40 |
41 | ## Requirements
42 |
43 | - iOS 8.0+ / macOS 10.10+ / tvOS 9.0+ / watchOS 2.0+
44 | - Swift 3 (Kingfisher 3.x), Swift 2.3 (Kingfisher 2.x)
45 |
46 | Main development of Kingfisher will support Swift 3. Only critical bug fixes will be made for Kingfisher 2.x.
47 |
48 | [Kingfisher 3.0 Migration Guide](https://github.com/onevcat/Kingfisher/wiki/Kingfisher-3.0-Migration-Guide) - If you are upgrading to Kingfisher 3.x from an earlier version, please read this for more information.
49 |
50 | ## Next Steps
51 |
52 | We prepared a [wiki page](https://github.com/onevcat/Kingfisher/wiki). You can find tons of useful things there.
53 |
54 | * [Installation Guide](https://github.com/onevcat/Kingfisher/wiki/Installation-Guide) - Follow it to integrate Kingfisher into your project.
55 | * [Cheat Sheet](https://github.com/onevcat/Kingfisher/wiki/Cheat-Sheet)- Curious about what Kingfisher could do and how would it look like when used in your project? See this page for useful code snippets. If you are already familiar with Kingfisher, you could also learn new tricks to improve the way you use Kingfisher!
56 | * [API Reference](http://onevcat.github.io/Kingfisher/) - Lastly, please remember to read the full whenever you may need a more detailed reference.
57 |
58 | ## Other
59 |
60 | ### Future of Kingfisher
61 |
62 | I want to keep Kingfisher lightweight. This framework will focus on providing a simple solution for downloading and caching images. This doesn’t mean the framework can’t be improved. Kingfisher is far from perfect, so necessary and useful updates will be made to make it better.
63 |
64 | ### Developments and Tests
65 |
66 | Any contributing and pull requests are warmly welcome. However, before you plan to implement some features or try to fix an uncertain issue, it is recommended to open a discussion first.
67 |
68 | The test images are contained in another project to keep this project repo fast and slim. You could run `./setup.sh` in the root folder of Kingfisher to clone the test images when you need to run the tests target. It would be appreciated if your pull requests could build and with all tests green. :)
69 |
70 | ### About the logo
71 |
72 | The logo of Kingfisher is inspired by [Tangram (七巧板)](http://en.wikipedia.org/wiki/Tangram), a dissection puzzle consisting of seven flat shapes from China. I believe she's a kingfisher bird instead of a swift, but someone insists that she is a pigeon. I guess I should give her a name. Hi, guys, do you have any suggestions?
73 |
74 | ### Contact
75 |
76 | Follow and contact me on [Twitter](http://twitter.com/onevcat) or [Sina Weibo](http://weibo.com/onevcat). If you find an issue, just [open a ticket](https://github.com/onevcat/Kingfisher/issues/new). Pull requests are warmly welcome as well.
77 |
78 | ### License
79 |
80 | Kingfisher is released under the MIT license. See LICENSE for details.
81 |
82 |
83 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Kingfisher/Sources/AnimatedImageView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AnimatableImageView.swift
3 | // Kingfisher
4 | //
5 | // Created by bl4ckra1sond3tre on 4/22/16.
6 | //
7 | // The AnimatableImageView, AnimatedFrame and Animator is a modified version of
8 | // some classes from kaishin's Gifu project (https://github.com/kaishin/Gifu)
9 | //
10 | // The MIT License (MIT)
11 | //
12 | // Copyright (c) 2017 Reda Lemeden.
13 | //
14 | // Permission is hereby granted, free of charge, to any person obtaining a copy of
15 | // this software and associated documentation files (the "Software"), to deal in
16 | // the Software without restriction, including without limitation the rights to
17 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
18 | // the Software, and to permit persons to whom the Software is furnished to do so,
19 | // subject to the following conditions:
20 | //
21 | // The above copyright notice and this permission notice shall be included in all
22 | // copies or substantial portions of the Software.
23 | //
24 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
26 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
27 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
28 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 | //
31 | // The name and characters used in the demo of this software are property of their
32 | // respective owners.
33 |
34 | import UIKit
35 | import ImageIO
36 |
37 | /// `AnimatedImageView` is a subclass of `UIImageView` for displaying animated image.
38 | open class AnimatedImageView: UIImageView {
39 |
40 | /// Proxy object for prevending a reference cycle between the CADDisplayLink and AnimatedImageView.
41 | class TargetProxy {
42 | private weak var target: AnimatedImageView?
43 |
44 | init(target: AnimatedImageView) {
45 | self.target = target
46 | }
47 |
48 | @objc func onScreenUpdate() {
49 | target?.updateFrame()
50 | }
51 | }
52 |
53 | // MARK: - Public property
54 | /// Whether automatically play the animation when the view become visible. Default is true.
55 | public var autoPlayAnimatedImage = true
56 |
57 | /// The size of the frame cache.
58 | public var framePreloadCount = 10
59 |
60 | /// Specifies whether the GIF frames should be pre-scaled to save memory. Default is true.
61 | public var needsPrescaling = true
62 |
63 | /// The animation timer's run loop mode. Default is `NSRunLoopCommonModes`. Set this property to `NSDefaultRunLoopMode` will make the animation pause during UIScrollView scrolling.
64 | public var runLoopMode = RunLoopMode.commonModes {
65 | willSet {
66 | if runLoopMode == newValue {
67 | return
68 | } else {
69 | stopAnimating()
70 | displayLink.remove(from: .main, forMode: runLoopMode)
71 | displayLink.add(to: .main, forMode: newValue)
72 | startAnimating()
73 | }
74 | }
75 | }
76 |
77 | // MARK: - Private property
78 | /// `Animator` instance that holds the frames of a specific image in memory.
79 | private var animator: Animator?
80 |
81 | /// A flag to avoid invalidating the displayLink on deinit if it was never created, because displayLink is so lazy. :D
82 | private var isDisplayLinkInitialized: Bool = false
83 |
84 | /// A display link that keeps calling the `updateFrame` method on every screen refresh.
85 | private lazy var displayLink: CADisplayLink = {
86 | self.isDisplayLinkInitialized = true
87 | let displayLink = CADisplayLink(target: TargetProxy(target: self), selector: #selector(TargetProxy.onScreenUpdate))
88 | displayLink.add(to: .main, forMode: self.runLoopMode)
89 | displayLink.isPaused = true
90 | return displayLink
91 | }()
92 |
93 | // MARK: - Override
94 | override open var image: Image? {
95 | didSet {
96 | if image != oldValue {
97 | reset()
98 | }
99 | setNeedsDisplay()
100 | layer.setNeedsDisplay()
101 | }
102 | }
103 |
104 | deinit {
105 | if isDisplayLinkInitialized {
106 | displayLink.invalidate()
107 | }
108 | }
109 |
110 | override open var isAnimating: Bool {
111 | if isDisplayLinkInitialized {
112 | return !displayLink.isPaused
113 | } else {
114 | return super.isAnimating
115 | }
116 | }
117 |
118 | /// Starts the animation.
119 | override open func startAnimating() {
120 | if self.isAnimating {
121 | return
122 | } else {
123 | displayLink.isPaused = false
124 | }
125 | }
126 |
127 | /// Stops the animation.
128 | override open func stopAnimating() {
129 | super.stopAnimating()
130 | if isDisplayLinkInitialized {
131 | displayLink.isPaused = true
132 | }
133 | }
134 |
135 | override open func display(_ layer: CALayer) {
136 | if let currentFrame = animator?.currentFrame {
137 | layer.contents = currentFrame.cgImage
138 | } else {
139 | layer.contents = image?.cgImage
140 | }
141 | }
142 |
143 | override open func didMoveToWindow() {
144 | super.didMoveToWindow()
145 | didMove()
146 | }
147 |
148 | override open func didMoveToSuperview() {
149 | super.didMoveToSuperview()
150 | didMove()
151 | }
152 |
153 | // This is for back compatibility that using regular UIImageView to show GIF.
154 | override func shouldPreloadAllGIF() -> Bool {
155 | return false
156 | }
157 |
158 | // MARK: - Private method
159 | /// Reset the animator.
160 | private func reset() {
161 | animator = nil
162 | if let imageSource = image?.kf.imageSource?.imageRef {
163 | animator = Animator(imageSource: imageSource, contentMode: contentMode, size: bounds.size, framePreloadCount: framePreloadCount)
164 | animator?.needsPrescaling = needsPrescaling
165 | animator?.prepareFramesAsynchronously()
166 | }
167 | didMove()
168 | }
169 |
170 | private func didMove() {
171 | if autoPlayAnimatedImage && animator != nil {
172 | if let _ = superview, let _ = window {
173 | startAnimating()
174 | } else {
175 | stopAnimating()
176 | }
177 | }
178 | }
179 |
180 | /// Update the current frame with the displayLink duration.
181 | private func updateFrame() {
182 | if animator?.updateCurrentFrame(duration: displayLink.duration) ?? false {
183 | layer.setNeedsDisplay()
184 | }
185 | }
186 | }
187 |
188 | /// Keeps a reference to an `Image` instance and its duration as a GIF frame.
189 | struct AnimatedFrame {
190 | var image: Image?
191 | let duration: TimeInterval
192 |
193 | static let null: AnimatedFrame = AnimatedFrame(image: .none, duration: 0.0)
194 | }
195 |
196 | // MARK: - Animator
197 | class Animator {
198 | // MARK: Private property
199 | fileprivate let size: CGSize
200 | fileprivate let maxFrameCount: Int
201 | fileprivate let imageSource: CGImageSource
202 |
203 | fileprivate var animatedFrames = [AnimatedFrame]()
204 | fileprivate let maxTimeStep: TimeInterval = 1.0
205 | fileprivate var frameCount = 0
206 | fileprivate var currentFrameIndex = 0
207 | fileprivate var currentPreloadIndex = 0
208 | fileprivate var timeSinceLastFrameChange: TimeInterval = 0.0
209 | fileprivate var needsPrescaling = true
210 |
211 | /// Loop count of animatd image.
212 | private var loopCount = 0
213 |
214 | var currentFrame: UIImage? {
215 | return frame(at: currentFrameIndex)
216 | }
217 |
218 | var contentMode = UIViewContentMode.scaleToFill
219 |
220 | private lazy var preloadQueue: DispatchQueue = {
221 | return DispatchQueue(label: "com.onevcat.Kingfisher.Animator.preloadQueue")
222 | }()
223 |
224 | /**
225 | Init an animator with image source reference.
226 |
227 | - parameter imageSource: The reference of animated image.
228 | - parameter contentMode: Content mode of AnimatedImageView.
229 | - parameter size: Size of AnimatedImageView.
230 | - parameter framePreloadCount: Frame cache size.
231 |
232 | - returns: The animator object.
233 | */
234 | init(imageSource source: CGImageSource, contentMode mode: UIViewContentMode, size: CGSize, framePreloadCount count: Int) {
235 | self.imageSource = source
236 | self.contentMode = mode
237 | self.size = size
238 | self.maxFrameCount = count
239 | }
240 |
241 | func frame(at index: Int) -> Image? {
242 | return animatedFrames[safe: index]?.image
243 | }
244 |
245 | func prepareFramesAsynchronously() {
246 | preloadQueue.async { [weak self] in
247 | self?.prepareFrames()
248 | }
249 | }
250 |
251 | private func prepareFrames() {
252 | frameCount = CGImageSourceGetCount(imageSource)
253 |
254 | if let properties = CGImageSourceCopyProperties(imageSource, nil),
255 | let gifInfo = (properties as NSDictionary)[kCGImagePropertyGIFDictionary as String] as? NSDictionary,
256 | let loopCount = gifInfo[kCGImagePropertyGIFLoopCount as String] as? Int
257 | {
258 | self.loopCount = loopCount
259 | }
260 |
261 | let frameToProcess = min(frameCount, maxFrameCount)
262 | animatedFrames.reserveCapacity(frameToProcess)
263 | animatedFrames = (0.. AnimatedFrame {
268 |
269 | guard let imageRef = CGImageSourceCreateImageAtIndex(imageSource, index, nil) else {
270 | return AnimatedFrame.null
271 | }
272 |
273 | let defaultGIFFrameDuration = 0.100
274 | let frameDuration = imageSource.kf.gifProperties(at: index).map {
275 | gifInfo -> Double in
276 |
277 | let unclampedDelayTime = gifInfo[kCGImagePropertyGIFUnclampedDelayTime as String] as Double?
278 | let delayTime = gifInfo[kCGImagePropertyGIFDelayTime as String] as Double?
279 | let duration = unclampedDelayTime ?? delayTime ?? 0.0
280 |
281 | /**
282 | http://opensource.apple.com/source/WebCore/WebCore-7600.1.25/platform/graphics/cg/ImageSourceCG.cpp
283 | Many annoying ads specify a 0 duration to make an image flash as quickly as
284 | possible. We follow Safari and Firefox's behavior and use a duration of 100 ms
285 | for any frames that specify a duration of <= 10 ms.
286 | See and for more information.
287 |
288 | See also: http://nullsleep.tumblr.com/post/16524517190/animated-gif-minimum-frame-delay-browser.
289 | */
290 | return duration > 0.011 ? duration : defaultGIFFrameDuration
291 | } ?? defaultGIFFrameDuration
292 |
293 | let image = Image(cgImage: imageRef)
294 | let scaledImage: Image?
295 |
296 | if needsPrescaling {
297 | scaledImage = image.kf.resize(to: size, for: contentMode)
298 | } else {
299 | scaledImage = image
300 | }
301 |
302 | return AnimatedFrame(image: scaledImage, duration: frameDuration)
303 | }
304 |
305 | /**
306 | Updates the current frame if necessary using the frame timer and the duration of each frame in `animatedFrames`.
307 | */
308 | func updateCurrentFrame(duration: CFTimeInterval) -> Bool {
309 | timeSinceLastFrameChange += min(maxTimeStep, duration)
310 | guard let frameDuration = animatedFrames[safe: currentFrameIndex]?.duration, frameDuration <= timeSinceLastFrameChange else {
311 | return false
312 | }
313 |
314 | timeSinceLastFrameChange -= frameDuration
315 |
316 | let lastFrameIndex = currentFrameIndex
317 | currentFrameIndex += 1
318 | currentFrameIndex = currentFrameIndex % animatedFrames.count
319 |
320 | if animatedFrames.count < frameCount {
321 | preloadFrameAsynchronously(at: lastFrameIndex)
322 | }
323 | return true
324 | }
325 |
326 | private func preloadFrameAsynchronously(at index: Int) {
327 | preloadQueue.async { [weak self] in
328 | self?.preloadFrame(at: index)
329 | }
330 | }
331 |
332 | private func preloadFrame(at index: Int) {
333 | animatedFrames[index] = prepareFrame(at: currentPreloadIndex)
334 | currentPreloadIndex += 1
335 | currentPreloadIndex = currentPreloadIndex % frameCount
336 | }
337 | }
338 |
339 | extension CGImageSource: KingfisherCompatible { }
340 | extension Kingfisher where Base: CGImageSource {
341 | func gifProperties(at index: Int) -> [String: Double]? {
342 | let properties = CGImageSourceCopyPropertiesAtIndex(base, index, nil) as Dictionary?
343 | return properties?[kCGImagePropertyGIFDictionary] as? [String: Double]
344 | }
345 | }
346 |
347 | extension Array {
348 | subscript(safe index: Int) -> Element? {
349 | return indices ~= index ? self[index] : nil
350 | }
351 | }
352 |
353 | private func pure(_ value: T) -> [T] {
354 | return [value]
355 | }
356 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Kingfisher/Sources/Box.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Box.swift
3 | // Kingfisher
4 | //
5 | // Created by WANG WEI on 2016/09/12.
6 | // Copyright © 2016年 Wei Wang. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class Box {
12 | let value: T
13 | init(value: T) {
14 | self.value = value
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Kingfisher/Sources/CacheSerializer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CacheSerializer.swift
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 2016/09/02.
6 | //
7 | // Copyright (c) 2017 Wei Wang
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | import Foundation
28 |
29 | /// An `CacheSerializer` would be used to convert some data to an image object for
30 | /// retrieving from disk cache and vice versa for storing to disk cache.
31 | public protocol CacheSerializer {
32 |
33 | /// Get the serialized data from a provided image
34 | /// and optional original data for caching to disk.
35 | ///
36 | ///
37 | /// - parameter image: The image needed to be serialized.
38 | /// - parameter original: The original data which is just downloaded.
39 | /// If the image is retrieved from cache instead of
40 | /// downloaded, it will be `nil`.
41 | ///
42 | /// - returns: A data which will be stored to cache, or `nil` when no valid
43 | /// data could be serialized.
44 | func data(with image: Image, original: Data?) -> Data?
45 |
46 | /// Get an image deserialized from provided data.
47 | ///
48 | /// - parameter data: The data from which an image should be deserialized.
49 | /// - parameter options: Options for deserialization.
50 | ///
51 | /// - returns: An image deserialized or `nil` when no valid image
52 | /// could be deserialized.
53 | func image(with data: Data, options: KingfisherOptionsInfo?) -> Image?
54 | }
55 |
56 |
57 | /// `DefaultCacheSerializer` is a basic `CacheSerializer` used in default cache of
58 | /// Kingfisher. It could serialize and deserialize PNG, JEPG and GIF images. For
59 | /// image other than these formats, a normalized `pngRepresentation` will be used.
60 | public struct DefaultCacheSerializer: CacheSerializer {
61 |
62 | public static let `default` = DefaultCacheSerializer()
63 | private init() {}
64 |
65 | public func data(with image: Image, original: Data?) -> Data? {
66 | let imageFormat = original?.kf.imageFormat ?? .unknown
67 |
68 | let data: Data?
69 | switch imageFormat {
70 | case .PNG: data = image.kf.pngRepresentation()
71 | case .JPEG: data = image.kf.jpegRepresentation(compressionQuality: 1.0)
72 | case .GIF: data = image.kf.gifRepresentation()
73 | case .unknown: data = original ?? image.kf.normalized.kf.pngRepresentation()
74 | }
75 |
76 | return data
77 | }
78 |
79 | public func image(with data: Data, options: KingfisherOptionsInfo?) -> Image? {
80 | let options = options ?? KingfisherEmptyOptionsInfo
81 | return Kingfisher.image(
82 | data: data,
83 | scale: options.scaleFactor,
84 | preloadAllGIFData: options.preloadAllGIFData,
85 | onlyFirstFrame: options.onlyLoadFirstFrame)
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Kingfisher/Sources/Filter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Filter.swift
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 2016/08/31.
6 | //
7 | // Copyright (c) 2017 Wei Wang
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 |
28 |
29 | import CoreImage
30 | import Accelerate
31 |
32 | // Reuse the same CI Context for all CI drawing.
33 | private let ciContext = CIContext(options: nil)
34 |
35 | /// Transformer method which will be used in to provide a `Filter`.
36 | public typealias Transformer = (CIImage) -> CIImage?
37 |
38 | /// Supply a filter to create an `ImageProcessor`.
39 | public protocol CIImageProcessor: ImageProcessor {
40 | var filter: Filter { get }
41 | }
42 |
43 | extension CIImageProcessor {
44 | public func process(item: ImageProcessItem, options: KingfisherOptionsInfo) -> Image? {
45 | switch item {
46 | case .image(let image):
47 | return image.kf.apply(filter)
48 | case .data(_):
49 | return (DefaultImageProcessor.default >> self).process(item: item, options: options)
50 | }
51 | }
52 | }
53 |
54 | /// Wrapper for a `Transformer` of CIImage filters.
55 | public struct Filter {
56 |
57 | let transform: Transformer
58 |
59 | public init(tranform: @escaping Transformer) {
60 | self.transform = tranform
61 | }
62 |
63 | /// Tint filter which will apply a tint color to images.
64 | public static var tint: (Color) -> Filter = {
65 | color in
66 | Filter { input in
67 | let colorFilter = CIFilter(name: "CIConstantColorGenerator")!
68 | colorFilter.setValue(CIColor(color: color), forKey: kCIInputColorKey)
69 |
70 | let colorImage = colorFilter.outputImage
71 | let filter = CIFilter(name: "CISourceOverCompositing")!
72 | filter.setValue(colorImage, forKey: kCIInputImageKey)
73 | filter.setValue(input, forKey: kCIInputBackgroundImageKey)
74 | return filter.outputImage?.cropping(to: input.extent)
75 | }
76 | }
77 |
78 | public typealias ColorElement = (CGFloat, CGFloat, CGFloat, CGFloat)
79 |
80 | /// Color control filter which will apply color control change to images.
81 | public static var colorControl: (ColorElement) -> Filter = {
82 | brightness, contrast, saturation, inputEV in
83 | Filter { input in
84 | let paramsColor = [kCIInputBrightnessKey: brightness,
85 | kCIInputContrastKey: contrast,
86 | kCIInputSaturationKey: saturation]
87 |
88 | let blackAndWhite = input.applyingFilter("CIColorControls", withInputParameters: paramsColor)
89 | let paramsExposure = [kCIInputEVKey: inputEV]
90 | return blackAndWhite.applyingFilter("CIExposureAdjust", withInputParameters: paramsExposure)
91 | }
92 |
93 | }
94 | }
95 |
96 | extension Kingfisher where Base: Image {
97 | /// Apply a `Filter` containing `CIImage` transformer to `self`.
98 | ///
99 | /// - parameter filter: The filter used to transform `self`.
100 | ///
101 | /// - returns: A transformed image by input `Filter`.
102 | ///
103 | /// - Note: Only CG-based images are supported. If any error happens during transforming, `self` will be returned.
104 | public func apply(_ filter: Filter) -> Image {
105 |
106 | guard let cgImage = cgImage else {
107 | assertionFailure("[Kingfisher] Tint image only works for CG-based image.")
108 | return base
109 | }
110 |
111 | let inputImage = CIImage(cgImage: cgImage)
112 | guard let outputImage = filter.transform(inputImage) else {
113 | return base
114 | }
115 |
116 | guard let result = ciContext.createCGImage(outputImage, from: outputImage.extent) else {
117 | assertionFailure("[Kingfisher] Can not make an tint image within context.")
118 | return base
119 | }
120 |
121 | #if os(macOS)
122 | return fixedForRetinaPixel(cgImage: result, to: size)
123 | #else
124 | return Image(cgImage: result, scale: base.scale, orientation: base.imageOrientation)
125 | #endif
126 | }
127 |
128 | }
129 |
130 | public extension Image {
131 |
132 | /// Apply a `Filter` containing `CIImage` transformer to `self`.
133 | ///
134 | /// - parameter filter: The filter used to transform `self`.
135 | ///
136 | /// - returns: A transformed image by input `Filter`.
137 | ///
138 | /// - Note: Only CG-based images are supported. If any error happens during transforming, `self` will be returned.
139 | @available(*, deprecated,
140 | message: "Extensions directly on Image are deprecated. Use `kf.apply` instead.",
141 | renamed: "kf.apply")
142 | public func kf_apply(_ filter: Filter) -> Image {
143 | return kf.apply(filter)
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Kingfisher/Sources/ImagePrefetcher.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImagePrefetcher.swift
3 | // Kingfisher
4 | //
5 | // Created by Claire Knight on 24/02/2016
6 | //
7 | // Copyright (c) 2017 Wei Wang
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 |
28 | #if os(macOS)
29 | import AppKit
30 | #else
31 | import UIKit
32 | #endif
33 |
34 |
35 | /// Progress update block of prefetcher.
36 | ///
37 | /// - `skippedResources`: An array of resources that are already cached before the prefetching starting.
38 | /// - `failedResources`: An array of resources that fail to be downloaded. It could because of being cancelled while downloading, encountered an error when downloading or the download not being started at all.
39 | /// - `completedResources`: An array of resources that are downloaded and cached successfully.
40 | public typealias PrefetcherProgressBlock = ((_ skippedResources: [Resource], _ failedResources: [Resource], _ completedResources: [Resource]) -> ())
41 |
42 | /// Completion block of prefetcher.
43 | ///
44 | /// - `skippedResources`: An array of resources that are already cached before the prefetching starting.
45 | /// - `failedResources`: An array of resources that fail to be downloaded. It could because of being cancelled while downloading, encountered an error when downloading or the download not being started at all.
46 | /// - `completedResources`: An array of resources that are downloaded and cached successfully.
47 | public typealias PrefetcherCompletionHandler = ((_ skippedResources: [Resource], _ failedResources: [Resource], _ completedResources: [Resource]) -> ())
48 |
49 | /// `ImagePrefetcher` represents a downloading manager for requesting many images via URLs, then caching them.
50 | /// This is useful when you know a list of image resources and want to download them before showing.
51 | public class ImagePrefetcher {
52 |
53 | /// The maximum concurrent downloads to use when prefetching images. Default is 5.
54 | public var maxConcurrentDownloads = 5
55 |
56 | private let prefetchResources: [Resource]
57 | private let optionsInfo: KingfisherOptionsInfo
58 | private var progressBlock: PrefetcherProgressBlock?
59 | private var completionHandler: PrefetcherCompletionHandler?
60 |
61 | private var tasks = [URL: RetrieveImageDownloadTask]()
62 |
63 | private var pendingResources: ArraySlice
64 | private var skippedResources = [Resource]()
65 | private var completedResources = [Resource]()
66 | private var failedResources = [Resource]()
67 |
68 | private var stopped = false
69 |
70 | // The created manager used for prefetch. We will use the helper method in manager.
71 | private let manager: KingfisherManager
72 |
73 | private var finished: Bool {
74 | return failedResources.count + skippedResources.count + completedResources.count == prefetchResources.count && self.tasks.isEmpty
75 | }
76 |
77 | /**
78 | Init an image prefetcher with an array of URLs.
79 |
80 | The prefetcher should be initiated with a list of prefetching targets. The URLs list is immutable.
81 | After you get a valid `ImagePrefetcher` object, you could call `start()` on it to begin the prefetching process.
82 | The images already cached will be skipped without downloading again.
83 |
84 | - parameter urls: The URLs which should be prefetched.
85 | - parameter options: A dictionary could control some behaviors. See `KingfisherOptionsInfo` for more.
86 | - parameter progressBlock: Called every time an resource is downloaded, skipped or cancelled.
87 | - parameter completionHandler: Called when the whole prefetching process finished.
88 |
89 | - returns: An `ImagePrefetcher` object.
90 |
91 | - Note: By default, the `ImageDownloader.defaultDownloader` and `ImageCache.defaultCache` will be used as
92 | the downloader and cache target respectively. You can specify another downloader or cache by using a customized `KingfisherOptionsInfo`.
93 | Both the progress and completion block will be invoked in main thread. The `CallbackDispatchQueue` in `optionsInfo` will be ignored in this method.
94 | */
95 | public convenience init(urls: [URL],
96 | options: KingfisherOptionsInfo? = nil,
97 | progressBlock: PrefetcherProgressBlock? = nil,
98 | completionHandler: PrefetcherCompletionHandler? = nil)
99 | {
100 | let resources: [Resource] = urls.map { $0 }
101 | self.init(resources: resources, options: options, progressBlock: progressBlock, completionHandler: completionHandler)
102 | }
103 |
104 | /**
105 | Init an image prefetcher with an array of resources.
106 |
107 | The prefetcher should be initiated with a list of prefetching targets. The resources list is immutable.
108 | After you get a valid `ImagePrefetcher` object, you could call `start()` on it to begin the prefetching process.
109 | The images already cached will be skipped without downloading again.
110 |
111 | - parameter resources: The resources which should be prefetched. See `Resource` type for more.
112 | - parameter options: A dictionary could control some behaviors. See `KingfisherOptionsInfo` for more.
113 | - parameter progressBlock: Called every time an resource is downloaded, skipped or cancelled.
114 | - parameter completionHandler: Called when the whole prefetching process finished.
115 |
116 | - returns: An `ImagePrefetcher` object.
117 |
118 | - Note: By default, the `ImageDownloader.defaultDownloader` and `ImageCache.defaultCache` will be used as
119 | the downloader and cache target respectively. You can specify another downloader or cache by using a customized `KingfisherOptionsInfo`.
120 | Both the progress and completion block will be invoked in main thread. The `CallbackDispatchQueue` in `optionsInfo` will be ignored in this method.
121 | */
122 | public init(resources: [Resource],
123 | options: KingfisherOptionsInfo? = nil,
124 | progressBlock: PrefetcherProgressBlock? = nil,
125 | completionHandler: PrefetcherCompletionHandler? = nil)
126 | {
127 | prefetchResources = resources
128 | pendingResources = ArraySlice(resources)
129 |
130 | // We want all callbacks from main queue, so we ignore the call back queue in options
131 | let optionsInfoWithoutQueue = options?.removeAllMatchesIgnoringAssociatedValue(.callbackDispatchQueue(nil))
132 | self.optionsInfo = optionsInfoWithoutQueue ?? KingfisherEmptyOptionsInfo
133 |
134 | let cache = self.optionsInfo.targetCache
135 | let downloader = self.optionsInfo.downloader
136 | manager = KingfisherManager(downloader: downloader, cache: cache)
137 |
138 | self.progressBlock = progressBlock
139 | self.completionHandler = completionHandler
140 | }
141 |
142 | /**
143 | Start to download the resources and cache them. This can be useful for background downloading
144 | of assets that are required for later use in an app. This code will not try and update any UI
145 | with the results of the process.
146 | */
147 | public func start()
148 | {
149 | // Since we want to handle the resources cancellation in main thread only.
150 | DispatchQueue.main.safeAsync {
151 |
152 | guard !self.stopped else {
153 | assertionFailure("You can not restart the same prefetcher. Try to create a new prefetcher.")
154 | self.handleComplete()
155 | return
156 | }
157 |
158 | guard self.maxConcurrentDownloads > 0 else {
159 | assertionFailure("There should be concurrent downloads value should be at least 1.")
160 | self.handleComplete()
161 | return
162 | }
163 |
164 | guard self.prefetchResources.count > 0 else {
165 | self.handleComplete()
166 | return
167 | }
168 |
169 | let initialConcurentDownloads = min(self.prefetchResources.count, self.maxConcurrentDownloads)
170 | for _ in 0 ..< initialConcurentDownloads {
171 | if let resource = self.pendingResources.popFirst() {
172 | self.startPrefetching(resource)
173 | }
174 | }
175 | }
176 | }
177 |
178 |
179 | /**
180 | Stop current downloading progress, and cancel any future prefetching activity that might be occuring.
181 | */
182 | public func stop() {
183 | DispatchQueue.main.safeAsync {
184 |
185 | if self.finished { return }
186 |
187 | self.stopped = true
188 | self.tasks.forEach { (_, task) -> () in
189 | task.cancel()
190 | }
191 | }
192 | }
193 |
194 | func downloadAndCache(_ resource: Resource) {
195 |
196 | let downloadTaskCompletionHandler: CompletionHandler = { (image, error, _, _) -> () in
197 | self.tasks.removeValue(forKey: resource.downloadURL)
198 | if let _ = error {
199 | self.failedResources.append(resource)
200 | } else {
201 | self.completedResources.append(resource)
202 | }
203 |
204 | self.reportProgress()
205 | if self.stopped {
206 | if self.tasks.isEmpty {
207 | self.failedResources.append(contentsOf: self.pendingResources)
208 | self.handleComplete()
209 | }
210 | } else {
211 | self.reportCompletionOrStartNext()
212 | }
213 | }
214 |
215 | let downloadTask = manager.downloadAndCacheImage(
216 | with: resource.downloadURL,
217 | forKey: resource.cacheKey,
218 | retrieveImageTask: RetrieveImageTask(),
219 | progressBlock: nil,
220 | completionHandler: downloadTaskCompletionHandler,
221 | options: optionsInfo)
222 |
223 | if let downloadTask = downloadTask {
224 | tasks[resource.downloadURL] = downloadTask
225 | }
226 | }
227 |
228 | func append(cached resource: Resource) {
229 | skippedResources.append(resource)
230 |
231 | reportProgress()
232 | reportCompletionOrStartNext()
233 | }
234 |
235 | func startPrefetching(_ resource: Resource)
236 | {
237 | if optionsInfo.forceRefresh {
238 | downloadAndCache(resource)
239 | } else {
240 | let alreadyInCache = manager.cache.isImageCached(forKey: resource.cacheKey,
241 | processorIdentifier: optionsInfo.processor.identifier).cached
242 |
243 | if alreadyInCache {
244 | append(cached: resource)
245 | } else {
246 | downloadAndCache(resource)
247 | }
248 | }
249 | }
250 |
251 | func reportProgress() {
252 | progressBlock?(skippedResources, failedResources, completedResources)
253 | }
254 |
255 | func reportCompletionOrStartNext() {
256 | if let resource = pendingResources.popFirst() {
257 | startPrefetching(resource)
258 | } else {
259 | guard tasks.isEmpty else { return }
260 | handleComplete()
261 | }
262 | }
263 |
264 | func handleComplete() {
265 | completionHandler?(skippedResources, failedResources, completedResources)
266 | completionHandler = nil
267 | progressBlock = nil
268 | }
269 | }
270 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Kingfisher/Sources/ImageTransition.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageTransition.swift
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 15/9/18.
6 | //
7 | // Copyright (c) 2017 Wei Wang
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | #if os(macOS)
28 | // Not implemented for macOS and watchOS yet.
29 |
30 | import AppKit
31 |
32 | /// Image transition is not supported on macOS.
33 | public enum ImageTransition {
34 | case none
35 | var duration: TimeInterval {
36 | return 0
37 | }
38 | }
39 |
40 | #elseif os(watchOS)
41 | import UIKit
42 | /// Image transition is not supported on watchOS.
43 | public enum ImageTransition {
44 | case none
45 | var duration: TimeInterval {
46 | return 0
47 | }
48 | }
49 | #else
50 | import UIKit
51 |
52 | /**
53 | Transition effect which will be used when an image downloaded and set by `UIImageView` extension API in Kingfisher.
54 | You can assign an enum value with transition duration as an item in `KingfisherOptionsInfo`
55 | to enable the animation transition.
56 |
57 | Apple's UIViewAnimationOptions is used under the hood.
58 | For custom transition, you should specified your own transition options, animations and
59 | comletion handler as well.
60 | */
61 | public enum ImageTransition {
62 | /// No animation transistion.
63 | case none
64 |
65 | /// Fade in the loaded image.
66 | case fade(TimeInterval)
67 |
68 | /// Flip from left transition.
69 | case flipFromLeft(TimeInterval)
70 |
71 | /// Flip from right transition.
72 | case flipFromRight(TimeInterval)
73 |
74 | /// Flip from top transition.
75 | case flipFromTop(TimeInterval)
76 |
77 | /// Flip from bottom transition.
78 | case flipFromBottom(TimeInterval)
79 |
80 | /// Custom transition.
81 | case custom(duration: TimeInterval,
82 | options: UIViewAnimationOptions,
83 | animations: ((UIImageView, UIImage) -> Void)?,
84 | completion: ((Bool) -> Void)?)
85 |
86 | var duration: TimeInterval {
87 | switch self {
88 | case .none: return 0
89 | case .fade(let duration): return duration
90 |
91 | case .flipFromLeft(let duration): return duration
92 | case .flipFromRight(let duration): return duration
93 | case .flipFromTop(let duration): return duration
94 | case .flipFromBottom(let duration): return duration
95 |
96 | case .custom(let duration, _, _, _): return duration
97 | }
98 | }
99 |
100 | var animationOptions: UIViewAnimationOptions {
101 | switch self {
102 | case .none: return []
103 | case .fade(_): return .transitionCrossDissolve
104 |
105 | case .flipFromLeft(_): return .transitionFlipFromLeft
106 | case .flipFromRight(_): return .transitionFlipFromRight
107 | case .flipFromTop(_): return .transitionFlipFromTop
108 | case .flipFromBottom(_): return .transitionFlipFromBottom
109 |
110 | case .custom(_, let options, _, _): return options
111 | }
112 | }
113 |
114 | var animations: ((UIImageView, UIImage) -> Void)? {
115 | switch self {
116 | case .custom(_, _, let animations, _): return animations
117 | default: return { $0.image = $1 }
118 | }
119 | }
120 |
121 | var completion: ((Bool) -> Void)? {
122 | switch self {
123 | case .custom(_, _, _, let completion): return completion
124 | default: return nil
125 | }
126 | }
127 | }
128 | #endif
129 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Kingfisher/Sources/Indicator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Indicator.swift
3 | // Kingfisher
4 | //
5 | // Created by João D. Moreira on 30/08/16.
6 | //
7 | // Copyright (c) 2017 Wei Wang
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | #if os(macOS)
28 | import AppKit
29 | #else
30 | import UIKit
31 | #endif
32 |
33 | #if os(macOS)
34 | public typealias IndicatorView = NSView
35 | #else
36 | public typealias IndicatorView = UIView
37 | #endif
38 |
39 | public enum IndicatorType {
40 | /// No indicator.
41 | case none
42 | /// Use system activity indicator.
43 | case activity
44 | /// Use an image as indicator. GIF is supported.
45 | case image(imageData: Data)
46 | /// Use a custom indicator, which conforms to the `Indicator` protocol.
47 | case custom(indicator: Indicator)
48 | }
49 |
50 | // MARK: - Indicator Protocol
51 | public protocol Indicator {
52 | func startAnimatingView()
53 | func stopAnimatingView()
54 |
55 | var viewCenter: CGPoint { get set }
56 | var view: IndicatorView { get }
57 | }
58 |
59 | extension Indicator {
60 | #if os(macOS)
61 | public var viewCenter: CGPoint {
62 | get {
63 | let frame = view.frame
64 | return CGPoint(x: frame.origin.x + frame.size.width / 2.0, y: frame.origin.y + frame.size.height / 2.0 )
65 | }
66 | set {
67 | let frame = view.frame
68 | let newFrame = CGRect(x: newValue.x - frame.size.width / 2.0,
69 | y: newValue.y - frame.size.height / 2.0,
70 | width: frame.size.width,
71 | height: frame.size.height)
72 | view.frame = newFrame
73 | }
74 | }
75 | #else
76 | public var viewCenter: CGPoint {
77 | get {
78 | return view.center
79 | }
80 | set {
81 | view.center = newValue
82 | }
83 | }
84 | #endif
85 | }
86 |
87 | // MARK: - ActivityIndicator
88 | // Displays a NSProgressIndicator / UIActivityIndicatorView
89 | struct ActivityIndicator: Indicator {
90 |
91 | #if os(macOS)
92 | private let activityIndicatorView: NSProgressIndicator
93 | #else
94 | private let activityIndicatorView: UIActivityIndicatorView
95 | #endif
96 |
97 | var view: IndicatorView {
98 | return activityIndicatorView
99 | }
100 |
101 | func startAnimatingView() {
102 | #if os(macOS)
103 | activityIndicatorView.startAnimation(nil)
104 | #else
105 | activityIndicatorView.startAnimating()
106 | #endif
107 | activityIndicatorView.isHidden = false
108 | }
109 |
110 | func stopAnimatingView() {
111 | #if os(macOS)
112 | activityIndicatorView.stopAnimation(nil)
113 | #else
114 | activityIndicatorView.stopAnimating()
115 | #endif
116 | activityIndicatorView.isHidden = true
117 | }
118 |
119 | init() {
120 | #if os(macOS)
121 | activityIndicatorView = NSProgressIndicator(frame: CGRect(x: 0, y: 0, width: 16, height: 16))
122 | activityIndicatorView.controlSize = .small
123 | activityIndicatorView.style = .spinningStyle
124 | #else
125 | #if os(tvOS)
126 | let indicatorStyle = UIActivityIndicatorViewStyle.white
127 | #else
128 | let indicatorStyle = UIActivityIndicatorViewStyle.gray
129 | #endif
130 | activityIndicatorView = UIActivityIndicatorView(activityIndicatorStyle:indicatorStyle)
131 | activityIndicatorView.autoresizingMask = [.flexibleLeftMargin, .flexibleRightMargin, .flexibleBottomMargin, .flexibleTopMargin]
132 | #endif
133 | }
134 | }
135 |
136 | // MARK: - ImageIndicator
137 | // Displays an ImageView. Supports gif
138 | struct ImageIndicator: Indicator {
139 | private let animatedImageIndicatorView: ImageView
140 |
141 | var view: IndicatorView {
142 | return animatedImageIndicatorView
143 | }
144 |
145 | init?(imageData data: Data, processor: ImageProcessor = DefaultImageProcessor.default, options: KingfisherOptionsInfo = KingfisherEmptyOptionsInfo) {
146 |
147 | var options = options
148 | // Use normal image view to show gif, so we need to preload all gif data.
149 | if !options.preloadAllGIFData {
150 | options.append(.preloadAllGIFData)
151 | }
152 |
153 | guard let image = processor.process(item: .data(data), options: options) else {
154 | return nil
155 | }
156 |
157 | animatedImageIndicatorView = ImageView()
158 | animatedImageIndicatorView.image = image
159 |
160 | #if os(macOS)
161 | // Need for gif to animate on macOS
162 | self.animatedImageIndicatorView.imageScaling = .scaleNone
163 | self.animatedImageIndicatorView.canDrawSubviewsIntoLayer = true
164 | #else
165 | animatedImageIndicatorView.contentMode = .center
166 |
167 | animatedImageIndicatorView.autoresizingMask = [.flexibleLeftMargin,
168 | .flexibleRightMargin,
169 | .flexibleBottomMargin,
170 | .flexibleTopMargin]
171 | #endif
172 | }
173 |
174 | func startAnimatingView() {
175 | #if os(macOS)
176 | animatedImageIndicatorView.animates = true
177 | #else
178 | animatedImageIndicatorView.startAnimating()
179 | #endif
180 | animatedImageIndicatorView.isHidden = false
181 | }
182 |
183 | func stopAnimatingView() {
184 | #if os(macOS)
185 | animatedImageIndicatorView.animates = false
186 | #else
187 | animatedImageIndicatorView.stopAnimating()
188 | #endif
189 | animatedImageIndicatorView.isHidden = true
190 | }
191 | }
192 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Kingfisher/Sources/Kingfisher.h:
--------------------------------------------------------------------------------
1 | //
2 | // Kingfisher.h
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 15/4/6.
6 | //
7 | // Copyright (c) 2017 Wei Wang
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | #import
28 |
29 | //! Project version number for Kingfisher.
30 | FOUNDATION_EXPORT double KingfisherVersionNumber;
31 |
32 | //! Project version string for Kingfisher.
33 | FOUNDATION_EXPORT const unsigned char KingfisherVersionString[];
34 |
35 | // In this header, you should import all the public headers of your framework using statements like #import
36 |
37 |
38 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Kingfisher/Sources/Kingfisher.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Kingfisher.swift
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 16/9/14.
6 | //
7 | // Copyright (c) 2017 Wei Wang
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | import Foundation
28 | import ImageIO
29 |
30 | #if os(macOS)
31 | import AppKit
32 | public typealias Image = NSImage
33 | public typealias Color = NSColor
34 | public typealias ImageView = NSImageView
35 | typealias Button = NSButton
36 | #else
37 | import UIKit
38 | public typealias Image = UIImage
39 | public typealias Color = UIColor
40 | #if !os(watchOS)
41 | public typealias ImageView = UIImageView
42 | typealias Button = UIButton
43 | #endif
44 | #endif
45 |
46 | public final class Kingfisher {
47 | public let base: Base
48 | public init(_ base: Base) {
49 | self.base = base
50 | }
51 | }
52 |
53 | /**
54 | A type that has Kingfisher extensions.
55 | */
56 | public protocol KingfisherCompatible {
57 | associatedtype CompatibleType
58 | var kf: CompatibleType { get }
59 | }
60 |
61 | public extension KingfisherCompatible {
62 | public var kf: Kingfisher {
63 | get { return Kingfisher(self) }
64 | }
65 | }
66 |
67 | extension Image: KingfisherCompatible { }
68 | #if !os(watchOS)
69 | extension ImageView: KingfisherCompatible { }
70 | extension Button: KingfisherCompatible { }
71 | #endif
72 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Kingfisher/Sources/KingfisherManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // KingfisherManager.swift
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 15/4/6.
6 | //
7 | // Copyright (c) 2017 Wei Wang
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | #if os(macOS)
28 | import AppKit
29 | #else
30 | import UIKit
31 | #endif
32 |
33 | public typealias DownloadProgressBlock = ((_ receivedSize: Int64, _ totalSize: Int64) -> ())
34 | public typealias CompletionHandler = ((_ image: Image?, _ error: NSError?, _ cacheType: CacheType, _ imageURL: URL?) -> ())
35 |
36 | /// RetrieveImageTask represents a task of image retrieving process.
37 | /// It contains an async task of getting image from disk and from network.
38 | public class RetrieveImageTask {
39 |
40 | public static let empty = RetrieveImageTask()
41 |
42 | // If task is canceled before the download task started (which means the `downloadTask` is nil),
43 | // the download task should not begin.
44 | var cancelledBeforeDownloadStarting: Bool = false
45 |
46 | /// The disk retrieve task in this image task. Kingfisher will try to look up in cache first. This task represent the cache search task.
47 | @available(*, deprecated,
48 | message: "diskRetrieveTask is not in use anymore. You cannot cancel a disk retrieve task anymore once it started.")
49 | public var diskRetrieveTask: RetrieveImageDiskTask?
50 |
51 | /// The network retrieve task in this image task.
52 | public var downloadTask: RetrieveImageDownloadTask?
53 |
54 | /**
55 | Cancel current task. If this task is already done, do nothing.
56 | */
57 | public func cancel() {
58 | if let downloadTask = downloadTask {
59 | downloadTask.cancel()
60 | } else {
61 | cancelledBeforeDownloadStarting = true
62 | }
63 | }
64 | }
65 |
66 | /// Error domain of Kingfisher
67 | public let KingfisherErrorDomain = "com.onevcat.Kingfisher.Error"
68 |
69 | /// Main manager class of Kingfisher. It connects Kingfisher downloader and cache.
70 | /// You can use this class to retrieve an image via a specified URL from web or cache.
71 | public class KingfisherManager {
72 |
73 | /// Shared manager used by the extensions across Kingfisher.
74 | public static let shared = KingfisherManager()
75 |
76 | /// Cache used by this manager
77 | public var cache: ImageCache
78 |
79 | /// Downloader used by this manager
80 | public var downloader: ImageDownloader
81 |
82 | convenience init() {
83 | self.init(downloader: .default, cache: .default)
84 | }
85 |
86 | init(downloader: ImageDownloader, cache: ImageCache) {
87 | self.downloader = downloader
88 | self.cache = cache
89 | }
90 |
91 | /**
92 | Get an image with resource.
93 | If KingfisherOptions.None is used as `options`, Kingfisher will seek the image in memory and disk first.
94 | If not found, it will download the image at `resource.downloadURL` and cache it with `resource.cacheKey`.
95 | These default behaviors could be adjusted by passing different options. See `KingfisherOptions` for more.
96 |
97 | - parameter resource: Resource object contains information such as `cacheKey` and `downloadURL`.
98 | - parameter options: A dictionary could control some behaviors. See `KingfisherOptionsInfo` for more.
99 | - parameter progressBlock: Called every time downloaded data changed. This could be used as a progress UI.
100 | - parameter completionHandler: Called when the whole retrieving process finished.
101 |
102 | - returns: A `RetrieveImageTask` task object. You can use this object to cancel the task.
103 | */
104 | @discardableResult
105 | public func retrieveImage(with resource: Resource,
106 | options: KingfisherOptionsInfo?,
107 | progressBlock: DownloadProgressBlock?,
108 | completionHandler: CompletionHandler?) -> RetrieveImageTask
109 | {
110 | let task = RetrieveImageTask()
111 |
112 | if let options = options, options.forceRefresh {
113 | _ = downloadAndCacheImage(
114 | with: resource.downloadURL,
115 | forKey: resource.cacheKey,
116 | retrieveImageTask: task,
117 | progressBlock: progressBlock,
118 | completionHandler: completionHandler,
119 | options: options)
120 | } else {
121 | tryToRetrieveImageFromCache(
122 | forKey: resource.cacheKey,
123 | with: resource.downloadURL,
124 | retrieveImageTask: task,
125 | progressBlock: progressBlock,
126 | completionHandler: completionHandler,
127 | options: options)
128 | }
129 |
130 | return task
131 | }
132 |
133 | @discardableResult
134 | func downloadAndCacheImage(with url: URL,
135 | forKey key: String,
136 | retrieveImageTask: RetrieveImageTask,
137 | progressBlock: DownloadProgressBlock?,
138 | completionHandler: CompletionHandler?,
139 | options: KingfisherOptionsInfo?) -> RetrieveImageDownloadTask?
140 | {
141 | let options = options ?? KingfisherEmptyOptionsInfo
142 | let downloader = options.downloader
143 | return downloader.downloadImage(with: url, retrieveImageTask: retrieveImageTask, options: options,
144 | progressBlock: { receivedSize, totalSize in
145 | progressBlock?(receivedSize, totalSize)
146 | },
147 | completionHandler: { image, error, imageURL, originalData in
148 |
149 | let targetCache = options.targetCache
150 | if let error = error, error.code == KingfisherError.notModified.rawValue {
151 | // Not modified. Try to find the image from cache.
152 | // (The image should be in cache. It should be guaranteed by the framework users.)
153 | targetCache.retrieveImage(forKey: key, options: options, completionHandler: { (cacheImage, cacheType) -> () in
154 | completionHandler?(cacheImage, nil, cacheType, url)
155 | })
156 | return
157 | }
158 |
159 | if let image = image, let originalData = originalData {
160 | targetCache.store(image,
161 | original: originalData,
162 | forKey: key,
163 | processorIdentifier:options.processor.identifier,
164 | cacheSerializer: options.cacheSerializer,
165 | toDisk: !options.cacheMemoryOnly,
166 | completionHandler: nil)
167 | }
168 |
169 | completionHandler?(image, error, .none, url)
170 |
171 | })
172 | }
173 |
174 | func tryToRetrieveImageFromCache(forKey key: String,
175 | with url: URL,
176 | retrieveImageTask: RetrieveImageTask,
177 | progressBlock: DownloadProgressBlock?,
178 | completionHandler: CompletionHandler?,
179 | options: KingfisherOptionsInfo?)
180 | {
181 | let diskTaskCompletionHandler: CompletionHandler = { (image, error, cacheType, imageURL) -> () in
182 | completionHandler?(image, error, cacheType, imageURL)
183 | }
184 |
185 | let targetCache = options?.targetCache ?? cache
186 | targetCache.retrieveImage(forKey: key, options: options,
187 | completionHandler: { image, cacheType in
188 | if image != nil {
189 | diskTaskCompletionHandler(image, nil, cacheType, url)
190 | } else if let options = options, options.onlyFromCache {
191 | let error = NSError(domain: KingfisherErrorDomain, code: KingfisherError.notCached.rawValue, userInfo: nil)
192 | diskTaskCompletionHandler(nil, error, .none, url)
193 | } else {
194 | self.downloadAndCacheImage(
195 | with: url,
196 | forKey: key,
197 | retrieveImageTask: retrieveImageTask,
198 | progressBlock: progressBlock,
199 | completionHandler: diskTaskCompletionHandler,
200 | options: options)
201 | }
202 | }
203 | )
204 | }
205 | }
206 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Kingfisher/Sources/KingfisherOptionsInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // KingfisherOptionsInfo.swift
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 15/4/23.
6 | //
7 | // Copyright (c) 2017 Wei Wang
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | #if os(macOS)
28 | import AppKit
29 | #else
30 | import UIKit
31 | #endif
32 |
33 |
34 | /**
35 | * KingfisherOptionsInfo is a typealias for [KingfisherOptionsInfoItem]. You can use the enum of option item with value to control some behaviors of Kingfisher.
36 | */
37 | public typealias KingfisherOptionsInfo = [KingfisherOptionsInfoItem]
38 | let KingfisherEmptyOptionsInfo = [KingfisherOptionsInfoItem]()
39 |
40 | /**
41 | Items could be added into KingfisherOptionsInfo.
42 | */
43 | public enum KingfisherOptionsInfoItem {
44 | /// The associated value of this member should be an ImageCache object. Kingfisher will use the specified
45 | /// cache object when handling related operations, including trying to retrieve the cached images and store
46 | /// the downloaded image to it.
47 | case targetCache(ImageCache)
48 |
49 | /// The associated value of this member should be an ImageDownloader object. Kingfisher will use this
50 | /// downloader to download the images.
51 | case downloader(ImageDownloader)
52 |
53 | /// Member for animation transition when using UIImageView. Kingfisher will use the `ImageTransition` of
54 | /// this enum to animate the image in if it is downloaded from web. The transition will not happen when the
55 | /// image is retrieved from either memory or disk cache by default. If you need to do the transition even when
56 | /// the image being retrieved from cache, set `ForceTransition` as well.
57 | case transition(ImageTransition)
58 |
59 | /// Associated `Float` value will be set as the priority of image download task. The value for it should be
60 | /// between 0.0~1.0. If this option not set, the default value (`NSURLSessionTaskPriorityDefault`) will be used.
61 | case downloadPriority(Float)
62 |
63 | /// If set, `Kingfisher` will ignore the cache and try to fire a download task for the resource.
64 | case forceRefresh
65 |
66 | /// If set, setting the image to an image view will happen with transition even when retrieved from cache.
67 | /// See `Transition` option for more.
68 | case forceTransition
69 |
70 | /// If set, `Kingfisher` will only cache the value in memory but not in disk.
71 | case cacheMemoryOnly
72 |
73 | /// If set, `Kingfisher` will only try to retrieve the image from cache not from network.
74 | case onlyFromCache
75 |
76 | /// Decode the image in background thread before using.
77 | case backgroundDecode
78 |
79 | /// The associated value of this member will be used as the target queue of dispatch callbacks when
80 | /// retrieving images from cache. If not set, `Kingfisher` will use main quese for callbacks.
81 | case callbackDispatchQueue(DispatchQueue?)
82 |
83 | /// The associated value of this member will be used as the scale factor when converting retrieved data to an image.
84 | /// It is the image scale, instead of your screen scale. You may need to specify the correct scale when you dealing
85 | /// with 2x or 3x retina images.
86 | case scaleFactor(CGFloat)
87 |
88 | /// Whether all the GIF data should be preloaded. Default it false, which means following frames will be
89 | /// loaded on need. If true, all the GIF data will be loaded and decoded into memory. This option is mainly
90 | /// used for back compatibility internally. You should not set it directly. `AnimatedImageView` will not preload
91 | /// all data, while a normal image view (`UIImageView` or `NSImageView`) will load all data. Choose to use
92 | /// corresponding image view type instead of setting this option.
93 | case preloadAllGIFData
94 |
95 | /// The `ImageDownloadRequestModifier` contained will be used to change the request before it being sent.
96 | /// This is the last chance you can modify the request. You can modify the request for some customizing purpose,
97 | /// such as adding auth token to the header, do basic HTTP auth or something like url mapping. The original request
98 | /// will be sent without any modification by default.
99 | case requestModifier(ImageDownloadRequestModifier)
100 |
101 | /// Processor for processing when the downloading finishes, a processor will convert the downloaded data to an image
102 | /// and/or apply some filter on it. If a cache is connected to the downloader (it happenes when you are using
103 | /// KingfisherManager or the image extension methods), the converted image will also be sent to cache as well as the
104 | /// image view. `DefaultImageProcessor.default` will be used by default.
105 | case processor(ImageProcessor)
106 |
107 | /// Supply an `CacheSerializer` to convert some data to an image object for
108 | /// retrieving from disk cache or vice versa for storing to disk cache.
109 | /// `DefaultCacheSerializer.default` will be used by default.
110 | case cacheSerializer(CacheSerializer)
111 |
112 | /// Keep the existing image while setting another image to an image view.
113 | /// By setting this option, the placeholder image parameter of imageview extension method
114 | /// will be ignored and the current image will be kept while loading or downloading the new image.
115 | case keepCurrentImageWhileLoading
116 |
117 | /// If set, Kingfisher will only load the first frame from a GIF file as a single image.
118 | /// Loading a lot of GIFs may take too much memory. It will be useful when you want to display a
119 | /// static preview of the first frame from a GIF image.
120 | /// This option will be ignored if the target image is not GIF.
121 | case onlyLoadFirstFrame
122 | }
123 |
124 | precedencegroup ItemComparisonPrecedence {
125 | associativity: none
126 | higherThan: LogicalConjunctionPrecedence
127 | }
128 |
129 | infix operator <== : ItemComparisonPrecedence
130 |
131 | // This operator returns true if two `KingfisherOptionsInfoItem` enum is the same, without considering the associated values.
132 | func <== (lhs: KingfisherOptionsInfoItem, rhs: KingfisherOptionsInfoItem) -> Bool {
133 | switch (lhs, rhs) {
134 | case (.targetCache(_), .targetCache(_)): return true
135 | case (.downloader(_), .downloader(_)): return true
136 | case (.transition(_), .transition(_)): return true
137 | case (.downloadPriority(_), .downloadPriority(_)): return true
138 | case (.forceRefresh, .forceRefresh): return true
139 | case (.forceTransition, .forceTransition): return true
140 | case (.cacheMemoryOnly, .cacheMemoryOnly): return true
141 | case (.onlyFromCache, .onlyFromCache): return true
142 | case (.backgroundDecode, .backgroundDecode): return true
143 | case (.callbackDispatchQueue(_), .callbackDispatchQueue(_)): return true
144 | case (.scaleFactor(_), .scaleFactor(_)): return true
145 | case (.preloadAllGIFData, .preloadAllGIFData): return true
146 | case (.requestModifier(_), .requestModifier(_)): return true
147 | case (.processor(_), .processor(_)): return true
148 | case (.cacheSerializer(_), .cacheSerializer(_)): return true
149 | case (.keepCurrentImageWhileLoading, .keepCurrentImageWhileLoading): return true
150 | case (.onlyLoadFirstFrame, .onlyLoadFirstFrame): return true
151 | default: return false
152 | }
153 | }
154 |
155 | extension Collection where Iterator.Element == KingfisherOptionsInfoItem {
156 | func firstMatchIgnoringAssociatedValue(_ target: Iterator.Element) -> Iterator.Element? {
157 | return index { $0 <== target }.flatMap { self[$0] }
158 | }
159 |
160 | func removeAllMatchesIgnoringAssociatedValue(_ target: Iterator.Element) -> [Iterator.Element] {
161 | return self.filter { !($0 <== target) }
162 | }
163 | }
164 |
165 | public extension Collection where Iterator.Element == KingfisherOptionsInfoItem {
166 | /// The target `ImageCache` which is used.
167 | public var targetCache: ImageCache {
168 | if let item = firstMatchIgnoringAssociatedValue(.targetCache(.default)),
169 | case .targetCache(let cache) = item
170 | {
171 | return cache
172 | }
173 | return ImageCache.default
174 | }
175 |
176 | /// The `ImageDownloader` which is specified.
177 | public var downloader: ImageDownloader {
178 | if let item = firstMatchIgnoringAssociatedValue(.downloader(.default)),
179 | case .downloader(let downloader) = item
180 | {
181 | return downloader
182 | }
183 | return ImageDownloader.default
184 | }
185 |
186 | /// Member for animation transition when using UIImageView.
187 | public var transition: ImageTransition {
188 | if let item = firstMatchIgnoringAssociatedValue(.transition(.none)),
189 | case .transition(let transition) = item
190 | {
191 | return transition
192 | }
193 | return ImageTransition.none
194 | }
195 |
196 | /// A `Float` value set as the priority of image download task. The value for it should be
197 | /// between 0.0~1.0.
198 | public var downloadPriority: Float {
199 | if let item = firstMatchIgnoringAssociatedValue(.downloadPriority(0)),
200 | case .downloadPriority(let priority) = item
201 | {
202 | return priority
203 | }
204 | return URLSessionTask.defaultPriority
205 | }
206 |
207 | /// Whether an image will be always downloaded again or not.
208 | public var forceRefresh: Bool {
209 | return contains{ $0 <== .forceRefresh }
210 | }
211 |
212 | /// Whether the transition should always happen or not.
213 | public var forceTransition: Bool {
214 | return contains{ $0 <== .forceTransition }
215 | }
216 |
217 | /// Whether cache the image only in memory or not.
218 | public var cacheMemoryOnly: Bool {
219 | return contains{ $0 <== .cacheMemoryOnly }
220 | }
221 |
222 | /// Whether only load the images from cache or not.
223 | public var onlyFromCache: Bool {
224 | return contains{ $0 <== .onlyFromCache }
225 | }
226 |
227 | /// Whether the image should be decoded in background or not.
228 | public var backgroundDecode: Bool {
229 | return contains{ $0 <== .backgroundDecode }
230 | }
231 |
232 | /// Whether the image data should be all loaded at once if it is a GIF.
233 | public var preloadAllGIFData: Bool {
234 | return contains { $0 <== .preloadAllGIFData }
235 | }
236 |
237 | /// The queue of callbacks should happen from Kingfisher.
238 | public var callbackDispatchQueue: DispatchQueue {
239 | if let item = firstMatchIgnoringAssociatedValue(.callbackDispatchQueue(nil)),
240 | case .callbackDispatchQueue(let queue) = item
241 | {
242 | return queue ?? DispatchQueue.main
243 | }
244 | return DispatchQueue.main
245 | }
246 |
247 | /// The scale factor which should be used for the image.
248 | public var scaleFactor: CGFloat {
249 | if let item = firstMatchIgnoringAssociatedValue(.scaleFactor(0)),
250 | case .scaleFactor(let scale) = item
251 | {
252 | return scale
253 | }
254 | return 1.0
255 | }
256 |
257 | /// The `ImageDownloadRequestModifier` will be used before sending a download request.
258 | public var modifier: ImageDownloadRequestModifier {
259 | if let item = firstMatchIgnoringAssociatedValue(.requestModifier(NoModifier.default)),
260 | case .requestModifier(let modifier) = item
261 | {
262 | return modifier
263 | }
264 | return NoModifier.default
265 | }
266 |
267 | /// `ImageProcessor` for processing when the downloading finishes.
268 | public var processor: ImageProcessor {
269 | if let item = firstMatchIgnoringAssociatedValue(.processor(DefaultImageProcessor.default)),
270 | case .processor(let processor) = item
271 | {
272 | return processor
273 | }
274 | return DefaultImageProcessor.default
275 | }
276 |
277 | /// `CacheSerializer` to convert image to data for storing in cache.
278 | public var cacheSerializer: CacheSerializer {
279 | if let item = firstMatchIgnoringAssociatedValue(.cacheSerializer(DefaultCacheSerializer.default)),
280 | case .cacheSerializer(let cacheSerializer) = item
281 | {
282 | return cacheSerializer
283 | }
284 | return DefaultCacheSerializer.default
285 | }
286 |
287 | /// Keep the existing image while setting another image to an image view.
288 | /// Or the placeholder will be used while downloading.
289 | public var keepCurrentImageWhileLoading: Bool {
290 | return contains { $0 <== .keepCurrentImageWhileLoading }
291 | }
292 |
293 | public var onlyLoadFirstFrame: Bool {
294 | return contains { $0 <== .onlyLoadFirstFrame }
295 | }
296 | }
297 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Kingfisher/Sources/RequestModifier.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RequestModifier.swift
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 2016/09/05.
6 | //
7 | // Copyright (c) 2017 Wei Wang
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | import Foundation
28 |
29 | /// Request modifier of image downloader.
30 | public protocol ImageDownloadRequestModifier {
31 | func modified(for request: URLRequest) -> URLRequest?
32 | }
33 |
34 | struct NoModifier: ImageDownloadRequestModifier {
35 | static let `default` = NoModifier()
36 | private init() {}
37 | func modified(for request: URLRequest) -> URLRequest? {
38 | return request
39 | }
40 | }
41 |
42 | public struct AnyModifier: ImageDownloadRequestModifier {
43 |
44 | let block: (URLRequest) -> URLRequest?
45 |
46 | public func modified(for request: URLRequest) -> URLRequest? {
47 | return block(request)
48 | }
49 |
50 | public init(modify: @escaping (URLRequest) -> URLRequest? ) {
51 | block = modify
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Kingfisher/Sources/Resource.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Resource.swift
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 15/4/6.
6 | //
7 | // Copyright (c) 2017 Wei Wang
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | import Foundation
28 |
29 |
30 | /// `Resource` protocol defines how to download and cache a resource from network.
31 | public protocol Resource {
32 | /// The key used in cache.
33 | var cacheKey: String { get }
34 |
35 | /// The target image URL.
36 | var downloadURL: URL { get }
37 | }
38 |
39 | /**
40 | ImageResource is a simple combination of `downloadURL` and `cacheKey`.
41 |
42 | When passed to image view set methods, Kingfisher will try to download the target
43 | image from the `downloadURL`, and then store it with the `cacheKey` as the key in cache.
44 | */
45 | public struct ImageResource: Resource {
46 | /// The key used in cache.
47 | public let cacheKey: String
48 |
49 | /// The target image URL.
50 | public let downloadURL: URL
51 |
52 | /**
53 | Create a resource.
54 |
55 | - parameter downloadURL: The target image URL.
56 | - parameter cacheKey: The cache key. If `nil`, Kingfisher will use the `absoluteString` of `downloadURL` as the key.
57 |
58 | - returns: A resource.
59 | */
60 | public init(downloadURL: URL, cacheKey: String? = nil) {
61 | self.downloadURL = downloadURL
62 | self.cacheKey = cacheKey ?? downloadURL.absoluteString
63 | }
64 | }
65 |
66 | /**
67 | URL conforms to `Resource` in Kingfisher.
68 | The `absoluteString` of this URL is used as `cacheKey`. And the URL itself will be used as `downloadURL`.
69 | If you need customize the url and/or cache key, use `ImageResource` instead.
70 | */
71 | extension URL: Resource {
72 | public var cacheKey: String { return absoluteString }
73 | public var downloadURL: URL { return self }
74 | }
75 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Kingfisher/Sources/String+MD5.swift:
--------------------------------------------------------------------------------
1 | //
2 | // String+MD5.swift
3 | // Kingfisher
4 | //
5 | // To date, adding CommonCrypto to a Swift framework is problematic. See:
6 | // http://stackoverflow.com/questions/25248598/importing-commoncrypto-in-a-swift-framework
7 | // We're using a subset and modified version of CryptoSwift as an alternative.
8 | // The following is an altered source version that only includes MD5. The original software can be found at:
9 | // https://github.com/krzyzanowskim/CryptoSwift
10 | // This is the original copyright notice:
11 |
12 | /*
13 | Copyright (C) 2014 Marcin Krzyżanowski
14 | This software is provided 'as-is', without any express or implied warranty.
15 | In no event will the authors be held liable for any damages arising from the use of this software.
16 | Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
17 | - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
18 | - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
19 | - This notice may not be removed or altered from any source or binary distribution.
20 | */
21 |
22 | import Foundation
23 |
24 | public struct StringProxy {
25 | fileprivate let base: String
26 | init(proxy: String) {
27 | base = proxy
28 | }
29 | }
30 |
31 | extension String: KingfisherCompatible {
32 | public typealias CompatibleType = StringProxy
33 | public var kf: CompatibleType {
34 | return StringProxy(proxy: self)
35 | }
36 | }
37 |
38 | extension StringProxy {
39 | var md5: String {
40 | if let data = base.data(using: .utf8, allowLossyConversion: true) {
41 |
42 | let message = data.withUnsafeBytes { bytes -> [UInt8] in
43 | return Array(UnsafeBufferPointer(start: bytes, count: data.count))
44 | }
45 |
46 | let MD5Calculator = MD5(message)
47 | let MD5Data = MD5Calculator.calculate()
48 |
49 | var MD5String = String()
50 | for c in MD5Data {
51 | MD5String += String(format: "%02x", c)
52 | }
53 | return MD5String
54 |
55 | } else {
56 | return base
57 | }
58 | }
59 | }
60 |
61 |
62 | /** array of bytes, little-endian representation */
63 | func arrayOfBytes(_ value: T, length: Int? = nil) -> [UInt8] {
64 | let totalBytes = length ?? (MemoryLayout.size * 8)
65 |
66 | let valuePointer = UnsafeMutablePointer.allocate(capacity: 1)
67 | valuePointer.pointee = value
68 |
69 | let bytes = valuePointer.withMemoryRebound(to: UInt8.self, capacity: totalBytes) { (bytesPointer) -> [UInt8] in
70 | var bytes = [UInt8](repeating: 0, count: totalBytes)
71 | for j in 0...size, totalBytes) {
72 | bytes[totalBytes - 1 - j] = (bytesPointer + j).pointee
73 | }
74 | return bytes
75 | }
76 |
77 | valuePointer.deinitialize()
78 | valuePointer.deallocate(capacity: 1)
79 |
80 | return bytes
81 | }
82 |
83 | extension Int {
84 | /** Array of bytes with optional padding (little-endian) */
85 | func bytes(_ totalBytes: Int = MemoryLayout.size) -> [UInt8] {
86 | return arrayOfBytes(self, length: totalBytes)
87 | }
88 |
89 | }
90 |
91 | extension NSMutableData {
92 |
93 | /** Convenient way to append bytes */
94 | func appendBytes(_ arrayOfBytes: [UInt8]) {
95 | append(arrayOfBytes, length: arrayOfBytes.count)
96 | }
97 |
98 | }
99 |
100 | protocol HashProtocol {
101 | var message: Array { get }
102 |
103 | /** Common part for hash calculation. Prepare header data. */
104 | func prepare(_ len: Int) -> Array
105 | }
106 |
107 | extension HashProtocol {
108 |
109 | func prepare(_ len: Int) -> Array {
110 | var tmpMessage = message
111 |
112 | // Step 1. Append Padding Bits
113 | tmpMessage.append(0x80) // append one bit (UInt8 with one bit) to message
114 |
115 | // append "0" bit until message length in bits ≡ 448 (mod 512)
116 | var msgLength = tmpMessage.count
117 | var counter = 0
118 |
119 | while msgLength % len != (len - 8) {
120 | counter += 1
121 | msgLength += 1
122 | }
123 |
124 | tmpMessage += Array(repeating: 0, count: counter)
125 | return tmpMessage
126 | }
127 | }
128 |
129 | func toUInt32Array(_ slice: ArraySlice) -> Array {
130 | var result = Array()
131 | result.reserveCapacity(16)
132 |
133 | for idx in stride(from: slice.startIndex, to: slice.endIndex, by: MemoryLayout.size) {
134 | let d0 = UInt32(slice[idx.advanced(by: 3)]) << 24
135 | let d1 = UInt32(slice[idx.advanced(by: 2)]) << 16
136 | let d2 = UInt32(slice[idx.advanced(by: 1)]) << 8
137 | let d3 = UInt32(slice[idx])
138 | let val: UInt32 = d0 | d1 | d2 | d3
139 |
140 | result.append(val)
141 | }
142 | return result
143 | }
144 |
145 | struct BytesIterator: IteratorProtocol {
146 |
147 | let chunkSize: Int
148 | let data: [UInt8]
149 |
150 | init(chunkSize: Int, data: [UInt8]) {
151 | self.chunkSize = chunkSize
152 | self.data = data
153 | }
154 |
155 | var offset = 0
156 |
157 | mutating func next() -> ArraySlice? {
158 | let end = min(chunkSize, data.count - offset)
159 | let result = data[offset.. 0 ? result : nil
162 | }
163 | }
164 |
165 | struct BytesSequence: Sequence {
166 | let chunkSize: Int
167 | let data: [UInt8]
168 |
169 | func makeIterator() -> BytesIterator {
170 | return BytesIterator(chunkSize: chunkSize, data: data)
171 | }
172 | }
173 |
174 | func rotateLeft(_ value: UInt32, bits: UInt32) -> UInt32 {
175 | return ((value << bits) & 0xFFFFFFFF) | (value >> (32 - bits))
176 | }
177 |
178 | class MD5: HashProtocol {
179 |
180 | static let size = 16 // 128 / 8
181 | let message: [UInt8]
182 |
183 | init (_ message: [UInt8]) {
184 | self.message = message
185 | }
186 |
187 | /** specifies the per-round shift amounts */
188 | private let shifts: [UInt32] = [7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
189 | 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
190 | 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
191 | 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21]
192 |
193 | /** binary integer part of the sines of integers (Radians) */
194 | private let sines: [UInt32] = [0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
195 | 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
196 | 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
197 | 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
198 | 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
199 | 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
200 | 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
201 | 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
202 | 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
203 | 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
204 | 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05,
205 | 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
206 | 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
207 | 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
208 | 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
209 | 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391]
210 |
211 | private let hashes: [UInt32] = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476]
212 |
213 | func calculate() -> [UInt8] {
214 | var tmpMessage = prepare(64)
215 | tmpMessage.reserveCapacity(tmpMessage.count + 4)
216 |
217 | // hash values
218 | var hh = hashes
219 |
220 | // Step 2. Append Length a 64-bit representation of lengthInBits
221 | let lengthInBits = (message.count * 8)
222 | let lengthBytes = lengthInBits.bytes(64 / 8)
223 | tmpMessage += lengthBytes.reversed()
224 |
225 | // Process the message in successive 512-bit chunks:
226 | let chunkSizeBytes = 512 / 8 // 64
227 |
228 | for chunk in BytesSequence(chunkSize: chunkSizeBytes, data: tmpMessage) {
229 | // break chunk into sixteen 32-bit words M[j], 0 ≤ j ≤ 15
230 | var M = toUInt32Array(chunk)
231 | assert(M.count == 16, "Invalid array")
232 |
233 | // Initialize hash value for this chunk:
234 | var A: UInt32 = hh[0]
235 | var B: UInt32 = hh[1]
236 | var C: UInt32 = hh[2]
237 | var D: UInt32 = hh[3]
238 |
239 | var dTemp: UInt32 = 0
240 |
241 | // Main loop
242 | for j in 0 ..< sines.count {
243 | var g = 0
244 | var F: UInt32 = 0
245 |
246 | switch j {
247 | case 0...15:
248 | F = (B & C) | ((~B) & D)
249 | g = j
250 | break
251 | case 16...31:
252 | F = (D & B) | (~D & C)
253 | g = (5 * j + 1) % 16
254 | break
255 | case 32...47:
256 | F = B ^ C ^ D
257 | g = (3 * j + 5) % 16
258 | break
259 | case 48...63:
260 | F = C ^ (B | (~D))
261 | g = (7 * j) % 16
262 | break
263 | default:
264 | break
265 | }
266 | dTemp = D
267 | D = C
268 | C = B
269 | B = B &+ rotateLeft((A &+ F &+ sines[j] &+ M[g]), bits: shifts[j])
270 | A = dTemp
271 | }
272 |
273 | hh[0] = hh[0] &+ A
274 | hh[1] = hh[1] &+ B
275 | hh[2] = hh[2] &+ C
276 | hh[3] = hh[3] &+ D
277 | }
278 |
279 | var result = [UInt8]()
280 | result.reserveCapacity(hh.count / 4)
281 |
282 | hh.forEach {
283 | let itemLE = $0.littleEndian
284 | let r1 = UInt8(itemLE & 0xff)
285 | let r2 = UInt8((itemLE >> 8) & 0xff)
286 | let r3 = UInt8((itemLE >> 16) & 0xff)
287 | let r4 = UInt8((itemLE >> 24) & 0xff)
288 | result += [r1, r2, r3, r4]
289 | }
290 | return result
291 | }
292 | }
293 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Kingfisher/Sources/ThreadHelper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ThreadHelper.swift
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 15/10/9.
6 | //
7 | // Copyright (c) 2017 Wei Wang
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | import Foundation
28 |
29 | extension DispatchQueue {
30 | // This method will dispatch the `block` to self.
31 | // If `self` is the main queue, and current thread is main thread, the block
32 | // will be invoked immediately instead of being dispatched.
33 | func safeAsync(_ block: @escaping ()->()) {
34 | if self === DispatchQueue.main && Thread.isMainThread {
35 | block()
36 | } else {
37 | async { block() }
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Manifest.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Kingfisher (3.6.2)
3 |
4 | DEPENDENCIES:
5 | - Kingfisher
6 |
7 | SPEC CHECKSUMS:
8 | Kingfisher: 2c94e72c6830622c71d06adf4ea024c37d316830
9 |
10 | PODFILE CHECKSUM: 6daf8f1d76fe64163802c6a83d3d697d2866e5e0
11 |
12 | COCOAPODS: 1.2.1
13 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Target Support Files/Kingfisher/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 3.6.2
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Target Support Files/Kingfisher/Kingfisher-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Kingfisher : NSObject
3 | @end
4 | @implementation PodsDummy_Kingfisher
5 | @end
6 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Target Support Files/Kingfisher/Kingfisher-prefix.pch:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Target Support Files/Kingfisher/Kingfisher-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 | #import "Kingfisher.h"
14 |
15 | FOUNDATION_EXPORT double KingfisherVersionNumber;
16 | FOUNDATION_EXPORT const unsigned char KingfisherVersionString[];
17 |
18 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Target Support Files/Kingfisher/Kingfisher.modulemap:
--------------------------------------------------------------------------------
1 | framework module Kingfisher {
2 | umbrella header "Kingfisher-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Target Support Files/Kingfisher/Kingfisher.xcconfig:
--------------------------------------------------------------------------------
1 | CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/Kingfisher
2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
3 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public"
4 | OTHER_LDFLAGS = -framework "CFNetwork"
5 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
6 | PODS_BUILD_DIR = $BUILD_DIR
7 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
8 | PODS_ROOT = ${SRCROOT}
9 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/Kingfisher
10 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
11 | SKIP_INSTALL = YES
12 | SWIFT_VERSION = 3.0
13 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Target Support Files/Pods-WRCycleScrollViewDemo/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Target Support Files/Pods-WRCycleScrollViewDemo/Pods-WRCycleScrollViewDemo-acknowledgements.markdown:
--------------------------------------------------------------------------------
1 | # Acknowledgements
2 | This application makes use of the following third party libraries:
3 |
4 | ## Kingfisher
5 |
6 | The MIT License (MIT)
7 |
8 | Copyright (c) 2017 Wei Wang
9 |
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 |
17 | The above copyright notice and this permission notice shall be included in all
18 | copies or substantial portions of the Software.
19 |
20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 | SOFTWARE.
27 |
28 |
29 | Generated by CocoaPods - https://cocoapods.org
30 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Target Support Files/Pods-WRCycleScrollViewDemo/Pods-WRCycleScrollViewDemo-acknowledgements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreferenceSpecifiers
6 |
7 |
8 | FooterText
9 | This application makes use of the following third party libraries:
10 | Title
11 | Acknowledgements
12 | Type
13 | PSGroupSpecifier
14 |
15 |
16 | FooterText
17 | The MIT License (MIT)
18 |
19 | Copyright (c) 2017 Wei Wang
20 |
21 | Permission is hereby granted, free of charge, to any person obtaining a copy
22 | of this software and associated documentation files (the "Software"), to deal
23 | in the Software without restriction, including without limitation the rights
24 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25 | copies of the Software, and to permit persons to whom the Software is
26 | furnished to do so, subject to the following conditions:
27 |
28 | The above copyright notice and this permission notice shall be included in all
29 | copies or substantial portions of the Software.
30 |
31 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
37 | SOFTWARE.
38 |
39 |
40 | License
41 | MIT
42 | Title
43 | Kingfisher
44 | Type
45 | PSGroupSpecifier
46 |
47 |
48 | FooterText
49 | Generated by CocoaPods - https://cocoapods.org
50 | Title
51 |
52 | Type
53 | PSGroupSpecifier
54 |
55 |
56 | StringsTable
57 | Acknowledgements
58 | Title
59 | Acknowledgements
60 |
61 |
62 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Target Support Files/Pods-WRCycleScrollViewDemo/Pods-WRCycleScrollViewDemo-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Pods_WRCycleScrollViewDemo : NSObject
3 | @end
4 | @implementation PodsDummy_Pods_WRCycleScrollViewDemo
5 | @end
6 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Target Support Files/Pods-WRCycleScrollViewDemo/Pods-WRCycleScrollViewDemo-frameworks.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 |
4 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
5 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
6 |
7 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
8 |
9 | install_framework()
10 | {
11 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
12 | local source="${BUILT_PRODUCTS_DIR}/$1"
13 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
14 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
15 | elif [ -r "$1" ]; then
16 | local source="$1"
17 | fi
18 |
19 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
20 |
21 | if [ -L "${source}" ]; then
22 | echo "Symlinked..."
23 | source="$(readlink "${source}")"
24 | fi
25 |
26 | # use filter instead of exclude so missing patterns dont' throw errors
27 | echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
28 | rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
29 |
30 | local basename
31 | basename="$(basename -s .framework "$1")"
32 | binary="${destination}/${basename}.framework/${basename}"
33 | if ! [ -r "$binary" ]; then
34 | binary="${destination}/${basename}"
35 | fi
36 |
37 | # Strip invalid architectures so "fat" simulator / device frameworks work on device
38 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
39 | strip_invalid_archs "$binary"
40 | fi
41 |
42 | # Resign the code if required by the build settings to avoid unstable apps
43 | code_sign_if_enabled "${destination}/$(basename "$1")"
44 |
45 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
46 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
47 | local swift_runtime_libs
48 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]})
49 | for lib in $swift_runtime_libs; do
50 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
51 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
52 | code_sign_if_enabled "${destination}/${lib}"
53 | done
54 | fi
55 | }
56 |
57 | # Signs a framework with the provided identity
58 | code_sign_if_enabled() {
59 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
60 | # Use the current code_sign_identitiy
61 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
62 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements '$1'"
63 |
64 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
65 | code_sign_cmd="$code_sign_cmd &"
66 | fi
67 | echo "$code_sign_cmd"
68 | eval "$code_sign_cmd"
69 | fi
70 | }
71 |
72 | # Strip invalid architectures
73 | strip_invalid_archs() {
74 | binary="$1"
75 | # Get architectures for current file
76 | archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)"
77 | stripped=""
78 | for arch in $archs; do
79 | if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then
80 | # Strip non-valid architectures in-place
81 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1
82 | stripped="$stripped $arch"
83 | fi
84 | done
85 | if [[ "$stripped" ]]; then
86 | echo "Stripped $binary of architectures:$stripped"
87 | fi
88 | }
89 |
90 |
91 | if [[ "$CONFIGURATION" == "Debug" ]]; then
92 | install_framework "$BUILT_PRODUCTS_DIR/Kingfisher/Kingfisher.framework"
93 | fi
94 | if [[ "$CONFIGURATION" == "Release" ]]; then
95 | install_framework "$BUILT_PRODUCTS_DIR/Kingfisher/Kingfisher.framework"
96 | fi
97 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
98 | wait
99 | fi
100 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Target Support Files/Pods-WRCycleScrollViewDemo/Pods-WRCycleScrollViewDemo-resources.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 |
4 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
5 |
6 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt
7 | > "$RESOURCES_TO_COPY"
8 |
9 | XCASSET_FILES=()
10 |
11 | case "${TARGETED_DEVICE_FAMILY}" in
12 | 1,2)
13 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
14 | ;;
15 | 1)
16 | TARGET_DEVICE_ARGS="--target-device iphone"
17 | ;;
18 | 2)
19 | TARGET_DEVICE_ARGS="--target-device ipad"
20 | ;;
21 | 3)
22 | TARGET_DEVICE_ARGS="--target-device tv"
23 | ;;
24 | 4)
25 | TARGET_DEVICE_ARGS="--target-device watch"
26 | ;;
27 | *)
28 | TARGET_DEVICE_ARGS="--target-device mac"
29 | ;;
30 | esac
31 |
32 | install_resource()
33 | {
34 | if [[ "$1" = /* ]] ; then
35 | RESOURCE_PATH="$1"
36 | else
37 | RESOURCE_PATH="${PODS_ROOT}/$1"
38 | fi
39 | if [[ ! -e "$RESOURCE_PATH" ]] ; then
40 | cat << EOM
41 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script.
42 | EOM
43 | exit 1
44 | fi
45 | case $RESOURCE_PATH in
46 | *.storyboard)
47 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}"
48 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
49 | ;;
50 | *.xib)
51 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}"
52 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
53 | ;;
54 | *.framework)
55 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
56 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
57 | echo "rsync -av $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
58 | rsync -av "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
59 | ;;
60 | *.xcdatamodel)
61 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\""
62 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom"
63 | ;;
64 | *.xcdatamodeld)
65 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\""
66 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd"
67 | ;;
68 | *.xcmappingmodel)
69 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\""
70 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm"
71 | ;;
72 | *.xcassets)
73 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH"
74 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE")
75 | ;;
76 | *)
77 | echo "$RESOURCE_PATH"
78 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY"
79 | ;;
80 | esac
81 | }
82 |
83 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
84 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
85 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then
86 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
87 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
88 | fi
89 | rm -f "$RESOURCES_TO_COPY"
90 |
91 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ]
92 | then
93 | # Find all other xcassets (this unfortunately includes those of path pods and other targets).
94 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d)
95 | while read line; do
96 | if [[ $line != "${PODS_ROOT}*" ]]; then
97 | XCASSET_FILES+=("$line")
98 | fi
99 | done <<<"$OTHER_XCASSETS"
100 |
101 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
102 | fi
103 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Target Support Files/Pods-WRCycleScrollViewDemo/Pods-WRCycleScrollViewDemo-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double Pods_WRCycleScrollViewDemoVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char Pods_WRCycleScrollViewDemoVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Target Support Files/Pods-WRCycleScrollViewDemo/Pods-WRCycleScrollViewDemo.debug.xcconfig:
--------------------------------------------------------------------------------
1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/Kingfisher"
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
5 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/Kingfisher/Kingfisher.framework/Headers"
6 | OTHER_LDFLAGS = $(inherited) -framework "Kingfisher"
7 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
8 | PODS_BUILD_DIR = $BUILD_DIR
9 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
11 | PODS_ROOT = ${SRCROOT}/Pods
12 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Target Support Files/Pods-WRCycleScrollViewDemo/Pods-WRCycleScrollViewDemo.modulemap:
--------------------------------------------------------------------------------
1 | framework module Pods_WRCycleScrollViewDemo {
2 | umbrella header "Pods-WRCycleScrollViewDemo-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/Pods/Target Support Files/Pods-WRCycleScrollViewDemo/Pods-WRCycleScrollViewDemo.release.xcconfig:
--------------------------------------------------------------------------------
1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/Kingfisher"
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
5 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/Kingfisher/Kingfisher.framework/Headers"
6 | OTHER_LDFLAGS = $(inherited) -framework "Kingfisher"
7 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
8 | PODS_BUILD_DIR = $BUILD_DIR
9 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
11 | PODS_ROOT = ${SRCROOT}/Pods
12 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // WRCycleScrollViewDemo
4 | //
5 | // Created by wangrui on 2017/5/12.
6 | // Copyright © 2017年 wangrui. All rights reserved.
7 | //
8 | // Github地址:https://github.com/wangrui460/WRCycleScrollView
9 |
10 | import UIKit
11 |
12 | let MainNavBarColor = UIColor.init(red: 0/255.0, green: 175/255.0, blue: 240/255.0, alpha: 1)
13 | let kScreenWidth = UIScreen.main.bounds.width
14 | let kScreenHeight = UIScreen.main.bounds.height
15 | let kTabBarHeight = 49
16 | let kNavBarBottom = 64
17 | let kNavBarHeight = 44
18 |
19 | @UIApplicationMain
20 | class AppDelegate: UIResponder, UIApplicationDelegate
21 | {
22 | var window: UIWindow?
23 |
24 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool
25 | {
26 |
27 | window = UIWindow.init(frame: UIScreen.main.bounds)
28 | window?.backgroundColor = UIColor.white
29 |
30 | let nav = BaseNavigationController.init(rootViewController: DemoListController())
31 | window?.rootViewController = nav
32 | window?.makeKeyAndVisible()
33 |
34 | setNavBarAppearence()
35 |
36 | return true
37 | }
38 |
39 | func setNavBarAppearence()
40 | {
41 | UIColor.defaultStatusBarStyle = .lightContent
42 | UIColor.defaultNavBarTintColor = UIColor.white
43 | UIColor.defaultNavBarBarTintColor = MainNavBarColor
44 | UIColor.defaultNavBarTitleColor = UIColor.white
45 | }
46 | }
47 |
48 | class BaseNavigationController: UINavigationController
49 | {
50 | override func pushViewController(_ viewController: UIViewController, animated: Bool)
51 | {
52 | if childViewControllers.count > 0 {
53 | viewController.hidesBottomBarWhenPushed = true
54 | }
55 | super.pushViewController(viewController, animated: animated)
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "60x60",
35 | "idiom" : "iphone",
36 | "filename" : "wr@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "60x60",
41 | "idiom" : "iphone",
42 | "filename" : "wr@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "idiom" : "ipad",
47 | "size" : "20x20",
48 | "scale" : "1x"
49 | },
50 | {
51 | "idiom" : "ipad",
52 | "size" : "20x20",
53 | "scale" : "2x"
54 | },
55 | {
56 | "idiom" : "ipad",
57 | "size" : "29x29",
58 | "scale" : "1x"
59 | },
60 | {
61 | "idiom" : "ipad",
62 | "size" : "29x29",
63 | "scale" : "2x"
64 | },
65 | {
66 | "idiom" : "ipad",
67 | "size" : "40x40",
68 | "scale" : "1x"
69 | },
70 | {
71 | "idiom" : "ipad",
72 | "size" : "40x40",
73 | "scale" : "2x"
74 | },
75 | {
76 | "idiom" : "ipad",
77 | "size" : "76x76",
78 | "scale" : "1x"
79 | },
80 | {
81 | "idiom" : "ipad",
82 | "size" : "76x76",
83 | "scale" : "2x"
84 | },
85 | {
86 | "idiom" : "ipad",
87 | "size" : "83.5x83.5",
88 | "scale" : "2x"
89 | },
90 | {
91 | "idiom" : "ios-marketing",
92 | "size" : "1024x1024",
93 | "scale" : "1x"
94 | }
95 | ],
96 | "info" : {
97 | "version" : 1,
98 | "author" : "xcode"
99 | }
100 | }
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/AppIcon.appiconset/wr@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangrui460/WRCycleScrollView/d48d12003bb5c5d7c3e52abec63510b5b5c692e5/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/AppIcon.appiconset/wr@2x.png
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/AppIcon.appiconset/wr@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangrui460/WRCycleScrollView/d48d12003bb5c5d7c3e52abec63510b5b5c692e5/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/AppIcon.appiconset/wr@3x.png
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/LaunchImage.launchimage/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "orientation" : "portrait",
5 | "idiom" : "ipad",
6 | "minimum-system-version" : "7.0",
7 | "extent" : "full-screen",
8 | "scale" : "2x"
9 | },
10 | {
11 | "orientation" : "landscape",
12 | "idiom" : "ipad",
13 | "minimum-system-version" : "7.0",
14 | "extent" : "full-screen",
15 | "scale" : "1x"
16 | },
17 | {
18 | "orientation" : "landscape",
19 | "idiom" : "ipad",
20 | "minimum-system-version" : "7.0",
21 | "extent" : "full-screen",
22 | "scale" : "2x"
23 | },
24 | {
25 | "orientation" : "portrait",
26 | "idiom" : "iphone",
27 | "minimum-system-version" : "7.0",
28 | "scale" : "2x"
29 | },
30 | {
31 | "orientation" : "portrait",
32 | "idiom" : "iphone",
33 | "minimum-system-version" : "7.0",
34 | "subtype" : "retina4",
35 | "scale" : "2x"
36 | },
37 | {
38 | "orientation" : "portrait",
39 | "idiom" : "ipad",
40 | "minimum-system-version" : "7.0",
41 | "extent" : "full-screen",
42 | "scale" : "1x"
43 | }
44 | ],
45 | "info" : {
46 | "version" : 1,
47 | "author" : "xcode"
48 | }
49 | }
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/dot/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/dot/currentDot.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "slider_current_dot.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "slider_current_dot@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "slider_current_dot@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/dot/currentDot.imageset/slider_current_dot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangrui460/WRCycleScrollView/d48d12003bb5c5d7c3e52abec63510b5b5c692e5/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/dot/currentDot.imageset/slider_current_dot.png
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/dot/currentDot.imageset/slider_current_dot@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangrui460/WRCycleScrollView/d48d12003bb5c5d7c3e52abec63510b5b5c692e5/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/dot/currentDot.imageset/slider_current_dot@2x.png
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/dot/currentDot.imageset/slider_current_dot@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangrui460/WRCycleScrollView/d48d12003bb5c5d7c3e52abec63510b5b5c692e5/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/dot/currentDot.imageset/slider_current_dot@3x.png
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/dot/defaultDot.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "slider_default_dot.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "slider_default_dot@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "slider_default_dot@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/dot/defaultDot.imageset/slider_default_dot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangrui460/WRCycleScrollView/d48d12003bb5c5d7c3e52abec63510b5b5c692e5/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/dot/defaultDot.imageset/slider_default_dot.png
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/dot/defaultDot.imageset/slider_default_dot@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangrui460/WRCycleScrollView/d48d12003bb5c5d7c3e52abec63510b5b5c692e5/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/dot/defaultDot.imageset/slider_default_dot@2x.png
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/dot/defaultDot.imageset/slider_default_dot@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangrui460/WRCycleScrollView/d48d12003bb5c5d7c3e52abec63510b5b5c692e5/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/dot/defaultDot.imageset/slider_default_dot@3x.png
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/image11.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "image11.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/image11.imageset/image11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangrui460/WRCycleScrollView/d48d12003bb5c5d7c3e52abec63510b5b5c692e5/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/image11.imageset/image11.png
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/image12.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "image12.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/image12.imageset/image12.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangrui460/WRCycleScrollView/d48d12003bb5c5d7c3e52abec63510b5b5c692e5/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/image12.imageset/image12.jpg
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/image13.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "image13.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/image13.imageset/image13.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangrui460/WRCycleScrollView/d48d12003bb5c5d7c3e52abec63510b5b5c692e5/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/image13.imageset/image13.png
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/image14.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "image14.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/image14.imageset/image14.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangrui460/WRCycleScrollView/d48d12003bb5c5d7c3e52abec63510b5b5c692e5/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/image14.imageset/image14.jpg
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/image15.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "image15.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/image15.imageset/image15.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangrui460/WRCycleScrollView/d48d12003bb5c5d7c3e52abec63510b5b5c692e5/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/image15.imageset/image15.jpg
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/localImg1.imageset/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangrui460/WRCycleScrollView/d48d12003bb5c5d7c3e52abec63510b5b5c692e5/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/localImg1.imageset/1.png
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/localImg1.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "1.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/localImg10.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "localImg10.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/localImg10.imageset/localImg10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangrui460/WRCycleScrollView/d48d12003bb5c5d7c3e52abec63510b5b5c692e5/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/localImg10.imageset/localImg10.jpg
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/localImg2.imageset/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangrui460/WRCycleScrollView/d48d12003bb5c5d7c3e52abec63510b5b5c692e5/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/localImg2.imageset/2.png
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/localImg2.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "2.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/localImg3.imageset/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangrui460/WRCycleScrollView/d48d12003bb5c5d7c3e52abec63510b5b5c692e5/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/localImg3.imageset/3.png
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/localImg3.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "3.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/localImg4.imageset/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangrui460/WRCycleScrollView/d48d12003bb5c5d7c3e52abec63510b5b5c692e5/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/localImg4.imageset/4.png
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/localImg4.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "4.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/localImg5.imageset/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangrui460/WRCycleScrollView/d48d12003bb5c5d7c3e52abec63510b5b5c692e5/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/localImg5.imageset/5.png
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/localImg5.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "5.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/localImg6.imageset/6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangrui460/WRCycleScrollView/d48d12003bb5c5d7c3e52abec63510b5b5c692e5/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/localImg6.imageset/6.jpg
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/localImg6.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "6.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/localImg7.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "localImg7.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/localImg7.imageset/localImg7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangrui460/WRCycleScrollView/d48d12003bb5c5d7c3e52abec63510b5b5c692e5/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/localImg7.imageset/localImg7.jpg
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/localImg8.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "localImg8.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/localImg8.imageset/localImg8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangrui460/WRCycleScrollView/d48d12003bb5c5d7c3e52abec63510b5b5c692e5/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/localImg8.imageset/localImg8.jpg
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/localImg9.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "localImg9.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/localImg9.imageset/localImg9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangrui460/WRCycleScrollView/d48d12003bb5c5d7c3e52abec63510b5b5c692e5/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/localImg9.imageset/localImg9.jpg
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/placeholder/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/placeholder/placeholder_720x360.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "placeholder_720x360@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "placeholder_720x360@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/placeholder/placeholder_720x360.imageset/placeholder_720x360@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangrui460/WRCycleScrollView/d48d12003bb5c5d7c3e52abec63510b5b5c692e5/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/placeholder/placeholder_720x360.imageset/placeholder_720x360@2x.png
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/placeholder/placeholder_720x360.imageset/placeholder_720x360@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangrui460/WRCycleScrollView/d48d12003bb5c5d7c3e52abec63510b5b5c692e5/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Assets.xcassets/placeholder/placeholder_720x360.imageset/placeholder_720x360@3x.png
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/CustomDotController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CustomDotController.swift
3 | // WRCycleScrollViewDemo
4 | //
5 | // Created by itwangrui on 2017/11/14.
6 | // Copyright © 2017年 wangrui. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class CustomDotController: UIViewController
12 | {
13 | var cycleScrollView:WRCycleScrollView?
14 |
15 | override func viewDidLoad()
16 | {
17 | super.viewDidLoad()
18 | view.backgroundColor = UIColor.white
19 | self.title = "网络URL"
20 |
21 | let height = 520 * kScreenWidth / 1080.0
22 | let frame = CGRect(x: 0, y: 150, width: kScreenWidth, height: height)
23 | let serverImages = ["http://p.lrlz.com/data/upload/mobile/special/s252/s252_05471521705899113.png",
24 | "http://p.lrlz.com/data/upload/mobile/special/s303/s303_05442007678060723.png",
25 | "http://p.lrlz.com/data/upload/mobile/special/s303/s303_05442007587372591.png",
26 | "http://p.lrlz.com/data/upload/mobile/special/s303/s303_05442007388249407.png",
27 | "http://p.lrlz.com/data/upload/mobile/special/s303/s303_05442007470310935.png"]
28 | cycleScrollView = WRCycleScrollView(frame: frame, type: .SERVER, imgs: serverImages)
29 | cycleScrollView?.defaultPageDotImage = UIImage(named: "defaultDot")
30 | cycleScrollView?.currentPageDotImage = UIImage(named: "currentDot")
31 | view.addSubview(cycleScrollView!)
32 | cycleScrollView?.delegate = self
33 | }
34 | }
35 |
36 | extension CustomDotController: WRCycleScrollViewDelegate
37 | {
38 | /// 点击图片事件
39 | func cycleScrollViewDidSelect(at index:Int, cycleScrollView:WRCycleScrollView)
40 | {
41 | print("点击了第\(index+1)个图片")
42 | }
43 | /// 图片滚动事件
44 | func cycleScrollViewDidScroll(to index:Int, cycleScrollView:WRCycleScrollView)
45 | {
46 | print("滚动到了第\(index+1)个图片")
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/DemoListController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DemoListController.swift
3 | // WRCycleScrollViewDemo
4 | //
5 | // Created by wangrui on 2017/4/19.
6 | // Copyright © 2017年 wangrui. All rights reserved.
7 | //
8 | // Github地址:https://github.com/wangrui460/WRCycleScrollView
9 |
10 | import UIKit
11 |
12 | class DemoListController: UIViewController
13 | {
14 | lazy var tableView:UITableView = UITableView(frame: CGRect.init(x: 0, y: 0, width: kScreenWidth, height: self.view.bounds.height), style: .plain)
15 |
16 | override func viewDidLoad() {
17 | super.viewDidLoad()
18 | view.backgroundColor = UIColor.green
19 | title = "WRCycleScrollView"
20 | view.addSubview(tableView)
21 | tableView.dataSource = self
22 | tableView.delegate = self
23 | }
24 | }
25 |
26 | // MARK: - tableView delegate / dataSource
27 | extension DemoListController: UITableViewDelegate, UITableViewDataSource
28 | {
29 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
30 | {
31 | return 8
32 | }
33 |
34 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
35 | {
36 | let cell = UITableViewCell.init(style: .default, reuseIdentifier: nil)
37 | var str:String? = nil
38 | switch indexPath.row {
39 | case 0:
40 | str = "本地图片"
41 | case 1:
42 | str = "网络URL"
43 | case 2:
44 | str = "支持StoryBoard创建"
45 | case 3:
46 | str = "不无限轮播"
47 | case 4:
48 | str = "不显示pageControl"
49 | case 5:
50 | str = "知乎日报效果"
51 | case 6:
52 | str = "自定义dot"
53 | case 7:
54 | str = "独立出dot"
55 | default:
56 | str = ""
57 | }
58 | cell.textLabel?.text = str
59 | cell.textLabel?.font = UIFont.systemFont(ofSize: 15)
60 | return cell
61 | }
62 |
63 | func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
64 | return 60
65 | }
66 |
67 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
68 | {
69 | tableView.deselectRow(at: indexPath, animated: true)
70 | switch indexPath.row {
71 | case 0:
72 | navigationController?.pushViewController(LocalImgController(), animated: true)
73 | case 1:
74 | navigationController?.pushViewController(ServerImgController(), animated: true)
75 | case 2:
76 |
77 | let SBVC:SBController = UIStoryboard.init(name: "StoryBoardController", bundle: nil).instantiateInitialViewController() as! SBController
78 | navigationController?.pushViewController(SBVC, animated: true)
79 | case 3:
80 | navigationController?.pushViewController(NoEndlessController(), animated: true)
81 | case 4:
82 | navigationController?.pushViewController(NoPageControlController(), animated: true)
83 | case 5:
84 | navigationController?.pushViewController(ZhiHuController(), animated: true)
85 | case 6:
86 | navigationController?.pushViewController(CustomDotController(), animated: true)
87 | case 7:
88 | navigationController?.pushViewController(StandaloneDotController(), animated: true)
89 | default:
90 | break
91 | }
92 | }
93 | }
94 |
95 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIcons
10 |
11 | CFBundleIcons~ipad
12 |
13 | CFBundleIdentifier
14 | $(PRODUCT_BUNDLE_IDENTIFIER)
15 | CFBundleInfoDictionaryVersion
16 | 6.0
17 | CFBundleName
18 | $(PRODUCT_NAME)
19 | CFBundlePackageType
20 | APPL
21 | CFBundleShortVersionString
22 | 1.0
23 | CFBundleVersion
24 | 1
25 | LSRequiresIPhoneOS
26 |
27 | NSAppTransportSecurity
28 |
29 | NSAllowsArbitraryLoads
30 |
31 |
32 | UILaunchStoryboardName
33 | LaunchScreen
34 | UIRequiredDeviceCapabilities
35 |
36 | armv7
37 |
38 | UISupportedInterfaceOrientations
39 |
40 | UIInterfaceOrientationPortrait
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 | UISupportedInterfaceOrientations~ipad
45 |
46 | UIInterfaceOrientationPortrait
47 | UIInterfaceOrientationPortraitUpsideDown
48 | UIInterfaceOrientationLandscapeLeft
49 | UIInterfaceOrientationLandscapeRight
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/LocalImgController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // WRCycleScrollViewDemo
4 | //
5 | // Created by wangrui on 2017/5/12.
6 | // Copyright © 2017年 wangrui. All rights reserved.
7 | //
8 | // Github地址:https://github.com/wangrui460/WRCycleScrollView
9 |
10 | import UIKit
11 |
12 | class LocalImgController: UIViewController
13 | {
14 | var cycleScrollView:WRCycleScrollView?
15 |
16 | override func viewDidLoad()
17 | {
18 | super.viewDidLoad()
19 | view.backgroundColor = UIColor.white
20 | self.title = "本地图片"
21 |
22 | let height:CGFloat = 200
23 | let frame = CGRect(x: 0, y: 150, width: kScreenWidth, height: height)
24 | let localImages = ["localImg6","localImg7","localImg8","localImg9","localImg10"]
25 | let descs = ["韩国防部回应停止部署萨德:遵照最高统帅指导方针",
26 | "勒索病毒攻击再次爆发 国内校园网大面积感染",
27 | "Win10秋季更新重磅功能:跟安卓与iOS无缝连接",
28 | "《琅琊榜2》为何没有胡歌?胡歌:我看过剧本,离开是种保护",
29 | "阿米尔汗在印度的影响力,我国的哪位影视明星能与之齐名呢?"]
30 | cycleScrollView = WRCycleScrollView(frame:frame, type:.LOCAL, imgs:localImages, descs:descs)
31 | cycleScrollView!.delegate = self
32 | cycleScrollView?.descLabelFont = UIFont.boldSystemFont(ofSize: 15)
33 | cycleScrollView?.descLabelHeight = 50
34 | cycleScrollView?.pageControlAliment = .RightBottom
35 | view.addSubview(cycleScrollView!)
36 | }
37 | }
38 |
39 | extension LocalImgController: WRCycleScrollViewDelegate
40 | {
41 | /// 点击图片回调
42 | func cycleScrollViewDidSelect(at index:Int, cycleScrollView:WRCycleScrollView)
43 | {
44 | print("点击了第\(index+1)个图片")
45 | }
46 | /// 图片滚动回调
47 | func cycleScrollViewDidScroll(to index:Int, cycleScrollView:WRCycleScrollView)
48 | {
49 | print("滚动到了第\(index+1)个图片")
50 | }
51 | }
52 |
53 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/NoEndlessController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ServerImgController.swift
3 | // WRCycleScrollViewDemo
4 | //
5 | // Created by wangrui on 2017/5/12.
6 | // Copyright © 2017年 wangrui. All rights reserved.
7 | //
8 | // Github地址:https://github.com/wangrui460/WRCycleScrollView
9 |
10 | import UIKit
11 |
12 | class NoEndlessController: UIViewController
13 | {
14 | var cycleScrollView:WRCycleScrollView?
15 |
16 | override func viewDidLoad()
17 | {
18 | super.viewDidLoad()
19 | view.backgroundColor = UIColor.white
20 | self.title = "不无限轮播"
21 |
22 | let height = 520 * kScreenWidth / 1080.0
23 | let frame = CGRect(x: 0, y: 150, width: kScreenWidth, height: height)
24 | let serverImages = ["http://p.lrlz.com/data/upload/mobile/special/s252/s252_05471521705899113.png",
25 | "http://p.lrlz.com/data/upload/mobile/special/s303/s303_05442007678060723.png",
26 | "http://p.lrlz.com/data/upload/mobile/special/s303/s303_05442007587372591.png",
27 | "http://p.lrlz.com/data/upload/mobile/special/s303/s303_05442007388249407.png",
28 | "http://p.lrlz.com/data/upload/mobile/special/s303/s303_05442007470310935.png"]
29 | cycleScrollView = WRCycleScrollView(frame: frame, type: .SERVER, imgs: serverImages)
30 | view.addSubview(cycleScrollView!)
31 | cycleScrollView?.delegate = self
32 | cycleScrollView?.isEndlessScroll = false
33 | }
34 | }
35 |
36 | extension NoEndlessController: WRCycleScrollViewDelegate
37 | {
38 | /// 点击图片回调
39 | func cycleScrollViewDidSelect(at index:Int, cycleScrollView:WRCycleScrollView)
40 | {
41 | print("点击了第\(index+1)个图片")
42 | }
43 | /// 图片滚动回调
44 | func cycleScrollViewDidScroll(to index:Int, cycleScrollView:WRCycleScrollView)
45 | {
46 | print("滚动到了第\(index+1)个图片")
47 | }
48 | }
49 |
50 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/NoPageControlController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // WRCycleScrollViewDemo
4 | //
5 | // Created by wangrui on 2017/5/12.
6 | // Copyright © 2017年 wangrui. All rights reserved.
7 | //
8 | // Github地址:https://github.com/wangrui460/WRCycleScrollView
9 |
10 | import UIKit
11 |
12 | class NoPageControlController: UIViewController
13 | {
14 | var cycleScrollView:WRCycleScrollView?
15 |
16 | override func viewDidLoad()
17 | {
18 | super.viewDidLoad()
19 | view.backgroundColor = UIColor.white
20 | self.title = "不显示pageControl"
21 |
22 | let height:CGFloat = 110
23 | let frame = CGRect(x: 0, y: 150, width: kScreenWidth, height: height)
24 | let localImages = ["image11","image13","image15"]
25 | cycleScrollView = WRCycleScrollView(frame:frame, type:.LOCAL, imgs:localImages)
26 | cycleScrollView!.delegate = self
27 | cycleScrollView?.showPageControl = false
28 | cycleScrollView?.imageContentModel = .scaleToFill
29 | view.addSubview(cycleScrollView!)
30 | }
31 | }
32 |
33 | extension NoPageControlController: WRCycleScrollViewDelegate
34 | {
35 | /// 点击图片回调
36 | func cycleScrollViewDidSelect(at index:Int, cycleScrollView:WRCycleScrollView)
37 | {
38 | print("点击了第\(index+1)个图片")
39 | }
40 | /// 图片滚动回调
41 | func cycleScrollViewDidScroll(to index:Int, cycleScrollView:WRCycleScrollView)
42 | {
43 | print("滚动到了第\(index+1)个图片")
44 | }
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/SBController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SBController.swift
3 | // WRCycleScrollViewDemo
4 | //
5 | // Created by wangrui on 2017/6/21.
6 | // Copyright © 2017年 wangrui. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class SBController: UIViewController
12 | {
13 |
14 | @IBOutlet weak var cycleScrollView: WRCycleScrollView!
15 |
16 | override func viewDidLoad() {
17 | super.viewDidLoad()
18 | view.backgroundColor = UIColor.white
19 | self.title = "StoryBoard创建"
20 |
21 | let localImages = ["localImg6","localImg7","localImg8","localImg9","localImg10"]
22 | let descs = ["韩国防部回应停止部署萨德:遵照最高统帅指导方针",
23 | " 勒索病毒攻击再次爆发 国内校园网大面积感染,Mac什么事都没有",
24 | "Win10秋季更新重磅功能:跟安卓与iOS无缝连接",
25 | "《琅琊榜2》为何没有胡歌?胡歌:我看过剧本,离开是种保护",
26 | "阿米尔汗在印度的影响力,我国的哪位影视明星能与之齐名呢?"]
27 |
28 | cycleScrollView.delegate = self
29 | view.addSubview(cycleScrollView)
30 | cycleScrollView.localImgArray = localImages
31 | cycleScrollView.descTextArray = descs
32 | cycleScrollView.descLabelHeight = 40
33 | cycleScrollView.descLabelFont = UIFont.systemFont(ofSize: 13)
34 | cycleScrollView.pageControlAliment = .RightBottom
35 | }
36 | }
37 |
38 |
39 | extension SBController: WRCycleScrollViewDelegate
40 | {
41 | /// 点击图片回调
42 | func cycleScrollViewDidSelect(at index:Int, cycleScrollView:WRCycleScrollView)
43 | {
44 | print("点击了第\(index+1)个图片")
45 | }
46 | /// 图片滚动回调
47 | func cycleScrollViewDidScroll(to index:Int, cycleScrollView:WRCycleScrollView)
48 | {
49 | print("滚动到了第\(index+1)个图片")
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/ServerImgController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ServerImgController.swift
3 | // WRCycleScrollViewDemo
4 | //
5 | // Created by wangrui on 2017/5/12.
6 | // Copyright © 2017年 wangrui. All rights reserved.
7 | //
8 | // Github地址:https://github.com/wangrui460/WRCycleScrollView
9 |
10 | import UIKit
11 |
12 | class ServerImgController: UIViewController
13 | {
14 | var cycleScrollView:WRCycleScrollView?
15 |
16 | override func viewDidLoad()
17 | {
18 | super.viewDidLoad()
19 | view.backgroundColor = UIColor.white
20 | self.title = "网络URL"
21 |
22 | let height = 520 * kScreenWidth / 1080.0
23 | let frame = CGRect(x: 0, y: 150, width: kScreenWidth, height: height)
24 | let serverImages = ["http://p.lrlz.com/data/upload/mobile/special/s252/s252_05471521705899113.png",
25 | "http://p.lrlz.com/data/upload/mobile/special/s303/s303_05442007678060723.png",
26 | "http://p.lrlz.com/data/upload/mobile/special/s303/s303_05442007587372591.png",
27 | "http://p.lrlz.com/data/upload/mobile/special/s303/s303_05442007388249407.png",
28 | "http://p.lrlz.com/data/upload/mobile/special/s303/s303_05442007470310935.png"]
29 | cycleScrollView = WRCycleScrollView(frame: frame, type: .SERVER, imgs: serverImages)
30 | view.addSubview(cycleScrollView!)
31 | cycleScrollView?.delegate = self
32 | }
33 | }
34 |
35 | extension ServerImgController: WRCycleScrollViewDelegate
36 | {
37 | /// 点击图片事件
38 | func cycleScrollViewDidSelect(at index:Int, cycleScrollView:WRCycleScrollView)
39 | {
40 | print("点击了第\(index+1)个图片")
41 | }
42 | /// 图片滚动事件
43 | func cycleScrollViewDidScroll(to index:Int, cycleScrollView:WRCycleScrollView)
44 | {
45 | print("滚动到了第\(index+1)个图片")
46 | }
47 | }
48 |
49 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/StandaloneDotController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StandaloneDotController.swift
3 | // WRCycleScrollViewDemo
4 | //
5 | // Created by itwangrui on 2017/11/14.
6 | // Copyright © 2017年 wangrui. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class StandaloneDotController: UIViewController {
12 |
13 | var cycleScrollView:WRCycleScrollView?
14 |
15 | override func viewDidLoad()
16 | {
17 | super.viewDidLoad()
18 | view.backgroundColor = UIColor.white
19 | self.title = "网络URL"
20 |
21 | let cycleScrollViewHeightTop:CGFloat = 150
22 | let cycleScrollViewHeight = 520 * kScreenWidth / 1080.0
23 | let cycleScrollViewFrame = CGRect(x: 0, y: cycleScrollViewHeightTop, width: kScreenWidth, height: cycleScrollViewHeight)
24 | let serverImages = ["http://p.lrlz.com/data/upload/mobile/special/s252/s252_05471521705899113.png",
25 | "http://p.lrlz.com/data/upload/mobile/special/s303/s303_05442007678060723.png",
26 | "http://p.lrlz.com/data/upload/mobile/special/s303/s303_05442007587372591.png",
27 | "http://p.lrlz.com/data/upload/mobile/special/s303/s303_05442007388249407.png",
28 | "http://p.lrlz.com/data/upload/mobile/special/s303/s303_05442007470310935.png"]
29 | cycleScrollView = WRCycleScrollView(frame: cycleScrollViewFrame, type: .SERVER, imgs: serverImages, defaultDotImage: UIImage(named: "defaultDot"), currentDotImage: UIImage(named: "currentDot"))
30 | view.addSubview(cycleScrollView!)
31 | cycleScrollView?.delegate = self
32 | cycleScrollView?.pageControlPointSpace = 0
33 |
34 | let top = cycleScrollViewHeightTop + cycleScrollViewHeight + 16
35 | cycleScrollView?.outerPageControlFrame = CGRect(x: 16, y: top, width: 0, height: 0)
36 | }
37 | }
38 |
39 | extension StandaloneDotController: WRCycleScrollViewDelegate
40 | {
41 | /// 点击图片事件
42 | func cycleScrollViewDidSelect(at index:Int, cycleScrollView:WRCycleScrollView)
43 | {
44 | print("点击了第\(index+1)个图片")
45 | }
46 | /// 图片滚动事件
47 | func cycleScrollViewDidScroll(to index:Int, cycleScrollView:WRCycleScrollView)
48 | {
49 | print("滚动到了第\(index+1)个图片")
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/StoryBoardController.storyboard:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/WRCycleScrollView/WRCycleCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WRCycleCell.swift
3 | // WRCycleScrollViewDemo
4 | //
5 | // Created by wangrui on 2017/5/12.
6 | // Copyright © 2017年 wangrui. All rights reserved.
7 | //
8 | // Github地址:https://github.com/wangrui460/WRCycleScrollView
9 |
10 | import UIKit
11 | import Kingfisher
12 |
13 | class WRCycleCell: UICollectionViewCell
14 | {
15 | //=======================================================
16 | // MARK: 对外提供的属性
17 | //=======================================================
18 | var imgSource:ImgSource = ImgSource.LOCAL(name: "placeholder") {
19 | didSet {
20 | switch imgSource {
21 | case let .SERVER(url):
22 | imgView.kf.setImage(with: url)
23 | case let .LOCAL(name):
24 | imgView.image = UIImage(named: name)
25 | }
26 | }
27 | }
28 |
29 | var placeholderImage: UIImage?
30 |
31 | var descText:String? {
32 | didSet {
33 | descLabel.isHidden = (descText == nil) ? true : false
34 | bottomView.isHidden = (descText == nil) ? true : false
35 | descLabel.text = descText
36 | }
37 | }
38 |
39 | override var frame: CGRect {
40 | didSet {
41 | bounds.size = frame.size
42 | }
43 | }
44 |
45 | var imageContentModel:UIViewContentMode = .scaleAspectFill {
46 | didSet {
47 | imgView.contentMode = imageContentModel
48 | }
49 | }
50 |
51 | var descLabelFont: UIFont = UIFont(name: "Helvetica-Bold", size: 18)! {
52 | didSet {
53 | descLabel.font = descLabelFont
54 | }
55 | }
56 | var descLabelTextColor: UIColor = UIColor.white {
57 | didSet {
58 | descLabel.textColor = descLabelTextColor
59 | }
60 | }
61 | var descLabelHeight: CGFloat = 60 {
62 | didSet {
63 | descLabel.frame.size.height = descLabelHeight
64 | }
65 | }
66 | var descLabelTextAlignment:NSTextAlignment = .left {
67 | didSet {
68 | descLabel.textAlignment = descLabelTextAlignment
69 | }
70 | }
71 | var bottomViewBackgroundColor: UIColor = UIColor.black.withAlphaComponent(0.5) {
72 | didSet {
73 | bottomView.backgroundColor = bottomViewBackgroundColor
74 | }
75 | }
76 |
77 | //=======================================================
78 | // MARK: 内部属性
79 | //=======================================================
80 | fileprivate var imgView:UIImageView!
81 | fileprivate var descLabel:UILabel!
82 | fileprivate var bottomView:UIView!
83 |
84 | //=======================================================
85 | // MARK: 构造方法
86 | //=======================================================
87 | override init(frame: CGRect)
88 | {
89 | super.init(frame: frame)
90 | backgroundColor = UIColor.white
91 | setupImgView()
92 | setupDescLabel()
93 | setupBottomView()
94 | }
95 | required init?(coder aDecoder: NSCoder) {
96 | fatalError("init(coder:) has not been implemented")
97 | }
98 | deinit {
99 | print("WRCycleCell deinit")
100 | }
101 |
102 |
103 | //=======================================================
104 | // MARK: 内部方法(layoutSubviews)
105 | //=======================================================
106 | override func layoutSubviews()
107 | {
108 | super.layoutSubviews()
109 | imgView.frame = self.bounds
110 |
111 | if let _ = descText
112 | {
113 | let margin:CGFloat = 16
114 | let labelWidth = imgView.bounds.width - 2 * margin
115 | let labelHeight = descLabelHeight
116 | let labelY = bounds.height - labelHeight
117 | descLabel.frame = CGRect(x: margin, y: labelY, width: labelWidth, height: labelHeight)
118 | bottomView.frame = CGRect(x: 0, y: labelY, width: imgView.bounds.width, height: labelHeight)
119 | bringSubview(toFront: descLabel)
120 | }
121 | }
122 | }
123 |
124 | //=======================================================
125 | // MARK: - 基本控件(图片、描述文字、底部view)
126 | //=======================================================
127 | extension WRCycleCell
128 | {
129 | fileprivate func setupImgView()
130 | {
131 | imgView = UIImageView()
132 | imgView.contentMode = imageContentModel
133 | imgView.clipsToBounds = true
134 | addSubview(imgView)
135 | }
136 |
137 | fileprivate func setupDescLabel()
138 | {
139 | descLabel = UILabel()
140 | descLabel.text = descText
141 | descLabel.numberOfLines = 0
142 | descLabel.font = descLabelFont
143 | descLabel.textColor = descLabelTextColor
144 | descLabel.frame.size.height = descLabelHeight
145 | descLabel.textAlignment = descLabelTextAlignment
146 | addSubview(descLabel)
147 | descLabel.isHidden = true
148 | }
149 |
150 | fileprivate func setupBottomView()
151 | {
152 | bottomView = UIView()
153 | bottomView.backgroundColor = bottomViewBackgroundColor
154 | addSubview(bottomView)
155 | bottomView.isHidden = true
156 | }
157 | }
158 |
159 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/WRCycleScrollView/WRPageControl.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WRPageControl.swift
3 | // WRCycleScrollViewDemo
4 | //
5 | // Created by itwangrui on 2017/11/14.
6 | // Copyright © 2017年 wangrui. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | private let WRPageControlPointWidth: CGFloat = 7
12 | private let WRPageControlPointHeight: CGFloat = 20
13 |
14 | class WRPageControl: UIPageControl
15 | {
16 | var currentImage: UIImage?
17 | var defaultImage: UIImage?
18 | var pointSpace: CGFloat = 15
19 | var pageSize: CGSize {
20 | get {
21 | if let curImage = currentImage, let defImage = defaultImage {
22 | let pageH = curImage.size.height
23 | let defDotW = defImage.size.width
24 | let curDotW = curImage.size.width
25 | let pageW = CGFloat(numberOfPages - 1) * (pointSpace + defDotW + defDotW) + curDotW
26 | return CGSize(width: pageW, height: pageH)
27 | }
28 | else {
29 | let pageW = CGFloat(numberOfPages - 1) * (pointSpace + WRPageControlPointWidth) + WRPageControlPointWidth
30 | return CGSize(width: pageW, height: WRPageControlPointHeight)
31 | }
32 | }
33 | }
34 |
35 | override var currentPage: Int {
36 | didSet {
37 | updatePageControl()
38 | }
39 | }
40 |
41 | init(frame: CGRect, currentImage: UIImage?, defaultImage: UIImage?)
42 | {
43 | super.init(frame: frame)
44 | self.currentImage = currentImage
45 | self.defaultImage = defaultImage
46 | }
47 | required init?(coder aDecoder: NSCoder) {
48 | fatalError("init(coder:) has not been implemented")
49 | }
50 | }
51 |
52 |
53 | // MARK: - update index
54 | extension WRPageControl
55 | {
56 | func updatePageControl()
57 | {
58 | for index in 0.. CGSize
92 | {
93 | var newSize = CGSize(width: 0, height: 0)
94 | if let curImage = currentImage, let defImage = defaultImage {
95 | if currentIndex == currentPage {
96 | newSize = curImage.size
97 | } else {
98 | newSize = defImage.size
99 | }
100 | } else {
101 | newSize = CGSize(width: WRPageControlPointWidth, height: WRPageControlPointWidth)
102 | }
103 | return newSize
104 | }
105 | }
106 |
107 |
108 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/WRCycleScrollView/WRProxy.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WRProxy.swift
3 | // WRCycleScrollViewDemo
4 | //
5 | // Created by wangrui on 2017/5/15.
6 | // Copyright © 2017年 wangrui. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | /////////////////////////////////////////////////////////////////////////////
12 | // MARK: 数据 相关
13 | /////////////////////////////////////////////////////////////////////////////
14 |
15 | // 图片资源
16 | enum ImgSource {
17 | case SERVER(url:URL)
18 | case LOCAL(name:String)
19 | }
20 |
21 | // 图片类型
22 | enum ImgType:Int {
23 | case SERVER = 0 // default
24 | case LOCAL = 1
25 | }
26 |
27 | struct Proxy
28 | {
29 | var imgType:ImgType = .SERVER
30 | var imgArray:[ImgSource] = [ImgSource]()
31 |
32 | // 下标法获取imgArray中对应索引的ImgSource eg: proxy[0] == imgArray[0]
33 | subscript (index:Int) -> ImgSource {
34 | get {
35 | return imgArray[index]
36 | }
37 | }
38 |
39 | // 构造方法
40 | init(type:ImgType, array:[String])
41 | {
42 | imgType = type
43 | if imgType == .SERVER
44 | {
45 | imgArray = array.map({ (urlStr) -> ImgSource in
46 | return ImgSource.SERVER(url: URL(string: urlStr)!)
47 | })
48 | }
49 | else
50 | {
51 | imgArray = array.map({ (name) -> ImgSource in
52 | return ImgSource.LOCAL(name: name)
53 | })
54 | }
55 | }
56 | }
57 |
58 |
59 | /////////////////////////////////////////////////////////////////////////////
60 | // MARK: pageControl 相关
61 | /////////////////////////////////////////////////////////////////////////////
62 |
63 | private let WRPageControlMargin: CGFloat = 15
64 | private let WRPageControlPointWidth: CGFloat = 2
65 |
66 | enum PageControlAliment {
67 | case CenterBottom
68 | case RightBottom
69 | case LeftBottom
70 | }
71 |
72 | protocol PageControlAlimentProtocol
73 | {
74 | // Property in protocol must have explicit { get } or { get set } specifier
75 | var pageControlAliment: PageControlAliment { get set }
76 | var pageControlPointSpace: CGFloat { get set }
77 | func relayoutPageControl(pageControl: WRPageControl)
78 | func relayoutPageControl(pageControl: WRPageControl, outerFrame:CGRect)
79 | }
80 |
81 | extension PageControlAlimentProtocol where Self : UIView
82 | { // TODO: 等待优化
83 | func relayoutPageControl(pageControl: WRPageControl)
84 | {
85 | if pageControl.isHidden == false
86 | {
87 | let pageH:CGFloat = 20//pageControl.pageSize.height
88 | let pageY = bounds.height - pageH
89 | let pageW = pageControl.pageSize.width
90 | var pageX:CGFloat = 0
91 |
92 | switch self.pageControlAliment {
93 | case .CenterBottom:
94 | pageX = CGFloat(self.bounds.width / 2) - pageW * 0.5
95 | case .RightBottom:
96 | pageX = bounds.width - pageW - WRPageControlMargin
97 | case .LeftBottom:
98 | pageX = bounds.origin.x + WRPageControlMargin
99 | }
100 | pageControl.frame = CGRect(x:pageX, y:pageY, width:pageW, height:pageH)
101 | }
102 | }
103 | func relayoutPageControl(pageControl: WRPageControl, outerFrame:CGRect)
104 | {
105 | if pageControl.isHidden == false {
106 | pageControl.frame = CGRect(x:outerFrame.origin.x, y:outerFrame.origin.y, width:pageControl.pageSize.width, height:pageControl.pageSize.height)
107 | }
108 | }
109 | }
110 |
111 |
112 | /////////////////////////////////////////////////////////////////////////////
113 | // MARK: 无限轮播 相关
114 | /////////////////////////////////////////////////////////////////////////////
115 |
116 | protocol EndlessScrollProtocol
117 | {
118 | /////////////////////////////////
119 | /// 是否自动滚动
120 | var isAutoScroll: Bool { get set }
121 | /// 自动滚动的时间间隔
122 | var autoScrollInterval: Double { get set }
123 | /// 用于自动滚动的定时器
124 | var timer:Timer? { get set }
125 |
126 | /////////////////////////////////
127 | /// 是否无限轮播
128 | var isEndlessScroll: Bool { get set }
129 | /// 无线轮播中,一组图片最多轮播多少次
130 | var endlessScrollTimes: Int { get }
131 | /// 真实的cell数量
132 | var itemsInSection: Int { get }
133 |
134 | /** 设置定时器,用于自动滚动 */
135 | func setupTimer()
136 |
137 | /** 滚动到第一个cell (在无限轮播中就是中间的那个cell) */
138 | func changeToFirstCycleCell(animated: Bool, collectionView: UICollectionView)
139 | }
140 |
141 | extension EndlessScrollProtocol where Self : UIView
142 | {
143 | func changeCycleCell(collectionView: UICollectionView)
144 | {
145 | guard itemsInSection != 0 else {
146 | return
147 | }
148 |
149 | let flowLayout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
150 | let curItem = Int(collectionView.contentOffset.x / flowLayout.itemSize.width)
151 | if curItem == itemsInSection - 1
152 | {
153 | let animated = (isEndlessScroll == true) ? false : true
154 | changeToFirstCycleCell(animated: animated, collectionView: collectionView)
155 | }
156 | else
157 | {
158 | let indexPath = IndexPath(item: curItem + 1, section: 0)
159 | collectionView.scrollToItem(at: indexPath, at: .init(rawValue: 0), animated: true)
160 | }
161 | }
162 |
163 | func changeToFirstCycleCell(animated: Bool, collectionView: UICollectionView)
164 | {
165 | guard itemsInSection != 0 else {
166 | return
167 | }
168 |
169 | let firstItem = (isEndlessScroll == true) ? (itemsInSection / 2) : 0
170 | let indexPath = IndexPath(item: firstItem, section: 0)
171 | collectionView.scrollToItem(at: indexPath, at: .init(rawValue: 0), animated: animated)
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 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemo/ZhiHuController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ZhiHuController.swift
3 | // ZhihuDaily-Swift3.0
4 | //
5 | // Created by wangrui on 2017/5/5.
6 | // Copyright © 2017年 wangrui. All rights reserved.
7 | //
8 | // Github地址:https://github.com/wangrui460/WRNavigationBar_swift
9 |
10 | import UIKit
11 |
12 | private let NAVBAR_COLORCHANGE_POINT:CGFloat = -80
13 | private let IMAGE_HEIGHT:CGFloat = 240
14 | private let SCROLL_DOWN_LIMIT:CGFloat = 100
15 | private let LIMIT_OFFSET_Y:CGFloat = -(IMAGE_HEIGHT + SCROLL_DOWN_LIMIT)
16 |
17 | class ZhiHuController: UIViewController
18 | {
19 | lazy var tableView:UITableView = {
20 | let table:UITableView = UITableView(frame: CGRect.init(x: 0, y: 0, width: Int(kScreenWidth), height: Int(self.view.bounds.height)), style: .plain)
21 | table.contentInset = UIEdgeInsetsMake(IMAGE_HEIGHT-CGFloat(kNavBarBottom), 0, 0, 0);
22 | table.showsVerticalScrollIndicator = false
23 | table.delegate = self
24 | table.dataSource = self
25 | return table
26 | }()
27 | lazy var cycleScrollView:WRCycleScrollView = {
28 | let frame = CGRect(x: 0, y: -IMAGE_HEIGHT, width: CGFloat(kScreenWidth), height: IMAGE_HEIGHT)
29 | let cycleView = WRCycleScrollView(frame: frame, type: .LOCAL, imgs: nil, descs: nil)
30 | return cycleView
31 | }()
32 |
33 | override func viewDidLoad()
34 | {
35 | super.viewDidLoad()
36 | self.title = "知乎日报"
37 | view.backgroundColor = UIColor.white
38 | let localImages = ["localImg6","localImg7","localImg8","localImg9","localImg10"]
39 | let descs = ["韩国防部回应停止部署萨德:遵照最高统帅指导方针",
40 | "勒索病毒攻击再次爆发 国内校园网大面积感染",
41 | "Win10秋季更新重磅功能:跟安卓与iOS无缝连接",
42 | "《琅琊榜2》为何没有胡歌?胡歌:我看过剧本,离开是种保护",
43 | "阿米尔汗在印度的影响力,我国的哪位影视明星能与之齐名呢?"]
44 | cycleScrollView.localImgArray = localImages
45 | cycleScrollView.descTextArray = descs
46 | cycleScrollView.descLabelFont = UIFont.boldSystemFont(ofSize: 16)
47 | tableView.addSubview(cycleScrollView)
48 | view.addSubview(tableView)
49 |
50 | navBarBarTintColor = MainNavBarColor
51 | navBarBackgroundAlpha = 0
52 | navBarTintColor = .white
53 | }
54 |
55 | deinit {
56 | tableView.delegate = nil
57 | print("ZhiHuVC deinit")
58 | }
59 | }
60 |
61 | // MARK: - ScrollViewDidScroll
62 | extension ZhiHuController
63 | {
64 | func scrollViewDidScroll(_ scrollView: UIScrollView)
65 | {
66 | let offsetY = scrollView.contentOffset.y
67 |
68 | if (offsetY > NAVBAR_COLORCHANGE_POINT)
69 | {
70 | let alpha = (offsetY - NAVBAR_COLORCHANGE_POINT) / CGFloat(kNavBarBottom)
71 | navBarBackgroundAlpha = alpha
72 | }
73 | else
74 | {
75 | navBarBackgroundAlpha = 0
76 | }
77 |
78 | // 限制下拉距离
79 | if (offsetY < LIMIT_OFFSET_Y) {
80 | scrollView.contentOffset = CGPoint.init(x: 0, y: LIMIT_OFFSET_Y)
81 | }
82 |
83 | // 改变图片框的大小 (上滑的时候不改变)
84 | // 这里不能使用offsetY,因为当(offsetY < LIMIT_OFFSET_Y)的时候,y = LIMIT_OFFSET_Y 不等于 offsetY
85 | let newOffsetY = scrollView.contentOffset.y
86 | if (newOffsetY < -IMAGE_HEIGHT)
87 | {
88 | cycleScrollView.frame = CGRect(x: 0, y: newOffsetY, width: CGFloat(kScreenWidth), height: -newOffsetY)
89 | }
90 | }
91 |
92 | // private
93 | fileprivate func imageScaledToSize(image:UIImage, newSize:CGSize) -> UIImage
94 | {
95 | UIGraphicsBeginImageContext(CGSize(width: newSize.width * 2.0, height: newSize.height * 2.0))
96 | image.draw(in: CGRect(x: 0, y: 0, width: newSize.width * 2.0, height: newSize.height * 2.0))
97 | let newImage:UIImage = UIGraphicsGetImageFromCurrentImageContext() ?? image
98 | UIGraphicsEndImageContext()
99 | return newImage
100 | }
101 | }
102 |
103 | extension ZhiHuController: UITableViewDelegate,UITableViewDataSource
104 | {
105 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
106 | return 15
107 | }
108 |
109 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
110 | {
111 | let cell = UITableViewCell.init(style: .default, reuseIdentifier: nil)
112 | let str = String(format: "知乎日报 %zd", indexPath.row)
113 | cell.textLabel?.text = str
114 | cell.textLabel?.font = UIFont.systemFont(ofSize: 15)
115 | return cell
116 | }
117 |
118 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
119 | {
120 | tableView.deselectRow(at: indexPath, animated: true)
121 | let vc:UIViewController = UIViewController()
122 | vc.view.backgroundColor = UIColor.white
123 | let str = String(format: "知乎日报 %zd", indexPath.row)
124 | vc.title = str
125 | navigationController?.pushViewController(vc, animated: true)
126 | }
127 | }
128 |
129 |
130 |
131 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemoTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/WRCycleScrollViewDemo/WRCycleScrollViewDemoTests/WRCycleScrollViewDemoTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WRCycleScrollViewDemoTests.swift
3 | // WRCycleScrollViewDemoTests
4 | //
5 | // Created by wangrui on 2017/5/12.
6 | // Copyright © 2017年 wangrui. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import WRCycleScrollViewDemo
11 |
12 | class WRCycleScrollViewDemoTests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | }
18 |
19 | override func tearDown() {
20 | // Put teardown code here. This method is called after the invocation of each test method in the class.
21 | super.tearDown()
22 | }
23 |
24 | func testExample() {
25 | // This is an example of a functional test case.
26 | // Use XCTAssert and related functions to verify your tests produce the correct results.
27 | }
28 |
29 | func testPerformanceExample() {
30 | // This is an example of a performance test case.
31 | self.measure {
32 | // Put the code you want to measure the time of here.
33 | }
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/screenshots/StoryBoard创建.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangrui460/WRCycleScrollView/d48d12003bb5c5d7c3e52abec63510b5b5c692e5/screenshots/StoryBoard创建.gif
--------------------------------------------------------------------------------
/screenshots/WRCycleScrollView.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangrui460/WRCycleScrollView/d48d12003bb5c5d7c3e52abec63510b5b5c692e5/screenshots/WRCycleScrollView.png
--------------------------------------------------------------------------------
/screenshots/demos.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangrui460/WRCycleScrollView/d48d12003bb5c5d7c3e52abec63510b5b5c692e5/screenshots/demos.png
--------------------------------------------------------------------------------
/screenshots/不无限轮播.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangrui460/WRCycleScrollView/d48d12003bb5c5d7c3e52abec63510b5b5c692e5/screenshots/不无限轮播.gif
--------------------------------------------------------------------------------
/screenshots/不显示pageControl.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangrui460/WRCycleScrollView/d48d12003bb5c5d7c3e52abec63510b5b5c692e5/screenshots/不显示pageControl.gif
--------------------------------------------------------------------------------
/screenshots/本地图片轮播.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangrui460/WRCycleScrollView/d48d12003bb5c5d7c3e52abec63510b5b5c692e5/screenshots/本地图片轮播.gif
--------------------------------------------------------------------------------
/screenshots/知乎日报.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangrui460/WRCycleScrollView/d48d12003bb5c5d7c3e52abec63510b5b5c692e5/screenshots/知乎日报.gif
--------------------------------------------------------------------------------
/screenshots/网络图片轮播.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangrui460/WRCycleScrollView/d48d12003bb5c5d7c3e52abec63510b5b5c692e5/screenshots/网络图片轮播.gif
--------------------------------------------------------------------------------