....................................................................................................
Introduction
A class with ad. pics auotmatic scrolling build in swift with image cache policy used.
Installtion
Manual:
Download This Project and drag the FGSwiftAutoScrollView
folder into your peroject, do not forget to ensure "copy item if need" being selected.
Usage
- Load Web Images:
//MARK:- //MARK:automatic scrollView with web images convenience init(frame:CGRect, placeHolder placeHolderImage:UIImage?,remoteImageUrls imgs:Array<String>?, selectImageAction imageDidSelectedAction:@escaping FGImageClickBlock){ self.init(frame: frame) self.createLoacalCacheFolder() self.placeHolderImage=placeHolderImage self.didSelectedImageAction=imageDidSelectedAction self.imageUrlArray=imgs DispatchQueue.main.async { self.createScrollView() } }
-
Load Local Images:
//MARK:automatic scrollView with local images convenience init(frame:CGRect,placeHolder placeHolderImage:UIImage?,localImageNames imgs:Array<String>?, selectImageAction imageDidSelectedAction:@escaping FGImageClickBlock){ self.init(frame: frame) self.placeHolderImage=placeHolderImage var fileUrlsArray:Array<String>=[] for name in imgs!{ var path:String? if name.hasSuffix("jpg")||name.hasSuffix("png"){ path=Bundle.main.path(forResource: name, ofType: nil) } else{ path=Bundle.main.path(forResource: name, ofType: "png") } if path==nil{ path="" } path=path?.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) let fullPath=String.init(format: "file://%@", path!) fileUrlsArray.append(fullPath) } self.didSelectedImageAction=imageDidSelectedAction self.imageUrlArray=fileUrlsArray self.createScrollView() }
- you can simply use the srcoll call back block if need (not necessary)
self.banner?.imageDidScrolledBlock={ (currentIndex) in
print("滚到到了第"+String(currentIndex)+"页了")
}
Explain:
If you don't need add image tap action, property didSelectedImageAction block can be nil.
How to implementation
Create a class:
FGSwiftAutoScrollView.swift
and confirm to the UIScrollViewDelegate
class FGSwiftAutoScrollView: UIView,UIScrollViewDelegate{
}
Add some properties
//auto scroll interval
let fg_scrollInterval=3.0
//disk cache path
let fg_cachePath=NSSearchPathForDirectoriesInDomains(.libraryDirectory, .userDomainMask, true).last!+"/FGGAutomaticScrollViewCache"
//memery cache
let fg_imageCache=NSCache<AnyObject,AnyObject>()
//maximun disk chache cycle
let fg_maxCacheCycle=TimeInterval(7*24*3600)
// tap image call action call back
private var didSelectedImageAction:FGImageClickBlock?
//image did scrolled call back
public var imageDidScrolledBlock:FGImageScrolledBlock?
//data source
public var imageUrlArray:Array<String>?{
//redifine setter
didSet{
//refresh UI on main queue
DispatchQueue.main.async {
self.createScrollView()
}
}
}
//main scrollView
private var scroll:UIScrollView?
//to ensure automatic scroll
private var timer:Timer!
//page control to show current page index
private var pageControl:UIPageControl!
//placeHolder image
var placeHolderImage:UIImage?
Override initWithFrame:
override init(frame:CGRect){
super.init(frame:frame)
self.createLoacalCacheFolder()
}
Create an area for disk image cache
//MARK:- create cache area
//MARK:create a cache area to cache web images
private func createLoacalCacheFolder(){
if !FileManager.default.fileExists(atPath: fg_cachePath){
do{
try FileManager.default.createDirectory(atPath: fg_cachePath, withIntermediateDirectories: true, attributes: nil)
}catch{
}
}
}
Give two convenience functions
//MARK:-Load Web Image
//MARK:automatic scrollView with web images
convenience init(frame:CGRect, placeHolder placeHolderImage:UIImage?,remoteImageUrls imgs:Array<String>?, selectImageAction imageDidSelectedAction:@escaping FGImageClickBlock){
self.init(frame: frame)
self.placeHolderImage=placeHolderImage
self.didSelectedImageAction=imageDidSelectedAction
self.imageUrlArray=imgs
DispatchQueue.main.async {
self.createScrollView()
}
}
//MARK:Load Local Image
//MARK:automatic scrollView with local images
convenience init(frame:CGRect,placeHolder placeHolderImage:UIImage?,localImageNames imgs:Array<String>?, selectImageAction imageDidSelectedAction:@escaping FGImageClickBlock){
self.init(frame: frame)
self.placeHolderImage=placeHolderImage
var fileUrlsArray:Array<String>=[]
for name in imgs!{
var path:String?
if name.hasSuffix("jpg")||name.hasSuffix("png"){
path=Bundle.main.path(forResource: name, ofType: nil)
}
else{
path=Bundle.main.path(forResource: name, ofType: "png")
}
if path==nil{
path=""
}
path=path?.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)
let fullPath=String.init(format: "file://%@", path!)
fileUrlsArray.append(fullPath)
}
self.didSelectedImageAction=imageDidSelectedAction
self.imageUrlArray=fileUrlsArray
self.createScrollView()
}
Create main scroll view
//MARK:-
//MARK:create scroll view
private func createScrollView(){
if self.scroll != nil{
for sub in self.subviews {
sub.removeFromSuperview()
}
self.scroll?.removeFromSuperview()
self.scroll=nil
}
self.scroll=UIScrollView.init(frame: self.bounds)
self.addSubview(self.scroll!)
self.scroll?.delegate=self
var count:Int?;
if self.imageUrlArray==nil{
count=0
}else{
count=self.imageUrlArray?.count
}
let width:CGFloat=CGFloat((count!+1))*self.bounds.size.width;
let height:CGFloat=self.bounds.size.height;
self.scroll?.contentSize=CGSize.init(width: width, height: height)
self.scroll?.isPagingEnabled=true
self.scroll?.showsHorizontalScrollIndicator=false
if self.timer != nil{
self.timer.invalidate()
self.timer=nil
}
//detach the timer
self.timer=Timer.scheduledTimer(withTimeInterval: fg_scrollInterval, repeats: true, block: { (t) in
if self.imageUrlArray?.count==0{
return
}
var index=Int((self.scroll?.contentOffset.x)!/self.bounds.size.width);
index+=1
if index==self.imageUrlArray?.count{
index=0
}
if self.imageDidScrolledBlock != nil{
self.imageDidScrolledBlock?(UInt(index))
}
self.pageControl.currentPage=index
UIView.animate(withDuration: 0.2, animations: {
self.scroll?.contentOffset=CGPoint.init(x: self.bounds.size.width*CGFloat(index), y: 0)
})
})
if count!>0{
for i in 0...count!{
let xpos=CGFloat(i)*self.bounds.size.width
let frm=CGRect.init(x: xpos, y: 0, width: self.bounds.size.width, height: self.bounds.size.height)
let imv=UIImageView.init(frame: frm)
imv.image=self.placeHolderImage
imv.isUserInteractionEnabled=true
let tap:UITapGestureRecognizer=UITapGestureRecognizer.init(target: self, action:#selector(FGSwiftAutoScrollView.tapImage))
imv.addGestureRecognizer(tap)
self.scroll?.addSubview(imv)
var urlString:String?
if i<count!{
urlString=self.imageUrlArray?[i]
}else{
urlString=imageUrlArray?.first
}
self.fg_setImageWithUrlString(imageView: imv,
urlString: urlString,
placeHolder:self.placeHolderImage)
}
}
if self.pageControl != nil{
self.pageControl.removeFromSuperview()
self.pageControl=nil
}
let pageControlFrame=CGRect.init(x: 0, y: 0, width: 200, height: 17)
self.pageControl=UIPageControl.init(frame: pageControlFrame)
self.pageControl.center=CGPoint.init(x: self.bounds.size.width/2, y: self.bounds.size.height-10)
self.pageControl.numberOfPages=count!
self.pageControl.pageIndicatorTintColor=UIColor.init(red: 225.0/255.0, green: 225.0/255.0, blue: 225.0/255.0, alpha: 1.0)
self.pageControl.currentPageIndicatorTintColor=UIColor.orange
self.addSubview(self.pageControl)
}
Impletatin of sroll view delegate
//MARK:-
//MARK:UIScrollView Delegate
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
var index=Int((self.scroll?.contentOffset.x)!/self.bounds.size.width);
if index==self.imageUrlArray?.count{
index=0;
}
if self.imageDidScrolledBlock != nil{
self.imageDidScrolledBlock?(UInt(index))
}
self.pageControl.currentPage=index
self.scroll?.contentOffset=CGPoint.init(x: self.bounds.size.width*CGFloat(index), y: 0)
}
Implementation of tap image action
//MARK:-
//MARK: Tag Image Action
func tapImage(){
if self.didSelectedImageAction != nil{
self.didSelectedImageAction?(UInt(self.pageControl.currentPage));
}
}
Destroy the timer in deinit
deinit{
if self.timer != nil{
self.timer .invalidate()
self.timer=nil
}
}
Write an extension to async download image like
SDWebImage
extension FGSwiftAutoScrollView{
}
Async image loading like
SDWebImage
with cache in memery an disk
func fg_setImageWithUrlString(imageView:UIImageView?,urlString:String?,placeHolder:UIImage?){
if imageView==nil{
return
}
imageView?.image=placeHolder
if urlString==nil{
return
}
var cachePath=fg_cachePath+"/"+String(describing: urlString?.hash)
if (urlString?.hasPrefix("file://"))!{//local path
cachePath=urlString!
}
//check the memery chache exist or not(both local and web images)
var data=fg_imageCache.object(forKey: cachePath as AnyObject)
if (data != nil) {//exist in memery cache
DispatchQueue.main.async{
imageView?.image=UIImage(data: data as! Data)
}
}else{//not in memery cache,check if exist in disk or not
//local images
if (urlString?.hasPrefix("file://"))!{
let url:NSURL=NSURL.init(string: urlString!)!
do{
try data=Data.init(contentsOf: url as URL) as AnyObject?
}catch{
}
//if local image exist
if data != nil{
fg_imageCache.setObject(data as AnyObject, forKey: cachePath as AnyObject)
DispatchQueue.main.async{
imageView?.image=UIImage(data: data as! Data)
}
}
else{//local image is not exist,just ingnore
//ingnore
}
}
//web images
else{
//check if exist in disk
let exist=FileManager.default.fileExists(atPath: cachePath)
if exist {//exist in disk
//check if expired
var attributes:Dictionary<FileAttributeKey,Any>?
do{
try attributes=FileManager.default.attributesOfItem(atPath: cachePath)
}catch{
}
let createDate:Date?=attributes?[FileAttributeKey.creationDate] as! Date?
let interval:TimeInterval?=Date.init().timeIntervalSince(createDate!)
let expired=(interval! > fg_maxCacheCycle)
if expired{//expired
//download image
self.donwloadDataAndRefreshImageView(imageView: imageView, urlString: urlString, cachePath: cachePath)
}
else{//not expired
//load from disk
let url:NSURL=NSURL.init(string: urlString!)!
do{
try data=Data.init(contentsOf: url as URL) as AnyObject?
}catch{
}
if data != nil{//if has data
//cached in memery
fg_imageCache.setObject(data as AnyObject, forKey: cachePath as AnyObject)
DispatchQueue.main.async{
imageView?.image=UIImage(data: data as! Data)
}
}
else{//has not data
//remove item from disk
let url:NSURL=NSURL.init(string: urlString!)!
do{
try data=Data.init(contentsOf: url as URL) as AnyObject?
}catch{
}
//donwload agin
self.donwloadDataAndRefreshImageView(imageView: imageView, urlString: urlString, cachePath: cachePath)
}
}
}
//not exist in disk
else{
//download image
self.donwloadDataAndRefreshImageView(imageView: imageView, urlString: urlString, cachePath: cachePath)
}
}
}
}
Donwload Image Task
//async download image
private func donwloadDataAndRefreshImageView(imageView:UIImageView?,urlString:String?,cachePath:String!){
do{
try FileManager.default.removeItem(atPath: cachePath)
}catch{
}
//download data
let url=URL.init(string: urlString!)
let session=URLSession.shared.dataTask(with: url!, completionHandler: { (resultData, res, err) in
let fileUrl=URL.init(fileURLWithPath: cachePath)
do{
try resultData?.write(to: fileUrl, options:.atomic)
}catch{
}
self.fg_imageCache.setObject(resultData as AnyObject, forKey: cachePath as AnyObject)
if resultData != nil{
DispatchQueue.main.async{
imageView?.image=UIImage(data: resultData!)
}
}
else{
//ingnore
}
})
session.resume()
}
End. Attached the address of my source code on GitHub
FGSwiftAutoScrollView Hope your star, fork or pull request.
Support Me
- Blog: CGPointZeero
- GitHub: Insfgg99x
- Mooc: CGPointZero
- Jianshu: CGPointZero
- Email: newbox0512@yahoo.com
................................................................................................
Copyright (c) 2016 CGPointZero. All rights reserved.<br>