带有圆角的 UIImage

UIImage with the corner round itself

由于自动布局功能,我尝试使用 UIImage 角半径而不是 UIImageView。当照片太大时,例如4k x 4k,圆角半径太细,但是当照片较小时,例如500 x 500,圆角半径太大。不管照片多大,我都希望圆角半径为25,大家有什么建议吗?

我尝试了下面的代码,但它没有解决我的问题。: https://newbedev.com/how-to-set-corner-radius-to-uiimage-not-uiimageview-in-ios-swift

我的目标是让角半径等于任何照片的大小。我测试了图像名称“demo”,它是 4,000 x 4,000,角半径是 5,“demo2”是 500 x 500,角半径是 50。

这是我的完整代码:

class TheCountdownDetails: UIViewController {
    let photoPreview = UIImageView()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        photoPreview.translatesAutoresizingMaskIntoConstraints = false
        photoPreview.contentMode = .scaleAspectFit
        view.addSubview(photoPreview)
        photoPreview.topAnchor.constraint(equalTo: view.topAnchor, constant: 20).isActive = true
        photoPreview.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20).isActive = true
        photoPreview.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -20).isActive = true
        photoPreview.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20).isActive = true
    }
    
    override func viewDidLayoutSubviews() {
        photoPreview.image = UIImage(named: "demo")?.withRoundedCorners(radius: 25)
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
    }
}


extension UIImage {
    public func withRoundedCorners(radius: CGFloat? = nil) -> UIImage? {
        let maxRadius = min(size.width, size.height) / 2
        let cornerRadius: CGFloat
        if let radius = radius, radius > 0 && radius <= maxRadius {
            cornerRadius = radius
        } else {
            cornerRadius = maxRadius
        }
        UIGraphicsBeginImageContextWithOptions(size, false, scale)
        let rect = CGRect(origin: .zero, size: size)
        UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius).addClip()
        draw(in: rect)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }
}

如果您使用调试检查从您的 withRoundedCorners(...) 函数返回的 UIImage,您会发现这两个图像确实具有相同的圆角。

问题是您在 4k x 4k 图像上使用 25 的半径,在 500 x 500 图像上使用 25 的半径,但是 [= =52=]缩放它们以适合您的 imageView.

如果您将 imageView 的内容模式更改为:

photoPreview.contentMode = .topLeft

图像不会缩放,您会发现圆角半径相同。

因此,您需要在剪切圆角的同时缩放图像。

这是对您的扩展程序的修改:

extension UIImage {

    func withRoundedCorners(radius: CGFloat? = nil, targetSize: CGSize) -> UIImage {
        // First, determine the scale factor that preserves aspect ratio
        let widthRatio = targetSize.width / size.width
        let heightRatio = targetSize.height / size.height
        
        let scaleFactor = min(widthRatio, heightRatio)
        
        // Compute the new image size that preserves aspect ratio
        let scaledImageSize = CGSize(
            width: size.width * scaleFactor,
            height: size.height * scaleFactor
        )
        
        let maxRadius = min(scaledImageSize.width, scaledImageSize.height) / 2
        let cornerRadius: CGFloat
        if let radius = radius, radius > 0 && radius <= maxRadius {
            cornerRadius = radius
        } else {
            cornerRadius = maxRadius
        }

        let newRect: CGRect = CGRect(origin: .zero, size: scaledImageSize)
        
        let renderer = UIGraphicsImageRenderer(size: newRect.size)
        
        let scaledImage = renderer.image { _ in
            UIBezierPath(roundedRect: newRect, cornerRadius: cornerRadius).addClip()
            self.draw(in: newRect)
        }
        
        return scaledImage
    }

}

还有一个示例控制器,将两个 imageView 放在一个堆栈视图中,这样我们就可以同时看到两个不同大小的图像:

class TheCountdownDetails: UIViewController {
    
    let photoPreview1 = UIImageView()
    let photoPreview2 = UIImageView()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let stack = UIStackView()
        stack.axis = .vertical
        stack.distribution = .fillEqually
        stack.spacing = 20
        stack.translatesAutoresizingMaskIntoConstraints = false
        
        stack.addArrangedSubview(photoPreview1)
        stack.addArrangedSubview(photoPreview2)
        view.addSubview(stack)
        
        photoPreview1.contentMode = .center
        photoPreview2.contentMode = .center
        
        let g = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            stack.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
            stack.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
            stack.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
            stack.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -20.0),
        ])

    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        // image views are in a stack view,
        //  so we need to force their layouts
        //  before asking for their frames
        photoPreview1.setNeedsLayout()
        photoPreview1.layoutIfNeeded()
        photoPreview2.setNeedsLayout()
        photoPreview2.layoutIfNeeded()
        
        guard let img1 = UIImage(named: "image4kx4k") else { return }
        guard let img2 = UIImage(named: "image500x500") else { return }
        
        let img1r = img1.withRoundedCorners(radius: 25, targetSize: photoPreview1.frame.size)
        let img2r = img2.withRoundedCorners(radius: 25, targetSize: photoPreview2.frame.size)

        photoPreview1.image = img1r
        photoPreview2.image = img2r

    }
    
}

使用这张4kx4k图片(原始来源:https://images.wallpaperscraft.com/image/single/night_city_aerial_view_city_lights_130879_4000x4000.jpg):

和这张500x500图片(原始来源:https://www.digitalphotopix.com/wp-content/uploads/2011/02/blue-lake.jpg

我们得到这个输出: