iOS swift版本无限滚动轮播图
之前写过oc版本的无限滚动轮播图,现在来一个swift版本全部使用snapKit布局,数字还是pageConrrol样式可选
enum typeStyle: Int {
case pageControl
case label
}
效果图:

代码:
//
// TYCarouselView.swift
// hxquan-swift
//
// Created by Tiny on 2018/11/12.
// Copyright © 2018年 hxq. All rights reserved.
// 轮播图
import UIKit
let ImgPlaceHolder = UIImage(named: "picture")
enum typeStyle: Int {
case pageControl
case label
}
class TYCarouselCell: UICollectionViewCell {
var url: String = ""{
didSet{
let cacheImg = SDImageCache.shared().imageFromDiskCache(forKey: url)
imgView.contentMode = .center
imgView.sd_setImage(with: URL(string: url),placeholderImage:cacheImg ?? ImgPlaceHolder) { [unowned self] (image, error, _, _) in
if image != nil && error == nil{
self.imgView.contentMode = .scaleAspectFill
}
}
}
}
lazy var imgView: UIImageView = {
let imgView = UIImageView()
imgView.layer.masksToBounds = true
imgView.contentMode = .center
imgView.image = ImgPlaceHolder
return imgView
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupUI()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupUI()
}
func setupUI(){
contentView.addSubview(imgView)
imgView.snp.makeConstraints { (make) in
make.edges.equalToSuperview()
}
}
}
class TYCarouselView: UIView {
var style: typeStyle = .pageControl{
didSet{
if style == .pageControl{
if pageControl.superview == nil{
addSubview(pageControl)
pageControl.snp.makeConstraints { (make) in
make.centerX.equalToSuperview()
make.bottom.equalToSuperview().offset(-10)
}
}
if label.superview != nil{
label.removeFromSuperview()
}
}else{
if label.superview == nil{
addSubview(label)
label.snp.makeConstraints { (make) in
make.right.equalToSuperview().offset(-20)
make.bottom.equalToSuperview().offset(-20)
}
}
if pageControl.superview != nil{
pageControl.removeFromSuperview()
}
}
}
}
/// 定时器是否开启
var isTimerEnable = true
fileprivate let maxsection: Int = 100
/// 滚动间隔
public let scroInterval: TimeInterval = 4
private var selectonBlock: ((Int)->Void)?
public var images = [String]() {
didSet{
//重写images set方法
//更新数据源
collectionView.reloadData()
if style == .pageControl {
pageControl.numberOfPages = images.count
}else{
if oldValue.count == 0{
label.attributedText = labelAttrText(1)
}
label.isHidden = images.count == 0
}
if isTimerEnable && !images.isEmpty{
timerStart()
}
}
}
lazy var pageControl: UIPageControl = {
let pageControl = UIPageControl()
pageControl.sizeToFit()
return pageControl
}()
lazy var label: UILabel = {
let label = UILabel()
label.font = UIFont.systemFont(ofSize: 12)
label.textColor = UIColor.white
label.attributedText = labelAttrText(0)
label.isHidden = true
return label
}()
fileprivate lazy var collectionView: UICollectionView = { [unowned self] in
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.minimumLineSpacing = 0
layout.minimumInteritemSpacing = 0
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.backgroundColor = UIColor.white
collectionView.showsVerticalScrollIndicator = false
collectionView.showsHorizontalScrollIndicator = false
collectionView.delegate = self
collectionView.dataSource = self
collectionView.isPagingEnabled = true
collectionView.register(TYCarouselCell.self, forCellWithReuseIdentifier: "TYCarouselCell")
return collectionView
}()
fileprivate lazy var timer: Timer = { [unowned self] in
let timer = Timer(timeInterval: scroInterval, target: self, selector: #selector(timerInterval), userInfo: nil, repeats: true)
RunLoop.current.add(timer, forMode: .common)
return timer
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupUI()
}
convenience init(frame: CGRect,selectonBlock: ((Int)->Void)?){
self.init(frame: frame)
self.selectonBlock = selectonBlock
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
private func setupUI(){
addSubview(collectionView)
collectionView.snp.makeConstraints { (make) in
make.edges.equalToSuperview()
}
addSubview(pageControl)
pageControl.snp.makeConstraints { (make) in
make.bottom.equalToSuperview().offset(-10)
make.centerX.equalToSuperview()
}
}
@objc func timerInterval(){
//取当前idnexPath
if let currentIndexPath = collectionView.indexPathsForVisibleItems.last{
//先让collectionViev滚动到中间
let currentIndexPathReset = IndexPath(row: currentIndexPath.row, section: maxsection/2)
collectionView.scrollToItem(at: currentIndexPathReset, at: .left, animated: false)
//让当前indexPath.row++
var row = currentIndexPath.row + 1
var nextsection = currentIndexPathReset.section
if row >= images.count{
row = 0
nextsection = nextsection + 1
}
if style == .pageControl {
pageControl.currentPage = row
}else{
label.attributedText = labelAttrText(row+1)
}
let nextIndexPath = IndexPath(row: row, section:nextsection)
collectionView.scrollToItem(at: nextIndexPath, at: .left, animated: true)
}
}
private func timerStart(){
if !timer.isValid {
timer.fire()
}
}
private func timerPause(){
if timer.isValid {
timer.invalidate()
}
}
private func labelAttrText(_ index: Int) -> NSAttributedString{
let lf = "\(index)"
let rt = "\(images.count)"
let str = lf + "/" + rt
let attr = NSMutableAttributedString(string: str)
attr.setAttributes([NSAttributedString.Key.foregroundColor : UIColor.red], range: NSRange(location: 0, length: 1))
return attr
}
}
extension TYCarouselView: UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout{
func numberOfSections(in collectionView: UICollectionView) -> Int {
return maxsection
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return images.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TYCarouselCell", for: indexPath) as! TYCarouselCell
cell.url = images[indexPath.row]
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: self.bounds.size.width, height: self.bounds.size.height)
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
selectonBlock?(indexPath.row)
}
//结束滚动
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let index = Int(scrollView.contentOffset.x / self.bounds.size.width + 0.5) % images.count
if style == .pageControl {
pageControl.currentPage = index
}else{
label.attributedText = labelAttrText(index+1)
}
if(isTimerEnable){
//定时器启动
if timer.isValid {
timer.fireDate = Date.init(timeIntervalSinceNow: scroInterval)
}
}
}
//拖动
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
if isTimerEnable{
//定时器暂停
if timer.isValid {
timer.fireDate = Date.distantFuture
}
}
}
}
使用方法:
lazy var carouselView: TYCarouselView = { [unowned self] in
let carouselView = TYCarouselView(frame: .zero, selectonBlock: { (index) in
print("\(index)")
})
carouselView.style = .label
carouselView.layer.masksToBounds = true
carouselView.layer.cornerRadius = 10
return carouselView
}()
override func viewDidLoad() {
super.viewDidLoad()
//添加到父视图
view.addSubview(carouselView)
//设置约束
carouselView.snp.makeConstraints { (make) in
make.left.equalTo(15)
make.right.equalTo(-15)
make.top.equalTo(10)
make.height.equalTo(170)
}
//设置数据源
var imgs = [String]()
for _ in 0..<5{
imgs.append("图url")
}
self.carouselView.images = imgs
}
iOS swift版本无限滚动轮播图的更多相关文章
- js原生选项卡(自动播放无缝滚动轮播图)二
今天分享一下自动播放轮播图,自动播放轮播图是在昨天分享的轮播图的基础上添加了定时器,用定时器控制图片的自动切换,函数中首先封装一个方向的自动播放工能的小函数,这个函数中添加定时器,定时器中可以放向右走 ...
- JavaScript+HTML+CSS 无缝滚动轮播图的两种方式
第一种方式 在轮播图最后添加第一张,一张重复的图片. 点击前一张,到了第一张,将父级oList移动到最后一张(也就是添加的重复的第一张),在进行后续动画. 点击下一张,到了最后一张(也就是添加的重复的 ...
- android-auto-scroll-view-pager (无限广告轮播图)
github 地址: https://github.com/Trinea/android-auto-scroll-view-pager Gradle: compile ('cn.trinea.andr ...
- js原生选项卡(包含无缝滚动轮播图)一
原生js选项卡的几种写法,整片文章我会由简及难的描述几种常用的原生选项卡的写法: Improve little by little every day! 1>基本选项卡: 思路:循环中先清除再添 ...
- jquery左右切换的无缝滚动轮播图
1.HTML结构: <head> <script type="text/javascript" src="../jquery-1.8.3/jquery. ...
- 无限循环轮播图之JS部分(原生JS)
JS逻辑与框架调用, <script type="text/javascript"> var oBox = document.getElementById('box') ...
- 无限循环轮播图之结构布局(原生JS)
html部分 <div class="box" id="box"> <ul> <li><img src="i ...
- 无限循环轮播图之运动框架(原生JS)
封装运动框架 function getStyle(obj,name){ if(obj.currentStyle){ return obj.currentStyle[name]; }else{ retu ...
- 从零开始学习前端JAVASCRIPT — 11、JavaScript运动模型及轮播图效果、放大镜效果、自适应瀑布流
未完待续...... 一.运动原理 通过连续不断的改变物体的位置,而发生移动变化. 使用setInterval实现. 匀速运动:速度值一直保持不变. 多物体同时运动:将定时器绑设置为对象的一个属性. ...
随机推荐
- python3开发进阶-Django框架学习前的小项目(一个简单的学员管理系统)
''' 自己独立写一个学员管理系统 表结构: 班级表: -id -grade_name 学生表: -id -student_name -grade 关联外键班级表 老师表: -id -teacher_ ...
- Problem S: 零起点学算法14——三位数反转
#include<stdio.h> #include<stdlib.h> int main() { int a,b,c,s; scanf("%d",& ...
- NDK之HelloWord!
使用工具:Android Studio 2.2.2 1. 配置local.properties添加NDK路径. 效果:当然,你也可以手输写进去. 2. 项目gradle.properties追加 ...
- Maven设置snapshot无法在远程仓库下载的问题解决
检查步骤如下: 1.检查nexus是否纳入public版本中: 2.配置中是否启用snapshots功能.以下方法两种设置都可以,任选一个即可. 一种是在项目pom.xml使用: <reposi ...
- 扩展gridview轻松实现冻结行和列
在实际的项目中,由于项目的需要,数据量比较大,同时显示栏位也比较多,要做gridview里显示完整,并做到用户体验比较好,这就需要冻结表头和关键列.由于用到的地方比较多,我们可以护展一个gridvie ...
- 解决小米手机Android Studio安装app 报错的问题It is possible that this issue is resolved by uninstalling an existi
问题描述 Android Studio升级到2.3版本之后,小米手机MIUI8不能运行Android Studio程序,报如下错误: Installation failed with message ...
- 简述es6各种简单方法
1.取代var的let和const 局部变量都可以使用let 固定变量都可以使用const 2.字符串的变化 反引号的使用 3.解构赋值 let [a, b, c] = [1, 2, 3]; let ...
- wordcount代码实现详解
阅读目录 1.MapReduce整体流程 2.WordCount源码 3.WordCount逐行解析 Hadoop的框架最核心的设计就是:HDFS和MapReduce.HDFS为海量的数据提供了存储, ...
- druid.io 海量实时OLAP数据仓库 (翻译+总结) (1)
介绍 我是NDPmedia公司的大数据OLAP的资深高级工程师, 专注于OLAP领域, 现将一个成熟的可靠的高性能的海量实时OLAP数据仓库介绍给大家: druid.io NDPmedia在2014年 ...
- JSP页面的基本结构 及声明变量
一.JSP页面的基本结构 在传统的HTML页面文件里增加Java程序片和JSP标签就构成了一个JSP页面文件. 一个JSP页面可由5种元素组合而成: 1.普通的HTML标记符 2.Jsp标签.如指令标 ...