簡(jiǎn)單粗暴的輪播圖(Banner)開(kāi)發(fā)

久別重逢,繼續(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ù)更新中!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末柱衔,一起剝皮案震驚了整個(gè)濱河市樊破,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌唆铐,老刑警劉巖哲戚,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異艾岂,居然都是意外死亡顺少,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)脆炎,“玉大人梅猿,你說(shuō)我怎么就攤上這事⊥罂” “怎么了粒没?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)簇爆。 經(jīng)常有香客問(wèn)我癞松,道長(zhǎng),這世上最難降的妖魔是什么入蛆? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任响蓉,我火速辦了婚禮,結(jié)果婚禮上哨毁,老公的妹妹穿的比我還像新娘枫甲。我一直安慰自己,他們只是感情好扼褪,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布想幻。 她就那樣靜靜地躺著,像睡著了一般话浇。 火紅的嫁衣襯著肌膚如雪脏毯。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,541評(píng)論 1 305
  • 那天幔崖,我揣著相機(jī)與錄音食店,去河邊找鬼。 笑死赏寇,一個(gè)胖子當(dāng)著我的面吹牛吉嫩,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播嗅定,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼自娩,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了渠退?” 一聲冷哼從身側(cè)響起忙迁,我...
    開(kāi)封第一講書(shū)人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎智什,沒(méi)想到半個(gè)月后动漾,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體丁屎,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡荠锭,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了晨川。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片证九。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡删豺,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出愧怜,到底是詐尸還是另有隱情呀页,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布拥坛,位于F島的核電站蓬蝶,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏猜惋。R本人自食惡果不足惜丸氛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望著摔。 院中可真熱鬧缓窜,春花似錦、人聲如沸谍咆。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)摹察。三九已至恩掷,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間港粱,已是汗流浹背螃成。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留查坪,地道東北人寸宏。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像偿曙,于是被迫代替她去往敵國(guó)和親氮凝。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容