简单粗暴的轮播图(Banner)开发
2017-07-24 本文已影响83人
MangoJ
久别重逢,继续完成功能模块的介绍.
今天要介绍的功能模块可以说覆盖了绝大多数APP,不信你试试,现在你就谁便打开你的手机应用,然后进入首页,是否看到了一个广告牌,在不停地循环播放,就是它..你没有看错.....轮播图,我喜欢叫他Banner.
闲话不多说😆,好像说的也不少了哈!进入主题.
"三思而后行"----意:做事谨慎,小心稳妥
开发亦是如此,首先我们要思考一下,做这个轮播图的思路:
1.首先,不难发现它是一个滚动视图,那么就要考虑能够提供滚动视图的有哪些类,是使用UITableView呢?,还是UICollectionView呢?其实选择哪个都可以实现轮播图控件实现,今天我要给大家分享的实现方法就是上面提到的这两个类的父类UIScrollView.
2.当然,只有滚动视图还不够还要能够展示图片,所以我们在UIScrollView上还要创建UIImageView用来展示图片,那么问题来了应用要展示的Banner图片数量不定,是不是每个图片都要创建一个UIImageView来展示Banner呢?,这里的处理是本将的"核心",如果每张图片都要创建一个UIImageView内存开销会很大,所以我们要尽可能少的去创建UIImageView,本讲用的三个UIImageView,依次展示最后一张图片,第一张图片,第二张图片具体实现方法下面代码区会有讲解.
3.轮播图...要实现轮播,必须要有一个定时器,每隔几秒去切换下一张图片,因此我们必须要使用Timer这个类来实现轮播效果.
4.除了图片轮播以外每个轮播图的实现还要用到一个控件就是UIPageControl,用来标记当前显示图片是第几张.
5.最后我们要实现的就是点击轮播图时,会有一个响应事件来处理我们点的那张图片.
6.还有一些细节比如:分页标签的位置等等,下面会一一讲到
到这里其实开发思路已经OK了
上面开发思路已经有了,下面👇就是具体的开发
github:下载地址
代码实现及介绍:
创建一个SirSlideshowView类继承UIView
import UIKit
//先导入一个第三方苦,用于加载网络图片
import Kingfisher
创建一个枚举用来设置分页标签的位置
///
/// - center: 中间
/// - left: 左侧
/// - right: 右侧
enum PagePosition {
case center
case left
case right
}
设置协议和协议中的方法
为了实现Banner点击事件
protocol SirSlideshowViewDelegate {
func ClickBanner(index:Int)
}
下面为SirSlideshowView类中所有的设置的属性和方法,代码注释比较多,相信你一定能看懂!
class SirSlideshowView: UIView {
//设置代理
var delegate : SirSlideshowViewDelegate?
fileprivate var scrollView : UIScrollView?
fileprivate var pageControl : UIPageControl?
//Banner的title
fileprivate var imagetitleLabel : UILabel?
fileprivate var imageTitleView : UIView?
fileprivate var isShow : Bool? = false
fileprivate var timer : Timer?
fileprivate var imageViews = [UIImageView]()
fileprivate var positionPage : PagePosition
/// 是否添加Banner图片标题:默认为false,不添加
var isShowImageTitle : Bool? = false {
didSet{
isShow = isShowImageTitle
setUIForImageTitle()
}
}
/// Banner图片数组
var images : [Any] = []{
didSet{
pageControl?.numberOfPages = images.count
reloadImage()
}
}
/// Banner标题数组
var imageTitles : [String] = []{
didSet{
reloadImage()
}
}
/// Banner标题颜色
var imageTitleColor : UIColor = UIColor.black{
didSet{
imagetitleLabel?.tintColor = imageTitleColor
}
}
/// 分页指示器非当前页小点颜色
var pageIndicatorColor : UIColor = UIColor.white{
didSet{
pageControl?.pageIndicatorTintColor = pageIndicatorColor
}
}
/// 分页指示器当前页小点颜色
var currentPageIndicatorColor : UIColor = UIColor.black{
didSet{
pageControl?.currentPageIndicatorTintColor = currentPageIndicatorColor
}
}
/// 初始化方法
///
/// - Parameters:
/// - frame: Frame
/// - images: Banner图片数组
/// - imageTitles: Banner标题数组
/// - pagePosition: 分页指示器的位置
init(frame: CGRect,images:[Any]? = [],imageTitles:[String]? = [],pagePosition:PagePosition? = .center) {
if images == nil {
self.images = [""]
}else{
self.images = images ?? []
}
self.imageTitles = imageTitles ?? []
self.positionPage = pagePosition!
super.init(frame: frame)
setUpUI()
addTimer()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
fileprivate func setUpUI() {
//创建scrollview
scrollView = UIScrollView(frame: self.bounds)
scrollView?.delegate = self
scrollView?.isPagingEnabled = true
scrollView?.showsHorizontalScrollIndicator = false
scrollView?.showsVerticalScrollIndicator = false
self.addSubview(scrollView!)
//创建3个imageView 用于显示轮播图片,图片依次设置好最后一个,第一个,第二个图片
for a in 0 ..< 3 {
let imageView = UIImageView()
if images.count > 0 {
self.imageString(imageView:imageView, imageS: "\(images[(a + images.count-1)%images.count])")
}
imageView.isUserInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: #selector(actionClick))
imageView.addGestureRecognizer(tap)
scrollView?.addSubview(imageView)
imageViews.append(imageView)
}
//创建分页控制标签
pageControl = UIPageControl()
self.addSubview(pageControl!)
pageControl?.currentPage = 0
pageControl?.pageIndicatorTintColor = pageIndicatorColor
pageControl?.currentPageIndicatorTintColor = currentPageIndicatorColor
}
/// 添加timer
fileprivate func addTimer() {
timer = Timer(timeInterval: 2, repeats: true, block: { [weak self] _ in
self?.nextImage()
})
guard let timer = timer else {
return
}
RunLoop.current.add(timer, forMode: .commonModes)
}
///停止timer,将timer设置为nil才会销毁
fileprivate func removeTimer() {
timer?.invalidate()
timer = nil
}
/// 下一个图片
fileprivate func nextImage() {
if pageControl?.currentPage == images.count - 1 {
pageControl?.currentPage = 0
} else {
pageControl?.currentPage += 1
}
let contentOffset = CGPoint(x: self.frame.width*2 , y: 0)
scrollView?.setContentOffset(contentOffset, animated: true)
}
/// 上一个图片
fileprivate func preImage() {
if pageControl?.currentPage == 0 {
pageControl?.currentPage = images.count - 1
} else {
pageControl?.currentPage -= 1
}
let contentOffset = CGPoint(x: 0, y: 0)
scrollView?.setContentOffset(contentOffset, animated: true)
}
/// 重新加载图片,设置3个imageView的图片
fileprivate func reloadImage() {
//通过pageControl当前选中的位置,获取当前轮播到哪一张图片
let currentIndex = pageControl?.currentPage
let nextIndex = (currentIndex! + 1) % images.count
let preIndex = (currentIndex! + images.count-1) % images.count
self.imageString(imageView: (scrollView?.subviews[0] as! UIImageView), imageS: "\(images[preIndex])")
self.imageString(imageView:(scrollView?.subviews[1] as! UIImageView), imageS: "\(images[currentIndex!])")
self.imageString(imageView: (scrollView?.subviews[2] as! UIImageView), imageS: "\(images[nextIndex])")
if self.isShow! {
if currentIndex! > imageTitles.count - 1 {
imagetitleLabel?.text = ""
}else{
imagetitleLabel?.text = imageTitles[currentIndex!]
}
}
}
/// 代理方法
@objc fileprivate func actionClick() {
self.delegate?.ClickBanner(index: (pageControl?.currentPage)!)
}
/// 设置图片
///
/// - Parameters:
/// - imageView: 要添加图片的ImageView
/// - imageS: image(本地图片或者url)
fileprivate func imageString(imageView:UIImageView, imageS:String){
var header : String?
if imageS.characters.count >= 4 {
header = (imageS as NSString).substring(to: 4)
}
if header == "http" {
imageView.kf.setImage(with: URL(string: "\(imageS)"), placeholder: UIImage(named: "placeholder")!, options: nil, progressBlock: nil, completionHandler: nil)
}else{
imageView.image = UIImage(named: "\(imageS )") ?? UIImage(named: "placeholder")!
}
}
fileprivate func setUIForImageTitle(){
if self.isShow! {
imageTitleView = UIView()
imageTitleView?.frame = CGRect(x: 0, y: self.frame.height - 30, width: self.frame.width, height: 30)
imageTitleView?.backgroundColor = .gray
imageTitleView?.alpha = 0.6
self.addSubview(imageTitleView!)
imagetitleLabel = UILabel()
imagetitleLabel?.tintColor = imageTitleColor
self.addSubview(imagetitleLabel!)
}
}
override func layoutSubviews() {
scrollView?.contentSize = CGSize(width: CGFloat(Int(self.frame.width) * images.count), height: self.frame.height)
scrollView?.contentOffset = CGPoint(x: self.frame.width, y: 0)
var i = 0
for imageView in imageViews {
imageView.frame = CGRect(x: CGFloat(i*Int(self.frame.width)), y: 0, width: self.frame.width, height: self.frame.height)
i = i+1
}
switch self.positionPage {
case .center:
pageControl?.frame = CGRect(x: 0, y: self.frame.height - 30, width: self.frame.width/3, height: 30)
pageControl?.center.x = self.center.x
case .left:
pageControl?.frame = CGRect(x: 0, y: self.frame.height - 30, width: self.frame.width/3, height: 30)
imagetitleLabel?.frame = CGRect(x: self.frame.width/3, y: self.frame.height - 30, width: self.frame.width*2/3, height: 30)
case .right:
pageControl?.frame = CGRect(x: self.frame.width/3*2, y: self.frame.height - 30, width: self.frame.width/3, height: 30)
imagetitleLabel?.frame = CGRect(x: 0, y: self.frame.height - 30, width: self.frame.width*2/3, height: 30)
}
}
}
extension SirSlideshowView :UIScrollViewDelegate{
/// 开始滑动的时候,停止timer,将timer设置为nil才会销毁
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
removeTimer()
}
/// 当停止滚动的时候重新设置三个ImageView的内容,然后显示中间那个imageView
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
reloadImage()
scrollView.setContentOffset(CGPoint(x: self.frame.width, y: 0), animated: false)
}
/// 停止拖拽,开始timer, 并且判断是显示上一个图片还是下一个图片
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
addTimer()
if scrollView.contentOffset.x < self.frame.width {
preImage()
} else {
nextImage()
}
}
}
简单使用如下:
class ViewController: UIViewController,SirSlideshowViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.navigationBar.isTranslucent = false
let bannerView = SirSlideshowView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: 200), images: nil, pagePosition: .right)
bannerView.isShowImageTitle = true
bannerView.delegate = self
bannerView.images = ["test1","test2","http://img.ph.126.net/ocT0cPlMSiTs2BgbZ8bHFw==/631348372762626203.jpg"]
bannerView.imageTitles = ["起舞飞扬","圣诞快乐","Love"]
bannerView.imageTitleColor = .red
bannerView.pageIndicatorColor = UIColor.red
self.view.addSubview(bannerView)
}
func ClickBanner(index:Int) {
let test = TestViewController()
test.title = "Banner\(index)详情"
self.navigationController?.pushViewController(test, animated: true)
}
}
2oo行代码,搞定轮播图(Banner),简单粗暴的轮播图(Banner)开发大功告成,相信本讲,对读者朋友会有所帮助,如果觉得文章还可以,点击下方👇喜欢鼓励一下,没关注的朋友可以点击一下关注,专题系列讲解持续更新中!