Swift:UIView 没有调整大小以适应内容

发布于 2025-01-15 02:29:09 字数 2435 浏览 4 评论 0原文

我正在构建一个应用程序,其中有一个评论列表。它们看起来像下面的截图 评论由于某种原因,我无法正确调整 UIView(从顶部浅灰色线到底部的灰色框)的大小。其中的白色文本(实际评论)超过 1 行,不应被截断,仅当达到最多 5 行时。问题是,当我没有为您在左侧看到的用户图像设置宽度和高度限制时,它就可以工作。删除这些将使视图正确调整大小,但会完全扭曲图像。图像顶部和底部锚点似乎粘在其水平 stackview 中的锚点上,这些锚点又用常量粘在 UIView 的顶部和底部锚点上,正如它应该的那样。但我没有说 UIView 应该始终具有图像的大小。我不明白为什么它不会比图像更大。

这是我的带有约束的结构的屏幕截图,希望它足够清楚: 结构

                NSLayoutConstraint.activate([
                //Main horizontal stackview (one Rating is the name of the UIView)
                hStack.leadingAnchor.constraint(equalTo: oneRating.leadingAnchor, constant: 23),
                hStack.trailingAnchor.constraint(equalTo: oneRating.trailingAnchor, constant: -18),
                hStack.topAnchor.constraint(equalTo: oneRating.topAnchor, constant: 15),
                hStack.bottomAnchor.constraint(equalTo: oneRating.bottomAnchor, constant: -13),
                
                reviewerImage.heightAnchor.constraint(equalToConstant: 80),
                reviewerImage.widthAnchor.constraint(equalToConstant: 80),
                                    
                //Limit the size of the Review Text to make sure its always at the same spot
                v2Stack.widthAnchor.constraint(equalToConstant: 220.0),
            ])
            
            //Verified checkmark constraints
            if isUserVerified == true {
                reviewerVerified.bottomAnchor.constraint(equalTo: reviewerImage.bottomAnchor).isActive = true
                reviewerVerified.trailingAnchor.constraint(equalTo: reviewerImage.trailingAnchor, constant: -2).isActive = true
            }

我知道这样很难提供帮助,但我已经尝试解决这个问题几天了,无论我做什么,我都无法让它发挥作用。

编辑: 根据请求,这是我必须将 ImageView 添加到我的 UIView() 的代码。

                //Add Image
            let reviewerImage = UIImageView()
            reviewerImage.contentMode = .scaleAspectFill
            reviewerImage.layer.cornerRadius = 40 //= 1/2 of width, because we hard coded the size
            reviewerImage.image = UIImage(named: "person-icon") //Placeholder. Download image here
            

reviewerImage.translatesAutoresizingMaskIntoConstraints = false VStack1.addArrangedSubview(reviewerImage)

I am building an app in which I have a list of Reviews. They look like the following screenshot
Review
For some reason, I am failing to make the UIView (Gray box from the top light gray line to the bottom one) resize correctly. The white text inside it (Actual review) is longer than 1 line and should not get cut off, only when reaching a maximum of say 5 lines. The thing is, it works when I don't set width and height constraints for the user image you see on the left side. Removing those will make the view resize correctly, but it will completely distort the image. The image top and botton anchors seem to be glued to the anchors in its horizontal stackview, which again are stuck to the UIView's top and botton anchors with constants, as it should. But nowhere do I say that the UIView should always have the size of the image. I don't get why it wont go bigger than the image.

Here is a screenshot of my structure with the constraints, hope it is clear enough:
Structure

                NSLayoutConstraint.activate([
                //Main horizontal stackview (one Rating is the name of the UIView)
                hStack.leadingAnchor.constraint(equalTo: oneRating.leadingAnchor, constant: 23),
                hStack.trailingAnchor.constraint(equalTo: oneRating.trailingAnchor, constant: -18),
                hStack.topAnchor.constraint(equalTo: oneRating.topAnchor, constant: 15),
                hStack.bottomAnchor.constraint(equalTo: oneRating.bottomAnchor, constant: -13),
                
                reviewerImage.heightAnchor.constraint(equalToConstant: 80),
                reviewerImage.widthAnchor.constraint(equalToConstant: 80),
                                    
                //Limit the size of the Review Text to make sure its always at the same spot
                v2Stack.widthAnchor.constraint(equalToConstant: 220.0),
            ])
            
            //Verified checkmark constraints
            if isUserVerified == true {
                reviewerVerified.bottomAnchor.constraint(equalTo: reviewerImage.bottomAnchor).isActive = true
                reviewerVerified.trailingAnchor.constraint(equalTo: reviewerImage.trailingAnchor, constant: -2).isActive = true
            }

I know it is hard to help like this but I have tried to fix this for a few days and no matter what I do, I can't get it to work.

EDIT:
As per request, here is the code I have to add the ImageView to my UIView().

                //Add Image
            let reviewerImage = UIImageView()
            reviewerImage.contentMode = .scaleAspectFill
            reviewerImage.layer.cornerRadius = 40 //= 1/2 of width, because we hard coded the size
            reviewerImage.image = UIImage(named: "person-icon") //Placeholder. Download image here
            

reviewerImage.translatesAutoresizingMaskIntoConstraints = false
VStack1.addArrangedSubview(reviewerImage)

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

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

发布评论

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

评论(1

初熏 2025-01-22 02:29:09

需要添加一些更多的大小限制,但是......

“技巧”是将您的“审阅者图像视图”嵌入到清晰的“容器”视图中。然后将图像视图限制到该容器的顶部。

这是一些接近您的布局的示例代码:

class JanView: UIView {
    
    let reviewerImageView: UIImageView = {
        let v = UIImageView()
        return v
    }()
    let starImageView: UIImageView = {
        let v = UIImageView()
        return v
    }()
    let chevronImageView: UIImageView = {
        let v = UIImageView()
        return v
    }()
    let nameLabel: UILabel = {
        let v = UILabel()
        return v
    }()
    let locLabel: UILabel = {
        let v = UILabel()
        return v
    }()
    let reviewTextLabel: UILabel = {
        let v = UILabel()
        v.numberOfLines = 5
        return v
    }()
    let publishedLabel: UILabel = {
        let v = UILabel()
        return v
    }()
    let starValueLabel: UILabel = {
        let v = UILabel()
        v.textAlignment = .center
        return v
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    func commonInit() -> Void {
        
        backgroundColor = .darkGray
        
        let outerHStack: UIStackView = {
            let v = UIStackView()
            v.spacing = 10
            return v
        }()
        let labelsVStack: UIStackView = {
            let v = UIStackView()
            v.axis = .vertical
            v.spacing = 0
            return v
        }()
        let starsAndChevronVStack: UIStackView = {
            let v = UIStackView()
            v.axis = .vertical
            v.spacing = 0
            return v
        }()
        let starsHStack: UIStackView = {
            let v = UIStackView()
            v.spacing = 0
            v.alignment = .center
            return v
        }()
        
        // review image container
        let reviewerImageContainer: UIView = {
            let v = UIView()
            return v
        }()
        
        [nameLabel, reviewTextLabel].forEach { v in
            v.textColor = .white
        }
        [locLabel, publishedLabel].forEach { v in
            v.textColor = .lightGray
        }
        starValueLabel.textColor = .systemYellow
        
        outerHStack.translatesAutoresizingMaskIntoConstraints = false
        
        addSubview(outerHStack)
        
        [nameLabel, locLabel, reviewTextLabel, publishedLabel].forEach { v in
            labelsVStack.addArrangedSubview(v)
        }
        [starValueLabel, starImageView].forEach { v in
            starsHStack.addArrangedSubview(v)
        }
        [starsHStack, chevronImageView].forEach { v in
            starsAndChevronVStack.addArrangedSubview(v)
        }
        [reviewerImageContainer, labelsVStack, starsAndChevronVStack].forEach { v in
            outerHStack.addArrangedSubview(v)
        }
        
        // add reviewer image view to container
        reviewerImageContainer.addSubview(reviewerImageView)
        reviewerImageView.translatesAutoresizingMaskIntoConstraints = false
        
        // specific properties
        reviewerImageView.contentMode = .scaleAspectFill
        reviewerImageView.layer.cornerRadius = 40
        reviewerImageView.layer.masksToBounds = true
        
        let cfg = UIImage.SymbolConfiguration(pointSize: 12.0, weight: .bold)
        if let img = UIImage(systemName: "star.fill", withConfiguration: cfg) {
            starImageView.image = img
        }
        starImageView.tintColor = .systemYellow
        starImageView.contentMode = .center
        starValueLabel.text = "4"
        
        if let img = UIImage(systemName: "chevron.right", withConfiguration: cfg) {
            chevronImageView.image = img
        }
        chevronImageView.tintColor = .lightGray
        chevronImageView.contentMode = .center
        
        nameLabel.text = "Name Here"
        locLabel.text = "Location Here"
        reviewTextLabel.text = "Review Text Here"
        publishedLabel.text = "Published Info Here"
        
        let g = self
        
        // to get the 2nd vertical stack view to fit (horizontally) to its content
        let sacWidth = starsAndChevronVStack.widthAnchor.constraint(equalToConstant: 10.0)
        sacWidth.priority = .defaultHigh
        
        let vPadding: CGFloat = 12
        let hPadding: CGFloat = 10
        
        NSLayoutConstraint.activate([
            
            outerHStack.topAnchor.constraint(equalTo: g.topAnchor, constant: vPadding),
            outerHStack.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: hPadding),
            outerHStack.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -hPadding),
            outerHStack.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -vPadding),
            
            reviewerImageView.widthAnchor.constraint(equalToConstant: 80.0),
            reviewerImageView.heightAnchor.constraint(equalTo: reviewerImageView.widthAnchor),
            
            // align the reviewer image view with the top of the container view
            reviewerImageView.topAnchor.constraint(equalTo: reviewerImageContainer.topAnchor),
            reviewerImageView.leadingAnchor.constraint(equalTo: reviewerImageContainer.leadingAnchor),
            reviewerImageView.trailingAnchor.constraint(equalTo: reviewerImageContainer.trailingAnchor),

            // give the stars value label a width, so it doesn't vary by text
            //  "5" is wider than "1" (or it may be "" ?)
            starValueLabel.widthAnchor.constraint(equalToConstant: 16.0),
            
            // make the star image view square
            starImageView.widthAnchor.constraint(equalTo: starImageView.heightAnchor),
            
            // make the stars HStack height equal to the stars label height
            starsHStack.heightAnchor.constraint(equalTo: starValueLabel.heightAnchor),
            
            sacWidth,
            
        ])
        
    }
    
}

和一个示例控制器:

class ReviewVC: UIViewController {
    let scrollView: UIScrollView = {
        let v = UIScrollView()
        return v
    }()
    let reviewsStack: UIStackView = {
        let v = UIStackView()
        v.axis = .vertical
        v.spacing = 0
        return v
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        [reviewsStack, scrollView].forEach { v in
            v.translatesAutoresizingMaskIntoConstraints = false
        }
        scrollView.addSubview(reviewsStack)
        view.addSubview(scrollView)
        
        let g = view.safeAreaLayoutGuide
        let contentG = scrollView.contentLayoutGuide
        let frameG = scrollView.frameLayoutGuide
        
        NSLayoutConstraint.activate([
            
            scrollView.topAnchor.constraint(equalTo: g.topAnchor, constant: 0.0),
            scrollView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
            scrollView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
            scrollView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0),
            
            reviewsStack.topAnchor.constraint(equalTo: contentG.topAnchor, constant: 0.0),
            reviewsStack.leadingAnchor.constraint(equalTo: contentG.leadingAnchor, constant: 0.0),
            reviewsStack.trailingAnchor.constraint(equalTo: contentG.trailingAnchor, constant: 0.0),
            reviewsStack.bottomAnchor.constraint(equalTo: contentG.bottomAnchor, constant: 0.0),

            reviewsStack.widthAnchor.constraint(equalTo: frameG.widthAnchor, constant: 0.0),
            
        ])
        
        let sampleLocs: [String] = [
            "Koblenz, Germany",
            "Westerwald, Germany",
            "Bonn, Germany",
            "Saarbrüken, Germany",
        ]
        let sampleRevs: [String] = [
            "For some reason, I am failing to make the UIView (Gray box from the top light gray line to the bottom one) resize correctly.",
            "A Single Line",
            "The white text inside it (Actual review) is longer than 1 line and should not get cut off, only when reaching a maximum of say 5 lines.",
            "The thing is, it works when I don't set width and height constraints for the user image you see on the left side. Removing those will make the view resize correctly, but it will completely distort the image.",
            "Another Single Line",
            "The image top and botton anchors seem to be glued to the anchors in its horizontal stackview, which again are stuck to the UIView's top and botton anchors with constants, as it should.",
        ]
        let sampleStars: [String] = [
            "5", "4", "3", "2", "1",
        ]
        for i in 0..<sampleRevs.count {
            let v = JanView()
            v.nameLabel.text = "Clara R."
            v.locLabel.text = sampleLocs[i % sampleLocs.count]
            v.reviewTextLabel.text = sampleRevs[i]
            v.publishedLabel.text = "Published less than 24h ago"
            v.starValueLabel.text = sampleStars[i % sampleStars.count]
            if let img = UIImage(named: "prof") {
                v.reviewerImageView.image = img
            }
            reviewsStack.addArrangedSubview(v)
            let sepView = UIView()
            sepView.backgroundColor = .lightGray
            sepView.heightAnchor.constraint(equalToConstant: 1.0).isActive = true
            reviewsStack.addArrangedSubview(sepView)
        }
        
    }
}

以下是它最终的外观:

在此处输入图像描述

You will need to add a few more sizing constraints, but...

The "trick" is to embed your "reviewer image view" in a clear "container" view. Then constrain the image view to the Top of that container.

Here is some sample code that gets close to your layout:

class JanView: UIView {
    
    let reviewerImageView: UIImageView = {
        let v = UIImageView()
        return v
    }()
    let starImageView: UIImageView = {
        let v = UIImageView()
        return v
    }()
    let chevronImageView: UIImageView = {
        let v = UIImageView()
        return v
    }()
    let nameLabel: UILabel = {
        let v = UILabel()
        return v
    }()
    let locLabel: UILabel = {
        let v = UILabel()
        return v
    }()
    let reviewTextLabel: UILabel = {
        let v = UILabel()
        v.numberOfLines = 5
        return v
    }()
    let publishedLabel: UILabel = {
        let v = UILabel()
        return v
    }()
    let starValueLabel: UILabel = {
        let v = UILabel()
        v.textAlignment = .center
        return v
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    func commonInit() -> Void {
        
        backgroundColor = .darkGray
        
        let outerHStack: UIStackView = {
            let v = UIStackView()
            v.spacing = 10
            return v
        }()
        let labelsVStack: UIStackView = {
            let v = UIStackView()
            v.axis = .vertical
            v.spacing = 0
            return v
        }()
        let starsAndChevronVStack: UIStackView = {
            let v = UIStackView()
            v.axis = .vertical
            v.spacing = 0
            return v
        }()
        let starsHStack: UIStackView = {
            let v = UIStackView()
            v.spacing = 0
            v.alignment = .center
            return v
        }()
        
        // review image container
        let reviewerImageContainer: UIView = {
            let v = UIView()
            return v
        }()
        
        [nameLabel, reviewTextLabel].forEach { v in
            v.textColor = .white
        }
        [locLabel, publishedLabel].forEach { v in
            v.textColor = .lightGray
        }
        starValueLabel.textColor = .systemYellow
        
        outerHStack.translatesAutoresizingMaskIntoConstraints = false
        
        addSubview(outerHStack)
        
        [nameLabel, locLabel, reviewTextLabel, publishedLabel].forEach { v in
            labelsVStack.addArrangedSubview(v)
        }
        [starValueLabel, starImageView].forEach { v in
            starsHStack.addArrangedSubview(v)
        }
        [starsHStack, chevronImageView].forEach { v in
            starsAndChevronVStack.addArrangedSubview(v)
        }
        [reviewerImageContainer, labelsVStack, starsAndChevronVStack].forEach { v in
            outerHStack.addArrangedSubview(v)
        }
        
        // add reviewer image view to container
        reviewerImageContainer.addSubview(reviewerImageView)
        reviewerImageView.translatesAutoresizingMaskIntoConstraints = false
        
        // specific properties
        reviewerImageView.contentMode = .scaleAspectFill
        reviewerImageView.layer.cornerRadius = 40
        reviewerImageView.layer.masksToBounds = true
        
        let cfg = UIImage.SymbolConfiguration(pointSize: 12.0, weight: .bold)
        if let img = UIImage(systemName: "star.fill", withConfiguration: cfg) {
            starImageView.image = img
        }
        starImageView.tintColor = .systemYellow
        starImageView.contentMode = .center
        starValueLabel.text = "4"
        
        if let img = UIImage(systemName: "chevron.right", withConfiguration: cfg) {
            chevronImageView.image = img
        }
        chevronImageView.tintColor = .lightGray
        chevronImageView.contentMode = .center
        
        nameLabel.text = "Name Here"
        locLabel.text = "Location Here"
        reviewTextLabel.text = "Review Text Here"
        publishedLabel.text = "Published Info Here"
        
        let g = self
        
        // to get the 2nd vertical stack view to fit (horizontally) to its content
        let sacWidth = starsAndChevronVStack.widthAnchor.constraint(equalToConstant: 10.0)
        sacWidth.priority = .defaultHigh
        
        let vPadding: CGFloat = 12
        let hPadding: CGFloat = 10
        
        NSLayoutConstraint.activate([
            
            outerHStack.topAnchor.constraint(equalTo: g.topAnchor, constant: vPadding),
            outerHStack.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: hPadding),
            outerHStack.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -hPadding),
            outerHStack.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -vPadding),
            
            reviewerImageView.widthAnchor.constraint(equalToConstant: 80.0),
            reviewerImageView.heightAnchor.constraint(equalTo: reviewerImageView.widthAnchor),
            
            // align the reviewer image view with the top of the container view
            reviewerImageView.topAnchor.constraint(equalTo: reviewerImageContainer.topAnchor),
            reviewerImageView.leadingAnchor.constraint(equalTo: reviewerImageContainer.leadingAnchor),
            reviewerImageView.trailingAnchor.constraint(equalTo: reviewerImageContainer.trailingAnchor),

            // give the stars value label a width, so it doesn't vary by text
            //  "5" is wider than "1" (or it may be "" ?)
            starValueLabel.widthAnchor.constraint(equalToConstant: 16.0),
            
            // make the star image view square
            starImageView.widthAnchor.constraint(equalTo: starImageView.heightAnchor),
            
            // make the stars HStack height equal to the stars label height
            starsHStack.heightAnchor.constraint(equalTo: starValueLabel.heightAnchor),
            
            sacWidth,
            
        ])
        
    }
    
}

and an example controller:

class ReviewVC: UIViewController {
    let scrollView: UIScrollView = {
        let v = UIScrollView()
        return v
    }()
    let reviewsStack: UIStackView = {
        let v = UIStackView()
        v.axis = .vertical
        v.spacing = 0
        return v
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        [reviewsStack, scrollView].forEach { v in
            v.translatesAutoresizingMaskIntoConstraints = false
        }
        scrollView.addSubview(reviewsStack)
        view.addSubview(scrollView)
        
        let g = view.safeAreaLayoutGuide
        let contentG = scrollView.contentLayoutGuide
        let frameG = scrollView.frameLayoutGuide
        
        NSLayoutConstraint.activate([
            
            scrollView.topAnchor.constraint(equalTo: g.topAnchor, constant: 0.0),
            scrollView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
            scrollView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
            scrollView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0),
            
            reviewsStack.topAnchor.constraint(equalTo: contentG.topAnchor, constant: 0.0),
            reviewsStack.leadingAnchor.constraint(equalTo: contentG.leadingAnchor, constant: 0.0),
            reviewsStack.trailingAnchor.constraint(equalTo: contentG.trailingAnchor, constant: 0.0),
            reviewsStack.bottomAnchor.constraint(equalTo: contentG.bottomAnchor, constant: 0.0),

            reviewsStack.widthAnchor.constraint(equalTo: frameG.widthAnchor, constant: 0.0),
            
        ])
        
        let sampleLocs: [String] = [
            "Koblenz, Germany",
            "Westerwald, Germany",
            "Bonn, Germany",
            "Saarbrüken, Germany",
        ]
        let sampleRevs: [String] = [
            "For some reason, I am failing to make the UIView (Gray box from the top light gray line to the bottom one) resize correctly.",
            "A Single Line",
            "The white text inside it (Actual review) is longer than 1 line and should not get cut off, only when reaching a maximum of say 5 lines.",
            "The thing is, it works when I don't set width and height constraints for the user image you see on the left side. Removing those will make the view resize correctly, but it will completely distort the image.",
            "Another Single Line",
            "The image top and botton anchors seem to be glued to the anchors in its horizontal stackview, which again are stuck to the UIView's top and botton anchors with constants, as it should.",
        ]
        let sampleStars: [String] = [
            "5", "4", "3", "2", "1",
        ]
        for i in 0..<sampleRevs.count {
            let v = JanView()
            v.nameLabel.text = "Clara R."
            v.locLabel.text = sampleLocs[i % sampleLocs.count]
            v.reviewTextLabel.text = sampleRevs[i]
            v.publishedLabel.text = "Published less than 24h ago"
            v.starValueLabel.text = sampleStars[i % sampleStars.count]
            if let img = UIImage(named: "prof") {
                v.reviewerImageView.image = img
            }
            reviewsStack.addArrangedSubview(v)
            let sepView = UIView()
            sepView.backgroundColor = .lightGray
            sepView.heightAnchor.constraint(equalToConstant: 1.0).isActive = true
            reviewsStack.addArrangedSubview(sepView)
        }
        
    }
}

Here is how it ends up looking:

enter image description here

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文