无法通过CGRect来定位UIImage。

huangapple go评论62阅读模式
英文:

Can't position UIImage through CGRect

问题

我正在尝试构建一个社交媒体用户个人资料的UIView,但在一开始就遇到了问题 - 当我尝试将用户图像(UIImage)添加到我的UIView时。以下是我尝试使用的代码:

import UIKit

class ProfileHeaderView: UIView {
    
    private lazy var profileImage: UIImageView = {
        let imageView = UIImageView(image: UIImage(named: "hipsterCat"))
        
        // 让图像变成圆形
        imageView.layer.cornerRadius = imageView.frame.size.width / 2
        imageView.clipsToBounds = true
        
        imageView.layer.borderColor = UIColor.white.cgColor
        imageView.layer.borderWidth = 3
                
        return imageView
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupView()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupView()
    }
    
    private func setupView() {
        backgroundColor = .lightGray
        addSubview(profileImage)
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        profileImage.frame = CGRect(
            x: bounds.midX - 64,
            y: bounds.midY - 64,
            width: 128,
            height: 128
        )
    }
}

我的任务是使用CGRect在父视图上定位UIImage,但一旦运行项目,它就不会显示在屏幕上(只有浅灰色背景可见)。

UIImageView没问题,当注释掉layoutSubviews()重写时图像会出现,但它没有定位。

英文:

I'm trying to build a UIView of Social Media User's Profile and got stuck right in the beginning - when adding a User Image (UIImage) to my UIView. Here's the code I'm trying to use:

import UIKit

class ProfileHeaderView: UIView {
    
    private lazy var profileImage: UIImageView = {
        let imageView = UIImageView(image: UIImage(named: "hipsterCat"))
        
        // Making Image Round
        imageView.layer.cornerRadius = imageView.frame.size.width / 2
        imageView.clipsToBounds = true
        
        imageView.layer.borderColor = UIColor.white.cgColor
        imageView.layer.borderWidth = 3
                
        return imageView
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupView()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupView()
    }
    
    private func setupView() {
        backgroundColor = .lightGray
        addSubview(profileImage)
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        profileImage.frame = CGRect(
            x: bounds.midX - 64,
            y: bounds.midY - 64,
            width: 128,
            height: 128
        )
    }
}

My task is to use CGRect to position UIImage on the superView, yet once I run the project it just doesn't appear on the screen (only light gray background is there).

UIImageView is all right, the image appears when commenting layoutSubviews() override but it's not positioned.

答案1

得分: 1

有多个可能出错的地方。你看到的最奇怪的结果是,一旦调整大小,你就完全看不到图像。

我最好的猜测是你也在ProfileHeaderView实例上设置了frame。请注意,有两个用于布局视图的API;一个是使用frame,另一个是自动布局。从自动布局中将调用一个名为layoutSubviews的方法。但是使用frame时,只会调用frame。因此,你可能漏掉了另一个重写。

尝试添加以下内容:

override var frame: CGRect {
    didSet {
        updateImagePosition()
    }
}

override func layoutSubviews() {
    super.layoutSubviews()

    updateImagePosition()
}

private func updateImagePosition() {
    profileImage.contentMode = .scaleAspectFit
    profileImage.frame = CGRect(
        x: bounds.midX - 64,
        y: bounds.midY - 64,
        width: 128,
        height: 128
    )
    profileImage.layer.cornerRadius = 64
}

除了添加对frame的重写之外,我还添加了两个选项,以确定视图的content mode。你可能想将其移到设置方法中,但如果保留在这里也不太糟糕。另一个是设置圆角半径,这肯定需要在这里设置。两者都由@HangarRash提到。

最后,公平地说,最好有类似以下的内容:

@IBDesignable
class ProfileHeaderView: UIView {

    @IBInspectable
    private var imageName: String = "hipsterCat" {
        didSet {
            profileImage.image = UIImage(named: imageName)
        }
    }
    @IBInspectable
    private var imageRadius: CGFloat = 64 {
        didSet {
            updateImagePosition()
        }
    }

    private lazy var profileImage: UIImageView = {
        let imageView = UIImageView(image: UIImage(named: imageName))
        imageView.contentMode = .scaleAspectFit
        imageView.clipsToBounds = true
        imageView.layer.borderColor = UIColor.white.cgColor
        imageView.layer.borderWidth = 3
        return imageView
    }()

    override var frame: CGRect {
        didSet {
            updateImagePosition()
        }
    }

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

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupView()
    }

    private func setupView() {
        backgroundColor = .lightGray
        addSubview(profileImage)
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        updateImagePosition()
    }

    private func updateImagePosition() {
        profileImage.frame = CGRect(
            x: bounds.midX - imageRadius,
            y: bounds.midY - imageRadius,
            width: imageRadius*2.0,
            height: imageRadius*2.0
        )
        profileImage.layer.cornerRadius = imageRadius
    }
}
英文:

There are multiple things that might have gotten wrong. The strangest result you are seeing is that you don't see the image at all once it is resized.

My best guess is that you are also setting the frame for the ProfileHeaderView instance. Note that there are 2 APIs for lay outing the views; one is using frame and the other one is auto layout. From auto layout a method layoutSubviews will be called. But using frame then only frame will be called. So you may be missing another override.

Try to add the following:

override var frame: CGRect {
    didSet {
        updateImagePosition()
    }
}

override func layoutSubviews() {
    super.layoutSubviews()
    
    updateImagePosition()
}

private func updateImagePosition() {
    profileImage.contentMode = .scaleAspectFit
    profileImage.frame = CGRect(
        x: bounds.midX - 64,
        y: bounds.midY - 64,
        width: 128,
        height: 128
    )
    profileImage.layer.cornerRadius = 64
}

Next to adding an override for frame I have also added to option to determine content mode of your view. You might want to move that into your setup method but it is not too bad if it stays here. And the other one is setting corner radius which for sure needs to be set in here. Both mentioned by @HangarRash.

In the end it would be nice to have something like the following to be fair:

@IBDesignable
class ProfileHeaderView: UIView {
    
    @IBInspectable
    private var imageName: String = "hipsterCat" {
        didSet {
            profileImage.image = UIImage(named: imageName)
        }
    }
    @IBInspectable
    private var imageRadius: CGFloat = 64 {
        didSet {
            updateImagePosition()
        }
    }
    
    private lazy var profileImage: UIImageView = {
        let imageView = UIImageView(image: UIImage(named: imageName))
        imageView.contentMode = .scaleAspectFit
        imageView.clipsToBounds = true
        imageView.layer.borderColor = UIColor.white.cgColor
        imageView.layer.borderWidth = 3
        return imageView
    }()
    
    override var frame: CGRect {
        didSet {
            updateImagePosition()
        }
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupView()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupView()
    }
    
    private func setupView() {
        backgroundColor = .lightGray
        addSubview(profileImage)
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        updateImagePosition()
    }
    
    private func updateImagePosition() {
        profileImage.frame = CGRect(
            x: bounds.midX - imageRadius,
            y: bounds.midY - imageRadius,
            width: imageRadius*2.0,
            height: imageRadius*2.0
        )
        profileImage.layer.cornerRadius = imageRadius
    }
}

答案2

得分: 0

我遵循了@HangarRash在评论中的建议,并成功解决了问题。我所做的是在layoutSubViews中设置了圆角半径(使图像变成圆形),同时还向UIImageView添加了.scaleAspectFill。最终的代码如下:

import UIKit

class ProfileHeaderView: UIView {
    
    private lazy var profileImage: UIImageView = {
        let imageView = UIImageView(image: UIImage(named: "hipsterCat"))
        imageView.contentMode = .scaleAspectFill
        
        return imageView
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupView()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupView()
    }
    
    private func setupView() {
        backgroundColor = .lightGray
        addSubview(profileImage)
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        profileImage.frame = CGRect(
            x: bounds.minX + 16,
            y: bounds.minY + 16,
            width: 128,
            height: 128
        )
        
        //Making image round
        profileImage.layer.cornerRadius = profileImage.frame.size.width / 2
        profileImage.clipsToBounds = true
        
        profileImage.layer.borderColor = UIColor.white.cgColor
        profileImage.layer.borderWidth = 3
    }
}
英文:

I was following @HangarRash advice from the comments and managed to fix the issue. The thing I did is setting corner radius (and making image rounded) in layoutSubViews while also adding .scaleAspectFill to UIImageView. The final code is:

import UIKit

class ProfileHeaderView: UIView {
    
    private lazy var profileImage: UIImageView = {
        let imageView = UIImageView(image: UIImage(named: "hipsterCat"))
        imageView.contentMode = .scaleAspectFit
        
        return imageView
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupView()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupView()
    }
    
    private func setupView() {
        backgroundColor = .lightGray
        addSubview(profileImage)
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        profileImage.frame = CGRect(
            x: bounds.minX + 16,
            y: bounds.minY + 16,
            width: 128,
            height: 128
        )
        
        //Making image round
        profileImage.layer.cornerRadius = profileImage.frame.size.width / 2
        profileImage.clipsToBounds = true
        
        profileImage.layer.borderColor = UIColor.white.cgColor
        profileImage.layer.borderWidth = 3
    }
}

huangapple
  • 本文由 发表于 2023年5月25日 06:59:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/76327893.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定