久別重逢,繼續(xù)完成功能模塊的介紹.
今天要介紹的功能模塊可以說(shuō)覆蓋了絕大多數(shù)APP,不信你試試,現(xiàn)在你就誰(shuí)便打開(kāi)你的手機(jī)應(yīng)用,然后進(jìn)入首頁(yè),是否看到了一個(gè)廣告牌,在不停地循環(huán)播放,就是它..你沒(méi)有看錯(cuò).....輪播圖,我喜歡叫他Banner.
閑話不多說(shuō)??,好像說(shuō)的也不少了哈!進(jìn)入主題.
"三思而后行"----意:做事謹(jǐn)慎哼鬓,小心穩(wěn)妥
開(kāi)發(fā)亦是如此,首先我們要思考一下,做這個(gè)輪播圖的思路:
1.首先,不難發(fā)現(xiàn)它是一個(gè)滾動(dòng)視圖,那么就要考慮能夠提供滾動(dòng)視圖的有哪些類,是使用UITableView呢?,還是UICollectionView呢?其實(shí)選擇哪個(gè)都可以實(shí)現(xiàn)輪播圖控件實(shí)現(xiàn),今天我要給大家分享的實(shí)現(xiàn)方法就是上面提到的這兩個(gè)類的父類UIScrollView.
2.當(dāng)然,只有滾動(dòng)視圖還不夠還要能夠展示圖片,所以我們?cè)赨IScrollView上還要?jiǎng)?chuàng)建UIImageView用來(lái)展示圖片,那么問(wèn)題來(lái)了應(yīng)用要展示的Banner圖片數(shù)量不定,是不是每個(gè)圖片都要?jiǎng)?chuàng)建一個(gè)UIImageView來(lái)展示Banner呢?,這里的處理是本將的"核心",如果每張圖片都要?jiǎng)?chuàng)建一個(gè)UIImageView內(nèi)存開(kāi)銷(xiāo)會(huì)很大,所以我們要盡可能少的去創(chuàng)建UIImageView,本講用的三個(gè)UIImageView,依次展示最后一張圖片,第一張圖片,第二張圖片具體實(shí)現(xiàn)方法下面代碼區(qū)會(huì)有講解.
3.輪播圖...要實(shí)現(xiàn)輪播,必須要有一個(gè)定時(shí)器,每隔幾秒去切換下一張圖片,因此我們必須要使用Timer這個(gè)類來(lái)實(shí)現(xiàn)輪播效果.
4.除了圖片輪播以外每個(gè)輪播圖的實(shí)現(xiàn)還要用到一個(gè)控件就是UIPageControl,用來(lái)標(biāo)記當(dāng)前顯示圖片是第幾張.
5.最后我們要實(shí)現(xiàn)的就是點(diǎn)擊輪播圖時(shí),會(huì)有一個(gè)響應(yīng)事件來(lái)處理我們點(diǎn)的那張圖片.
6.還有一些細(xì)節(jié)比如:分頁(yè)標(biāo)簽的位置等等,下面會(huì)一一講到
到這里其實(shí)開(kāi)發(fā)思路已經(jīng)OK了
上面開(kāi)發(fā)思路已經(jīng)有了,下面??就是具體的開(kāi)發(fā)
github:下載地址
代碼實(shí)現(xiàn)及介紹:
創(chuàng)建一個(gè)SirSlideshowView類繼承UIView
import UIKit
//先導(dǎo)入一個(gè)第三方苦,用于加載網(wǎng)絡(luò)圖片
import Kingfisher
創(chuàng)建一個(gè)枚舉用來(lái)設(shè)置分頁(yè)標(biāo)簽的位置
///
/// - center: 中間
/// - left: 左側(cè)
/// - right: 右側(cè)
enum PagePosition {
case center
case left
case right
}
設(shè)置協(xié)議和協(xié)議中的方法
為了實(shí)現(xiàn)Banner點(diǎn)擊事件
protocol SirSlideshowViewDelegate {
func ClickBanner(index:Int)
}
下面為SirSlideshowView類中所有的設(shè)置的屬性和方法,代碼注釋比較多,相信你一定能看懂!
class SirSlideshowView: UIView {
//設(shè)置代理
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圖片標(biāo)題:默認(rèn)為false,不添加
var isShowImageTitle : Bool? = false {
didSet{
isShow = isShowImageTitle
setUIForImageTitle()
}
}
/// Banner圖片數(shù)組
var images : [Any] = []{
didSet{
pageControl?.numberOfPages = images.count
reloadImage()
}
}
/// Banner標(biāo)題數(shù)組
var imageTitles : [String] = []{
didSet{
reloadImage()
}
}
/// Banner標(biāo)題顏色
var imageTitleColor : UIColor = UIColor.black{
didSet{
imagetitleLabel?.tintColor = imageTitleColor
}
}
/// 分頁(yè)指示器非當(dāng)前頁(yè)小點(diǎn)顏色
var pageIndicatorColor : UIColor = UIColor.white{
didSet{
pageControl?.pageIndicatorTintColor = pageIndicatorColor
}
}
/// 分頁(yè)指示器當(dāng)前頁(yè)小點(diǎn)顏色
var currentPageIndicatorColor : UIColor = UIColor.black{
didSet{
pageControl?.currentPageIndicatorTintColor = currentPageIndicatorColor
}
}
/// 初始化方法
///
/// - Parameters:
/// - frame: Frame
/// - images: Banner圖片數(shù)組
/// - imageTitles: Banner標(biāo)題數(shù)組
/// - pagePosition: 分頁(yè)指示器的位置
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() {
//創(chuàng)建scrollview
scrollView = UIScrollView(frame: self.bounds)
scrollView?.delegate = self
scrollView?.isPagingEnabled = true
scrollView?.showsHorizontalScrollIndicator = false
scrollView?.showsVerticalScrollIndicator = false
self.addSubview(scrollView!)
//創(chuàng)建3個(gè)imageView 用于顯示輪播圖片,圖片依次設(shè)置好最后一個(gè)苦酱,第一個(gè),第二個(gè)圖片
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)
}
//創(chuàng)建分頁(yè)控制標(biāo)簽
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設(shè)置為nil才會(huì)銷(xiāo)毀
fileprivate func removeTimer() {
timer?.invalidate()
timer = nil
}
/// 下一個(gè)圖片
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)
}
/// 上一個(gè)圖片
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)
}
/// 重新加載圖片法瑟,設(shè)置3個(gè)imageView的圖片
fileprivate func reloadImage() {
//通過(guò)pageControl當(dāng)前選中的位置,獲取當(dāng)前輪播到哪一張圖片
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)!)
}
/// 設(shè)置圖片
///
/// - 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{
/// 開(kāi)始滑動(dòng)的時(shí)候钟病,停止timer蟹地,將timer設(shè)置為nil才會(huì)銷(xiāo)毀
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
removeTimer()
}
/// 當(dāng)停止?jié)L動(dòng)的時(shí)候重新設(shè)置三個(gè)ImageView的內(nèi)容贯莺,然后顯示中間那個(gè)imageView
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
reloadImage()
scrollView.setContentOffset(CGPoint(x: self.frame.width, y: 0), animated: false)
}
/// 停止拖拽,開(kāi)始timer, 并且判斷是顯示上一個(gè)圖片還是下一個(gè)圖片
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
addTimer()
if scrollView.contentOffset.x < self.frame.width {
preImage()
} else {
nextImage()
}
}
}
簡(jiǎn)單使用如下:
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 = ["起舞飛揚(yáng)","圣誕快樂(lè)","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),簡(jiǎn)單粗暴的輪播圖(Banner)開(kāi)發(fā)大功告成,相信本講,對(duì)讀者朋友會(huì)有所幫助,如果覺(jué)得文章還可以,點(diǎn)擊下方??喜歡鼓勵(lì)一下,沒(méi)關(guān)注的朋友可以點(diǎn)擊一下關(guān)注,專題系列講解持續(xù)更新中!