带有圆角的 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)
我们得到这个输出:
由于自动布局功能,我尝试使用 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)
我们得到这个输出: