使用Swift开发一个贝乐虎启蒙App - 识字页面布局

1,038 阅读2分钟

前言

现在都不知道写些什么了,今天我们来画个这个页面

1111111.gif

看效果图发现,底部是个背景图片,背景图上面放了一个一个的小图片,小图片是有规律的排版。 所以我的思路是:

1、最底部是一个scrollViewscrollView上面放一个背景图片,scrollViewcontentSize的高度是图片的高度
2、scrollView上面再放个tableViewtableViewcell就是一个一个的小图片,然后tableView的高度设置成背景图片的高度
3、根据规则计算小图片的位置

好了那我们就开始做吧

新建一个StudyViewController

  • 我们使用JXCategoryView来做分页,先初始化JXCategoryView
class StudyViewController: BaseViewController {

    var id: String = ""
    private var controllers = [StudyChildViewController]()
    private var titles = [StudySecItemModel]()
    private var cateId: String = ""
    private var imageBaseName = ""

    private lazy var titleView: JXCategoryNumberView = {
        let lineView = JXCategoryIndicatorLineView()
        lineView.indicatorColor = .theme
        lineView.indicatorHeight = 4
        let titleView = JXCategoryNumberView()
        titleView.defaultSelectedIndex = 0
        titleView.delegate = self
        titleView.indicators = [lineView]
        titleView.titleColor = .c999999
        titleView.titleSelectedColor = .theme
        titleView.titleFont = 14.font
        titleView.titleSelectedFont = 16.font
        titleView.isTitleColorGradientEnabled = true
        titleView.backgroundColor = .white
        titleView.isAverageCellSpacingEnabled = true
        titleView.cellSpacing = 0
        return titleView
    }()

    private lazy var listContainerView: JXCategoryListContainerView = {
        let listContainerView = JXCategoryListContainerView(type: .scrollView, delegate: self)
        listContainerView?.setDefaultSelectedIndex(0)
        return listContainerView!
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        addSubviews()
        requestStudyDetailData()
    }

    private func addSubviews() {
        automaticallyAdjustsScrollViewInsets = false

        view.addSubview(titleView)
        view.addSubview(listContainerView)

        titleView.snp.makeConstraints { (make) in
            make.top.equalTo(topLayoutGuideBottom)
            make.left.right.equalToSuperview()
            make.height.equalTo(40)
        }

        listContainerView.snp.makeConstraints { make in
            make.left.right.equalToSuperview()
            make.top.equalTo(titleView.snp.bottom)
            make.bottom.equalTo(safeAreaLayoutGuideBottom)
        }

        titleView.contentScrollView = listContainerView.scrollView
    }
}

// MARK: JXCategoryViewDelegate
extension StudyViewController: JXCategoryViewDelegate {
    func categoryView(_ categoryView: JXCategoryBaseView!, didClickSelectedItemAt index: Int) {
        listContainerView.didClickSelectedItem(at: index)
    }
}

// MARK: JXCategoryListContainerViewDelegate
extension StudyViewController: JXCategoryListContainerViewDelegate {

    func number(ofListsInlistContainerView listContainerView: JXCategoryListContainerView!) -> Int {
        return controllers.count
    }

    func listContainerView(_ listContainerView: JXCategoryListContainerView!, initListFor index: Int) -> JXCategoryListContentViewDelegate! {
        return controllers[index]
    }
}
  • 获取数据
extension StudyViewController {
    /// 详情数据
    private func requestStudyDetailData() {
        Network.School
            .studyDetail(id: id)
            .request()
            .responseData(StudyDetailModel.self) { [weak self] model in
                guard let `self` = self else { return }
                self.navigation.item.title = model.result.title
                self.cateId = model.result.interactLesson.resourceId
                self.imageBaseName = model.result.interactLesson.imageBaseName
                self.requestStudySecData()
        } failure: { error in
            Toast.show(info: error.errorMessage)
        }
    }
    /// 标题数据
    private func requestStudySecData() {
        Network.School
            .studySec(cateId: cateId)
            .request()
            .responseData(StudySecModel.self) { [weak self] model in
                guard let `self` = self else { return }
                self.titles = model.result.items
                self.reloadData()
        } failure: { error in
            Toast.show(info: error.errorMessage)
        }
    }
}
  • 配置数据并刷新
private func reloadData() {
    titleView.titles = titles.map({
        return $0.name
    })
    for item in titles {
        let vc = StudyChildViewController()
        vc.imageName = imageBaseName + String(format: "%02ld", item.nameIndex)
        vc.cateId = cateId
        vc.secId = item.secId
        controllers.append(vc)
    }
    titleView.reloadData()
    listContainerView.reloadData()
}

新建一个StudyChildViewController

  • 初始化scrollView,并在scrollView里面添加imageViewtableView
class StudyChildViewController: BaseViewController {

    var cateId = ""
    var secId = ""
    var imageName: String = ""
    private var imageViewHeight: CGFloat = 0
    private var dataSource = [StudySecItemModel]()

    private lazy var scrollView: UIScrollView = {
        let view = UIScrollView()
        view.bounces = false
        return view
    }()

    private lazy var imageView: UIImageView = {
        let view = UIImageView()
        view.contentMode = .scaleAspectFit
        return view
    }()

    private lazy var tableView: UITableView = {
        let view = UITableView(frame: .zero, style: .plain)
        view.separatorStyle = .none
        view.delegate = self
        view.dataSource = self
        view.backgroundColor = .clear
        view.register(cellWithClass: StudyUnitCell.self)
        return view
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        addSubviews()
        requestStudyUnitData()
    }

    private func addSubviews() {
        disablesAdjustScrollViewInsets(scrollView)
        disablesAdjustScrollViewInsets(tableView)

        /// 设置image,并计算image高度
        if let image = UIImage(named: imageName) {
            imageView.image = image
            let imageW = image.size.width
            let imageH = image.size.height
            let sc = imageH/imageW
            imageViewHeight = UIScreen.width * sc
        }

        view.addSubview(scrollView)
        scrollView.addSubview(imageView)
        scrollView.addSubview(tableView)

        scrollView.snp.makeConstraints { make in
            make.left.top.right.equalToSuperview()
            make.bottom.equalToSuperview()
        }

        imageView.snp.makeConstraints { make in
            make.left.top.equalToSuperview()
            make.width.equalTo(UIScreen.width)
            make.height.equalTo(imageViewHeight)
        }

        tableView.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(10)
            make.left.equalToSuperview()
            make.width.equalTo(UIScreen.width)
            make.height.equalTo(imageViewHeight - 70)
        }

        scrollView.contentSize = CGSize(width: UIScreen.width, height: imageViewHeight)
        scrollView.scrollToBottom()
    }

}

extension StudyChildViewController: UITableViewDelegate, UITableViewDataSource {

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return dataSource.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withClass: StudyUnitCell.self)
        cell.backgroundColor = .clear
        cell.iconView.kf_set(dataSource[indexPath.row].coverVer)
        cell.updateLayout(indexPath.row)
        return cell
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {}

    /// 根据总高度和item的数量计算cell高度
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return (imageViewHeight - 70) / CGFloat(dataSource.count)
    }
}

extension StudyChildViewController: JXCategoryListContentViewDelegate {
    func listView() -> UIView! {
        return view
    }
}
  • 获取数据
extension StudyChildViewController {

    private func requestStudyUnitData() {
        Network.School
            .studyUnitList(cateId: cateId, secId: secId)
            .request()
            .responseData(StudyUnitModel.self) { [weak self] model in
                guard let `self` = self else { return }
                self.dataSource = model.result.items.sorted(by: {
                    $0.index > $1.index
                })
                self.tableView.reloadData()
        } failure: { error in
            Toast.show(info: error.errorMessage)
        }
    }
}
  • 看效果图发现,上面的小图片是每5个会重置,所以在cell里面这样修改小图片的布局,具体的细节可以自己调
func updateLayout(_ index: Int) {
    let i = index % 4
    switch i {
    case 0:
        iconView.snp.updateConstraints { make in
            make.centerX.equalToSuperview().offset(20)
        }
    case 1:
        iconView.snp.updateConstraints { make in
            make.centerX.equalToSuperview().offset(-60)
        }
    case 2:
        iconView.snp.updateConstraints { make in
            make.centerX.equalToSuperview().offset(-20)
        }
    case 3:
        iconView.snp.updateConstraints { make in
            make.centerX.equalToSuperview().offset(60)
        }
    default:
        break
    }
}

效果:

222.gif

如果你们有更好的实现方法,欢迎与我分享