#ios #swift #uiimageview #uiimage #cornerradius
#iOS #swift #uiimageview #uiimage #cornerradius
Вопрос:
Из-за функции автоматической компоновки я попытался использовать UIImage corner radius вместо UIImageView. Радиус угла был слишком маленьким, когда фотография была слишком большой, например, 4k x 4k, но когда фотография была маленькой, например 500 x 500, радиус угла был слишком большим. Независимо от того, какого размера фотография, я хочу, чтобы радиус угла был 25. У вас есть какие-либо предложения?
Я попробовал следующий код из этого, но он не решает мою проблему.: https://newbedev.com/how-to-set-corner-radius-to-uiimage-not-uiimageview-in-ios-swift
Моя цель — сделать радиус угла равным размеру любой фотографии. Я протестировал название изображения «demo» размером 4000 x 4000, радиус угла равен 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 amp;amp; 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
}
}
Ответ №1:
Если вы используете debug для проверки UIImage
возвращаемых данных из вашей withRoundedCorners(...)
функции, вы увидите, что оба изображения на самом деле имеют одинаковые закругленные углы.
Проблема в том, что вы используете радиус 25
4k x 4k
изображения и радиус 25
500 x 500
изображения, но затем масштабируете их в соответствии с вашим представлением изображения.
Если вы измените режим содержимого вашего 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 amp;amp; 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
}
}
и пример контроллера, помещающий два представления изображений в представление стека, чтобы мы могли видеть два изображения разного размера одновременно:
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 )
Мы получаем этот вывод: