「Swift」类抖音、小红书等个人中心多个子控制器功能

需求背景:类似抖音小红书等个人中心文章发布、文章点赞、文章收藏等多子控制器功能,并且子控制器可左右滑动和下拉刷新

技术方案:JXPagingView使用方法详情(JXPagingListRefreshView子页面刷新)

寻找相关资料,发现github上JXPagingView可以实现该功能,以下详细介绍JXPagingListRefreshView使用方法

github: github.com/pujiaxin33/...

首先在podfile中引入相关库文件

swift 复制代码
   pod 'JXPagingView'
   pod 'JXSegmentedView'

ps:JXSegmentedView是个分类切换滚动视图

github:github.com/pujiaxin33/...

父控制器相关代码:

swift 复制代码
import UIKit
import JXPagingView
import JXSegmentedView

/// 父控制器
class HomeViewController: BaseViewController {
	///文章分类上方部分
    private var myHeaderView = HomeHeaderView()
    
    ///三个子控制器
    private var hotChildVC = HomeHotListChildViewController()
    private var newChildVC = HomeNewListChildViewController()
    private var allChildVC = HomeAllListChildViewController()
    
   	///这里上滑触顶的时候,状态栏为透明色
    private var blankView = UIView()
    
    lazy var pagingView: JXPagingListRefreshView = JXPagingListRefreshView(delegate: self)
    
    lazy var segmentedView: JXSegmentedView = JXSegmentedView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: CGFloat(headerInSectionHeight)))
    var dataSource = JXSegmentedTitleDataSource()
    var titles = ["热门", "最新", "全部"]
    
    ///分类上方头部高度
    private var headerViewHeight: Int = Int(205.fit() + Common.navigationBarHeight)
    ///分类标题高度
    private var headerInSectionHeight: Int = Int(52.fit())
    ///上滑触顶偏移量
    private var pagingViewPinSectionHeaderVerticalOffset: Int = Int(31.fit())
 
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        initView()
        setupLayout()
    }
    
    private func initView() {
        self.isNavBarisHidden = true
        self.view.backgroundColor = UIColor.design(.design_F7F7F7)
        
        blankView.backgroundColor = UIColor.design(.design_F7F7F7)
        
        ///分类标题栏数据内容
        dataSource.titles = titles
        dataSource.titleSelectedColor = UIColor.design(.design_24292B)
        dataSource.titleNormalColor = UIColor.design(.design_9DA2A5)
        dataSource.titleNormalFont = UIFont.font(of: 16.fit(), weight: .medium)
        dataSource.isTitleColorGradientEnabled = true
        dataSource.isTitleZoomEnabled = false

        segmentedView.backgroundColor = UIColor.design(.design_F7F7F7)
        segmentedView.delegate = self
        segmentedView.dataSource = dataSource
        segmentedView.listContainer = pagingView.listContainerView

        //扣边返回处理,下面的代码要加上(demo中展示需加上)
        pagingView.listContainerView.scrollView.panGestureRecognizer.require(toFail: self.navigationController!.interactivePopGestureRecognizer!)
        pagingView.mainTableView.panGestureRecognizer.require(toFail: self.navigationController!.interactivePopGestureRecognizer!)
               self.navigationController?.interactivePopGestureRecognizer?.isEnabled = true
        
        pagingView.pinSectionHeaderVerticalOffset = pagingViewPinSectionHeaderVerticalOffset

        pagingView.backgroundColor = UIColor.design(.design_F7F7F7)

        self.view.addSubview(pagingView)
        self.view.addSubview(blankView)
    }
    
    private func setupLayout() {        
        pagingView.snp.makeConstraints { make in
            make.top.equalToSuperview()
            make.left.equalToSuperview()
            make.width.equalTo(Common.screenWidth)
            make.height.equalTo(Common.screenHeight)
        }
        
        blankView.snp.makeConstraints { make in
            make.top.equalToSuperview()
            make.left.equalToSuperview()
            make.width.equalTo(Common.screenWidth)
            make.height.equalTo(Common.navigationBarHeight)
        }
    }
    
}

///JXpagingView代理方法
extension HomeViewController: JXPagingViewDelegate {
    func tableHeaderViewHeight(in pagingView: JXPagingView) -> Int {
    	///上方头部高度
        return headerViewHeight
    }
    
    func tableHeaderView(in pagingView: JXPagingView) -> UIView {
    	///上方头部View(我这里使用的自定义View,建议提出单独写View)
        return myHeaderView
    }
    
    func heightForPinSectionHeader(in pagingView: JXPagingView) -> Int {
    	///上滑移动最大偏移量(大于这个偏移量就无法再上滑)
        return headerInSectionHeight
    }
    
    func viewForPinSectionHeader(in pagingView: JXPagingView) -> UIView {
    	///分类文章标题View
        return segmentedView
    }
    
    func numberOfLists(in pagingView: JXPagingView) -> Int {
    	///分类标题个数
        return titles.count
    }
    
    func pagingView(_ pagingView: JXPagingView, initListAtIndex index: Int) -> JXPagingViewListViewDelegate {
        ///每个标题分别对应的子控制器
        if index == 0 {
            return hotChildVC
            
        } else if index == 1 {
            return newChildVC
            
        } else {
            return allChildVC
        }
    }
    
    func pagingView(_ pagingView: JXPagingView, mainTableViewDidScroll scrollView: UIScrollView) {
        
    }

}

extension HomeViewController: JXSegmentedViewDelegate {
	///默认的分类标题选择项
    func segmentedView(_ segmentedView: JXSegmentedView, didSelectedItemAt index: Int) {
        self.navigationController?.interactivePopGestureRecognizer?.isEnabled = (index == 0)
    }
}

/// 需要将JXPagingListContainerView继承JXSegmentedViewListContainer,不然会报错,开发文档中也有所提及
extension JXPagingListContainerView: JXSegmentedViewListContainer {}

子控制器相关代码:

swift 复制代码
import UIKit
import JXPagingView
import MJRefresh

/// 热门商品列表
class HomeHotListChildViewController: UIViewController, JXPagingViewListViewDelegate {
	///三个子控制器需要添加的代理方法
    func listView() -> UIView {
        return self.view
    }

    func listScrollView() -> UIScrollView {
    	///传入带有UIScrollView的组件,可以进行滚动
        return self.myTableView
    }

    func listViewDidScrollCallback(callback: @escaping (UIScrollView) -> ()) {
    	///这个比较重要,可以将父控制器的上下滚动传递进来
        self.scrollCallback = callback
    }

    private var myTableView: UITableView!
    
    private var productList = [productModel]()
    
    /// scrollView回调
    var scrollCallback:((UIScrollView) -> Void)?

    override func viewDidLoad() {
        super.viewDidLoad()

        initView()
        setupLayout()
        requestData()
        addUpDownPullRefresh()
    }
    
    private func initView() {
        self.view.backgroundColor = UIColor.design(.design_F7F7F7)
        
        myTableView = UITableView(frame: .zero, style: .plain)
        myTableView.backgroundColor = UIColor.design(.design_F7F7F7)
        myTableView.showsVerticalScrollIndicator = false
        myTableView.separatorStyle = .none
        myTableView.delegate = self
        myTableView.dataSource = self
        
        myTableView.register(HomeProductCell.self, forCellReuseIdentifier: NSStringFromClass(HomeProductCell.self))
        
        self.view.addSubview(myTableView)
        
    }
    
    private func setupLayout() {
        myTableView.snp.makeConstraints { make in
            make.top.equalTo(8.fit())
            make.left.equalTo(16.fit())
            make.right.equalTo(-16.fit())
            make.bottom.equalToSuperview()
        }
    }
    
    ///添加tableView的下拉刷新和上拉加载更多
    private func addUpDownPullRefresh() {
        myTableView.mj_header = MJRefreshNormalHeader(refreshingBlock: { [weak self] in
            guard let self = self else {return}
            self.requestData()
        })
        
        myTableView.mj_footer = MJRefreshAutoNormalFooter(refreshingBlock: { [weak self] in
            guard let self = self else {return}
            self.requestDataMore()
        })
    }
    
    private func requestData() {
		print("requestData")

        myTableView.mj_footer?.resetNoMoreData()
        myTableView.mj_header?.endRefreshing()
    }
    
    private func requestDataMore() {
        print("requestDataMore")
        
        myTableView.mj_footer?.endRefreshing()
    }
}

///下面就是常规的UITableView代理方法
extension HomeHotListChildViewController: UITableViewDelegate,
                                          UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return productList.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: NSStringFromClass(HomeProductCell.self), for: indexPath) as! HomeProductCell
        cell.selectionStyle = .none
        cell.updateCellWithModel(model: productList[indexPath.row])
        cell.clickLearnMoreBtnAction = { [self] in
            print("success Click")
            let vc = HomeProductDetailViewController(model: productList[indexPath.row])
            vc.hidesBottomBarWhenPushed = true
            
            self.navigationController?.pushViewController(vc, animated: true)
        }
        
        return cell
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        if indexPath.row == productList.count - 1 {
            return 120.fit()
            
        } else {
            return 132.fit()
        }
    }
    
    ///记得加上ScrollView的回调 
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        self.scrollCallback?(scrollView)
    }
}
其他子控制器与此类似

效果展示:

该代码部分取自原先项目,以此记录以便后续查看,如有可以改进之处也希望各位大佬多多指出!希望大家多多点赞!
相关推荐
__zhangheng3 小时前
Info.plist contained no UIScene configuration dictionary (looking for configura
macos·ios·objective-c·cocoa·swift
m0_748238923 天前
webgis入门实战案例——智慧校园
开发语言·ios·swift
Swift社区4 天前
Excel 列名称转换问题 Swift 解答
开发语言·excel·swift
东坡肘子5 天前
肘子的 Swift 周报 #063|异种肾脏移植取得突破
swiftui·swift·apple
威化饼的一隅5 天前
【多模态】swift-3框架使用
人工智能·深度学习·大模型·swift·多模态
opentogether7 天前
Swift 的动态性
开发语言·ssh·swift
苍墨穹天8 天前
SWIFT基本使用
linux·swift
SchneeDuan8 天前
从源码分析swift GCD_DispatchGroup
ios·swift·源码分析·gcd
请叫我飞哥@10 天前
iOS在项目中设置 Dev、Staging 和 Prod 三个不同的环境
ios·xcode·swift
Cedric_Anik12 天前
iOS渲染概述
ui·ios·swift