LLSegmentViewController详解

LLCtlPageView类分析

2019-11-12  本文已影响0人  谌文

LLCtlPageView分析

LLCtlPageView是用来陈放自控制器view的容器,是继承UIScrollView

open class LLCtlPageView: UIScrollView {

实现的一个类, 功能类似系统的tableview,有协议方法LLCtlPageViewDataSource, 用于获取数据源

实现原理

通过LLCtlPageViewDataSource获取自控制器view数据源
然后通过实现UIScrollViewDelegate代理方法scrollViewDidScroll来刷新和设置(reloadCurrentShowView)子控制器view的frame位置
注意点: 此类由于是UIScrollView类型,在侧滑时会与导航侧滑想冲突,所以为了解决这个问题,该类实现extension LLCtlPageView:UIGestureRecognizerDelegate该代理的

    // 这个方法返回YES,第一个和第二个互斥时,第二个会失效, 解决手势冲突,返回false不处理,系统会默认处理
    public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool 

的方法

//
//  LLViewControllerContainerView.swift
//  LLScrollerView
//
//  Created by apple on 2019/1/17.
//  Copyright © 2019年 lilin. All rights reserved.
//

import UIKit

// MARK: 获取自控制器view的代理方法
public protocol LLCtlPageViewDataSource:NSObjectProtocol {
    func numberOfItems(in pageView:LLCtlPageView) -> Int
    func pageView(_ pageView: LLCtlPageView, viewForItemAt index: NSInteger) -> UIView
}

// MARK: - 盛放子控制器view的类
open class LLCtlPageView: UIScrollView {
    //预加载范围,当前view前面几个,后面几个
    public var preLoadRange = 0...0
    
    private var itemCount = 0
    internal weak var dataSoure:LLCtlPageViewDataSource!{
        didSet{
            reloadData()
        }
    }
    
    init(frame: CGRect,ctls:[UIViewController]) {
        super.init(frame: frame)
        initSubViews()
    }
    required public init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    fileprivate func initSubViews() {
        self.delegate = self
        self.backgroundColor = UIColor.clear
        /// 整页滚动
        self.isPagingEnabled = true
        /// 不需要弹性
        self.bounces = false
        /// 内边距为0
        self.contentInset = UIEdgeInsets.zero
        /// 不展示横竖滑动条
        self.showsHorizontalScrollIndicator = false
        self.showsVerticalScrollIndicator = false
        self.isDirectionalLockEnabled = true
        if #available(iOS 11.0, *) {
            self.contentInsetAdjustmentBehavior = .never
        }
    }
}

// MARK: - 盛放子控制器view的类,扩展方法
extension LLCtlPageView{
    /// 展示那个子控制器view
    internal func reloadCurrentIndex(index:NSInteger){
        self.contentOffset = CGPoint.init(x: CGFloat(index)*self.bounds.width, y: 0)
    }
    
    /// 刷新(如添加或者减少啦一个自控制器view)
    internal func reloadData() {
        /// 获取代理实现的自控制器的数量
        itemCount = dataSoure.numberOfItems(in: self)
        self.contentSize = CGSize.init(width: CGFloat(itemCount)*self.bounds.width, height: self.bounds.height)
        /// 刷新当前展示的自控制器view
        reloadCurrentShowView()
    }
    
    /// 刷新当前展示的自控制器view和pageview
    fileprivate func reloadCurrentShowView() {
        guard itemCount > 0 else { return }
        
        let showPages = getShowPageIndex(maxCount: itemCount - 1)
        var pages = [NSInteger]()
        let left = showPages.leftIndex - preLoadRange.lowerBound
        let right = showPages.rightIndex + preLoadRange.upperBound
        for index in left...right {
            if (0...itemCount-1).contains(index){
                pages.append(index)
            }
        }
        
        for index in pages {
            let showView = dataSoure.pageView(self, viewForItemAt: index)
            showView.frame = CGRect.init(x: CGFloat(index)*bounds.width, y: 0, width: bounds.width, height: bounds.height)
            if !subviews.contains(showView){
                addSubview(showView)
            }
        }
    }
}

// MARK: - 实现手势代理
extension LLCtlPageView:UIGestureRecognizerDelegate{
    // 这个方法返回YES,第一个和第二个互斥时,第二个会失效, 解决手势冲突,返回false不处理,系统会默认处理
    public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        if !gestureRecognizer.isKind(of: UIPanGestureRecognizer.classForCoder()) || !otherGestureRecognizer.isKind(of: UIPanGestureRecognizer.classForCoder()){
            return false
        }
        
        guard let gestureView = gestureRecognizer.view as? LLCtlPageView else{
            return false
        }
        
        guard let otherGestureView = otherGestureRecognizer.view as? LLCtlPageView else{
            return false
        }

        if gestureView != self {
            return false
        }
        
        let currentIndex = Int(gestureView.contentOffset.x / gestureView.bounds.width)
        let subIndex = Int(otherGestureView.contentOffset.x / otherGestureView.bounds.width)
        if subIndex > 0 {
            return false
        }else if subIndex == 0 {
            if currentIndex == gestureView.itemCount - 1 {
                return true
            }
            return false
        }
        return false
    }
}

extension LLCtlPageView:UIScrollViewDelegate{
    public func scrollViewDidScroll(_ scrollView: UIScrollView) {
        reloadCurrentShowView()
    }
}

extension UIScrollView{
    fileprivate func getShowPageIndex(maxCount:NSInteger) -> (leftIndex:NSInteger,rightIndex:NSInteger) {
        let index = self.contentOffset.x/self.bounds.width
        let leftItemIndex = max(0, min(maxCount, Int((index))))
        let rightItemIndex = max(0, min(maxCount, Int(ceil(index))))
        return (leftItemIndex,rightItemIndex)
    }
}

上一篇 下一篇

猜你喜欢

热点阅读