在UISCrollView中添加垂直uitableview

发布于 2025-01-20 20:05:20 字数 12031 浏览 4 评论 0原文

我有一个包含一些内容的屏幕,在它的底部我想要一个 UITablView 并且我希望两者同步。如果我滚动底部的 UITableView,UIView 上方的内容也会滚动,有点像粘性标题,但不同之处在于整个屏幕可以被 UITableView 填充。

现在怎么样(底部的图像只是我试图添加下面的元素):

在此处输入图像描述

它应该是怎样的 - 注意底部的列表,我们可以继续滚动它。

输入图片这里的描述

这是我现在的代码:

//
//  HomeViewController.swift
//  FeatureExplorer
//
//  Created by Rodrigo Vieira on 10/04/22.
//

import UIKit
import Combine

class HomeViewController: UIViewController {
    var networkService = NetworkService.shared
    var observers = [AnyCancellable]()
    
    var rootScrollView: UIScrollView = {
        var sv = UIScrollView()
        sv.translatesAutoresizingMaskIntoConstraints = false
        
        return sv
    }()
    
    var rootStackView: UIStackView = {
        var rc = UIStackView()
        rc.translatesAutoresizingMaskIntoConstraints = false
        
        return rc
    }()
    
    var welcomeLabel: UILabel = {
        let label = UILabel()
        
        label.text = "Welcome!"
        label.font = UIFont.boldSystemFont(ofSize: 20)
        
        return label
    }()
    
    var profileImageView: UIImageView = {
        let imageView = UIImageView(image: HomePageImages.profileIconImage!)
        imageView.contentMode = .scaleAspectFit
        
        return imageView
    }()
    
    var searchBar: UITextField = {
        let textField = UITextField()
        
        var leftPaddingView = UIView(
            frame: CGRect(x: 0, y: 0, width: 10, height: 0)
        )
        
        textField.leftView = leftPaddingView
        textField.leftViewMode = .always
        
        textField.layer.cornerRadius = 12
        textField.backgroundColor = .white
        textField.placeholder = "Search cocktails"
        
        textField.layer.shadowColor = UIColor.black.cgColor
        textField.layer.shadowOffset = .init(width: 1, height: 1)
        textField.layer.shadowRadius = 8
        textField.layer.shadowOpacity = 0.2
        
        return textField
    }()
    
    var screenContentContainerView: UIView = {
        let view = UIView()
        
        view.backgroundColor = .white
        view.layer.cornerRadius = 30
        
        view.layer.shadowColor = UIColor.black.cgColor
        view.layer.shadowOpacity = 0.3
        view.layer.shadowOffset = CGSize(width: 1, height: 1)
        view.layer.shadowRadius = 12
        
        return view
    }()
    
    var latestDrinksLabel: UILabel = {
        let label = UILabel()
        
        label.text = "Last cocktails published"
        label.font = UIFont.boldSystemFont(ofSize: 18)
        
        return label
    }()
    
    var recentDrinksCollectionView: RecentDrinksCollectionView = {
        let collectionViewLayout = UICollectionViewFlowLayout()
        collectionViewLayout.scrollDirection = .horizontal
        
        let collectionView = RecentDrinksCollectionView(
            collectionViewLayout: collectionViewLayout
        )
        
        return collectionView
    }()
    
    var popularCocktailsLabel: UILabel = {
        var label = UILabel()
        
        label.font = UIFont.boldSystemFont(ofSize: 18)
        label.text = "Popular drinks"
        
        return label
    }()
    
    override func viewDidLayoutSubviews() {
        
        addScrollViewLayout()
        addRootStackViewLayout()
        addWelcomeLabelLayout()
        addSearchBarLayout()
        addScreenContentViewLayout()
        addLatestLabelLayout()
        addRecentDrinksCollectionLayout()
        addPopularLabelLayout()
        addPopularDrinksTableViewLayout()
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        fetchAndDisplayPopularCocktails()

        view.backgroundColor = Colors.mainRedColor
    }
    
    func addScrollViewLayout() {
        view.addSubview(rootScrollView)
        
        NSLayoutConstraint.activate([
            rootScrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            rootScrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            rootScrollView.topAnchor.constraint(equalTo: view.topAnchor),
            rootScrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])
    }
    
    func addRootStackViewLayout() {
        rootScrollView.addSubview(rootStackView)
        
        NSLayoutConstraint.activate([
            rootStackView.leadingAnchor.constraint(
                equalTo: rootScrollView.contentLayoutGuide.leadingAnchor
            ),
            rootStackView.trailingAnchor.constraint(
                equalTo: rootScrollView.contentLayoutGuide.trailingAnchor
            ),
            rootStackView.topAnchor.constraint(
                equalTo: rootScrollView.contentLayoutGuide.topAnchor
            ),
            rootStackView.bottomAnchor.constraint(
                equalTo: rootScrollView.contentLayoutGuide.bottomAnchor
            ),
            rootStackView.widthAnchor.constraint(
                equalTo: rootScrollView.frameLayoutGuide.widthAnchor
            )
        ])
    }
    
    func addWelcomeLabelLayout() {
        welcomeLabel.translatesAutoresizingMaskIntoConstraints = false
        profileImageView.translatesAutoresizingMaskIntoConstraints = false
    
        rootStackView.addSubview(profileImageView)
        rootStackView.addSubview(welcomeLabel)
        
        NSLayoutConstraint.activate([
            welcomeLabel.leadingAnchor.constraint(
                equalTo: rootStackView.leadingAnchor,
                constant: 20
            ),
            welcomeLabel.trailingAnchor.constraint(
                equalTo: rootStackView.trailingAnchor,
                constant: -20
            ),
            welcomeLabel.topAnchor.constraint(
                equalTo: rootStackView.topAnchor,
                constant: 20
            ),
            profileImageView.topAnchor.constraint(
                equalTo: rootStackView.topAnchor, constant: 20
            ),
            profileImageView.centerXAnchor.constraint(
                equalTo: rootStackView.trailingAnchor,
                constant: -50
            ),
            profileImageView.heightAnchor.constraint(equalToConstant: 60),
            welcomeLabel.centerYAnchor.constraint(
                equalTo: profileImageView.centerYAnchor
            ),
        ])
    }
    
    func addSearchBarLayout() {
        searchBar.translatesAutoresizingMaskIntoConstraints = false
        
        rootStackView.addSubview(searchBar)
        
        NSLayoutConstraint.activate([
            searchBar.leadingAnchor.constraint(
                equalTo: rootStackView.leadingAnchor, constant: 20
            ),
            searchBar.trailingAnchor.constraint(
                equalTo: rootStackView.trailingAnchor, constant: -20
            ),
            searchBar.topAnchor.constraint(
                equalTo: profileImageView.bottomAnchor, constant: 20
            ),
            searchBar.heightAnchor.constraint(equalToConstant: 50),
        ])
    }
    
    func addScreenContentViewLayout() {
        screenContentContainerView.translatesAutoresizingMaskIntoConstraints = false
        rootStackView.addSubview(screenContentContainerView)
        
        NSLayoutConstraint.activate([
            screenContentContainerView.leadingAnchor.constraint(
                equalTo: rootStackView.leadingAnchor
            ),
            screenContentContainerView.trailingAnchor.constraint(
                equalTo: rootStackView.trailingAnchor
            ),
            screenContentContainerView.bottomAnchor.constraint(
                equalTo: view.bottomAnchor
            ),
            screenContentContainerView.topAnchor.constraint(
                equalTo: searchBar.bottomAnchor, constant: 25
            )
        ])
    }
    
    func addLatestLabelLayout() {
        latestDrinksLabel.translatesAutoresizingMaskIntoConstraints = false
        rootStackView.addSubview(latestDrinksLabel)
        
        NSLayoutConstraint.activate([
            latestDrinksLabel.leadingAnchor.constraint(
                equalTo: view.leadingAnchor, constant: 20
            ),
            latestDrinksLabel.trailingAnchor.constraint(
                equalTo: view.trailingAnchor, constant: -20
            ),
            latestDrinksLabel.topAnchor.constraint(
                equalTo: screenContentContainerView.topAnchor, constant: 30
            )
        ])
    }
    
    func addRecentDrinksCollectionLayout() {
        addChild(recentDrinksCollectionView)
        
        recentDrinksCollectionView
            .view
            .translatesAutoresizingMaskIntoConstraints = false
        
        screenContentContainerView.addSubview(recentDrinksCollectionView.view)
        
        NSLayoutConstraint.activate([
            recentDrinksCollectionView.view.topAnchor.constraint(
                equalTo: latestDrinksLabel.bottomAnchor,
                constant: 20
            ),
            recentDrinksCollectionView.view.leadingAnchor.constraint(
                equalTo: view.leadingAnchor
            ),
            recentDrinksCollectionView.view.trailingAnchor.constraint(
                equalTo: view.trailingAnchor
            ),
            recentDrinksCollectionView.view.heightAnchor.constraint(
                equalToConstant: 280
            )
        ])
    }
    
    func addPopularLabelLayout() {
        popularCocktailsLabel.translatesAutoresizingMaskIntoConstraints = false
        screenContentContainerView.addSubview(popularCocktailsLabel)
        
        NSLayoutConstraint.activate([
            popularCocktailsLabel.topAnchor.constraint(
                equalTo: recentDrinksCollectionView.view.bottomAnchor,
                constant: 20
            ),
            popularCocktailsLabel.leadingAnchor.constraint(
                equalTo: rootStackView.leadingAnchor,
                constant: 20
            ),
            popularCocktailsLabel.trailingAnchor.constraint(
                equalTo: rootStackView.trailingAnchor,
                constant: -20
            ),
        ])
    }
    
    func addPopularDrinksTableViewLayout() {
        
    }
    
    func displayTwoFirstPopularDrinks(drinks: [DrinkModel]) {
        let firstPopularDrinkView = PopularDrinkView()
        rootStackView.addSubview(firstPopularDrinkView)
        
        NSLayoutConstraint.activate([
            firstPopularDrinkView.topAnchor.constraint(
                equalTo: popularCocktailsLabel.bottomAnchor,
                constant: 50
            ),
            firstPopularDrinkView.leadingAnchor.constraint(
                equalTo: rootStackView.leadingAnchor,
                constant: 20
            ),
            firstPopularDrinkView.trailingAnchor.constraint(
                equalTo: rootStackView.trailingAnchor,
                constant: -20
            ),
            firstPopularDrinkView.heightAnchor.constraint(
                equalToConstant: 300
            ),
            firstPopularDrinkView.bottomAnchor.constraint(
                equalTo: rootStackView.bottomAnchor
            )
        ])
        
//        firstPopularDrinkView.addContentToView(drink: drinks.first!)
    }
    
    func fetchAndDisplayPopularCocktails() {
        networkService
            .fetchPopularCocktails()
            .receive(on: DispatchQueue.main)
            .sink { completion in
                switch completion {
                case .failure(let error):
                    print(error)
                case .finished:
                    print("finished")
                }
            } receiveValue: { [weak self] value in
                self?.displayTwoFirstPopularDrinks(drinks: value)
            }
            .store(in: &observers)
    }
}

非常感谢您的帮助,真的!

I have a screen that contains some content, and on the bottom of it I'd like to have a UITablView and I'd like that the two were synchronized. If I scroll the UITableView on the bottom, the content that's above the UIView would scroll as well, kinda like a sticky header but different in the sense that the entire screen could be filled by the UITableView.

How it is right now (the image on the bottom is simply me trying to add the element below):

enter image description here

How it should be - notice the list on the bottom, we can keep scrolling it.

enter image description here

This is my code right now:

//
//  HomeViewController.swift
//  FeatureExplorer
//
//  Created by Rodrigo Vieira on 10/04/22.
//

import UIKit
import Combine

class HomeViewController: UIViewController {
    var networkService = NetworkService.shared
    var observers = [AnyCancellable]()
    
    var rootScrollView: UIScrollView = {
        var sv = UIScrollView()
        sv.translatesAutoresizingMaskIntoConstraints = false
        
        return sv
    }()
    
    var rootStackView: UIStackView = {
        var rc = UIStackView()
        rc.translatesAutoresizingMaskIntoConstraints = false
        
        return rc
    }()
    
    var welcomeLabel: UILabel = {
        let label = UILabel()
        
        label.text = "Welcome!"
        label.font = UIFont.boldSystemFont(ofSize: 20)
        
        return label
    }()
    
    var profileImageView: UIImageView = {
        let imageView = UIImageView(image: HomePageImages.profileIconImage!)
        imageView.contentMode = .scaleAspectFit
        
        return imageView
    }()
    
    var searchBar: UITextField = {
        let textField = UITextField()
        
        var leftPaddingView = UIView(
            frame: CGRect(x: 0, y: 0, width: 10, height: 0)
        )
        
        textField.leftView = leftPaddingView
        textField.leftViewMode = .always
        
        textField.layer.cornerRadius = 12
        textField.backgroundColor = .white
        textField.placeholder = "Search cocktails"
        
        textField.layer.shadowColor = UIColor.black.cgColor
        textField.layer.shadowOffset = .init(width: 1, height: 1)
        textField.layer.shadowRadius = 8
        textField.layer.shadowOpacity = 0.2
        
        return textField
    }()
    
    var screenContentContainerView: UIView = {
        let view = UIView()
        
        view.backgroundColor = .white
        view.layer.cornerRadius = 30
        
        view.layer.shadowColor = UIColor.black.cgColor
        view.layer.shadowOpacity = 0.3
        view.layer.shadowOffset = CGSize(width: 1, height: 1)
        view.layer.shadowRadius = 12
        
        return view
    }()
    
    var latestDrinksLabel: UILabel = {
        let label = UILabel()
        
        label.text = "Last cocktails published"
        label.font = UIFont.boldSystemFont(ofSize: 18)
        
        return label
    }()
    
    var recentDrinksCollectionView: RecentDrinksCollectionView = {
        let collectionViewLayout = UICollectionViewFlowLayout()
        collectionViewLayout.scrollDirection = .horizontal
        
        let collectionView = RecentDrinksCollectionView(
            collectionViewLayout: collectionViewLayout
        )
        
        return collectionView
    }()
    
    var popularCocktailsLabel: UILabel = {
        var label = UILabel()
        
        label.font = UIFont.boldSystemFont(ofSize: 18)
        label.text = "Popular drinks"
        
        return label
    }()
    
    override func viewDidLayoutSubviews() {
        
        addScrollViewLayout()
        addRootStackViewLayout()
        addWelcomeLabelLayout()
        addSearchBarLayout()
        addScreenContentViewLayout()
        addLatestLabelLayout()
        addRecentDrinksCollectionLayout()
        addPopularLabelLayout()
        addPopularDrinksTableViewLayout()
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        fetchAndDisplayPopularCocktails()

        view.backgroundColor = Colors.mainRedColor
    }
    
    func addScrollViewLayout() {
        view.addSubview(rootScrollView)
        
        NSLayoutConstraint.activate([
            rootScrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            rootScrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            rootScrollView.topAnchor.constraint(equalTo: view.topAnchor),
            rootScrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])
    }
    
    func addRootStackViewLayout() {
        rootScrollView.addSubview(rootStackView)
        
        NSLayoutConstraint.activate([
            rootStackView.leadingAnchor.constraint(
                equalTo: rootScrollView.contentLayoutGuide.leadingAnchor
            ),
            rootStackView.trailingAnchor.constraint(
                equalTo: rootScrollView.contentLayoutGuide.trailingAnchor
            ),
            rootStackView.topAnchor.constraint(
                equalTo: rootScrollView.contentLayoutGuide.topAnchor
            ),
            rootStackView.bottomAnchor.constraint(
                equalTo: rootScrollView.contentLayoutGuide.bottomAnchor
            ),
            rootStackView.widthAnchor.constraint(
                equalTo: rootScrollView.frameLayoutGuide.widthAnchor
            )
        ])
    }
    
    func addWelcomeLabelLayout() {
        welcomeLabel.translatesAutoresizingMaskIntoConstraints = false
        profileImageView.translatesAutoresizingMaskIntoConstraints = false
    
        rootStackView.addSubview(profileImageView)
        rootStackView.addSubview(welcomeLabel)
        
        NSLayoutConstraint.activate([
            welcomeLabel.leadingAnchor.constraint(
                equalTo: rootStackView.leadingAnchor,
                constant: 20
            ),
            welcomeLabel.trailingAnchor.constraint(
                equalTo: rootStackView.trailingAnchor,
                constant: -20
            ),
            welcomeLabel.topAnchor.constraint(
                equalTo: rootStackView.topAnchor,
                constant: 20
            ),
            profileImageView.topAnchor.constraint(
                equalTo: rootStackView.topAnchor, constant: 20
            ),
            profileImageView.centerXAnchor.constraint(
                equalTo: rootStackView.trailingAnchor,
                constant: -50
            ),
            profileImageView.heightAnchor.constraint(equalToConstant: 60),
            welcomeLabel.centerYAnchor.constraint(
                equalTo: profileImageView.centerYAnchor
            ),
        ])
    }
    
    func addSearchBarLayout() {
        searchBar.translatesAutoresizingMaskIntoConstraints = false
        
        rootStackView.addSubview(searchBar)
        
        NSLayoutConstraint.activate([
            searchBar.leadingAnchor.constraint(
                equalTo: rootStackView.leadingAnchor, constant: 20
            ),
            searchBar.trailingAnchor.constraint(
                equalTo: rootStackView.trailingAnchor, constant: -20
            ),
            searchBar.topAnchor.constraint(
                equalTo: profileImageView.bottomAnchor, constant: 20
            ),
            searchBar.heightAnchor.constraint(equalToConstant: 50),
        ])
    }
    
    func addScreenContentViewLayout() {
        screenContentContainerView.translatesAutoresizingMaskIntoConstraints = false
        rootStackView.addSubview(screenContentContainerView)
        
        NSLayoutConstraint.activate([
            screenContentContainerView.leadingAnchor.constraint(
                equalTo: rootStackView.leadingAnchor
            ),
            screenContentContainerView.trailingAnchor.constraint(
                equalTo: rootStackView.trailingAnchor
            ),
            screenContentContainerView.bottomAnchor.constraint(
                equalTo: view.bottomAnchor
            ),
            screenContentContainerView.topAnchor.constraint(
                equalTo: searchBar.bottomAnchor, constant: 25
            )
        ])
    }
    
    func addLatestLabelLayout() {
        latestDrinksLabel.translatesAutoresizingMaskIntoConstraints = false
        rootStackView.addSubview(latestDrinksLabel)
        
        NSLayoutConstraint.activate([
            latestDrinksLabel.leadingAnchor.constraint(
                equalTo: view.leadingAnchor, constant: 20
            ),
            latestDrinksLabel.trailingAnchor.constraint(
                equalTo: view.trailingAnchor, constant: -20
            ),
            latestDrinksLabel.topAnchor.constraint(
                equalTo: screenContentContainerView.topAnchor, constant: 30
            )
        ])
    }
    
    func addRecentDrinksCollectionLayout() {
        addChild(recentDrinksCollectionView)
        
        recentDrinksCollectionView
            .view
            .translatesAutoresizingMaskIntoConstraints = false
        
        screenContentContainerView.addSubview(recentDrinksCollectionView.view)
        
        NSLayoutConstraint.activate([
            recentDrinksCollectionView.view.topAnchor.constraint(
                equalTo: latestDrinksLabel.bottomAnchor,
                constant: 20
            ),
            recentDrinksCollectionView.view.leadingAnchor.constraint(
                equalTo: view.leadingAnchor
            ),
            recentDrinksCollectionView.view.trailingAnchor.constraint(
                equalTo: view.trailingAnchor
            ),
            recentDrinksCollectionView.view.heightAnchor.constraint(
                equalToConstant: 280
            )
        ])
    }
    
    func addPopularLabelLayout() {
        popularCocktailsLabel.translatesAutoresizingMaskIntoConstraints = false
        screenContentContainerView.addSubview(popularCocktailsLabel)
        
        NSLayoutConstraint.activate([
            popularCocktailsLabel.topAnchor.constraint(
                equalTo: recentDrinksCollectionView.view.bottomAnchor,
                constant: 20
            ),
            popularCocktailsLabel.leadingAnchor.constraint(
                equalTo: rootStackView.leadingAnchor,
                constant: 20
            ),
            popularCocktailsLabel.trailingAnchor.constraint(
                equalTo: rootStackView.trailingAnchor,
                constant: -20
            ),
        ])
    }
    
    func addPopularDrinksTableViewLayout() {
        
    }
    
    func displayTwoFirstPopularDrinks(drinks: [DrinkModel]) {
        let firstPopularDrinkView = PopularDrinkView()
        rootStackView.addSubview(firstPopularDrinkView)
        
        NSLayoutConstraint.activate([
            firstPopularDrinkView.topAnchor.constraint(
                equalTo: popularCocktailsLabel.bottomAnchor,
                constant: 50
            ),
            firstPopularDrinkView.leadingAnchor.constraint(
                equalTo: rootStackView.leadingAnchor,
                constant: 20
            ),
            firstPopularDrinkView.trailingAnchor.constraint(
                equalTo: rootStackView.trailingAnchor,
                constant: -20
            ),
            firstPopularDrinkView.heightAnchor.constraint(
                equalToConstant: 300
            ),
            firstPopularDrinkView.bottomAnchor.constraint(
                equalTo: rootStackView.bottomAnchor
            )
        ])
        
//        firstPopularDrinkView.addContentToView(drink: drinks.first!)
    }
    
    func fetchAndDisplayPopularCocktails() {
        networkService
            .fetchPopularCocktails()
            .receive(on: DispatchQueue.main)
            .sink { completion in
                switch completion {
                case .failure(let error):
                    print(error)
                case .finished:
                    print("finished")
                }
            } receiveValue: { [weak self] value in
                self?.displayTwoFirstPopularDrinks(drinks: value)
            }
            .store(in: &observers)
    }
}

Thanks a lot for helping out, really!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

顾挽 2025-01-27 20:05:20

正如 @son 提到的,我建议使用 tableView ,甚至更好地使用 collectionView 而不是滚动视图,并将 UI 拆分为不同的单元格。
但如果您想要添加 scrollView ,那么请尝试以下操作。

  • 禁用 tableView 上的滚动。
  • 255 优先级为 tableView 添加高度。
  • 添加tableView.sizeToFit()

As @son mentioned, I would suggest to go with a tableView or even better with a collectionView instead of a scroll view and split the UI into different cells.
But if adding a scrollView is what you want then try the following.

  • Disable the scroll on the tableView.
  • Add height to the tableView with 255 priority.
  • Add tableView.sizeToFit().
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文