实现思路
无论有多少张滚动图片,UIScrollView
只有三张图片显示. scrollView
的contentOffset
始终保持在中间图片, 当向左或者向右滚动一张图片结束后, 重新设置contentOffset
在中间图片位置, 并重新设置imageView
里面的image
. 以达到图片滚动的效果.
import UIKit
class PageScrollView: UIView {
private let imageViewMaxCount = 3 //scrollview最大图片数
private var imageScrollView: UIScrollView!
private var pageControl: UIPageControl!
private var timer: NSTimer?
private var placeholderImage: UIImage?
private var imageClick:((index: Int) -> ())? //图片点击回调
//传入scrollview图片data
var headData: HeadResources? {
didSet {
//设置data后, 先停止滚动
if timer != nil {
timer!.invalidate()
timer = nil
}
if headData?.count >= 0 {
//设置pagecontrol的page数量, 并设置从0开始滚动
pageControl.numberOfPages = (headData?.count)!
pageControl.currentPage = 0
//重置scrollview的contentoffset并且设置imageview的图片
updatePageScrollView()
//开始自动滚动
startTimer()
}
}
}
override init(frame: CGRect) {
super.init(frame: frame)
buildImageScrollView()
buildPageControl()
}
convenience init(frame: CGRect, placeholder: UIImage, focusImageViewClick:((index: Int) -> Void)){
self.init(frame: frame)
placeholderImage = placeholder
imageClick = focusImageViewClick
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: (3)设置scrollview和pageControl的位置和尺寸, 并设置scrollview中imageview位置和尺寸
override func layoutSubviews() {
super.layoutSubviews()
imageScrollView.frame = bounds
imageScrollView.contentSize = CGSizeMake(CGFloat(imageViewMaxCount) * width, 0)
//设置scrollview中imageview位置和尺寸
for i in 0...imageViewMaxCount - 1 {
let imageView = imageScrollView.subviews[i] as! UIImageView
imageView.userInteractionEnabled = true
imageView.frame = CGRectMake(CGFloat(i) * imageScrollView.width, 0, imageScrollView.width, imageScrollView.height)
}
let pageW: CGFloat = 80
let pageH: CGFloat = 20
let pageX: CGFloat = imageScrollView.width - pageW
let pageY: CGFloat = imageScrollView.height - pageH
pageControl.frame = CGRectMake(pageX, pageY, pageW, pageH)
updatePageScrollView()
}
// MARK: (1)创建scrollview
private func buildImageScrollView() {
imageScrollView = UIScrollView()
imageScrollView.bounces = false
imageScrollView.showsHorizontalScrollIndicator = false
imageScrollView.showsVerticalScrollIndicator = false
imageScrollView.pagingEnabled = true
imageScrollView.delegate = self
addSubview(imageScrollView)
//添加imageview,并添加点击手势
for _ in 0..<3 {
let imageView = UIImageView()
let tap = UITapGestureRecognizer(target: self, action: "imageViewClick:")
imageView.addGestureRecognizer(tap)
imageScrollView.addSubview(imageView)
}
}
// MARK: (2)创建pageControl
private func buildPageControl() {
pageControl = UIPageControl()
pageControl.hidesForSinglePage = true
pageControl.pageIndicatorTintColor = UIColor(patternImage: UIImage(named: "v2_home_cycle_dot_normal")!)
pageControl.currentPageIndicatorTintColor = UIColor(patternImage: UIImage(named: "v2_home_cycle_dot_selected")!)
addSubview(pageControl)
}
// A - 第一步标记imageview.tag来标记image的位置 (判断的根据是currentpage)
//如果有5张image, 第一次显示的时候, currentpage = 0, 三个imageview.tag分别为4,0,1
//第二次显示时, currentpage = 1 , 三个imageview.tag分别为0,1,2
private func updatePageScrollView() {
for var i = 0; i < imageScrollView.subviews.count; i++ {
let imageView = imageScrollView.subviews[i] as! UIImageView
//拿到当前页位置
var index = pageControl.currentPage
if i == 0 {
//第一个image, index-1
index--
} else if 2 == i { //最多就三个imageview,也有可能就两个或一个
//第三个image, index+1
index++
}
if index < 0 {
index = self.pageControl.numberOfPages - 1
} else if index >= pageControl.numberOfPages {
index = 0
}
//标记imageview中image所在的位置
imageView.tag = index
if headData?.focus?.count > 0 {
imageView.sd_setImageWithURL(NSURL(string: headData!.focus![index].img!), placeholderImage: placeholderImage)
}
}
//始终设置contentOffset在中间一个imageview
imageScrollView.contentOffset = CGPointMake(imageScrollView.width, 0)
}
//timer
private func startTimer() {
timer = NSTimer(timeInterval: 3.0, target: self, selector: "next", userInfo: nil, repeats: true)
NSRunLoop.mainRunLoop().addTimer(timer!, forMode: NSRunLoopCommonModes)
}
private func stopTimer() {
timer?.invalidate()
timer = nil
}
func next() {
imageScrollView.setContentOffset(CGPointMake(2.0 * imageScrollView.frame.size.width, 0), animated: true)
}
// action
func imageViewClick(tap: UITapGestureRecognizer) {
if imageClick != nil {
imageClick!(index: tap.view!.tag)
}
}
}
// MARK:- UIScrollViewDelegate
extension PageScrollView: UIScrollViewDelegate {
//scrollview滚动一半时设置pagecontrol.
//B - 第一次(4,0,1)如果向下滚动一张时, 滚动到一半后, currentpage变为1
func scrollViewDidScroll(scrollView: UIScrollView) {
var page: Int = 0
var minDistance: CGFloat = CGFloat(MAXFLOAT)
for i in 0..<imageScrollView.subviews.count {
let imageView = imageScrollView.subviews[i] as! UIImageView
let distance:CGFloat = abs(imageView.x - scrollView.contentOffset.x)
//选择imageview.x 到 contentoffset.x 的最小距离(绝对值, 超过一半的位置),
//那么当前就是向那个imageview滚动, 设置currentpage为那个imageview.tag
if distance < minDistance {
minDistance = distance
page = imageView.tag
}
}
pageControl.currentPage = page
}
//用户拖动是停止自动滚动
func scrollViewWillBeginDragging(scrollView: UIScrollView) {
stopTimer()
}
//停止拖动后开始自动滚动
func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
startTimer()
}
//拖动结束后更新位置和图片
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
updatePageScrollView()
}
//自动滚动结束后更新位置和图片
func scrollViewDidEndScrollingAnimation(scrollView: UIScrollView) {
updatePageScrollView()
}
}
网友评论