简体   繁体   English

以编程方式添加 NSLayout 约束的问题

[英]Problem with adding NSLayout constraints programmatically

I'm having an issue with using greaterThanOrEqualTo constraint with my current project.我在当前项目中使用 GreaterThanOrEqualTo 约束时遇到问题。

在此处输入图片说明

What I need is making the height of the cell dynamic, so I need the title of recipes to be multi-lines based on what returns from the API, and make the favorite button take constant constraint from trailingAnchor.我需要的是使单元格的高度动态化,因此我需要基于从 API 返回的内容将菜谱的标题设为多行,并使收藏按钮从 trailingAnchor 获得恒定约束。 But what I got is in the screenshot.但我得到的是截图。

If I used XIB I would have done it easily but it's my first time making UI programmatically.如果我使用 XIB,我会很容易完成,但这是我第一次以编程方式制作 UI。

HomeTableViewCell: HomeTableViewCell:

class HomeTableViewCell: UITableViewCell {

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        layoutUI()
        selectionStyle = .none
        self.backgroundColor = .clear
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    lazy var containerView: UIView = {
        let containerView = UIView()
        containerView.backgroundColor = .white
        containerView.translatesAutoresizingMaskIntoConstraints = false
        containerView.layer.cornerRadius = 8.0
//        containerView.clipsToBounds = true
        return containerView
    }()

    lazy var foodImage: UIImageView = {
        let foodImage = UIImageView()
        foodImage.translatesAutoresizingMaskIntoConstraints = false
        foodImage.contentMode = .scaleAspectFill
        foodImage.clipsToBounds = true
        foodImage.layer.cornerRadius = 8.0
        return foodImage
    }()

    lazy var favouriteButton: UIButton = {
        var favouriteButton = UIButton()
        favouriteButton.setImage(UIImage(systemName: "heart"), for: .normal)
        favouriteButton.tintColor = .red
        favouriteButton.translatesAutoresizingMaskIntoConstraints = false
        return favouriteButton
    }()

    lazy var foodTitle: UILabel = {
        let foodTitle = UILabel()
        foodTitle.textColor = .CustomGreen()
        foodTitle.numberOfLines = 0
        foodTitle.translatesAutoresizingMaskIntoConstraints = false
        return foodTitle
    }()

    func setupContainerView() {
        NSLayoutConstraint.activate([
            containerView.topAnchor.constraint(equalTo: topAnchor, constant: 16),
            containerView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -16),
            containerView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
            containerView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
        ])
    }

    func setupFoodImage() {
        NSLayoutConstraint.activate([
            foodImage.topAnchor.constraint(equalTo: containerView.topAnchor),
            foodImage.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
            foodImage.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
            foodImage.heightAnchor.constraint(equalToConstant: self.bounds.width / 1.8)
        ])
    }

    func setupFoodTitle() {
        NSLayoutConstraint.activate([
            foodTitle.topAnchor.constraint(equalTo: foodImage.bottomAnchor, constant: 16),
            foodTitle.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: -16),
            foodTitle.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 16),
            foodTitle.trailingAnchor.constraint(greaterThanOrEqualTo: favouriteButton.leadingAnchor, constant: -16)

        ])
    }

    func setupFavouriteButtonConstraints() {
        NSLayoutConstraint.activate([
            favouriteButton.centerYAnchor.constraint(equalTo: foodTitle.centerYAnchor),
            favouriteButton.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -16)
        ])
    }

    func addSubview() {
        addSubview(containerView)
        containerView.addSubview(foodImage)
        containerView.addSubview(foodTitle)
        containerView.addSubview(favouriteButton)
    }

    func layoutUI() {
        addSubview()
        setupContainerView()
        setupFoodImage()
        setupFoodTitle()
        setupFavouriteButtonConstraints()
    }

}

HomeView:主页视图:

class HomeView: UIView {

    var recipes: Recipes?
    var recipesDetails = [Recipe]()
    let indicator = ActivityIndicator()

    let categories = ["italian food", "chinese food", "korean food", "italian food", "chinese food", "korean food", "italian food", "chinese food", "korean food", "italian food", "chinese food", "korean food"]

    override init( frame: CGRect) {
        super.init(frame: frame)
        layoutUI()
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    lazy var foodTableView: UITableView = {
        let foodTableView = UITableView()
        foodTableView.translatesAutoresizingMaskIntoConstraints = false
        foodTableView.backgroundColor = #colorLiteral(red: 0.9568627451, green: 0.9568627451, blue: 0.9568627451, alpha: 1)
        foodTableView.delegate = self
        foodTableView.dataSource = self
        foodTableView.register(CategoriesTableViewCellCollectionViewCell.self, forCellReuseIdentifier: "CategoriesTableViewCellCollectionViewCell")
        foodTableView.register(HomeTableViewCell.self, forCellReuseIdentifier: "HomeTableViewCell")
        foodTableView.rowHeight = UITableView.automaticDimension
//        foodTableView.estimatedRowHeight = 100
        foodTableView.showsVerticalScrollIndicator = false
        foodTableView.separatorStyle = .none
        return foodTableView
    }()

    func setupFoodTableView() {
        NSLayoutConstraint.activate([
            foodTableView.topAnchor.constraint(equalTo: topAnchor),
            foodTableView.bottomAnchor.constraint(equalTo: bottomAnchor),
            foodTableView.leadingAnchor.constraint(equalTo: leadingAnchor),
            foodTableView.trailingAnchor.constraint(equalTo: trailingAnchor)
        ])
    }

    func addSubview() {
        addSubview(foodTableView)
    }

    func layoutUI() {
        indicator.setupIndicatorView(self, containerColor: .customDarkGray(), indicatorColor: .white)
        addSubview()
        setupFoodTableView()
        fetchData()

    }

    func fetchData() {
        AF.request("apilink.com").responseJSON { (response) in
            if let error = response.error {
                print(error)
            }
            do {
                if let data = response.data {
                    self.recipes = try JSONDecoder().decode(Recipes.self, from: data)
                    self.recipesDetails = self.recipes?.recipes ?? []
                    DispatchQueue.main.async {
                        self.foodTableView.reloadData()
                    }
                }

            } catch {
                print(error)
            }
            self.indicator.hideIndicatorView()
        }
    }

}

extension HomeView: UITableViewDelegate, UITableViewDataSource {

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

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        if indexPath.row == 0 {
            let cell = tableView.dequeueReusableCell(withIdentifier: "CategoriesTableViewCellCollectionViewCell", for: indexPath) as! CategoriesTableViewCellCollectionViewCell
//            cell.layoutIfNeeded()
            cell.collectionView.reloadData()
            return cell
        }

        let cell = tableView.dequeueReusableCell(withIdentifier: "HomeTableViewCell", for: indexPath) as! HomeTableViewCell
        let url = URL(string: recipesDetails[indexPath.row].image ?? "Error")
        cell.foodImage.kf.setImage(with: url)
        cell.foodTitle.text = recipesDetails[indexPath.row].title
//        cell.layoutIfNeeded()
        return cell

    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        if indexPath.row == 0 {
            return 160
        } else {
            return UITableView.automaticDimension
        }

    }

}

You can change the foodTitleLabel trailing to equalTo will fix the issue.您可以将尾随的foodTitleLabel更改为equalTo将解决该问题。 with the label and the favorite button.带有标签和收藏夹按钮。 but if still you don't want that to be equalTo then in this case as you are already using the negative values you know that you have not reversed your constraints you have to use lessThanOrEqualTo to achieve what you want to do.但是,如果您仍然不希望它成为equalTo,那么在这种情况下,因为您已经在使用负值,您知道您没有反转约束,您必须使用lessThanOrEqualTo来实现您想要做的事情。 it's the exact reverse of what you might do in a storyboard.这与您在故事板中所做的完全相反。

func setupFoodTitle() {
    NSLayoutConstraint.activate([
        foodTitle.topAnchor.constraint(equalTo: foodImage.bottomAnchor, constant: 16),
        foodTitle.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: -16),
        foodTitle.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 16),
        foodTitle.trailingAnchor.constraint(lessThanOrEqualTo: favouriteButton.leadingAnchor, constant: -16)

    ])
}

Also in the Home view where you are setting your tablview use use these you already have the code that takes care of automatic dymintions but you have commented out the estimated height un comment that as well同样在您设置 tablview 的 Home 视图中使用这些,您已经拥有处理自动 dymintions 的代码,但您也注释掉了估计的高度 un 注释

foodTableView.estimatedRowHeight = 100
foodTableView.rowHeight = UITableView.automaticDimension

Update: You have to change the content hugging and content comprision priority on the foodTitleLabel更新:您必须更改 foodTitleLabel 上的内容拥抱和内容压缩优先级

foodTitle.setContentHuggingPriority(.init(240.0), for: .horizontal)
foodTitle.setContentCompressionResistancePriority(.init(740.0), for: .horizontal)

Content hugging priority: Sets the priority with which a view resists being made larger than its intrinsic size.内容拥抱优先级:设置视图抵抗使其大于其固有大小的优先级。

Content Compression priority: Sets the priority with which a view resists being made smaller than its intrinsic size.内容压缩优先级:设置视图阻止小于其固有大小的优先级。

That's why the layout at the moment trys to make you're favorite button smaller than the title Label这就是为什么目前的布局试图让你最喜欢的按钮比标题标签小

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM