iOS JXBanner - (多功能無(wú)限輪播圖框架)

(JXBanner 支持多種動(dòng)畫變換, 支持純代碼布局和Xib布局)

JXBanner依賴于JXPageControl,并包含許多自定義接口,如轉(zhuǎn)換動(dòng)畫、視圖結(jié)構(gòu)和設(shè)置


    1. 開(kāi)發(fā)環(huán)境: Xcode 7
    1. 運(yùn)行條件: iOS(8.0+)
  • 開(kāi)源框架:github地址

?

(如果使用有什么問(wèn)題,可以留言,歡迎一起學(xué)習(xí),歡迎star)


Installation [安裝]

安裝,只需將以下面代碼添加到您的Podfile:


platform :ios, '8.0'

target 'TargetName' do
pod 'JXBanner'
end


UI效果

  • default

不需要設(shè)置JXBanner -> JXBannerLayoutParams

default.gif

  • JXBannerTransformLinear
linear.gif

  • JXBannerTransformCoverflow
coverflow.gif

  • custom

需要實(shí)現(xiàn)JXBannerTransformable協(xié)議, 修改 UICollectionViewLayoutAttributes -> transform3D 或 transform 屬性

custom.gif

Frame set [框架集合]

?

Banner 輪播圖框架公用類文件
  • API ---> 開(kāi)發(fā)者可以調(diào)用的所有接口
  • Cell ---> 框架提供cell基類 (如果想自定義cell內(nèi)容, 可以新建cell繼承于JXBannerBaseCell)
  • Common ---> 框架公用類文件
  • Transform ---> 動(dòng)畫效果類文件 ( 如果框架提供的動(dòng)畫效果不能滿足開(kāi)發(fā)者需求, 可以新建實(shí)現(xiàn)JXBannerTransformable協(xié)議的struct/class, 修改 UICollectionViewLayoutAttributes -> transform3D 或 transform 屬性)
PageControl 指示器類文件
  • JXBannerPageControlBuilder ---> pageControl的構(gòu)建者類
  • JXBannerPageControlDefault ---> 框架默認(rèn)的pageControl樣式 (可以通過(guò)實(shí)現(xiàn)JXBannerDataSource -> 【jxBanner(pageControl banner: numberOfPages: coverView: builder:) -> JXBannerPageControlBuilder】協(xié)議方法修改樣式)

JXBanner 重要文件介紹

?

JXBannerParams 【banner 屬性】
  • isAutoPlay ---> 自動(dòng)播放
  • isBounces ---> 邊界能否越界滑動(dòng)
  • timeInterval ---> 播放調(diào)度間隔
  • isShowPageControl ---> 是否加載內(nèi)部指示器(JXPageControl(框架特色)
  • cycleWay ---> 輪播方式(框架特色) (forward:無(wú)線向右播放, skipEnd:首尾自定義動(dòng)畫跳轉(zhuǎn), rollingBack:左右回滾模式)
  • edgeTransitionType ---> cycleWay 使用 skipEnd 中 可以選取動(dòng)畫方式
  • edgeTransitionSubtype ---> cycleWay 使用 skipEnd 中 可以選取動(dòng)畫方式

JXBannerLayoutParams 【banner布局、動(dòng)畫屬性】
  • itemSize ---> cell大小。
  • itemSpacing --->cell左右邊距。
  • layoutType ---> 動(dòng)畫效果JXBannerTransformable(框架特色)
  • minimumScale ---> cell 縮放系數(shù)。
  • minimumAlpha ---> cell 透明度系數(shù)。
  • maximumAngle ---> cell 旋轉(zhuǎn)系數(shù)。
  • rateOfChange ---> cell 變化系數(shù)。
  • rateHorisonMargin ---> cell 水平間距調(diào)整系數(shù)。

JXBannerCellRegister 【cell注冊(cè)構(gòu)建者】
  • type ---> 注冊(cè)cell的類型,必須是JXBannerBaseCell的子類

  • reuseIdentifier ---> cell重用標(biāo)識(shí)

    var type: JXBannerBaseCell.Type
    var reuseIdentifier: String


JXBanner 使用

?

Example 1
  • 默認(rèn)實(shí)現(xiàn)示例

?


import SnapKit
import JXBanner

class JXDefaultVC: UIViewController {
    
    var pageCount = 5
    
    lazy var banner: JXBanner = {
        let banner = JXBanner()
        banner.backgroundColor = UIColor.black
        banner.placeholderImgView.image = UIImage(named: "banner_placeholder")
        banner.delegate = self
        banner.dataSource = self
        return banner
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(banner)
        banner.snp.makeConstraints { (maker) in
            maker.left.right.equalTo(view)
            maker.height.equalTo(250)
            maker.top.equalTo(view.snp_top).offset(100)
        }
        self.automaticallyAdjustsScrollViewInsets = false
    }
    
    deinit {
        print("\(#function) ----------> \(#file.components(separatedBy: "/").last?.components(separatedBy: ".").first ?? #file)")
    }
}

//MARK:- JXBannerDataSource
extension JXDefaultVC: JXBannerDataSource {
    
    // 注冊(cè)重用Cell標(biāo)識(shí)
    func jxBanner(_ banner: JXBannerType)
        -> (JXBannerCellRegister) {
            return JXBannerCellRegister(type: JXBannerCell.self,
                                        reuseIdentifier: "JXDefaultVCCell")
    }
    
    // 輪播總數(shù)
    func jxBanner(numberOfItems banner: JXBannerType)
        -> Int { return pageCount }
    
    // 輪播cell內(nèi)容設(shè)置
    func jxBanner(_ banner: JXBannerType,
                  cellForItemAt index: Int,
                  cell: JXBannerBaseCell)
        -> JXBannerBaseCell {
            let tempCell: JXBannerCell = cell as! JXBannerCell
            tempCell.layer.cornerRadius = 8
            tempCell.layer.masksToBounds = true
            tempCell.imageView.image = UIImage(named: "banner_placeholder")
            tempCell.msgLabel.text = String(index) + "---來(lái)嘍來(lái)嘍,他真的來(lái)嘍~"
            return tempCell
    }
    
    // banner基本設(shè)置(可選)
    func jxBanner(_ banner: JXBannerType,
                  layoutParams: JXBannerLayoutParams)
        -> JXBannerLayoutParams {
        return layoutParams
            .itemSize(CGSize(width: UIScreen.main.bounds.width - 40, height: 200))
            .itemSpacing(20)
    }
}

//MARK:- JXBannerDelegate
extension JXDefaultVC: JXBannerDelegate {
    
    // 點(diǎn)擊cell回調(diào)
    public func jxBanner(_ banner: JXBannerType,
                         didSelectItemAt index: Int) {
        print(index)
    }
    
}



Example 2

?

  • 個(gè)性化設(shè)置

import SnapKit
import JXBanner
import JXPageControl

class JXCustomVC: UIViewController {
    
    var pageCount = 5
    
    lazy var linearBanner: JXBanner = {[weak self] in
        let banner = JXBanner()
        banner.placeholderImgView.image = UIImage(named: "banner_placeholder")
        banner.backgroundColor = UIColor.black
        banner.indentify = "linearBanner"
        banner.delegate = self
        banner.dataSource = self
        return banner
    }()
    
    lazy var converflowBanner: JXBanner = {
        let banner = JXBanner()
        banner.placeholderImgView.image = UIImage(named: "banner_placeholder")
        banner.backgroundColor = UIColor.black
        banner.indentify = "converflowBanner"
        banner.delegate = self
        banner.dataSource = self
        return banner
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(linearBanner)
        view.addSubview(converflowBanner)
        linearBanner.snp.makeConstraints {(maker) in
            maker.left.right.equalTo(view)
            maker.height.equalTo(200)
            maker.top.equalTo(view.snp_top).offset(100)
        }
        
        converflowBanner.snp.makeConstraints {(maker) in
            maker.left.right.height.equalTo(linearBanner)
            maker.top.equalTo(linearBanner.snp_bottom).offset(100)
        }
        
        self.automaticallyAdjustsScrollViewInsets = false
    }
    
    deinit {
        print("\(#function) ----------> \(#file.components(separatedBy: "/").last?.components(separatedBy: ".").first ?? #file)")
    }
}

//MARK:- JXBannerDataSource
extension JXCustomVC: JXBannerDataSource {
    
    // 注冊(cè)重用Cell標(biāo)識(shí)
    func jxBanner(_ banner: JXBannerType)
        -> (JXBannerCellRegister) {

            if banner.indentify == "linearBanner" {
                return JXBannerCellRegister(type: JXBannerCell.self,
                                            reuseIdentifier: "LinearBannerCell")
            }else {
                return JXBannerCellRegister(type: JXBannerCell.self,
                                            reuseIdentifier: "ConverflowBannerCell")
            }
    }
    
    // 輪播總數(shù)
    func jxBanner(numberOfItems banner: JXBannerType)
        -> Int { return pageCount }
    
    // 輪播cell內(nèi)容設(shè)置
    func jxBanner(_ banner: JXBannerType,
                  cellForItemAt index: Int,
                  cell: JXBannerBaseCell)
        -> JXBannerBaseCell {
            let tempCell: JXBannerCell = cell as! JXBannerCell
            tempCell.layer.cornerRadius = 8
            tempCell.layer.masksToBounds = true
            tempCell.imageView.image = UIImage(named: "banner_placeholder")
            tempCell.msgLabel.text = String(index) + "---來(lái)嘍來(lái)嘍,他真的來(lái)嘍~"
            return tempCell
    }
    
    // banner基本設(shè)置(可選)
    func jxBanner(_ banner: JXBannerType,
                  params: JXBannerParams)
        -> JXBannerParams {
        
            if banner.indentify == "linearBanner" {
                return params
                    .timeInterval(2)
                    .cycleWay(.forward)
            }else {
                return params
                    .timeInterval(3)
                    .cycleWay(.forward)
            }
    }
    
    // banner布局、動(dòng)畫設(shè)置
    func jxBanner(_ banner: JXBannerType,
                  layoutParams: JXBannerLayoutParams)
        -> JXBannerLayoutParams {
            
            if banner.indentify == "linearBanner" {
                return layoutParams
                    .layoutType(JXBannerTransformLinear())
                    .itemSize(CGSize(width: 250, height: 190))
                    .itemSpacing(10)
                    .rateOfChange(0.8)
                    .minimumScale(0.7)
                    .rateHorisonMargin(0.5)
                    .minimumAlpha(0.8)
            }else {
                return layoutParams
                    .layoutType(JXBannerTransformCoverflow())
                    .itemSize(CGSize(width: 300, height: 190))
                    .itemSpacing(0)
                    .maximumAngle(0.25)
                    .rateHorisonMargin(0.3)
                    .minimumAlpha(0.8)
            }
    }
    
    // 自定義pageControl樣式、布局
    //(基于jxPageControl, 如果不適用JXPageControl, 設(shè)置isShowPageControl = false, 內(nèi)部pageControl將不會(huì)再次加載 ) 
    func jxBanner(pageControl banner: JXBannerType,
                  numberOfPages: Int,
                  coverView: UIView,
                  builder: JXBannerPageControlBuilder) -> JXBannerPageControlBuilder {

        if banner.indentify == "linearBanner" {
            let pageControl = JXPageControlScale()
            pageControl.contentMode = .bottom
            pageControl.activeSize = CGSize(width: 15, height: 6)
            pageControl.inactiveSize = CGSize(width: 6, height: 6)
            pageControl.activeColor = UIColor.red
            pageControl.inactiveColor = UIColor.lightGray
            pageControl.columnSpacing = 0
            pageControl.isAnimation = true
            builder.pageControl = pageControl
            builder.layout = {
                pageControl.snp.makeConstraints { (maker) in
                    maker.left.right.equalTo(coverView)
                    maker.top.equalTo(coverView.snp_bottom).offset(10)
                    maker.height.equalTo(20)
                }
            }
            return builder

        }else {
            let pageControl = JXPageControlExchange()
            pageControl.contentMode = .bottom
            pageControl.activeSize = CGSize(width: 15, height: 6)
            pageControl.inactiveSize = CGSize(width: 6, height: 6)
            pageControl.activeColor = UIColor.red
            pageControl.inactiveColor = UIColor.lightGray
            pageControl.columnSpacing = 0
            builder.pageControl = pageControl
            builder.layout = {
                pageControl.snp.makeConstraints { (maker) in
                    maker.left.right.equalTo(coverView)
                    maker.top.equalTo(coverView.snp_bottom).offset(10)
                    maker.height.equalTo(20)
                }
            }
            return builder
        }

    }
    
}

//MARK:- JXBannerDelegate
extension JXCustomVC: JXBannerDelegate {
    
    // 點(diǎn)擊cell回調(diào)
    public func jxBanner(_ banner: JXBannerType,
                         didSelectItemAt index: Int) {
        print(index)
    }
    
    // 設(shè)置自定義覆蓋View, 比如添加自定義外部pageControl和布局
    func jxBanner(_ banner: JXBannerType, coverView: UIView) {
        let title = UILabel()
        title.frame = CGRect(x: 0, y: 0, width: 100, height: 30)
        title.text = "JXBanner"
        title.textColor = UIColor.red
        title.font = UIFont.systemFont(ofSize: 16)
        coverView.addSubview(title)
    }
    
    // 最中心顯示cell 索引
    func jxBanner(_ banner: JXBannerType, center index: Int) {
        print(index)
    }
}

Example 3

如果框架提供的動(dòng)畫效果不能滿足開(kāi)發(fā)者需求:

    1. 輪播圖動(dòng)畫樣式開(kāi)發(fā)者可以自定義實(shí)現(xiàn), 只要是新建實(shí)現(xiàn)JXBannerTransformable協(xié)議的struct/class, 修改 UICollectionViewLayoutAttributes -> transform3D 或 transform 屬性)

//
//  JXCustomTransform.swift
//  JXBanner_Example
//
//  Created by 譚家祥 on 2019/7/30.
//  Copyright ? 2019 CocoaPods. All rights reserved.
//

import UIKit
import JXBanner

struct JXCustomTransform: JXBannerTransformable {
    
    public func transformToAttributes(collectionView: UICollectionView,
                                      params: JXBannerLayoutParams,
                                      attributes: UICollectionViewLayoutAttributes) {
        
        let collectionViewWidth = collectionView.frame.width
        if collectionViewWidth <= 0 { return }
        
        let centetX = collectionView.contentOffset.x + collectionViewWidth * 0.5;
        let delta = abs(attributes.center.x - centetX)
        let calculateRate = 1 - delta / collectionViewWidth
        let angle = min(delta / collectionViewWidth * (1 - params.rateOfChange), params.maximumAngle)
        let alpha = max(calculateRate, params.minimumAlpha)
        
        
        applyCoverflowTransformToAttributes(viewCentetX: centetX,
                                            attributes: attributes,
                                            params: params,
                                            angle: angle,
                                            alpha: alpha,
                                            calculateRate: calculateRate)
    }
    
    func applyCoverflowTransformToAttributes(viewCentetX: CGFloat,
                                             attributes: UICollectionViewLayoutAttributes,
                                             params: JXBannerLayoutParams,
                                             angle: CGFloat,
                                             alpha: CGFloat,
                                             calculateRate: CGFloat) -> Void {
        var transform3D: CATransform3D = CATransform3DIdentity
        
        
        let location = JXBannerTransfrom.itemLocation(viewCentetX: viewCentetX,
                                                      itemCenterX: attributes.center.x)

        var _angle = angle
        var _alpha = alpha
        var _translateX: CGFloat = 0
        var _translateY: CGFloat = 0
        attributes.zIndex = 0
        
        switch location {
        case .left:
            _angle = angle
            _translateX = 0.2 * attributes.size.width * (1 - calculateRate) / 4
            _translateY = 0.4 * attributes.size.height * (1 - calculateRate)
            
            
        case .right:
            _angle = -angle
            _translateX = -0.2 * attributes.size.width * (1 - calculateRate) / 4
            _translateY = 0.4 * attributes.size.height * (1 - calculateRate)
            
        case .center:
            _angle = 0
            _alpha = 1
            _translateY = 0
            attributes.zIndex = 10000
        }
        
        transform3D = CATransform3DTranslate(transform3D, _translateX, _translateY, 0)
        transform3D = CATransform3DRotate(transform3D, -CGFloat.pi * _angle, 0, 0, 1)
        attributes.alpha = _alpha
        attributes.transform3D = transform3D
    }

}


    1. 設(shè)置自定義實(shí)現(xiàn)動(dòng)畫

JXBannerDataSource -> 【jxBanner(_ banner: layoutParams: ) -> JXBannerLayoutParams】


    // JXCustomTransform()

    func jxBanner(_ banner: JXBannerType,
                  layoutParams: JXBannerLayoutParams)
        -> JXBannerLayoutParams {
            
            return layoutParams
                .layoutType(JXCustomTransform())
    }

更多設(shè)置可以參考示例 Demo地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容